https://gcc.gnu.org/g:41a3c8a9c31e4389f1238a75709bb7e8e7da76cf

commit r17-1078-g41a3c8a9c31e4389f1238a75709bb7e8e7da76cf
Author: Arthur Cohen <[email protected]>
Date:   Mon Mar 23 05:36:16 2026 +0100

    gccrs: nr: Move path resolution from ForeverStack to NRCtx
    
    gcc/rust/ChangeLog:
    
            * resolve/rust-forever-stack.h: Move declarations from ForeverStack 
to NRCtx, make most
            of the ForeverStack members public as it helps the Ctx a lot.
            * resolve/rust-forever-stack.hxx: Move implementation of 
resolve_path methods to NRCtx.
            * resolve/rust-name-resolution-context.h: Declare resolve_path 
methods.
            * resolve/rust-name-resolution-context.hxx: New file with 
resolve_path impls.

Diff:
---
 gcc/rust/resolve/rust-forever-stack.h             |  30 +--
 gcc/rust/resolve/rust-forever-stack.hxx           | 214 -------------------
 gcc/rust/resolve/rust-name-resolution-context.h   |  62 ++++--
 gcc/rust/resolve/rust-name-resolution-context.hxx | 249 ++++++++++++++++++++++
 4 files changed, 296 insertions(+), 259 deletions(-)

diff --git a/gcc/rust/resolve/rust-forever-stack.h 
b/gcc/rust/resolve/rust-forever-stack.h
index f6e351a1c4f7..242b588a3945 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -749,23 +749,6 @@ public:
   tl::optional<Rib::Definition> get_from_prelude (NodeId prelude,
                                                  const Identifier &name);
 
-  /**
-   * Resolve a path to its definition in the current `ForeverStack`
-   *
-   * // TODO: Add documentation for `segments`
-   *
-   * @return a valid option with the Definition if the path is present in the
-   *         current map, an empty one otherwise.
-   */
-  tl::optional<Rib::Definition> resolve_path (
-    const ResolutionPath &path, ResolutionMode mode,
-    std::function<void (Usage, Definition)> insert_segment_resolution,
-    std::vector<Error> &collect_errors);
-  tl::optional<Rib::Definition> resolve_path (
-    const ResolutionPath &path, ResolutionMode mode,
-    std::function<void (Usage, Definition)> insert_segment_resolution,
-    std::vector<Error> &collect_errors, NodeId starting_point_id);
-
   // FIXME: Documentation
   tl::optional<Rib &> to_rib (NodeId rib_id);
   tl::optional<const Rib &> to_rib (NodeId rib_id) const;
@@ -778,7 +761,6 @@ public:
    */
   bool is_module_descendant (NodeId parent, NodeId child) const;
 
-private:
   /**
    * A link between two Nodes in our trie data structure. This class represents
    * the edges of the graph
@@ -826,18 +808,8 @@ private:
     tl::optional<Node &> parent; // `None` only if the node is a root
   };
 
-  /**
-   * Private overloads which allow specifying a starting point
-   */
-
   tl::optional<Rib::Definition> get (Node &start, const Identifier &name);
 
