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