LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.0 % 188 171
Test Date: 2026-02-28 14:20:25 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 "rust-compile-item.h"
      21              : #include "rust-compile-implitem.h"
      22              : #include "rust-hir-type-bounds.h"
      23              : #include "rust-compile-type.h"
      24              : #include "rust-substitution-mapper.h"
      25              : #include "rust-type-util.h"
      26              : #include "rust-session-manager.h"
      27              : 
      28              : namespace Rust {
      29              : namespace Compile {
      30              : 
      31         4072 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
      32         4072 :   : crate (crate), ctx (ctx)
      33         4072 : {}
      34              : 
      35         4072 : CompileCrate::~CompileCrate () {}
      36              : 
      37              : void
      38         4072 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
      39              : {
      40         4072 :   CompileCrate c (crate, ctx);
      41         4072 :   c.go ();
      42         4072 : }
      43              : 
      44              : void
      45         4072 : CompileCrate::go ()
      46              : {
      47        20967 :   for (auto &item : crate.get_items ())
      48        16895 :     CompileItem::compile (item.get (), ctx);
      49         4072 :   auto crate_type
      50         4072 :     = Rust::Session::get_instance ().options.target_data.get_crate_type ();
      51         4072 :   if (crate_type == TargetOptions::CrateType::PROC_MACRO)
      52            0 :     add_proc_macro_symbols ();
      53         4072 : }
      54              : 
      55              : // Shared methods in compilation
      56              : 
      57              : tree
      58        42767 : HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval,
      59              :                                TyTy::BaseType *lval, location_t lvalue_locus,
      60              :                                location_t rvalue_locus)
      61              : {
      62        42767 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
      63        42767 :   bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
      64        42767 :   if (ok)
      65              :     {
      66        29767 :       rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
      67              :     }
      68              : 
      69        42767 :   return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
      70              : }
      71              : 
      72              : tree
      73        48719 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
      74              :                                 TyTy::BaseType *lval, location_t lvalue_locus,
      75              :                                 location_t rvalue_locus)
      76              : {
      77        48719 :   if (rvalue == error_mark_node)
      78              :     return error_mark_node;
      79              : 
      80        48613 :   TyTy::BaseType *actual = rval->destructure ();
      81        48613 :   TyTy::BaseType *expected = lval->destructure ();
      82              : 
      83        48613 :   if (expected->get_kind () == TyTy::TypeKind::REF)
      84              :     {
      85              :       // this is a dyn object
      86         4263 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
      87              :         {
      88              :           return rvalue;
      89              :         }
      90              : 
      91              :       // bad coercion... of something to a reference
      92         1914 :       if (actual->get_kind () != TyTy::TypeKind::REF)
      93            0 :         return error_mark_node;
      94              : 
      95         1914 :       const TyTy::ReferenceType *exp
      96              :         = static_cast<const TyTy::ReferenceType *> (expected);
      97         1914 :       const TyTy::ReferenceType *act
      98              :         = static_cast<const TyTy::ReferenceType *> (actual);
      99              : 
     100         1914 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     101         1914 :       tree coerced
     102         1914 :         = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
     103              :                           lvalue_locus, rvalue_locus);
     104         1914 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     105              :         return coerced;
     106              : 
     107         1914 :       return address_expression (coerced, rvalue_locus);
     108              :     }
     109        44350 :   else if (expected->get_kind () == TyTy::TypeKind::POINTER)
     110              :     {
     111              :       // this is a dyn object
     112         5161 :       if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
     113              :         {
     114              :           return rvalue;
     115              :         }
     116              : 
     117              :       // bad coercion... of something to a reference
     118         4038 :       bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
     119         4038 :                             || actual->get_kind () == TyTy::TypeKind::POINTER;
     120         4038 :       if (!valid_coercion)
     121            0 :         return error_mark_node;
     122              : 
     123         4038 :       const TyTy::PointerType *exp
     124              :         = static_cast<const TyTy::PointerType *> (expected);
     125              : 
     126         4038 :       TyTy::BaseType *actual_base = nullptr;
     127         4038 :       if (actual->get_kind () == TyTy::TypeKind::REF)
     128              :         {
     129          268 :           const TyTy::ReferenceType *act
     130              :             = static_cast<const TyTy::ReferenceType *> (actual);
     131              : 
     132          268 :           actual_base = act->get_base ();
     133              :         }
     134         3770 :       else if (actual->get_kind () == TyTy::TypeKind::POINTER)
     135              :         {
     136         3770 :           const TyTy::PointerType *act
     137              :             = static_cast<const TyTy::PointerType *> (actual);
     138              : 
     139         3770 :           actual_base = act->get_base ();
     140              :         }
     141         4038 :       rust_assert (actual_base != nullptr);
     142              : 
     143         4038 :       tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
     144         4038 :       tree coerced
     145         4038 :         = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
     146              :                           lvalue_locus, rvalue_locus);
     147              : 
     148         4038 :       if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
     149              :         return coerced;
     150              : 
     151         4038 :       return address_expression (coerced, rvalue_locus);
     152              :     }
     153        39189 :   else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
     154              :     {
     155          846 :       if (actual->get_kind () != TyTy::TypeKind::ARRAY)
     156            0 :         return error_mark_node;
     157              : 
     158          846 :       tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
     159          846 :       tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
     160          846 :       if (!verify_array_capacities (tree_lval_type, tree_rval_type,
     161              :                                     lvalue_locus, rvalue_locus))
     162            0 :         return error_mark_node;
     163              :     }
     164        38343 :   else if (expected->get_kind () == TyTy::TypeKind::SLICE)
     165              :     {
     166              :       // bad coercion
     167            0 :       bool valid_coercion = actual->get_kind () == TyTy::TypeKind::SLICE
     168            0 :                             || actual->get_kind () == TyTy::TypeKind::ARRAY;
     169            0 :       if (!valid_coercion)
     170            0 :         return error_mark_node;
     171              : 
     172              :       // nothing to do here
     173            0 :       if (actual->get_kind () == TyTy::TypeKind::SLICE)
     174              :         return rvalue;
     175              : 
     176              :       // return an unsized coercion
     177            0 :       Resolver::Adjustment unsize_adj (
     178            0 :         Resolver::Adjustment::AdjustmentType::UNSIZE, actual, expected);
     179            0 :       return resolve_unsized_adjustment (unsize_adj, rvalue, rvalue_locus);
     180              :     }
     181              : 
     182              :   return rvalue;
     183              : }
     184              : 
     185              : tree
     186          124 : HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
     187              :                                       const TyTy::DynamicObjectType *ty,
     188              :                                       location_t locus)
     189              : {
     190              :   // DST's get wrapped in a pseudo reference that doesnt exist...
     191          124 :   const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
     192          124 :                                TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
     193              : 
     194          124 :   tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
     195          124 :   tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
     196          124 :   tree vtable_field = DECL_CHAIN (dynamic_object_fields);
     197          124 :   rust_assert (TREE_CODE (TREE_TYPE (vtable_field)) == ARRAY_TYPE);
     198              : 
     199              :   //' this assumes ordering and current the structure is
     200              :   // __trait_object_ptr
     201              :   // [list of function ptrs]
     202              : 
     203          124 :   auto probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
     204          124 :   tree address_of_compiled_ref = null_pointer_node;
     205          124 :   if (!actual->is_unit ())
     206          109 :     address_of_compiled_ref = address_expression (compiled_ref, locus);
     207              : 
     208          124 :   std::vector<tree> vtable_ctor_elems;
     209          124 :   std::vector<unsigned long> vtable_ctor_idx;
     210          124 :   unsigned long i = 0;
     211          315 :   for (auto &bound : ty->get_object_items ())
     212              :     {
     213          191 :       const Resolver::TraitItemReference *item = bound.first;
     214          191 :       const TyTy::TypeBoundPredicate *predicate = bound.second;
     215              : 
     216          191 :       auto address = compute_address_for_trait_item (item, predicate,
     217              :                                                      probed_bounds_for_receiver,
     218          191 :                                                      actual, actual, locus);
     219          191 :       vtable_ctor_elems.push_back (address);
     220          191 :       vtable_ctor_idx.push_back (i++);
     221          124 :     }
     222              : 
     223          124 :   tree vtable_ctor
     224          124 :     = Backend::array_constructor_expression (TREE_TYPE (vtable_field),
     225              :                                              vtable_ctor_idx, vtable_ctor_elems,
     226              :                                              locus);
     227              : 
     228          124 :   std::vector<tree> dyn_ctor = {address_of_compiled_ref, vtable_ctor};
     229          124 :   return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
     230          124 :                                           locus);
     231          124 : }
     232              : 
     233              : tree
     234          191 : HIRCompileBase::compute_address_for_trait_item (
     235              :   const Resolver::TraitItemReference *ref,
     236              :   const TyTy::TypeBoundPredicate *predicate,
     237              :   std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
     238              :     &receiver_bounds,
     239              :   const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
     240              : {
     241          191 :   tl::optional<TyTy::TypeBoundPredicateItem> predicate_item
     242          191 :     = predicate->lookup_associated_item (ref->get_identifier ());
     243          191 :   rust_assert (predicate_item.has_value ());
     244              : 
     245              :   // This is the expected end type
     246          191 :   TyTy::BaseType *trait_item_type
     247          191 :     = predicate_item->get_tyty_for_receiver (root);
     248          191 :   rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
     249          191 :   TyTy::FnType *trait_item_fntype
     250              :     = static_cast<TyTy::FnType *> (trait_item_type);
     251              : 
     252              :   // Loop through the list of trait references and impls that we satisfy.
     253              :   // We are looking for one that has an implementation for "ref", a trait
     254              :   // item.
     255          277 :   for (auto &item : receiver_bounds)
     256              :     {
     257          263 :       HIR::ImplBlock *impl_block = item.second;
     258          263 :       rust_assert (impl_block != nullptr);
     259              : 
     260              :       // Checks for empty impl blocks, triggered by Sized trait.
     261          263 :       if (!impl_block->has_type ())
     262           86 :         continue;
     263              : 
     264              :       // Lookup type for potentially associated impl.
     265          256 :       HIR::Type &self_type_path = impl_block->get_type ();
     266              : 
     267              :       // Convert HIR::Type to TyTy::BaseType
     268          256 :       TyTy::BaseType *self = nullptr;
     269          256 :       bool ok = ctx->get_tyctx ()->lookup_type (
     270          256 :         self_type_path.get_mappings ().get_hirid (), &self);
     271              : 
     272          256 :       rust_assert (ok);
     273              : 
     274              :       // Look through the relevant bounds on our type, and find which one our
     275              :       // impl block satisfies
     276          256 :       TyTy::TypeBoundPredicate *self_bound = nullptr;
     277          256 :       for (auto &bound : self->get_specified_bounds ())
     278              :         {
     279          256 :           const Resolver::TraitReference *bound_ref = bound.get ();
     280          256 :           const Resolver::TraitReference *specified_ref = predicate->get ();
     281              :           // If this impl is for one of our types or supertypes
     282          256 :           if (specified_ref->satisfies_bound (*bound_ref))
     283              :             {
     284              :               self_bound = &bound;
     285              :               break;
     286              :             }
     287              :         }
     288              : 
     289              :       // This impl block doesn't help us
     290          256 :       if (self_bound == nullptr)
     291            0 :         continue;
     292              : 
     293              :       // Find the specific function in the impl block that matches "ref".
     294              :       // This is the one we want to compute the address for.
     295          256 :       HIR::Function *associated_function = nullptr;
     296          512 :       for (auto &impl_item : impl_block->get_impl_items ())
     297              :         {
     298          256 :           bool is_function = impl_item->get_impl_item_type ()
     299          256 :                              == HIR::ImplItem::ImplItemType::FUNCTION;
     300          256 :           if (!is_function)
     301            0 :             continue;
     302              : 
     303          256 :           HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
     304          256 :           bool found_associated_item
     305          256 :             = fn->get_function_name ().as_string ().compare (
     306          512 :                 ref->get_identifier ())
     307          256 :               == 0;
     308          256 :           if (found_associated_item)
     309          256 :             associated_function = fn;
     310              :         }
     311              : 
     312              :       // This impl block satisfies the bound, but doesn't contain the relevant
     313              :       // function. This could happen because of supertraits.
     314          256 :       if (associated_function == nullptr)
     315           79 :         continue;
     316              : 
     317              :       // lookup the associated type for this item
     318          177 :       TyTy::BaseType *lookup = nullptr;
     319          177 :       ok = ctx->get_tyctx ()->lookup_type (
     320          177 :         associated_function->get_mappings ().get_hirid (), &lookup);
     321          177 :       rust_assert (ok);
     322          177 :       rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
     323          177 :       TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
     324              : 
     325          177 :       if (lookup_fntype->needs_substitution ())
     326              :         {
     327            7 :           TyTy::BaseType *infer
     328            7 :             = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
     329            7 :           infer
     330            7 :             = Resolver::unify_site (infer->get_ref (),
     331            7 :                                     TyTy::TyWithLocation (trait_item_fntype),
     332            7 :                                     TyTy::TyWithLocation (infer),
     333              :                                     UNDEF_LOCATION);
     334            7 :           rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
     335              :           lookup_fntype = static_cast<TyTy::FnType *> (infer);
     336              :         }
     337              : 
     338          177 :       return CompileInherentImplItem::Compile (associated_function, ctx,
     339          177 :                                                lookup_fntype, locus);
     340              :     }
     341              : 
     342              :   // we can only compile trait-items with a body
     343           14 :   bool trait_item_has_definition = ref->is_optional ();
     344           14 :   rust_assert (trait_item_has_definition);
     345              : 
     346           14 :   HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
     347           14 :   return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
     348           14 :                                     locus);
     349          191 : }
     350              : 
     351              : bool
     352          846 : HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
     353              :                                          location_t lvalue_locus,
     354              :                                          location_t rvalue_locus)
     355              : {
     356          846 :   rust_assert (ltype != NULL_TREE);
     357          846 :   rust_assert (rtype != NULL_TREE);
     358              : 
     359              :   // lets just return ok as other errors have already occurred
     360          846 :   if (ltype == error_mark_node || rtype == error_mark_node)
     361              :     return true;
     362              : 
     363          846 :   tree ltype_domain = TYPE_DOMAIN (ltype);
     364          846 :   if (!ltype_domain)
     365              :     return false;
     366              : 
     367          846 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
     368              :     return false;
     369              : 
     370          846 :   unsigned HOST_WIDE_INT ltype_length
     371         1692 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
     372         1692 :                  - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
     373          846 :                TYPE_PRECISION (TREE_TYPE (ltype_domain)),
     374          846 :                TYPE_SIGN (TREE_TYPE (ltype_domain)))
     375          846 :         .to_uhwi ();
     376              : 
     377          846 :   tree rtype_domain = TYPE_DOMAIN (rtype);
     378          846 :   if (!rtype_domain)
     379              :     return false;
     380              : 
     381          846 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
     382              :     return false;
     383              : 
     384          846 :   unsigned HOST_WIDE_INT rtype_length
     385         1692 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
     386         1692 :                  - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
     387          846 :                TYPE_PRECISION (TREE_TYPE (rtype_domain)),
     388          846 :                TYPE_SIGN (TREE_TYPE (rtype_domain)))
     389          846 :         .to_uhwi ();
     390              : 
     391          846 :   if (ltype_length != rtype_length)
     392              :     {
     393            0 :       rust_error_at (rvalue_locus, ErrorCode::E0308,
     394              :                      "mismatched types, expected an array with a fixed size "
     395              :                      "of " HOST_WIDE_INT_PRINT_UNSIGNED
     396              :                      " elements, found one with " HOST_WIDE_INT_PRINT_UNSIGNED
     397              :                      " elements",
     398              :                      ltype_length, rtype_length);
     399            0 :       return false;
     400              :     }
     401              : 
     402              :   return true;
     403              : }
     404              : 
     405              : } // namespace Compile
     406              : } // 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.