-  tl::optional<Rib::Definition> resolve_path (
-    const ResolutionPath &path, ResolutionMode mode,
-    std::function<void (Usage, Definition)> insert_segment_resolution,
-    std::vector<Error> &collect_errors,
-    std::reference_wrapper<Node> starting_point);
-
   /* Should we keep going upon seeing a Rib? */
   enum class KeepGoing
   {
@@ -859,6 +831,7 @@ private:
 
   Node &cursor ();
   const Node &cursor () const;
+
   void update_cursor (Node &new_cursor);
 
   /* The forever stack's actual nodes */
@@ -930,7 +903,6 @@ private:
   tl::optional<const Node &> dfs_node (const Node &starting_point,
                                       NodeId to_find) const;
 
-public:
   bool forward_declared (NodeId definition, NodeId usage)
   {
     if (peek ().kind != Rib::Kind::ForwardTypeParamBan)
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx 
b/gcc/rust/resolve/rust-forever-stack.hxx
index c7f90ae3a216..e3cd5b7add3b 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -667,220 +667,6 @@ ForeverStack<N>::resolve_final_segment (Node &final_node, 
std::string &seg_name,
   return final_node.rib.get (seg_name);
 }
 
-template <Namespace N>
-tl::optional<Rib::Definition>
-ForeverStack<N>::resolve_path (
-  const ResolutionPath &path, ResolutionMode mode,
-  std::function<void (Usage, Definition)> insert_segment_resolution,
-  std::vector<Error> &collect_errors, NodeId starting_point_id)
-{
-  auto starting_point = dfs_node (root, starting_point_id);
-
-  // We may have a prelude, but haven't visited it yet and thus it's not in our
-  // nodes
-  if (!starting_point)
-    return tl::nullopt;
-
-  return resolve_path (path, mode, insert_segment_resolution, collect_errors,
-                      *starting_point);
-}
-
-template <Namespace N>
-tl::optional<Rib::Definition>
-ForeverStack<N>::resolve_path (
-  const ResolutionPath &path, ResolutionMode mode,
-  std::function<void (Usage, Definition)> insert_segment_resolution,
-  std::vector<Error> &collect_errors)
-{
-  std::reference_wrapper<Node> starting_point = cursor ();
-
-  return resolve_path (path, mode, insert_segment_resolution, collect_errors,
-                      starting_point);
-}
-
-template <Namespace N>
-tl::optional<Rib::Definition>
-ForeverStack<N>::resolve_path (
-  const ResolutionPath &path, ResolutionMode mode,
-  std::function<void (Usage, Definition)> insert_segment_resolution,
-  std::vector<Error> &collect_errors,
-  std::reference_wrapper<Node> starting_point)
-{
-  bool can_descend = true;
-
-  rust_debug ("resolving %s", path.as_string ().c_str ());
-
-  if (auto lang_item = path.get_lang_prefix ())
-    {
-      NodeId seg_id
-       = Analysis::Mappings::get ().get_lang_item_node (lang_item->first);
-
-      insert_segment_resolution (Usage (lang_item->second),
-                                Definition (seg_id));
-
-      if (path.get_segments ().empty ())
-       return Rib::Definition::NonShadowable (seg_id);
-
-      auto new_start = dfs_node (root, seg_id);
-      rust_assert (new_start.has_value ());
-      starting_point = new_start.value ();
-
-      can_descend = false;
-    }
-  else
-    {
-      switch (mode)
-       {
-       case ResolutionMode::Normal:
-         break; // default
-       case ResolutionMode::FromRoot:
-         starting_point = root;
-         break;
-       case ResolutionMode::FromExtern:
-         starting_point = extern_prelude;
-         break;
-       default:
-         rust_unreachable ();
-       }
-    }
-
-  if (path.get_segments ().empty ())
-    {
-      return Rib::Definition::NonShadowable (starting_point.get ().id);
-    }
-
-  auto &segments = path.get_segments ();
-
-  // if there's only one segment, we just use `get`
-  if (can_descend && segments.size () == 1)
-    {
-      auto &seg = segments.front ();
-
-      tl::optional<Rib::Definition> res = get (starting_point.get (), 
seg.name);
-
-      if (!res)
-       res = get_lang_prelude (seg.name);
-
-      if (N == Namespace::Types && !res)
-       {
-         if (seg.is_crate_path_seg ())
-           {
-             insert_segment_resolution (Usage (seg.node_id),
-                                        Definition (root.id));
-             // TODO: does NonShadowable matter?
-             return Rib::Definition::NonShadowable (root.id);
-           }
-         else if (seg.is_lower_self_seg ())
-           {
-             NodeId id = find_closest_module (starting_point.get ()).id;
-             insert_segment_resolution (Usage (seg.node_id), Definition (id));
-             // TODO: does NonShadowable matter?
-             return Rib::Definition::NonShadowable (id);
-           }
-         else if (seg.is_super_path_seg ())
-           {
-             Node &closest_module
-               = find_closest_module (starting_point.get ());
-             if (closest_module.is_root ())
-               {
-                 rust_error_at (seg.locus, ErrorCode::E0433,
-                                "too many leading %<super%> keywords");
-                 return tl::nullopt;
-               }
-
-             NodeId id
-               = find_closest_module (closest_module.parent.value ()).id;
-             insert_segment_resolution (Usage (seg.node_id), Definition (id));
-             // TODO: does NonShadowable matter?
-             return Rib::Definition::NonShadowable (id);
-           }
-         else
-           {
-             // HACK: check for a module after we check the language prelude
-             for (auto &kv :
-                  find_closest_module (starting_point.get ()).children)
-               {
-                 auto &link = kv.first;
-
-                 if (link.path.map_or (
-                       [&seg] (Identifier path) {
-                         auto &path_str = path.as_string ();
-                         return path_str == seg.name;
-                       },
-                       false))
-                   {
-                     insert_segment_resolution (Usage (seg.node_id),
-                                                Definition (kv.second.id));
-                     return Rib::Definition::NonShadowable (kv.second.id);
-                   }
-               }
-           }
-       }
-
-      if (res && !res->is_ambiguous ())
-       insert_segment_resolution (Usage (seg.node_id),
-                                  Definition (res->get_node_id ()));
-      return res;
-    }
-
-  auto iterator = segments.begin ();
-  if (can_descend)
-    {
-      if (auto res
-         = find_starting_point (segments, starting_point,
-                                insert_segment_resolution, collect_errors))
-       iterator = *res;
-      else
-       return tl::nullopt;
-    }
-
-  return resolve_segments (starting_point.get (), segments, iterator,
-                          insert_segment_resolution, collect_errors)
-    .and_then ([this, &segments, &insert_segment_resolution] (
-                Node &final_node) -> tl::optional<Rib::Definition> {
-      // leave resolution within impl blocks to type checker
-      if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
-       return tl::nullopt;
-
-      auto &seg = segments.back ();
-      std::string seg_name = seg.name;
-
-      tl::optional<Rib::Definition> res
-       = resolve_final_segment (final_node, seg_name,
-                                seg.is_lower_self_seg ());
-      // Ok we didn't find it in the rib, Lets try the prelude...
-      if (!res)
-       res = get_lang_prelude (seg_name);
-
-      if (N == Namespace::Types && !res)
-       {
-         // HACK: check for a module after we check the language prelude
-         for (auto &kv : final_node.children)
-           {
-             auto &link = kv.first;
-
-             if (link.path.map_or (
-                   [&seg_name] (Identifier path) {
-                     auto &path_str = path.as_string ();
-                     return path_str == seg_name;
-                   },
-                   false))
-               {
-                 insert_segment_resolution (Usage (seg.node_id),
-                                            Definition (kv.second.id));
-                 return Rib::Definition::NonShadowable (kv.second.id);
-               }
-           }
-       }
-
-      if (res && !res->is_ambiguous ())
-       insert_segment_resolution (Usage (seg.node_id),
-                                  Definition (res->get_node_id ()));
-
-      return res;
-    });
-}
-
 template <Namespace N>
 tl::optional<typename ForeverStack<N>::DfsResult>
 ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h 
b/gcc/rust/resolve/rust-name-resolution-context.h
index eac38eb62d61..c5b2d0b1c00c 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -543,20 +543,20 @@ public:
     switch (ns)
       {
       case Namespace::Values:
-       resolved = values.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors);
+       resolved = resolve_path (values, path, mode, insert_segment_resolution,
+                                collect_errors);
        break;
       case Namespace::Types:
-       resolved = types.resolve_path (path, mode, insert_segment_resolution,
-                                      collect_errors);
+       resolved = resolve_path (types, path, mode, insert_segment_resolution,
+                                collect_errors);
        break;
       case Namespace::Macros:
-       resolved = macros.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors);
+       resolved = resolve_path (macros, path, mode, insert_segment_resolution,
+                                collect_errors);
        break;
       case Namespace::Labels:
-       resolved = labels.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors);
+       resolved = resolve_path (labels, path, mode, insert_segment_resolution,
+                                collect_errors);
        break;
       default:
        rust_unreachable ();
