LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-resolve-path.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.2 % 190 177
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-resolve-path.h"
      20              : #include "options.h"
      21              : #include "rust-compile-intrinsic.h"
      22              : #include "rust-compile-item.h"
      23              : #include "rust-compile-implitem.h"
      24              : #include "rust-compile-expr.h"
      25              : #include "rust-hir-map.h"
      26              : #include "rust-hir-trait-resolve.h"
      27              : #include "rust-hir-path-probe.h"
      28              : #include "rust-compile-extern.h"
      29              : #include "rust-constexpr.h"
      30              : #include "rust-tyty.h"
      31              : 
      32              : namespace Rust {
      33              : namespace Compile {
      34              : 
      35              : tree
      36          113 : ResolvePathRef::Compile (HIR::QualifiedPathInExpression &expr, Context *ctx)
      37              : {
      38          113 :   ResolvePathRef resolver (ctx);
      39          113 :   return resolver.resolve_path_like (expr);
      40          113 : }
      41              : 
      42              : tree
      43        41429 : ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx)
      44              : {
      45        41429 :   ResolvePathRef resolver (ctx);
      46        41429 :   return resolver.resolve_path_like (expr);
      47        41429 : }
      48              : 
      49        41542 : ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {}
      50              : 
      51              : template <typename T>
      52              : tree
      53        41542 : ResolvePathRef::resolve_path_like (T &expr)
      54              : {
      55        41542 :   if (expr.is_lang_item ())
      56              :     {
      57              :       auto lang_item
      58           34 :         = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ());
      59              : 
      60              :       // FIXME: Is that correct? :/
      61           34 :       auto final_segment
      62           68 :         = HIR::PathIdentSegment (LangItem::ToString (expr.get_lang_item ()));
      63              : 
      64           34 :       return resolve_with_node_id (final_segment, expr.get_mappings (),
      65              :                                    expr.get_locus (), true, lang_item);
      66           34 :     }
      67              : 
      68        41508 :   return resolve (expr.get_final_segment ().get_segment (),
      69        41508 :                   expr.get_mappings (), expr.get_locus (), true);
      70              : }
      71              : 
      72              : tree
      73         1273 : ResolvePathRef::attempt_constructor_expression_lookup (
      74              :   TyTy::BaseType *lookup, Context *ctx, const Analysis::NodeMapping &mappings,
      75              :   location_t expr_locus)
      76              : {
      77              :   // it might be an enum data-less enum variant
      78         1273 :   if (lookup->get_kind () != TyTy::TypeKind::ADT)
      79            0 :     return error_mark_node;
      80              : 
      81         1273 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
      82         1273 :   if (adt->is_unit ())
      83          182 :     return unit_expression (expr_locus);
      84              : 
      85         1091 :   if (!adt->is_enum ())
      86            1 :     return error_mark_node;
      87              : 
      88         1090 :   HirId variant_id;
      89         1090 :   if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
      90              :                                                      &variant_id))
      91            0 :     return error_mark_node;
      92              : 
      93         1090 :   int union_disriminator = -1;
      94         1090 :   TyTy::VariantDef *variant = nullptr;
      95         1090 :   if (!adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator))
      96            0 :     return error_mark_node;
      97              : 
      98              :   // this can only be for discriminant variants the others are built up
      99              :   // using call-expr or struct-init
     100         1090 :   if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM)
     101              :     {
     102            1 :       rust_error_at (expr_locus, "variant expected constructor call");
     103            1 :       return error_mark_node;
     104              :     }
     105              : 
     106              :   // we need the actual gcc type
     107         1089 :   tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
     108              : 
     109              :   // make the ctor for the union
     110         1089 :   HIR::Expr &discrim_expr = variant->get_discriminant ();
     111         1089 :   ctx->push_const_context ();
     112         1089 :   tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
     113         1089 :   ctx->pop_const_context ();
     114         1089 :   tree folded_discrim_expr = fold_expr (discrim_expr_node);
     115         1089 :   tree qualifier = folded_discrim_expr;
     116              : 
     117              :   // false for is enum but this is an enum but we have a new layout
     118         1089 :   return Backend::constructor_expression (compiled_adt_type, false, {qualifier},
     119              :                                           -1, expr_locus);
     120              : }
     121              : 
     122              : tree
     123        41542 : ResolvePathRef::resolve_with_node_id (
     124              :   const HIR::PathIdentSegment &final_segment,
     125              :   const Analysis::NodeMapping &mappings, location_t expr_locus,
     126              :   bool is_qualified_path, NodeId resolved_node_id)
     127              : {
     128        41542 :   TyTy::BaseType *lookup = nullptr;
     129        41542 :   bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
     130        41542 :   rust_assert (ok);
     131              : 
     132        41542 :   tl::optional<HirId> hid
     133        41542 :     = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
     134        41542 :   if (!hid.has_value ())
     135            0 :     return error_mark_node;
     136              : 
     137        41542 :   auto ref = hid.value ();
     138              : 
     139              :   // might be a constant
     140        41542 :   tree constant_expr;
     141        41542 :   if (ctx->lookup_const_decl (ref, &constant_expr))
     142              :     {
     143          576 :       TREE_USED (constant_expr) = 1;
     144          576 :       return constant_expr;
     145              :     }
     146              : 
     147              :   // maybe closure binding
     148        40966 :   tree closure_binding = error_mark_node;
     149        40966 :   if (ctx->lookup_closure_binding (ref, &closure_binding))
     150              :     {
     151           14 :       TREE_USED (closure_binding) = 1;
     152           14 :       return closure_binding;
     153              :     }
     154              : 
     155              :   // this might be a variable reference or a function reference
     156        40952 :   Bvariable *var = nullptr;
     157        40952 :   if (ctx->lookup_var_decl (ref, &var))
     158              :     {
     159              :       // TREE_USED is setup in the gcc abstraction here
     160        29663 :       return Backend::var_expression (var, expr_locus);
     161              :     }
     162              : 
     163              :   // might be a match pattern binding
     164        11289 :   tree binding = error_mark_node;
     165        11289 :   if (ctx->lookup_pattern_binding (ref, &binding))
     166              :     {
     167          840 :       TREE_USED (binding) = 1;
     168          840 :       return binding;
     169              :     }
     170              : 
     171              :   // it might be a function call
     172        10449 :   if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
     173              :     {
     174         9032 :       TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
     175         9032 :       tree fn = NULL_TREE;
     176         9032 :       if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
     177              :         {
     178         4900 :           TREE_USED (fn) = 1;
     179         7079 :           return address_expression (fn, expr_locus);
     180              :         }
     181         4132 :       else if (fntype->get_abi () == ABI::INTRINSIC)
     182              :         {
     183         2179 :           Intrinsics compile (ctx);
     184         2179 :           fn = compile.compile (fntype);
     185         2179 :           TREE_USED (fn) = 1;
     186         2179 :           return address_expression (fn, expr_locus);
     187              :         }
     188              :     }
     189              : 
     190              :   // possibly a const expr value
     191         3370 :   if (lookup->get_kind () == TyTy::TypeKind::CONST)
     192              :     {
     193           35 :       auto d = lookup->destructure ();
     194           35 :       rust_assert (d->get_kind () == TyTy::TypeKind::CONST);
     195           35 :       auto c = d->as_const_type ();
     196           35 :       rust_assert (c->const_kind () == TyTy::BaseConstType::ConstKind::Value);
     197           35 :       auto val = static_cast<TyTy::ConstValueType *> (c);
     198           35 :       return val->get_value ();
     199              :     }
     200              : 
     201              :   // Handle unit struct
     202         3335 :   tree resolved_item = error_mark_node;
     203         3335 :   if (lookup->get_kind () == TyTy::TypeKind::ADT)
     204         1273 :     resolved_item
     205         1273 :       = attempt_constructor_expression_lookup (lookup, ctx, mappings,
     206              :                                                expr_locus);
     207              : 
     208         3335 :   if (!error_operand_p (resolved_item))
     209              :     return resolved_item;
     210              : 
     211              :   // let the query system figure it out
     212         2064 :   resolved_item = query_compile (ref, lookup, final_segment, mappings,
     213              :                                  expr_locus, is_qualified_path);
     214         2064 :   if (resolved_item != error_mark_node)
     215         2060 :     TREE_USED (resolved_item) = 1;
     216              : 
     217              :   return resolved_item;
     218              : }
     219              : 
     220              : tree
     221        41508 : ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
     222              :                          const Analysis::NodeMapping &mappings,
     223              :                          location_t expr_locus, bool is_qualified_path)
     224              : {
     225        41508 :   TyTy::BaseType *lookup = nullptr;
     226        41508 :   bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
     227        41508 :   if (!ok)
     228            0 :     return error_mark_node;
     229              : 
     230              :   // need to look up the reference for this identifier
     231              : 
     232              :   // this can fail because it might be a Constructor for something
     233              :   // in that case the caller should attempt ResolvePathType::Compile
     234        41508 :   auto &nr_ctx
     235        41508 :     = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     236              : 
     237        41508 :   auto resolved = nr_ctx.lookup (mappings.get_nodeid ());
     238              : 
     239        41508 :   if (!resolved)
     240            0 :     return attempt_constructor_expression_lookup (lookup, ctx, mappings,
     241            0 :                                                   expr_locus);
     242              : 
     243        41508 :   return resolve_with_node_id (final_segment, mappings, expr_locus,
     244        83016 :                                is_qualified_path, *resolved);
     245              : }
     246              : 
     247              : tree
     248         2064 : HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
     249              :                                const HIR::PathIdentSegment &final_segment,
     250              :                                const Analysis::NodeMapping &mappings,
     251              :                                location_t expr_locus, bool is_qualified_path)
     252              : {
     253         2064 :   bool is_fn = lookup->get_kind () == TyTy::TypeKind::FNDEF;
     254         2064 :   if (auto resolved_item = ctx->get_mappings ().lookup_hir_item (ref))
     255              :     {
     256          886 :       if (!lookup->has_substitutions_defined ())
     257         2061 :         return CompileItem::compile (*resolved_item, ctx, nullptr, expr_locus);
     258              :       else
     259          693 :         return CompileItem::compile (*resolved_item, ctx, lookup, expr_locus);
     260              :     }
     261         1178 :   else if (auto hir_extern_item
     262         1178 :            = ctx->get_mappings ().lookup_hir_extern_item (ref))
     263              :     {
     264           23 :       HIR::ExternalItem *resolved_extern_item = hir_extern_item->first;
     265           23 :       if (!lookup->has_substitutions_defined ())
     266           23 :         return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
     267         1175 :                                            expr_locus);
     268              :       else
     269            0 :         return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
     270            0 :                                            expr_locus);
     271              :     }
     272              :   else
     273              :     {
     274         1155 :       if (is_fn)
     275              :         {
     276         1151 :           TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
     277         1151 :           TyTy::BaseType *receiver = nullptr;
     278              : 
     279         2147 :           if (fn->is_method ())
     280              :             {
     281          383 :               receiver = fn->get_self_type ();
     282          383 :               receiver = receiver->destructure ();
     283              : 
     284          383 :               return resolve_method_address (fn, receiver, expr_locus);
     285              :             }
     286              :         }
     287              : 
     288          772 :       if (auto resolved_item = ctx->get_mappings ().lookup_hir_implitem (ref))
     289              :         {
     290          525 :           if (!lookup->has_substitutions_defined ())
     291          314 :             return CompileInherentImplItem::Compile (resolved_item->first, ctx,
     292          769 :                                                      nullptr, expr_locus);
     293              :           else
     294          211 :             return CompileInherentImplItem::Compile (resolved_item->first, ctx,
     295          211 :                                                      lookup, expr_locus);
     296              :         }
     297          247 :       else if (auto trait_item
     298          247 :                = ctx->get_mappings ().lookup_hir_trait_item (ref))
     299              :         {
     300          244 :           HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
     301          244 :             trait_item.value ()->get_mappings ().get_hirid ());
     302              : 
     303          244 :           Resolver::TraitReference *trait_ref
     304          244 :             = &Resolver::TraitReference::error_node ();
     305          244 :           bool ok = ctx->get_tyctx ()->lookup_trait_reference (
     306          244 :             trait->get_mappings ().get_defid (), &trait_ref);
     307          244 :           rust_assert (ok);
     308              : 
     309          244 :           if (trait_item.value ()->get_item_kind ()
     310              :               == HIR::TraitItem::TraitItemKind::CONST)
     311              :             {
     312            1 :               auto &c
     313            1 :                 = *static_cast<HIR::TraitItemConst *> (trait_item.value ());
     314            1 :               if (!c.has_expr ())
     315              :                 {
     316            1 :                   rich_location r (line_table, expr_locus);
     317            1 :                   r.add_range (trait->get_locus ());
     318            1 :                   r.add_range (c.get_locus ());
     319            1 :                   rust_error_at (r, "no default expression on trait constant");
     320            1 :                   return error_mark_node;
     321            1 :                 }
     322              : 
     323            0 :               return CompileExpr::Compile (c.get_expr (), ctx);
     324              :             }
     325              : 
     326          243 :           if (trait_item.value ()->get_item_kind ()
     327              :               != HIR::TraitItem::TraitItemKind::FUNC)
     328            0 :             return error_mark_node;
     329              : 
     330              :           // the type resolver can only resolve type bounds to their trait
     331              :           // item so its up to us to figure out if this path should resolve
     332              :           // to an trait-impl-block-item or if it can be defaulted to the
     333              :           // trait-impl-item's definition
     334              :           //
     335              :           // because we know this is resolved to a trait item we can actually
     336              :           // just grab the Self type parameter here for the receiver to match
     337              :           // the appropriate impl block
     338              : 
     339          243 :           rust_assert (lookup->is<TyTy::FnType> ());
     340          243 :           auto fn = lookup->as<TyTy::FnType> ();
     341          243 :           rust_assert (fn->get_num_type_params () > 0);
     342          243 :           TyTy::SubstitutionParamMapping &self = fn->get_substs ().at (0);
     343          243 :           TyTy::BaseGeneric *receiver = self.get_param_ty ();
     344          243 :           TyTy::BaseType *r = receiver;
     345          243 :           if (!receiver->can_resolve ())
     346              :             {
     347          110 :               bool ok
     348          110 :                 = ctx->get_tyctx ()->lookup_type (receiver->get_ref (), &r);
     349          110 :               rust_assert (ok);
     350              :             }
     351              : 
     352          243 :           auto candidates
     353          243 :             = Resolver::PathProbeImplTrait::Probe (r, final_segment, trait_ref);
     354          243 :           if (candidates.size () == 0)
     355              :             {
     356              :               // this means we are defaulting back to the trait_item if
     357              :               // possible
     358          110 :               Resolver::TraitItemReference *trait_item_ref = nullptr;
     359          110 :               bool ok = trait_ref->lookup_hir_trait_item (*trait_item.value (),
     360              :                                                           &trait_item_ref);
     361          110 :               rust_assert (ok);                             // found
     362          110 :               rust_assert (trait_item_ref->is_optional ()); // has definition
     363              : 
     364          110 :               return CompileTraitItem::Compile (
     365              :                 trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
     366              :                 expr_locus);
     367              :             }
     368              :           else
     369              :             {
     370          133 :               rust_assert (candidates.size () == 1);
     371              : 
     372          133 :               auto candidate = *candidates.begin ();
     373          133 :               rust_assert (candidate.is_impl_candidate ());
     374              : 
     375          133 :               HIR::ImplBlock *impl = candidate.item.impl.parent;
     376          133 :               HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
     377              : 
     378          133 :               TyTy::BaseType *self = nullptr;
     379          266 :               bool ok = ctx->get_tyctx ()->lookup_type (
     380          133 :                 impl->get_type ().get_mappings ().get_hirid (), &self);
     381          133 :               rust_assert (ok);
     382              : 
     383          133 :               if (!lookup->has_substitutions_defined ())
     384            0 :                 return CompileInherentImplItem::Compile (impl_item, ctx,
     385            0 :                                                          nullptr, expr_locus);
     386              :               else
     387          133 :                 return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
     388          133 :                                                          expr_locus);
     389              :             }
     390          243 :         }
     391              :     }
     392              : 
     393            3 :   return error_mark_node;
     394              : }
     395              : 
     396              : } // namespace Compile
     397              : } // 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.