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: 72.3 % 184 133
Test Date: 2026-07-11 15:47:05 Functions: 87.5 % 24 21
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        34562 : BindingLayer::BindingLayer (BindingSource source) : source (source)
      29              : {
      30        34562 :   push (Binding::Kind::Product);
      31        34562 : }
      32              : 
      33              : bool
      34        49502 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
      35              : {
      36        99344 :   for (auto &bind : bindings)
      37              :     {
      38        49908 :       if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
      39        49908 :           && bind.kind == kind)
      40              :         {
      41        49502 :           return true;
      42              :         }
      43              :     }
      44              :   return false;
      45              : }
      46              : 
      47              : void
      48        35153 : BindingLayer::push (Binding::Kind kind)
      49              : {
      50        35153 :   bindings.push_back (Binding (kind));
      51        35153 : }
      52              : 
      53              : bool
      54        24755 : BindingLayer::is_and_bound (Identifier ident)
      55              : {
      56        24755 :   return bind_test (ident, Binding::Kind::Product);
      57              : }
      58              : 
      59              : bool
      60        24747 : BindingLayer::is_or_bound (Identifier ident)
      61              : {
      62        24747 :   return bind_test (ident, Binding::Kind::Or);
      63              : }
      64              : 
      65              : void
      66        24747 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
      67              :                             bool is_mut)
      68              : {
      69        24747 :   bindings.back ().idents.emplace (
      70        24747 :     std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
      71        24747 : }
      72              : 
      73              : void
      74          591 : BindingLayer::merge ()
      75              : {
      76          591 :   auto last_binding = std::move (bindings.back ());
      77          591 :   bindings.pop_back ();
      78              : 
      79          591 :   if (bindings.back ().has_expected_bindings)
      80              :     {
      81          267 :       for (auto &value : bindings.back ().idents)
      82              :         {
      83           58 :           auto ident = value.first;
      84           58 :           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           58 :         }
      92              :     }
      93              : 
      94          765 :   for (auto &value : last_binding.idents)
      95              :     {
      96          174 :       auto res = bindings.back ().idents.emplace (value);
      97          174 :       if (res.second)
      98              :         {
      99          116 :           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           58 :           auto this_mode = value.second.second;
     111           58 :           auto other_mode = res.first->second.second;
     112          232 :           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          591 :   if (bindings.back ().kind == Binding::Kind::Or)
     125          400 :     bindings.back ().has_expected_bindings = true;
     126          591 : }
     127              : 
     128              : BindingSource
     129            8 : BindingLayer::get_source () const
     130              : {
     131            8 :   return source;
     132              : }
     133              : 
     134              : Resolver::CanonicalPath
     135        75766 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &,
     136              :                                        Namespace ns)
     137              : {
     138       151532 :   auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
     139        75766 :   ret.set_crate_num (crate_num);
     140        75766 :   return ret;
     141              : }
     142              : 
     143              : Resolver::CanonicalPath
     144       148957 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx,
     145              :                                     Namespace ns)
     146              : {
     147       148957 :   auto parent_path = get_parent ().as_path (ctx, ns);
     148       297914 :   return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
     149       148957 : }
     150              : 
     151              : Resolver::CanonicalPath
     152        27751 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx,
     153              :                                     Namespace ns)
     154              : {
     155        27751 :   if (!cache)
     156              :     {
     157              :       // TODO: what namespace do we use here? can the caller give one?
     158        17399 :       auto res = ctx.lookup (lookup_id, ns).and_then ([&ctx] (NodeId id) {
     159         9370 :         return ctx.canonical_ctx.get_record_opt (id);
     160              :       });
     161              : 
     162        17399 :       if (!res)
     163              :         {
     164              :           // HACK: use a dummy value
     165              :           // this should bring us roughly to parity with nr1.0
     166              :           // since nr1.0 doesn't seem to handle canonical paths for generics
     167              :           //   quite right anyways
     168        24754 :           return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
     169              :         }
     170              : 
     171         5022 :       cache = res.value ();
     172              :     }
     173        15374 :   return cache->as_path (ctx, ns);
     174              : }
     175              : 
     176              : Resolver::CanonicalPath
     177         6943 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx,
     178              :                                   Namespace ns)
     179              : {
     180         6943 :   auto parent_path = get_parent ().as_path (ctx, ns);
     181         6943 :   return parent_path.append (
     182        13886 :     Resolver::CanonicalPath::inherent_impl_seg (impl_id,
     183        20829 :                                                 type_record.as_path (ctx, ns)));
     184         6943 : }
     185              : 
     186              : Resolver::CanonicalPath
     187        10404 : CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx,
     188              :                                        Namespace ns)
     189              : {
     190              :   // Maybe this doesn't need the namespace and will always be in the types NS?
     191        10404 :   auto parent_path = get_parent ().as_path (ctx, ns);
     192        10404 :   return parent_path.append (
     193        20808 :     Resolver::CanonicalPath::trait_impl_projection_seg (
     194        20808 :       impl_id, trait_path_record.as_path (ctx, ns),
     195        31212 :       type_record.as_path (ctx, ns)));
     196        10404 : }
     197              : 
     198         4771 : NameResolutionContext::NameResolutionContext ()
     199         4771 :   : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
     200         4771 : {}
     201              : 
     202              : tl::expected<NodeId, DuplicateNameError>
     203       156936 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
     204              : {
     205       156936 :   switch (ns)
     206              :     {
     207        71817 :     case Namespace::Values:
     208        71817 :       return values.insert (name, id);
     209        84955 :     case Namespace::Types:
     210        84955 :       return types.insert (name, id);
     211          164 :     case Namespace::Macros:
     212          164 :       return macros.insert (name, id);
     213            0 :     case Namespace::Labels:
     214            0 :     default:
     215              :       // return labels.insert (name, id);
     216            0 :       rust_unreachable ();
     217              :     }
     218              : }
     219              : 
     220              : tl::expected<NodeId, DuplicateNameError>
     221         4348 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
     222              :                                        bool is_also_value)
     223              : {
     224         4348 :   auto res = types.insert_variant (name, id);
     225         4348 :   if (res.has_value () && is_also_value)
     226         1194 :     res = values.insert_variant (name, id);
     227         4348 :   return res;
     228              : }
     229              : 
     230              : tl::expected<NodeId, DuplicateNameError>
     231            0 : NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
     232              :                                           Namespace ns)
     233              : {
     234            0 :   switch (ns)
     235              :     {
     236            0 :     case Namespace::Values:
     237            0 :       return values.insert_shadowable (name, id);
     238            0 :     case Namespace::Types:
     239            0 :       return types.insert_shadowable (name, id);
     240            0 :     case Namespace::Macros:
     241            0 :       return macros.insert_shadowable (name, id);
     242            0 :     case Namespace::Labels:
     243            0 :     default:
     244              :       // return labels.insert (name, id);
     245            0 :       rust_unreachable ();
     246              :     }
     247              : }
     248              : 
     249              : tl::expected<NodeId, DuplicateNameError>
     250           84 : NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
     251              : {
     252           84 :   switch (ns)
     253              :     {
     254           42 :     case Namespace::Values:
     255           42 :       return values.insert_globbed (name, id);
     256           42 :     case Namespace::Types:
     257           42 :       return types.insert_globbed (name, id);
     258            0 :     case Namespace::Macros:
     259            0 :       return macros.insert_globbed (name, id);
     260            0 :     case Namespace::Labels:
     261            0 :     default:
     262              :       // return labels.insert (name, id);
     263            0 :       rust_unreachable ();
     264              :     }
     265              : }
     266              : 
     267              : // TODO: Maybe this should take a NamespacedDefinition as argument?
     268              : void
     269       214779 : NameResolutionContext::map_usage (Usage usage, Definition definition,
     270              :                                   Namespace ns)
     271              : {
     272       214779 :   switch (ns)
     273              :     {
     274        76620 :     case Namespace::Values:
     275        76620 :       values.map_usage (usage, definition);
     276        76620 :       break;
     277       137757 :     case Namespace::Types:
     278       137757 :       types.map_usage (usage, definition);
     279       137757 :       break;
     280           25 :     case Namespace::Labels:
     281           25 :       labels.map_usage (usage, definition);
     282           25 :       break;
     283          377 :     case Namespace::Macros:
     284          377 :       macros.map_usage (usage, definition);
     285          377 :       break;
     286              :     }
     287       214779 : }
     288              : 
     289              : tl::optional<NodeId>
     290      3207152 : NameResolutionContext::lookup (NodeId usage, Namespace ns) const
     291              : {
     292      3207152 :   switch (ns)
     293              :     {
     294       311727 :     case Namespace::Values:
     295       311727 :       return values.lookup (usage);
     296      2895324 :     case Namespace::Types:
     297      2895324 :       return types.lookup (usage);
     298          101 :     case Namespace::Labels:
     299          101 :       return labels.lookup (usage);
     300            0 :     case Namespace::Macros:
     301            0 :       return macros.lookup (usage);
     302            0 :     default:
     303            0 :       rust_unreachable ();
     304              :     }
     305              : }
     306              : 
     307              : tl::optional<NameResolutionContext::NSLookup>
     308       190275 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2) const
     309              : {
     310       190275 :   if (auto result = lookup (usage, ns1))
     311       130710 :     return NSLookup (*result, ns1);
     312              : 
     313        59565 :   return lookup (usage, ns2).map ([&ns2] (NodeId id) {
     314        55699 :     return NSLookup (id, ns2);
     315              :   });
     316              : }
     317              : 
     318              : tl::optional<NameResolutionContext::NSLookup>
     319            0 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2,
     320              :                                Namespace ns3) const
     321              : {
     322            0 :   if (auto result = lookup (usage, ns1, ns2))
     323            0 :     return result;
     324              : 
     325            0 :   return lookup (usage, ns3).map ([&ns3] (NodeId id) {
     326            0 :     return NSLookup (id, ns3);
     327              :   });
     328              : }
     329              : 
     330              : void
     331       540154 : NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
     332              :                                std::function<void (void)> lambda,
     333              :                                tl::optional<Identifier> path)
     334              : {
     335              :   // NOTE: You must be at the root node when pushing the prelude rib.
     336       540154 :   values.push (rib_kind, id, path);
     337       540154 :   types.push (rib_kind, id, path);
     338       540154 :   macros.push (rib_kind, id, path);
     339              :   // labels.push (rib, id);
     340              : 
     341       540154 :   lambda ();
     342              : 
     343       540146 :   values.pop ();
     344       540146 :   types.pop ();
     345       540146 :   macros.pop ();
     346              :   // labels.pop (rib);
     347       540146 : }
     348              : 
     349              : void
     350            0 : NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
     351              :                                NodeId scope_id,
     352              :                                std::function<void (void)> lambda,
     353              :                                tl::optional<Identifier> path)
     354              : {
     355              :   // This could work... I'm not sure why you would want to do this though.
     356            0 :   rust_assert (rib_kind != Rib::Kind::Prelude);
     357              : 
     358            0 :   switch (ns)
     359              :     {
     360            0 :     case Namespace::Values:
     361            0 :       values.push (rib_kind, scope_id, path);
     362            0 :       break;
     363            0 :     case Namespace::Types:
     364            0 :       types.push (rib_kind, scope_id, path);
     365            0 :       break;
     366            0 :     case Namespace::Labels:
     367            0 :     case Namespace::Macros:
     368            0 :       gcc_unreachable ();
     369              :     }
     370              : 
     371            0 :   lambda ();
     372              : 
     373            0 :   switch (ns)
     374              :     {
     375            0 :     case Namespace::Values:
     376            0 :       values.pop ();
     377            0 :       break;
     378            0 :     case Namespace::Types:
     379            0 :       types.pop ();
     380            0 :       break;
     381              :     case Namespace::Labels:
     382              :     case Namespace::Macros:
     383              :       gcc_unreachable ();
     384              :     }
     385            0 : }
     386              : 
     387              : #if 0
     388              : void
     389              : NameResolutionContext::flatten ()
     390              : {
     391              :   values.flatten ();
     392              :   types.flatten ();
     393              :   macros.flatten ();
     394              :   labels.flatten ();
     395              : }
     396              : #endif
     397              : 
     398              : } // namespace Resolver2_0
     399              : } // 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.