LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.3 % 221 204
Test Date: 2026-09-19 16:22:48 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         4443 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
      33         4443 :   : crate (crate), ctx (ctx)
      34         4443 : {}
      35              : 
      36         4441 : CompileCrate::~CompileCrate () {}
      37              : 
      38              : void
      39         4443 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
      40              : {
      41         4443 :   CompileCrate c (crate, ctx);
      42         4443 :   c.go ();
      43         4441 : }
      44              : 
      45              : void
      46         4443 : CompileCrate::go ()
      47              : {
      48        23378 :   for (auto &item : crate.get_items ())
      49        18937 :     CompileItem::compile (item.get (), ctx);
      50         4441 :   auto crate_type
      51         4441 :     = Rust::Session::get_instance ().options.target_data.get_crate_type ();
      52         4441 :   if (crate_type == TargetOptions::CrateType::PROC_MACRO)
      53            0 :     add_proc_macro_symbols ();
      54         4441 : }
      55              : 
      56              : // Shared methods in compilation
      57              : 
      58              : tree
      59        47317 : 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        47317 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
      64        47317 :   bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
      65        47317 :   if (ok)
      66              :     {
      67        33414 :       rvalue = resolve_adjustments (*adjustments, rvalue, rvalue_locus);
      68              :     }
      69              : 
      70        47317 :   return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
      71              : }
      72              : 
      73              : tree
      74        53802 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
      75              :                                 TyTy::BaseType *lval, location_t lvalue_locus,
      76              :                                 location_t rvalue_locus)
      77              : {
      78        53802 :   if (rvalue == error_mark_node)
      79              :     return error_mark_node;
      80              : 
      81        53776 :   TyTy::BaseType *actual = rval->destructure ();
      82        53776 :   TyTy::BaseType *expected = lval->destructure ();
      83              : 
      84        53776 :   if (expected->get_kind () == TyTy::TypeKind::REF)
      85              :     {
      86              :       // this is a dyn object
      87         4435 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
      88              :         {
      89              :           return rvalue;
      90              :         }
      91              : 
      92              :       // bad coercion... of something to a reference
      93         1979 :       if (actual->get_kind () != TyTy::TypeKind::REF)
      94            1 :         return error_mark_node;
      95              : 
      96         1978 :       const TyTy::ReferenceType *exp
      97              :         = static_cast<const TyTy::ReferenceType *> (expected);
      98         1978 :       const TyTy::ReferenceType *act
      99              :         = static_cast<const TyTy::ReferenceType *> (actual);
     100              : 
     101         1978 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     102         1978 :       tree coerced
     103         1978 :         = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
     104              :                           lvalue_locus, rvalue_locus);
     105         1978 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     106              :         return coerced;
     107              : 
     108         1978 :       return address_expression (coerced, rvalue_locus);
     109              :     }
     110        49341 :   else if (expected->get_kind () == TyTy::TypeKind::POINTER)
     111              :     {
     112              :       // this is a dyn object
     113         5653 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
     114              :         {
     115              :           return rvalue;
     116              :         }
     117              : 
     118              :       // bad coercion... of something to a reference
     119         4507 :       bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
     120         4507 :                             || actual->get_kind () == TyTy::TypeKind::POINTER;
     121            0 :       if (!valid_coercion)
     122            0 :         return error_mark_node;
     123              : 
     124         4507 :       const TyTy::PointerType *exp
     125              :         = static_cast<const TyTy::PointerType *> (expected);
     126              : 
     127         4507 :       TyTy::BaseType *actual_base = nullptr;
     128         4507 :       if (actual->get_kind () == TyTy::TypeKind::REF)
     129              :         {
     130          300 :           const TyTy::ReferenceType *act
     131              :             = static_cast<const TyTy::ReferenceType *> (actual);
     132              : 
     133          300 :           actual_base = act->get_base ();
     134              :         }
     135         4207 :       else if (actual->get_kind () == TyTy::TypeKind::POINTER)
     136              :         {
     137         4207 :           const TyTy::PointerType *act
     138              :             = static_cast<const TyTy::PointerType *> (actual);
     139              : 
     140         4207 :           actual_base = act->get_base ();
     141              :         }
     142         4507 :       rust_assert (actual_base != nullptr);
     143              : 
     144         4507 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     145         4507 :       tree coerced
     146         4507 :         = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
     147              :                           lvalue_locus, rvalue_locus);
     148              : 
     149         4507 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     150              :         return coerced;
     151              : 
     152         4507 :       return address_expression (coerced, rvalue_locus);
     153              :     }
     154        43688 :   else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
     155              :     {
     156          937 :       if (actual->get_kind () != TyTy::TypeKind::ARRAY)
     157            0 :         return error_mark_node;
     158              : 
     159          937 :       tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
     160          937 :       tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
     161          937 :       if (!verify_array_capacities (tree_lval_type, tree_rval_type,
     162              :                                     lvalue_locus, rvalue_locus))
     163            0 :         return error_mark_node;
     164              :     }
     165        42751 :   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          174 : HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
     188              :                                       const TyTy::DynamicObjectType *ty,
     189              :                                       location_t locus)
     190              : {
     191          174 :   tree dynamic_object = TyTyResolveCompile::compile (ctx, ty);
     192          174 :   tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
     193          174 :   tree vtableptr_field = DECL_CHAIN (dynamic_object_fields);
     194          174 :   rust_assert (TREE_CODE (TREE_TYPE (vtableptr_field)) == POINTER_TYPE);
     195          174 :   rust_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (vtableptr_field))));
     196              : 
     197              :   //' this assumes ordering and current the structure is
     198              :   // __trait_object_ptr
     199              :   // __trait_vtable_ptr
     200              : 
     201          174 :   auto probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
     202          174 :   tree address_of_compiled_ref = null_pointer_node;
     203          174 :   if (!actual->is_unit ())
     204          159 :     address_of_compiled_ref = address_expression (compiled_ref, locus);
     205              : 
     206          174 :   size_t dyn_obj_ty_hash = TYPE_HASH (dynamic_object);
     207          174 :   size_t compiled_ref_ty_hash = TYPE_HASH (TREE_TYPE (compiled_ref));
     208          174 :   auto pair = std::make_pair (compiled_ref_ty_hash, dyn_obj_ty_hash);
     209              : 
     210          174 :   tree vtable_decl = NULL_TREE;
     211          174 :   Bvariable *cached_vtable = nullptr;
     212          174 :   if (ctx->lookup_vtable (pair, &cached_vtable))
     213              :     {
     214            7 :       vtable_decl = Backend::var_expression (cached_vtable, locus);
     215              :     }
     216              :   else
     217              :     {
     218          167 :       tree compiled_ref_ty = TREE_TYPE (compiled_ref);
     219              :       // drop_in_place is not implemented yet!
     220          167 :       tree drop_in_place = null_pointer_node;
     221          167 :       tree size = TYPE_SIZE_UNIT (compiled_ref_ty);
     222          167 :       tree align
     223          167 :         = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (compiled_ref_ty));
     224              : 
     225          167 :       std::vector<tree> vtable_ctor_elems;
     226          167 :       vtable_ctor_elems.emplace_back (drop_in_place);
     227          167 :       vtable_ctor_elems.emplace_back (size);
     228          167 :       vtable_ctor_elems.emplace_back (align);
     229              : 
     230          394 :       for (auto &bound : ty->get_object_items ())
     231              :         {
     232          227 :           const Resolver::TraitItemReference *item = bound.first;
     233          227 :           const TyTy::TypeBoundPredicate *predicate = bound.second;
     234              : 
     235          227 :           auto address
     236          227 :             = compute_address_for_trait_item (item, predicate,
     237              :                                               probed_bounds_for_receiver,
     238          227 :                                               actual, actual, locus);
     239          227 :           vtable_ctor_elems.push_back (address);
     240          167 :         }
     241          167 :       tree vtable_ctor
     242          167 :         = Backend::constructor_expression (TREE_TYPE (
     243              :                                              TREE_TYPE (vtableptr_field)),
     244              :                                            false, vtable_ctor_elems, -1, locus);
     245              : 
     246          167 :       std::string vtable_name = "__R_vtable_"
     247          334 :                                 + std::to_string (compiled_ref_ty_hash) + "_"
     248          334 :                                 + std::to_string (dyn_obj_ty_hash);
     249              : 
     250              :       // https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_mir/src/interpret/traits.rs#L17
     251          167 :       Bvariable *vtable_bvar
     252          167 :         = Backend::global_variable (vtable_name, vtable_name,
     253          167 :                                     TREE_TYPE (vtable_ctor), false, true, true,
     254              :                                     locus);
     255          167 :       Backend::global_variable_set_init (vtable_bvar, vtable_ctor);
     256          167 :       ctx->push_var (vtable_bvar);
     257          167 :       ctx->insert_vtable (pair, vtable_bvar);
     258              : 
     259          167 :       vtable_decl = Backend::var_expression (vtable_bvar, locus);
     260              : 
     261          167 :       DECL_ARTIFICIAL (vtable_decl) = 1;
     262          167 :       TREE_READONLY (vtable_decl) = 1;
     263          167 :       DECL_IGNORED_P (vtable_decl) = 1;
     264          167 :     }
     265              : 
     266          174 :   tree address_of_vtable = build_fold_addr_expr_loc (locus, vtable_decl);
     267          174 :   std::vector<tree> dyn_ctor = {address_of_compiled_ref, address_of_vtable};
     268          174 :   return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
     269          174 :                                           locus);
     270          174 : }
     271              : 
     272              : tree
     273          227 : HIRCompileBase::compute_address_for_trait_item (
     274              :   const Resolver::TraitItemReference *ref,
     275              :   const TyTy::TypeBoundPredicate *predicate,
     276              :   std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
     277              :     &receiver_bounds,
     278              :   const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
     279              : {
     280          227 :   tl::optional<TyTy::TypeBoundPredicateItem> predicate_item
     281          227 :     = predicate->lookup_associated_item (ref->get_identifier ());
     282          227 :   rust_assert (predicate_item.has_value ());
     283              : 
     284              :   // This is the expected end type
     285          227 :   TyTy::BaseType *trait_item_type
     286          227 :     = predicate_item->get_tyty_for_receiver (root);
     287          227 :   rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
     288          227 :   TyTy::FnType *trait_item_fntype
     289              :     = static_cast<TyTy::FnType *> (trait_item_type);
     290              : 
     291              :   // Loop through the list of trait references and impls that we satisfy.
     292              :   // We are looking for one that has an implementation for "ref", a trait
     293              :   // item.
     294          328 :   for (auto &item : receiver_bounds)
     295              :     {
     296          310 :       HIR::ImplBlock *impl_block = item.second;
     297          310 :       rust_assert (impl_block != nullptr);
     298              : 
     299              :       // Checks for empty impl blocks, triggered by Sized trait.
     300          310 :       if (!impl_block->has_type ())
     301          101 :         continue;
     302              : 
     303              :       // Lookup type for potentially associated impl.
     304          299 :       HIR::Type &self_type_path = impl_block->get_type ();
     305              : 
     306              :       // Convert HIR::Type to TyTy::BaseType
     307          299 :       TyTy::BaseType *self = nullptr;
     308          299 :       bool ok = ctx->get_tyctx ()->lookup_type (
     309          299 :         self_type_path.get_mappings ().get_hirid (), &self);
     310              : 
     311          299 :       rust_assert (ok);
     312              : 
     313          299 :       TyTy::BaseType *mut_receiver = const_cast<TyTy::BaseType *> (receiver);
     314          299 :       bool receiver_matches = Resolver::types_compatable (
     315          299 :         TyTy::TyWithLocation (self, self->get_locus ()),
     316          299 :         TyTy::TyWithLocation (mut_receiver, mut_receiver->get_locus ()),
     317              :         UNDEF_LOCATION, false);
     318              : 
     319          299 :       if (!receiver_matches)
     320            0 :         continue;
     321              : 
     322              :       // Look through the relevant bounds on our type, and find which one our
     323              :       // impl block satisfies
     324          299 :       TyTy::TypeBoundPredicate *self_bound = nullptr;
     325          306 :       for (auto &bound : self->get_specified_bounds ())
     326              :         {
     327          299 :           const Resolver::TraitReference *bound_ref = bound.get ();
     328          299 :           const Resolver::TraitReference *specified_ref = predicate->get ();
     329              :           // If this impl is for one of our types or supertypes
     330          299 :           if (specified_ref->satisfies_bound (*bound_ref))
     331              :             {
     332              :               self_bound = &bound;
     333              :               break;
     334              :             }
     335              :         }
     336              : 
     337              :       // This impl block doesn't help us
     338          299 :       if (self_bound == nullptr)
     339            7 :         continue;
     340              : 
     341              :       // Find the specific function in the impl block that matches "ref".
     342              :       // This is the one we want to compute the address for.
     343          292 :       HIR::Function *associated_function = nullptr;
     344          580 :       for (auto &impl_item : impl_block->get_impl_items ())
     345              :         {
     346          288 :           bool is_function = impl_item->get_impl_item_type ()
     347          288 :                              == HIR::ImplItem::ImplItemType::FUNCTION;
     348          288 :           if (!is_function)
     349            0 :             continue;
     350              : 
     351          288 :           HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
     352          288 :           bool found_associated_item
     353          288 :             = fn->get_function_name ().as_string ().compare (
     354          576 :                 ref->get_identifier ())
     355          288 :               == 0;
     356          288 :           if (found_associated_item)
     357          288 :             associated_function = fn;
     358              :         }
     359              : 
     360              :       // This impl block satisfies the bound, but doesn't contain the relevant
     361              :       // function. This could happen because of supertraits.
     362          292 :       if (associated_function == nullptr)
     363           83 :         continue;
     364              : 
     365              :       // lookup the associated type for this item
     366          209 :       TyTy::BaseType *lookup = nullptr;
     367          209 :       ok = ctx->get_tyctx ()->lookup_type (
     368          209 :         associated_function->get_mappings ().get_hirid (), &lookup);
     369          209 :       rust_assert (ok);
     370          209 :       rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
     371          209 :       TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
     372              : 
     373          209 :       if (lookup_fntype->needs_substitution ())
     374              :         {
     375            7 :           TyTy::BaseType *infer
     376            7 :             = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
     377            7 :           infer
     378            7 :             = Resolver::unify_site (infer->get_ref (),
     379            7 :                                     TyTy::TyWithLocation (trait_item_fntype),
     380            7 :                                     TyTy::TyWithLocation (infer),
     381              :                                     UNDEF_LOCATION);
     382            7 :           rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
     383              :           lookup_fntype = static_cast<TyTy::FnType *> (infer);
     384              :         }
     385              : 
     386          209 :       return CompileInherentImplItem::Compile (associated_function, ctx,
     387          209 :                                                lookup_fntype, locus);
     388              :     }
     389              : 
     390              :   // we can only compile trait-items with a body
     391           18 :   bool trait_item_has_definition = ref->is_optional ();
     392           18 :   rust_assert (trait_item_has_definition);
     393              : 
     394           18 :   HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
     395           18 :   return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
     396           18 :                                     locus);
     397          227 : }
     398              : 
     399              : bool
     400          937 : HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
     401              :                                          location_t lvalue_locus,
     402              :                                          location_t rvalue_locus)
     403              : {
     404          937 :   rust_assert (ltype != NULL_TREE);
     405          937 :   rust_assert (rtype != NULL_TREE);
     406              : 
     407              :   // lets just return ok as other errors have already occurred
     408          937 :   if (ltype == error_mark_node || rtype == error_mark_node)
     409              :     return true;
     410              : 
     411          937 :   tree ltype_domain = TYPE_DOMAIN (ltype);
     412          937 :   if (!ltype_domain)
     413              :     return false;
     414              : 
     415          937 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
     416              :     return false;
     417              : 
     418          937 :   unsigned HOST_WIDE_INT ltype_length
     419         1874 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
     420         1874 :                  - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
     421          937 :                TYPE_PRECISION (TREE_TYPE (ltype_domain)),
     422          937 :                TYPE_SIGN (TREE_TYPE (ltype_domain)))
     423          937 :         .to_uhwi ();
     424              : 
     425          937 :   tree rtype_domain = TYPE_DOMAIN (rtype);
     426          937 :   if (!rtype_domain)
     427              :     return false;
     428              : 
     429          937 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
     430              :     return false;
     431              : 
     432          937 :   unsigned HOST_WIDE_INT rtype_length
     433         1874 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
     434         1874 :                  - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
     435          937 :                TYPE_PRECISION (TREE_TYPE (rtype_domain)),
     436          937 :                TYPE_SIGN (TREE_TYPE (rtype_domain)))
     437          937 :         .to_uhwi ();
     438              : 
     439          937 :   if (ltype_length != rtype_length)
     440              :     {
     441            0 :       rust_error_at (rvalue_locus, ErrorCode::E0308,
     442              :                      "mismatched types, expected an array with a fixed size "
     443              :                      "of " HOST_WIDE_INT_PRINT_UNSIGNED
     444              :                      " elements, found one with " HOST_WIDE_INT_PRINT_UNSIGNED
     445              :                      " elements",
     446              :                      ltype_length, rtype_length);
     447            0 :       return false;
     448              :     }
     449              : 
     450              :   return true;
     451              : }
     452              : 
     453              : } // namespace Compile
     454              : } // 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.