@@ -569,17 +569,17 @@ public:
        switch (ns)
          {
          case Namespace::Values:
-           return values.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors, *prelude);
+           return resolve_path (values, path, mode, insert_segment_resolution,
+                                collect_errors, *prelude);
          case Namespace::Types:
-           return types.resolve_path (path, mode, insert_segment_resolution,
-                                      collect_errors, *prelude);
+           return resolve_path (types, path, mode, insert_segment_resolution,
+                                collect_errors, *prelude);
          case Namespace::Macros:
-           return macros.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors, *prelude);
+           return resolve_path (macros, path, mode, insert_segment_resolution,
+                                collect_errors, *prelude);
          case Namespace::Labels:
-           return labels.resolve_path (path, mode, insert_segment_resolution,
-                                       collect_errors, *prelude);
+           return resolve_path (labels, path, mode, insert_segment_resolution,
+                                collect_errors, *prelude);
          default:
            rust_unreachable ();
          }
@@ -774,6 +774,34 @@ public:
                         std::forward<Args> (args)...);
   }
 
+  /**
+   * Resolve a path to its definition in the current `ForeverStack`
+   *
+   * // TODO: Add documentation for `segments`
+   *
+   * @return a valid option with the Definition if the path is present in the
+   *         current map, an empty one otherwise.
+   */
+  template <Namespace N>
+  tl::optional<Rib::Definition> resolve_path (
+    ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
+    std::vector<Error> &collect_errors);
+
+  template <Namespace N>
+  tl::optional<Rib::Definition> resolve_path (
+    ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
+    std::vector<Error> &collect_errors, NodeId starting_point_id);
+
+  /* TODO: Make private? */
+  template <Namespace N>
+  tl::optional<Rib::Definition> resolve_path (
+    ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
+    std::vector<Error> &collect_errors,
+    std::reference_wrapper<typename ForeverStack<N>::Node> starting_point);
+
   /* If declared with #[prelude_import], the current standard library module */
   tl::optional<NodeId> prelude;
 
