LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-name-resolution-context.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.8 % 227 163
Test Date: 2026-08-22 16:33:35 Functions: 86.2 % 29 25
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-name-resolution-context.h"
      20              : #include "optional.h"
      21              : #include "rust-mapping-common.h"
      22              : #include "rust-rib.h"
      23              : #include "rust-system.h"
      24              : 
      25              : namespace Rust {
      26              : namespace Resolver2_0 {
      27              : 
      28       100005 : BindingLayer::BindingLayer (BindingSource source) : source (source)
      29              : {
      30       100005 :   push (Binding::Kind::Product);
      31       100005 : }
      32              : 
      33              : bool
      34        91362 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
      35              : {
      36       183070 :   for (auto &bind : bindings)
      37              :     {
      38        91775 :       if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
      39        91775 :           && bind.kind == kind)
      40              :         {
      41        91362 :           return true;
      42              :         }
      43              :     }
      44              :   return false;
      45              : }
      46              : 
      47              : void
      48       100736 : BindingLayer::push (Binding::Kind kind)
      49              : {
      50       100736 :   bindings.push_back (Binding (kind));
      51       100736 : }
      52              : 
      53              : bool
      54        45685 : BindingLayer::is_and_bound (Identifier ident)
      55              : {
      56        45685 :   return bind_test (ident, Binding::Kind::Product);
      57              : }
      58              : 
      59              : bool
      60        45677 : BindingLayer::is_or_bound (Identifier ident)
      61              : {
      62        45677 :   return bind_test (ident, Binding::Kind::Or);
      63              : }
      64              : 
      65              : void
      66        45677 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
      67              :                             bool is_mut)
      68              : {
      69        45677 :   bindings.back ().idents.emplace (
      70        45677 :     std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
      71        45677 : }
      72              : 
      73              : void
      74          731 : BindingLayer::merge ()
      75              : {
      76          731 :   auto last_binding = std::move (bindings.back ());
      77          731 :   bindings.pop_back ();
      78              : 
      79          731 :   if (bindings.back ().has_expected_bindings)
      80              :     {
      81          330 :       for (auto &value : bindings.back ().idents)
      82              :         {
      83           59 :           auto ident = value.first;
      84           59 :           if (last_binding.idents.find (ident) == last_binding.idents.end ())
      85              :             {
      86            0 :               location_t locus = value.second.first;
      87            0 :               rust_error_at (locus, ErrorCode::E0408,
      88              :                              "variable %qs is not bound in all patterns",
      89              :                              ident.c_str ());
      90              :             }
      91           59 :         }
      92              :     }
      93              : 
      94          908 :   for (auto &value : last_binding.idents)
      95              :     {
      96          177 :       auto res = bindings.back ().idents.emplace (value);
      97          177 :       if (res.second)
      98              :         {
      99          118 :           if (bindings.back ().has_expected_bindings)
     100              :             {
     101           14 :               auto &ident = value.first;
     102           14 :               location_t locus = value.second.first;
     103           14 :               rust_error_at (locus, ErrorCode::E0408,
     104              :                              "variable %qs is not bound in all patterns",
     105              :                              ident.c_str ());
     106              :             }
     107              :         }
     108              :       else
     109              :         {
     110           59 :           auto this_mode = value.second.second;
     111           59 :           auto other_mode = res.first->second.second;
     112          236 :           if (this_mode != other_mode)
     113              :             {
     114            7 :               auto &ident = value.first;
     115            7 :               location_t locus = value.second.first;
     116            7 :               rust_error_at (locus, ErrorCode::E0409,
     117              :                              "variable %qs is bound inconsistently across "
     118              :                              "pattern alternatives",
     119              :                              ident.c_str ());
     120              :             }
     121              :         }
     122              :     }
     123              : 
     124          731 :   if (bindings.back ().kind == Binding::Kind::Or)
     125          501 :     bindings.back ().has_expected_bindings = true;
     126          731 : }
     127              : 
     128              : BindingSource
     129            8 : BindingLayer::get_source () const
     130              : {
     131            8 :   return source;
     132              : }
     133              : 
     134              : Resolver::CanonicalPath
     135        76239 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &,
     136              :                                        Namespace ns)
     137              : {
     138       152478 :   auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
     139        76239 :   ret.set_crate_num (crate_num);
     140        76239 :   return ret;
     141              : }
     142              : 
     143              : Resolver::CanonicalPath
     144       136171 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx,
     145              :                                     Namespace ns)
     146              : {
     147       136171 :   auto &parent = ctx.canonical_ctx.get_record (get_parent ());
     148       136171 :   auto parent_path = parent.as_path (ctx, ns);
     149       272342 :   return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
     150       136171 : }
     151              : 
     152              : Resolver::CanonicalPath
     153        27831 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx,
     154              :                                     Namespace ns)
     155              : {
     156        27831 :   if (!cache)
     157              :     {
     158              :       // TODO: what namespace do we use here? can the caller give one?
     159        17428 :       auto res = ctx.lookup (lookup_id, ns).and_then ([&ctx] (NodeId id) {
     160         9396 :         return ctx.canonical_ctx.get_record_opt (id);
     161              :       });
     162              : 
     163        17428 :       if (!res)
     164              :         {
     165              :           // HACK: use a dummy value
     166              :           // this should bring us roughly to parity with nr1.0
     167              :           // since nr1.0 doesn't seem to handle canonical paths for generics
     168              :           //   quite right anyways
     169        12380 :           return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
     170              :         }
     171              : 
     172         5048 :       cache = res.value ();
     173              :     }
     174        15451 :   return cache->as_path (ctx, ns);
     175              : }
     176              : 
     177              : Resolver::CanonicalPath
     178         6963 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx,
     179              :                                   Namespace ns)
     180              : {
     181         6963 :   auto parent_path
     182         6963 :     = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
     183         6963 :   return parent_path.append (
     184        13926 :     Resolver::CanonicalPath::inherent_impl_seg (impl_id,
     185        20889 :                                                 type_record.as_path (ctx, ns)));
     186         6963 : }
     187              : 
     188              : Resolver::CanonicalPath
     189        10434 : CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx,
     190              :                                        Namespace ns)
     191              : {
     192              :   // Maybe this doesn't need the namespace and will always be in the types NS?
     193        10434 :   auto parent_path
     194        10434 :     = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
     195        10434 :   return parent_path.append (
     196        20868 :     Resolver::CanonicalPath::trait_impl_projection_seg (
     197        20868 :       impl_id, trait_path_record.as_path (ctx, ns),
     198        31302 :       type_record.as_path (ctx, ns)));
     199        10434 : }
     200              : 
     201         4869 : NameResolutionContext::NameResolutionContext ()
     202         4869 :   : root (std::make_unique<Node> (Rib::Kind::Normal, UNKNOWN_NODEID)),
     203         4869 :     lang_prelude (
     204         4869 :       std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID, *root)),
     205         4869 :     extern_prelude (
     206         4869 :       std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID)),
     207         4869 :     values (*root, *lang_prelude, *extern_prelude),
     208         4869 :     types (*root, *lang_prelude, *extern_prelude),
     209         4869 :     macros (*root, *lang_prelude, *extern_prelude),
     210         4869 :     labels (*root, *lang_prelude, *extern_prelude),
     211         4869 :     mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
     212         4869 : {}
     213              : 
     214              : tl::expected<NodeId, DuplicateNameError>
     215      1268254 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
     216              : {
     217      1268254 :   switch (ns)
     218              :     {
     219       547758 :     case Namespace::Values:
     220       547758 :       return values.insert (name, id);
     221       718442 :     case Namespace::Types:
     222       718442 :       return types.insert (name, id);
     223         2054 :     case Namespace::Macros:
     224         2054 :       return macros.insert (name, id);
     225            0 :     case Namespace::Labels:
     226            0 :     default:
     227            0 :       return labels.insert (name, id);
     228              :       rust_unreachable ();
     229              :     }
     230              : }
     231              : 
     232              : tl::expected<NodeId, DuplicateNameError>
     233         7606 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
     234              :                                        bool is_also_value)
     235              : {
     236         7606 :   auto res = types.insert_variant (name, id);
     237         7606 :   if (res.has_value () && is_also_value)
     238         1301 :     res = values.insert_variant (name, id);
     239         7606 :   return res;
     240              : }
     241              : 
     242              : tl::expected<NodeId, DuplicateNameError>
     243            0 : NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
     244              :                                           Namespace ns)
     245              : {
     246            0 :   switch (ns)
     247              :     {
     248            0 :     case Namespace::Values:
     249            0 :       return values.insert_shadowable (name, id);
     250            0 :     case Namespace::Types:
     251            0 :       return types.insert_shadowable (name, id);
     252            0 :     case Namespace::Macros:
     253            0 :       return macros.insert_shadowable (name, id);
     254            0 :     case Namespace::Labels:
     255            0 :       return labels.insert (name, id);
     256            0 :     default:
     257            0 :       rust_unreachable ();
     258              :     }
     259              : }
     260              : 
     261              : tl::expected<NodeId, DuplicateNameError>
     262            0 : NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
     263              : {
     264            0 :   switch (ns)
     265              :     {
     266            0 :     case Namespace::Values:
     267            0 :       return values.insert_globbed (name, id);
     268            0 :     case Namespace::Types:
     269            0 :       return types.insert_globbed (name, id);
     270            0 :     case Namespace::Macros:
     271            0 :       return macros.insert_globbed (name, id);
     272            0 :     case Namespace::Labels:
     273            0 :       return labels.insert (name, id);
     274            0 :     default:
     275            0 :       rust_unreachable ();
     276              :     }
     277              : }
     278              : 
     279              : // TODO: Maybe this should take a NamespacedDefinition as argument?
     280              : void
     281       772387 : NameResolutionContext::map_usage (Usage usage, Definition definition,
     282              :                                   Namespace ns)
     283              : {
     284       772387 :   switch (ns)
     285              :     {
     286       356320 :     case Namespace::Values:
     287       356320 :       values.map_usage (usage, definition);
     288       356320 :       break;
     289       366807 :     case Namespace::Types:
     290       366807 :       types.map_usage (usage, definition);
     291       366807 :       break;
     292           45 :     case Namespace::Labels:
     293           45 :       labels.map_usage (usage, definition);
     294           45 :       break;
     295        49215 :     case Namespace::Macros:
     296        49215 :       macros.map_usage (usage, definition);
     297        49215 :       break;
     298              :     }
     299       772387 : }
     300              : 
     301              : tl::optional<NodeId>
     302      3259834 : NameResolutionContext::lookup (NodeId usage, Namespace ns) const
     303              : {
     304      3259834 :   switch (ns)
     305              :     {
     306       320505 :     case Namespace::Values:
     307       320505 :       return values.lookup (usage);
     308      2939189 :     case Namespace::Types:
     309      2939189 :       return types.lookup (usage);
     310          140 :     case Namespace::Labels:
     311          140 :       return labels.lookup (usage);
     312            0 :     case Namespace::Macros:
     313            0 :       return macros.lookup (usage);
     314            0 :     default:
     315            0 :       rust_unreachable ();
     316              :     }
     317              : }
     318              : 
     319              : tl::optional<NameResolutionContext::NSLookup>
     320       198147 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2) const
     321              : {
     322       198147 :   if (auto result = lookup (usage, ns1))
     323       133877 :     return NSLookup (*result, ns1);
     324              : 
     325        64270 :   return lookup (usage, ns2).map ([&ns2] (NodeId id) {
     326        60403 :     return NSLookup (id, ns2);
     327              :   });
     328              : }
     329              : 
     330              : tl::optional<NameResolutionContext::NSLookup>
     331            0 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2,
     332              :                                Namespace ns3) const
     333              : {
     334            0 :   if (auto result = lookup (usage, ns1, ns2))
     335            0 :     return result;
     336              : 
     337            0 :   return lookup (usage, ns3).map ([&ns3] (NodeId id) {
     338            0 :     return NSLookup (id, ns3);
     339              :   });
     340              : }
     341              : 
     342              : void
     343      7686477 : NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
     344              :                                std::function<void (void)> lambda,
     345              :                                tl::optional<Identifier> path)
     346              : {
     347              :   // NOTE: You must be at the root node when pushing the prelude rib.
     348      7686477 :   values.push (rib_kind, id, path);
     349      7686477 :   types.push (rib_kind, id, path);
     350      7686477 :   macros.push (rib_kind, id, path);
     351      7686477 :   labels.push (rib_kind, id, path);
     352              : 
     353      7686477 :   lambda ();
     354              : 
     355      7686468 :   values.pop ();
     356      7686468 :   types.pop ();
     357      7686468 :   macros.pop ();
     358      7686468 :   labels.pop ();
     359      7686468 : }
     360              : 
     361              : void
     362            0 : NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
     363              :                                NodeId scope_id,
     364              :                                std::function<void (void)> lambda,
     365              :                                tl::optional<Identifier> path)
     366              : {
     367              :   // This could work... I'm not sure why you would want to do this though.
     368            0 :   rust_assert (rib_kind != Rib::Kind::Prelude);
     369              : 
     370            0 :   switch (ns)
     371              :     {
     372            0 :     case Namespace::Values:
     373            0 :       values.push (rib_kind, scope_id, path);
     374            0 :       break;
     375            0 :     case Namespace::Types:
     376            0 :       types.push (rib_kind, scope_id, path);
     377            0 :       break;
     378            0 :     case Namespace::Labels:
     379            0 :       labels.push (rib_kind, scope_id, path);
     380            0 :       break;
     381            0 :     case Namespace::Macros:
     382            0 :       gcc_unreachable ();
     383              :     }
     384              : 
     385            0 :   lambda ();
     386              : 
     387            0 :   switch (ns)
     388              :     {
     389            0 :     case Namespace::Values:
     390            0 :       values.pop ();
     391            0 :       break;
     392            0 :     case Namespace::Types:
     393            0 :       types.pop ();
     394            0 :       break;
     395            0 :     case Namespace::Labels:
     396            0 :       labels.pop ();
     397            0 :       break;
     398              :     case Namespace::Macros:
     399              :       gcc_unreachable ();
     400              :     }
     401            0 : }
     402              : 
     403              : void
     404           24 : NameResolutionContext::merge (NameResolutionContext &other, NodeId at)
     405              : {
     406              :   // TODO: merge once, for all namespaces at once
     407              : 
     408          120 :   auto merge_fstack = [&] (auto &stack, auto &other_stack, Namespace ns) {
     409           96 :     auto node = stack.dfs_node (stack.root, at);
     410           96 :     if (node)
     411              :       {
     412           96 :         auto &extern_crate_node = node.value ();
     413          416 :         for (auto kv : other_stack.root.children)
     414              :           {
     415          160 :             auto link = kv.first;
     416          160 :             auto child = kv.second;
     417          320 :             extern_crate_node.insert_child (link, child);
     418          160 :             child.parent = extern_crate_node;
     419              :           }
     420          176 :         for (auto kv : other_stack.root.rib (ns).get_values ())
     421              :           {
     422           40 :             auto name = kv.first;
     423           40 :             auto def = kv.second;
     424           80 :             extern_crate_node.rib (ns).insert (name, def);
     425              :           }
     426              :       }
     427           96 :     stack.resolved_nodes.insert (other_stack.resolved_nodes.begin (),
     428              :                                  other_stack.resolved_nodes.end ());
     429          120 :   };
     430              : 
     431           24 :   merge_fstack (values, other.values, Namespace::Values);
     432           24 :   merge_fstack (types, other.types, Namespace::Types);
     433           24 :   merge_fstack (macros, other.macros, Namespace::Macros);
     434           24 :   merge_fstack (labels, other.labels, Namespace::Labels);
     435           24 :   canonical_ctx.merge (std::move (other.canonical_ctx));
     436           24 : }
     437              : 
     438              : #if 0
     439              : void
     440              : NameResolutionContext::flatten ()
     441              : {
     442              :   values.flatten ();
     443              :   types.flatten ();
     444              :   macros.flatten ();
     445              :   labels.flatten ();
     446              : }
     447              : #endif
     448              : 
     449              : } // namespace Resolver2_0
     450              : } // 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.