LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.8 % 223 207
Test Date: 2026-07-11 15:47:05 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-compile.h"
      20              : #include "fold-const.h"
      21              : #include "rust-compile-item.h"
      22              : #include "rust-compile-implitem.h"
      23              : #include "rust-hir-type-bounds.h"
      24              : #include "rust-compile-type.h"
      25              : #include "rust-substitution-mapper.h"
      26              : #include "rust-type-util.h"
      27              : #include "rust-session-manager.h"
      28              : 
      29              : namespace Rust {
      30              : namespace Compile {
      31              : 
      32         4290 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
      33         4290 :   : crate (crate), ctx (ctx)
      34         4290 : {}
      35              : 
      36         4290 : CompileCrate::~CompileCrate () {}
      37              : 
      38              : void
      39         4290 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
      40              : {
      41         4290 :   CompileCrate c (crate, ctx);
      42         4290 :   c.go ();
      43         4290 : }
      44              : 
      45              : void
      46         4290 : CompileCrate::go ()
      47              : {
      48        21994 :   for (auto &item : crate.get_items ())
      49        17704 :     CompileItem::compile (item.get (), ctx);
      50         4290 :   auto crate_type
      51         4290 :     = Rust::Session::get_instance ().options.target_data.get_crate_type ();
      52         4290 :   if (crate_type == TargetOptions::CrateType::PROC_MACRO)
      53            0 :     add_proc_macro_symbols ();
      54         4290 : }
      55              : 
      56              : // Shared methods in compilation
      57              : 
      58              : tree
      59        44198 : HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval,
      60              :                                TyTy::BaseType *lval, location_t lvalue_locus,
      61              :                                location_t rvalue_locus)
      62              : {
      63        44198 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
      64        44198 :   bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
      65        44198 :   if (ok)
      66              :     {
      67        30972 :       rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
      68              :     }
      69              : 
      70        44198 :   return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
      71              : }
      72              : 
      73              : tree
      74        50241 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
      75              :                                 TyTy::BaseType *lval, location_t lvalue_locus,
      76              :                                 location_t rvalue_locus)
      77              : {
      78        50241 :   if (rvalue == error_mark_node)
      79              :     return error_mark_node;
      80              : 
      81        50146 :   TyTy::BaseType *actual = rval->destructure ();
      82        50146 :   TyTy::BaseType *expected = lval->destructure ();
      83              : 
      84        50146 :   if (expected->get_kind () == TyTy::TypeKind::REF)
      85              :     {
      86              :       // this is a dyn object
      87         4331 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
      88              :         {
      89              :           return rvalue;
      90              :         }
      91              : 
      92              :       // bad coercion... of something to a reference
      93         1915 :       if (actual->get_kind () != TyTy::TypeKind::REF)
      94            1 :         return error_mark_node;
      95              : 
      96         1914 :       const TyTy::ReferenceType *exp
      97              :         = static_cast<const TyTy::ReferenceType *> (expected);
      98         1914 :       const TyTy::ReferenceType *act
      99              :         = static_cast<const TyTy::ReferenceType *> (actual);
     100              : 
     101         1914 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     102         1914 :       tree coerced
     103         1914 :         = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
     104              :                           lvalue_locus, rvalue_locus);
     105         1914 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     106              :         return coerced;
     107              : 
     108         1914 :       return address_expression (coerced, rvalue_locus);
     109              :     }
     110        45815 :   else if (expected->get_kind () == TyTy::TypeKind::POINTER)
     111              :     {
     112              :       // this is a dyn object
     113         5263 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
     114              :         {
     115              :           return rvalue;
     116              :         }
     117              : 
     118              :       // bad coercion... of something to a reference
     119         4129 :       bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
     120         4129 :                             || actual->get_kind () == TyTy::TypeKind::POINTER;
     121         4129 :       if (!valid_coercion)
     122            0 :         return error_mark_node;
     123              : 
     124         4129 :       const TyTy::PointerType *exp
     125              :         = static_cast<const TyTy::PointerType *> (expected);
     126              : 
     127         4129 :       TyTy::BaseType *actual_base = nullptr;
     128         4129 :       if (actual->get_kind () == TyTy::TypeKind::REF)
     129              :         {
     130          268 :           const TyTy::ReferenceType *act
     131              :             = static_cast<const TyTy::ReferenceType *> (actual);
     132              : 
     133          268 :           actual_base = act->get_base ();
     134              :         }
     135         3861 :       else if (actual->get_kind () == TyTy::TypeKind::POINTER)
     136              :         {
     137         3861 :           const TyTy::PointerType *act
     138              :             = static_cast<const TyTy::PointerType *> (actual);
     139              : 
     140         3861 :           actual_base = act->get_base ();
     141              :         }
     142         4129 :       rust_assert (actual_base != nullptr);
     143              : 
     144         4129 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     145         4129 :       tree coerced
     146         4129 :         = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
     147              :                           lvalue_locus, rvalue_locus);
     148              : 
     149         4129 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     150              :         return coerced;
     151              : 
     152         4129 :       return address_expression (coerced, rvalue_locus);
     153              :     }
     154        40552 :   else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
     155              :     {
     156          852 :       if (actual->get_kind () != TyTy::TypeKind::ARRAY)
     157            0 :         return error_mark_node;
     158              : 
     159          852 :       tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
     160          852 :       tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
     161          852 :       if (!verify_array_capacities (tree_lval_type, tree_rval_type,
     162              :                                     lvalue_locus, rvalue_locus))
     163            0 :         return error_mark_node;
     164              :     }
     165        39700 :   else if (expected->get_kind () == TyTy::TypeKind::SLICE)
     166              :     {
     167              :       // bad coercion
     168            0 :       bool valid_coercion = actual->get_kind () == TyTy::TypeKind::SLICE
     169            0 :                             || actual->get_kind () == TyTy::TypeKind::ARRAY;
     170            0 :       if (!valid_coercion)
     171            0 :         return error_mark_node;
     172              : 
     173              :       // nothing to do here
     174            0 :       if (actual->get_kind () == TyTy::TypeKind::SLICE)
     175              :         return rvalue;
     176              : 
     177              :       // return an unsized coercion
     178            0 :       Resolver::Adjustment unsize_adj (
     179            0 :         Resolver::Adjustment::AdjustmentType::UNSIZE, actual, expected);
     180            0 :       return resolve_unsized_adjustment (unsize_adj, rvalue, rvalue_locus);
     181              :     }
     182              : 
     183              :   return rvalue;
     184              : }
     185              : 
     186              : tree
     187          169 : HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
     188              :                                       const TyTy::DynamicObjectType *ty,
     189              :                                       location_t locus)
     190              : {
     191              :   // DST's get wrapped in a pseudo reference that doesnt exist...
     192          169 :   const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
     193          169 :                                TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
     194              : 
     195          169 :   tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
     196          169 :   tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
     197          169 :   tree vtableptr_field = DECL_CHAIN (dynamic_object_fields);
     198          169 :   rust_assert (TREE_CODE (TREE_TYPE (vtableptr_field)) == POINTER_TYPE);
     199          169 :   rust_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (vtableptr_field))));
     200              : 
     201              :   //' this assumes ordering and current the structure is
     202              :   // __trait_object_ptr
     203              :   // __trait_vtable_ptr
     204              : 
     205          169 :   auto probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
     206          169 :   tree address_of_compiled_ref = null_pointer_node;
     207          169 :   if (!actual->is_unit ())
     208          154 :     address_of_compiled_ref = address_expression (compiled_ref, locus);
     209              : 
     210          169 :   size_t dyn_obj_ty_hash = TYPE_HASH (dynamic_object);
     211          169 :   size_t compiled_ref_ty_hash = TYPE_HASH (TREE_TYPE (compiled_ref));
     212          169 :   auto pair = std::make_pair (compiled_ref_ty_hash, dyn_obj_ty_hash);
     213              : 
     214          169 :   tree vtable_decl = NULL_TREE;
     215          169 :   Bvariable *cached_vtable = nullptr;
     216          169 :   if (ctx->lookup_vtable (pair, &cached_vtable))
     217              :     {
     218            7 :       vtable_decl = Backend::var_expression (cached_vtable, locus);
     219              :     }
     220              :   else
     221              :     {
     222          162 :       tree compiled_ref_ty = TREE_TYPE (compiled_ref);
     223              :       // drop_in_place is not implemented yet!
     224          162 :       tree drop_in_place = null_pointer_node;
     225          162 :       tree size = TYPE_SIZE_UNIT (compiled_ref_ty);
     226          162 :       tree align
     227          162 :         = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (compiled_ref_ty));
     228              : 
     229          162 :       std::vector<tree> vtable_ctor_elems;
     230          162 :       vtable_ctor_elems.emplace_back (drop_in_place);
     231          162 :       vtable_ctor_elems.emplace_back (size);
     232          162 :       vtable_ctor_elems.emplace_back (align);
     233              : 
     234          384 :       for (auto &bound : ty->get_object_items ())
     235              :         {
     236          222 :           const Resolver::TraitItemReference *item = bound.first;
     237          222 :           const TyTy::TypeBoundPredicate *predicate = bound.second;
     238              : 
     239          222 :           auto address
     240          222 :             = compute_address_for_trait_item (item, predicate,
     241              :                                               probed_bounds_for_receiver,
     242          222 :                                               actual, actual, locus);
     243          222 :           vtable_ctor_elems.push_back (address);
     244          162 :         }
     245          162 :       tree vtable_ctor
     246          162 :         = Backend::constructor_expression (TREE_TYPE (
     247              :                                              TREE_TYPE (vtableptr_field)),
     248              :                                            false, vtable_ctor_elems, -1, locus);
     249              : 
     250          162 :       std::string vtable_name = "__R_vtable_"
     251          324 :                                 + std::to_string (compiled_ref_ty_hash) + "_"
     252          324 :                                 + std::to_string (dyn_obj_ty_hash);
     253              : 
     254              :       // https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_mir/src/interpret/traits.rs#L17
     255          162 :       Bvariable *vtable_bvar
     256          162 :         = Backend::global_variable (vtable_name, vtable_name,
     257          162 :                                     TREE_TYPE (vtable_ctor), false, true, true,
     258              :                                     locus);
     259          162 :       Backend::global_variable_set_init (vtable_bvar, vtable_ctor);
     260          162 :       ctx->push_var (vtable_bvar);
     261          162 :       ctx->insert_vtable (pair, vtable_bvar);
     262              : 
     263          162 :       vtable_decl = Backend::var_expression (vtable_bvar, locus);
     264              : 
     265          162 :       DECL_ARTIFICIAL (vtable_decl) = 1;
     266          162 :       TREE_READONLY (vtable_decl) = 1;
     267          162 :       DECL_IGNORED_P (vtable_decl) = 1;
     268          162 :     }
     269              : 
     270          169 :   tree address_of_vtable = build_fold_addr_expr_loc (locus, vtable_decl);
     271          169 :   std::vector<tree> dyn_ctor = {address_of_compiled_ref, address_of_vtable};
     272          169 :   return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
     273          169 :                                           locus);
     274          169 : }
     275              : 
     276              : tree
     277          222 : HIRCompileBase::compute_address_for_trait_item (
     278              :   const Resolver::TraitItemReference *ref,
     279              :   const TyTy::TypeBoundPredicate *predicate,
     280              :   std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
     281              :     &receiver_bounds,
     282              :   const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
     283              : {
     284          222 :   tl::optional<TyTy::TypeBoundPredicateItem> predicate_item
     285          222 :     = predicate->lookup_associated_item (ref->get_identifier ());
     286          222 :   rust_assert (predicate_item.has_value ());
     287              : 
     288              :   // This is the expected end type
     289          222 :   TyTy::BaseType *trait_item_type
     290          222 :     = predicate_item->get_tyty_for_receiver (root);
     291          222 :   rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
     292          222 :   TyTy::FnType *trait_item_fntype
     293              :     = static_cast<TyTy::FnType *> (trait_item_type);
     294              : 
     295              :   // Loop through the list of trait references and impls that we satisfy.
     296              :   // We are looking for one that has an implementation for "ref", a trait
     297              :   // item.
     298          323 :   for (auto &item : receiver_bounds)
     299              :     {
     300          305 :       HIR::ImplBlock *impl_block = item.second;
     301          305 :       rust_assert (impl_block != nullptr);
     302              : 
     303              :       // Checks for empty impl blocks, triggered by Sized trait.
     304          305 :       if (!impl_block->has_type ())
     305          101 :         continue;
     306              : 
     307              :       // Lookup type for potentially associated impl.
     308          294 :       HIR::Type &self_type_path = impl_block->get_type ();
     309              : 
     310              :       // Convert HIR::Type to TyTy::BaseType
     311          294 :       TyTy::BaseType *self = nullptr;
     312          294 :       bool ok = ctx->get_tyctx ()->lookup_type (
     313          294 :         self_type_path.get_mappings ().get_hirid (), &self);
     314              : 
     315          294 :       rust_assert (ok);
     316              : 
     317          294 :       TyTy::BaseType *mut_receiver = const_cast<TyTy::BaseType *> (receiver);
     318          294 :       bool receiver_matches = Resolver::types_compatable (
     319          294 :         TyTy::TyWithLocation (self, self->get_locus ()),
     320          294 :         TyTy::TyWithLocation (mut_receiver, mut_receiver->get_locus ()),
     321              :         UNDEF_LOCATION, false);
     322              : 
     323          294 :       if (!receiver_matches)
     324            0 :         continue;
     325              : 
     326              :       // Look through the relevant bounds on our type, and find which one our
     327              :       // impl block satisfies
     328          294 :       TyTy::TypeBoundPredicate *self_bound = nullptr;
     329          301 :       for (auto &bound : self->get_specified_bounds ())
     330              :         {
     331          294 :           const Resolver::TraitReference *bound_ref = bound.get ();
     332          294 :           const Resolver::TraitReference *specified_ref = predicate->get ();
     333              :           // If this impl is for one of our types or supertypes
     334          294 :           if (specified_ref->satisfies_bound (*bound_ref))
     335              :             {
     336              :               self_bound = &bound;
     337              :               break;
     338              :             }
     339              :         }
     340              : 
     341              :       // This impl block doesn't help us
     342          294 :       if (self_bound == nullptr)
     343            7 :         continue;
     344              : 
     345              :       // Find the specific function in the impl block that matches "ref".
     346              :       // This is the one we want to compute the address for.
     347          287 :       HIR::Function *associated_function = nullptr;
     348          570 :       for (auto &impl_item : impl_block->get_impl_items ())
     349              :         {
     350          283 :           bool is_function = impl_item->get_impl_item_type ()
     351          283 :                              == HIR::ImplItem::ImplItemType::FUNCTION;
     352          283 :           if (!is_function)
     353            0 :             continue;
     354              : 
     355          283 :           HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
     356          283 :           bool found_associated_item
     357          283 :             = fn->get_function_name ().as_string ().compare (
     358          566 :                 ref->get_identifier ())
     359          283 :               == 0;
     360          283 :           if (found_associated_item)
     361          283 :             associated_function = fn;
     362              :         }
     363              : 
     364              :       // This impl block satisfies the bound, but doesn't contain the relevant
     365              :       // function. This could happen because of supertraits.
     366          287 :       if (associated_function == nullptr)
     367           83 :         continue;
     368              : 
     369              :       // lookup the associated type for this item
     370          204 :       TyTy::BaseType *lookup = nullptr;
     371          204 :       ok = ctx->get_tyctx ()->lookup_type (
     372          204 :         associated_function->get_mappings ().get_hirid (), &lookup);
     373          204 :       rust_assert (ok);
     374          204 :       rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
     375          204 :       TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
     376              : 
     377          204 :       if (lookup_fntype->needs_substitution ())
     378              :         {
     379            7 :           TyTy::BaseType *infer
     380            7 :             = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
     381            7 :           infer
     382            7 :             = Resolver::unify_site (infer->get_ref (),
     383            7 :                                     TyTy::TyWithLocation (trait_item_fntype),
     384            7 :                                     TyTy::TyWithLocation (infer),
     385              :                                     UNDEF_LOCATION);
     386            7 :           rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
     387              :           lookup_fntype = static_cast<TyTy::FnType *> (infer);
     388              :         }
     389              : 
     390          204 :       return CompileInherentImplItem::Compile (associated_function, ctx,
     391          204 :                                                lookup_fntype, locus);
     392              :     }
     393              : 
     394              :   // we can only compile trait-items with a body
     395           18 :   bool trait_item_has_definition = ref->is_optional ();
     396           18 :   rust_assert (trait_item_has_definition);
     397              : 
     398           18 :   HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
     399           18 :   return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
     400           18 :                                     locus);
     401          222 : }
     402              : 
     403              : bool
     404          852 : HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
     405              :                                          location_t lvalue_locus,
     406              :                                          location_t rvalue_locus)
     407              : {
     408          852 :   rust_assert (ltype != NULL_TREE);
     409          852 :   rust_assert (rtype != NULL_TREE);
     410              : 
     411              :   // lets just return ok as other errors have already occurred
     412          852 :   if (ltype == error_mark_node || rtype == error_mark_node)
     413              :     return true;
     414              : 
     415          852 :   tree ltype_domain = TYPE_DOMAIN (ltype);
     416          852 :   if (!ltype_domain)
     417              :     return false;
     418              : 
     419          852 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
     420              :     return false;
     421              : 
     422          852 :   unsigned HOST_WIDE_INT ltype_length
     423         1704 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
     424         1704 :                  - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
     425          852 :                TYPE_PRECISION (TREE_TYPE (ltype_domain)),
     426          852 :                TYPE_SIGN (TREE_TYPE (ltype_domain)))
     427          852 :         .to_uhwi ();
     428              : 
     429          852 :   tree rtype_domain = TYPE_DOMAIN (rtype);
     430          852 :   if (!rtype_domain)
     431              :     return false;
     432              : 
     433          852 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
     434              :     return false;
     435              : 
     436          852 :   unsigned HOST_WIDE_INT rtype_length
     437         1704 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
     438         1704 :                  - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
     439          852 :                TYPE_PRECISION (TREE_TYPE (rtype_domain)),
     440          852 :                TYPE_SIGN (TREE_TYPE (rtype_domain)))
     441          852 :         .to_uhwi ();
     442              : 
     443          852 :   if (ltype_length != rtype_length)
     444              :     {
     445            0 :       rust_error_at (rvalue_locus, ErrorCode::E0308,
     446              :                      "mismatched types, expected an array with a fixed size "
     447              :                      "of " HOST_WIDE_INT_PRINT_UNSIGNED
     448              :                      " elements, found one with " HOST_WIDE_INT_PRINT_UNSIGNED
     449              :                      " elements",
     450              :                      ltype_length, rtype_length);
     451            0 :       return false;
     452              :     }
     453              : 
     454              :   return true;
     455              : }
     456              : 
     457              : } // namespace Compile
     458              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.