@@ -785,4 +813,6 @@ private:
 } // namespace Resolver2_0
 } // namespace Rust
 
+#include "rust-name-resolution-context.hxx"
+
 #endif // ! RUST_NAME_RESOLVER_2_0_CTX_H
diff --git a/gcc/rust/resolve/rust-name-resolution-context.hxx 
b/gcc/rust/resolve/rust-name-resolution-context.hxx
new file mode 100644
index 000000000000..ae89126153de
--- /dev/null
+++ b/gcc/rust/resolve/rust-name-resolution-context.hxx
@@ -0,0 +1,249 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-name-resolution-context.h"
+
+/**
+ * Split the actual path resolution logic in its own file because it's a lot,
+ * and it could get even worse for certain edge cases.
+ */
+
+namespace Rust {
+namespace Resolver2_0 {
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+NameResolutionContext::resolve_path (
+  ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
+  std::vector<Error> &collect_errors)
+{
+  std::reference_wrapper<typename ForeverStack<N>::Node> starting_point
+    = stack.cursor ();
+
+  return NameResolutionContext::resolve_path (stack, path, mode,
+                                             insert_segment_resolution,
+                                             collect_errors, starting_point);
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+NameResolutionContext::resolve_path (
+  ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
+  std::vector<Error> &collect_errors, NodeId starting_point_id)
+
+{
+  auto starting_point = stack.dfs_node (stack.root, starting_point_id);
+
+  // We may have a prelude, but haven't visited it yet and thus it's not in
+  // our nodes
+  if (!starting_point)
+    return tl::nullopt;
+
+  return NameResolutionContext::resolve_path (stack, path, mode,
+                                             insert_segment_resolution,
+                                             collect_errors, *starting_point);
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+NameResolutionContext::resolve_path (
+  ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
+  std::vector<Error> &collect_errors,
+  std::reference_wrapper<typename ForeverStack<N>::Node> starting_point)
+{
+  bool can_descend = true;
+
+  rust_debug ("resolving %s", path.as_string ().c_str ());
+
+  if (auto lang_item = path.get_lang_prefix ())
+    {
+      NodeId seg_id
+       = Analysis::Mappings::get ().get_lang_item_node (lang_item->first);
+
+      insert_segment_resolution (Usage (lang_item->second),
+                                Definition (seg_id));
+
+      if (path.get_segments ().empty ())
+       return Rib::Definition::NonShadowable (seg_id);
+
+      auto new_start = stack.dfs_node (stack.root, seg_id);
+      rust_assert (new_start.has_value ());
+      starting_point = new_start.value ();
+
+      can_descend = false;
+    }
+  else
+    {
+      switch (mode)
+       {
+       case ResolutionMode::Normal:
+         break; // default
+       case ResolutionMode::FromRoot:
+         starting_point = stack.root;
+         break;
+       case ResolutionMode::FromExtern:
+         starting_point = stack.extern_prelude;
+         break;
+       default:
+         rust_unreachable ();
+       }
+    }
+
+  if (path.get_segments ().empty ())
+    return Rib::Definition::NonShadowable (starting_point.get ().id);
+
+  auto &segments = path.get_segments ();
+
+  // if there's only one segment, we just use `get`
+  if (can_descend && segments.size () == 1)
+    {
+      auto &seg = segments.front ();
+
+      tl::optional<Rib::Definition> res
+       = stack.get (starting_point.get (), seg.name);
+
+      if (!res)
+       res = stack.get_lang_prelude (seg.name);
+
+      if (N == Namespace::Types && !res)
+       {
+         if (seg.is_crate_path_seg ())
+           {
+             insert_segment_resolution (Usage (seg.node_id),
+                                        Definition (stack.root.id));
+             // TODO: does NonShadowable matter?
+             return Rib::Definition::NonShadowable (stack.root.id);
+           }
+         else if (seg.is_lower_self_seg ())
+           {
+             NodeId id = stack.find_closest_module (starting_point.get ()).id;
+             insert_segment_resolution (Usage (seg.node_id), Definition (id));
+             // TODO: does NonShadowable matter?
+             return Rib::Definition::NonShadowable (id);
+           }
+         else if (seg.is_super_path_seg ())
+           {
+             auto &closest_module
+               = stack.find_closest_module (starting_point.get ());
+             if (closest_module.is_root ())
+               {
+                 rust_error_at (seg.locus, ErrorCode::E0433,
+                                "too many leading %<super%> keywords");
+                 return tl::nullopt;
+               }
+
+             NodeId id
+               = stack.find_closest_module (closest_module.parent.value ()).id;
+             insert_segment_resolution (Usage (seg.node_id), Definition (id));
+             // TODO: does NonShadowable matter?
+             return Rib::Definition::NonShadowable (id);
+           }
+         else
+           {
+             // HACK: check for a module after we check the language prelude
+             for (auto &kv :
+                  stack.find_closest_module (starting_point.get ()).children)
+               {
+                 auto &link = kv.first;
+
+                 if (link.path.map_or (
+                       [&seg] (Identifier path) {
+                         auto &path_str = path.as_string ();
+                         return path_str == seg.name;
+                       },
+                       false))
+                   {
+                     insert_segment_resolution (Usage (seg.node_id),
+                                                Definition (kv.second.id));
+                     return Rib::Definition::NonShadowable (kv.second.id);
+                   }
+               }
+           }
+       }
+
+      if (res && !res->is_ambiguous ())
+       insert_segment_resolution (Usage (seg.node_id),
+                                  Definition (res->get_node_id ()));
+      return res;
+    }
+
+  auto iterator = segments.begin ();
+  if (can_descend)
+    {
+      if (auto res = stack.find_starting_point (segments, starting_point,
+                                               insert_segment_resolution,
+                                               collect_errors))
+       iterator = *res;
+      else
+       return tl::nullopt;
+    }
+
+  return stack
+    .resolve_segments (starting_point.get (), segments, iterator,
+                      insert_segment_resolution, collect_errors)
+    .and_then ([&segments, &insert_segment_resolution,
+               &stack] (typename ForeverStack<N>::Node &final_node)
+                -> tl::optional<Rib::Definition> {
+      // leave resolution within impl blocks to type checker
+      if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
+       return tl::nullopt;
+
+      auto &seg = segments.back ();
+      std::string seg_name = seg.name;
+
+      tl::optional<Rib::Definition> res
+       = stack.resolve_final_segment (final_node, seg_name,
+                                      seg.is_lower_self_seg ());
+      // Ok we didn't find it in the rib, Lets try the prelude...
+      if (!res)
+       res = stack.get_lang_prelude (seg_name);
+
+      if (N == Namespace::Types && !res)
+       {
+         // HACK: check for a module after we check the language prelude
+         for (auto &kv : final_node.children)
+           {
+             auto &link = kv.first;
+
+             if (link.path.map_or (
+                   [&seg_name] (Identifier path) {
+                     auto &path_str = path.as_string ();
+                     return path_str == seg_name;
+                   },
+                   false))
+               {
+                 insert_segment_resolution (Usage (seg.node_id),
+                                            Definition (kv.second.id));
+                 return Rib::Definition::NonShadowable (kv.second.id);
+               }
+           }
+       }
+
+      if (res && !res->is_ambiguous ())
+       insert_segment_resolution (Usage (seg.node_id),
+                                  Definition (res->get_node_id ()));
+
+      return res;
+    });
+}
+
+} // namespace Resolver2_0
+} // namespace Rust

Reply via email to