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-09-12 16:25:28 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       100296 : BindingLayer::BindingLayer (BindingSource source) : source (source)
      29              : {
      30       100296 :   push (Binding::Kind::Product);
      31       100296 : }
      32              : 
      33              : bool
      34        91752 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
      35              : {
      36       183850 :   for (auto &bind : bindings)
      37              :     {
      38        92165 :       if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
      39        92165 :           && bind.kind == kind)
      40              :         {
      41        91752 :           return true;
      42              :         }
      43              :     }
      44              :   return false;
      45              : }
      46              : 
      47              : void
      48       101027 : BindingLayer::push (Binding::Kind kind)
      49              : {
      50       101027 :   bindings.push_back (Binding (kind));
      51       101027 : }
      52              : 
      53              : bool
      54        45880 : BindingLayer::is_and_bound (Identifier ident)
      55              : {
      56        45880 :   return bind_test (ident, Binding::Kind::Product);
      57              : }
      58              : 
      59              : bool
      60        45872 : BindingLayer::is_or_bound (Identifier ident)
      61              : {
      62        45872 :   return bind_test (ident, Binding::Kind::Or);
      63              : }
      64              : 
      65              : void
      66        45872 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
      67              :                             bool is_mut)
      68              : {
      69        45872 :   bindings.back ().idents.emplace (
      70        45872 :     std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
      71        45872 : }
      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        76829 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &,
     136              :                                        Namespace ns)
     137              : {
     138       153658 :   auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
     139        76829 :   ret.set_crate_num (crate_num);
     140        76829 :   return ret;
     141              : }
     142              : 
     143              : Resolver::CanonicalPath
     144       136838 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx,
     145              :                                     Namespace ns)
     146              : {
     147       136838 :   auto &parent = ctx.canonical_ctx.get_record (get_parent ());
     148       136838 :   auto parent_path = parent.as_path (ctx, ns);
     149       273676 :   return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
     150       136838 : }
     151              : 
     152              : Resolver::CanonicalPath
     153        28030 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx,
     154              :                                     Namespace ns)
     155              : {
     156        28030 :   if (!cache)
     157              :     {
     158              :       // TODO: what namespace do we use here? can the caller give one?
     159        17500 :       auto res = ctx.lookup (lookup_id, ns).and_then ([&ctx] (NodeId id) {
     160         9457 :         return ctx.canonical_ctx.get_record_opt (id);
     161              :       });
     162              : 
     163        17500 :       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        12392 :           return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
     170              :         }
     171              : 
     172         5108 :       cache = res.value ();
     173              :     }
     174        15638 :   return cache->as_path (ctx, ns);
     175              : }
     176              : 
     177              : Resolver::CanonicalPath
     178         6976 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx,
     179              :                                   Namespace ns)
     180              : {
     181         6976 :   auto parent_path
     182         6976 :     = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
     183         6976 :   return parent_path.append (
     184        13952 :     Resolver::CanonicalPath::inherent_impl_seg (impl_id,
     185        20928 :                                                 type_record.as_path (ctx, ns)));
     186         6976 : }
     187              : 
     188              : Resolver::CanonicalPath
     189        10527 : 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        10527 :   auto parent_path
     194        10527 :     = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
     195        10527 :   return parent_path.append (
     196        21054 :     Resolver::CanonicalPath::trait_impl_projection_seg (
     197        21054 :       impl_id, trait_path_record.as_path (ctx, ns),
     198        31581 :       type_record.as_path (ctx, ns)));
     199        10527 : }
     200              : 
     201         4960 : NameResolutionContext::NameResolutionContext ()
     202         4960 :   : root (std::make_unique<Node> (Rib::Kind::Normal, UNKNOWN_NODEID)),
     203         4960 :     lang_prelude (
     204         4960 :       std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID, *root)),
     205         4960 :     extern_prelude (
     206         4960 :       std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID)),
     207         4960 :     values (*root, *lang_prelude, *extern_prelude),
     208         4960 :     types (*root, *lang_prelude, *extern_prelude),
     209         4960 :     macros (*root, *lang_prelude, *extern_prelude),
     210         4960 :     labels (*root, *lang_prelude, *extern_prelude),
     211         4960 :     mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
     212         4960 : {}
     213              : 
     214              : tl::expected<NodeId, DuplicateNameError>
     215      1270040 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
     216              : {
     217      1270040 :   switch (ns)
     218              :     {
     219       548380 :     case Namespace::Values:
     220       548380 :       return values.insert (name, id);
     221       719606 :     case Namespace::Types:
     222       719606 :       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         7621 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
     234              :                                        bool is_also_value)
     235              : {
     236         7621 :   auto res = types.insert_variant (name, id);
     237         7621 :   if (res.has_value () && is_also_value)
     238         1306 :     res = values.insert_variant (name, id);
     239         7621 :   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       744607 : NameResolutionContext::map_usage (Usage usage, Definition definition,
     282              :                                   Namespace ns)
     283              : {
     284       744607 :   switch (ns)
     285              :     {
     286       356726 :     case Namespace::Values:
     287       356726 :       values.map_usage (usage, definition);
     288       356726 :       break;
     289       368288 :     case Namespace::Types:
     290       368288 :       types.map_usage (usage, definition);
     291       368288 :       break;
     292           46 :     case Namespace::Labels:
     293           46 :       labels.map_usage (usage, definition);
     294           46 :       break;
     295        19547 :     case Namespace::Macros:
     296        19547 :       macros.map_usage (usage, definition);
     297        19547 :       break;
     298              :     }
     299       744607 : }
     300              : 
     301              : tl::optional<NodeId>
     302      4739160 : NameResolutionContext::lookup (NodeId usage, Namespace ns) const
     303              : {
     304      4739160 :   switch (ns)
     305              :     {
     306       322398 :     case Namespace::Values:
     307       322398 :       return values.lookup (usage);
     308      4416617 :     case Namespace::Types:
     309      4416617 :       return types.lookup (usage);
     310          145 :     case Namespace::Labels:
     311          145 :       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       199274 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2) const
     321              : {
     322       199274 :   if (auto result = lookup (usage, ns1))
     323       134618 :     return NSLookup (*result, ns1);
     324              : 
     325        64656 :   return lookup (usage, ns2).map ([&ns2] (NodeId id) {
     326        60769 :     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      7691451 : 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      7691451 :   values.push (rib_kind, id, path);
     349      7691451 :   types.push (rib_kind, id, path);
     350      7691451 :   macros.push (rib_kind, id, path);
     351      7691451 :   labels.push (rib_kind, id, path);
     352              : 
     353      7691451 :   lambda ();
     354              : 
     355      7691442 :   values.pop ();
     356      7691442 :   types.pop ();
     357      7691442 :   macros.pop ();
     358      7691442 :   labels.pop ();
     359      7691442 : }
     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           48 : NameResolutionContext::merge (NameResolutionContext &other, NodeId at)
     405              : {
     406              :   // TODO: merge once, for all namespaces at once
     407              : 
     408          240 :   auto merge_fstack = [&] (auto &stack, auto &other_stack, Namespace ns) {
     409          192 :     auto node = stack.dfs_node (stack.root, at);
     410          192 :     if (node)
     411              :       {
     412          192 :         auto &extern_crate_node = node.value ();
     413          512 :         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          272 :         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          192 :     stack.resolved_nodes.insert (other_stack.resolved_nodes.begin (),
     428              :                                  other_stack.resolved_nodes.end ());
     429          240 :   };
     430              : 
     431           48 :   merge_fstack (values, other.values, Namespace::Values);
     432           48 :   merge_fstack (types, other.types, Namespace::Types);
     433           48 :   merge_fstack (macros, other.macros, Namespace::Macros);
     434           48 :   merge_fstack (labels, other.labels, Namespace::Labels);
     435           48 :   canonical_ctx.merge (std::move (other.canonical_ctx));
     436           48 : }
     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.