[gccrs COMMIT] Improve path resolution

gerris.rs@gmail.com gerris.rs@gmail.com
Fri Mar 20 16:02:53 GMT 2026


From: Owen Avery <powerboat9.gamer@gmail.com>

This makes path resolution less dependent on templates for path
handling.

gcc/rust/ChangeLog:

	* resolve/rust-forever-stack.h: Include more headers.
	(class ResolutionPath): New class for representing paths.
	(ForeverStack::resolve_path): Change function signature.
	(ForeverStack::find_starting_point): Likewise.
	(ForeverStack::resolve_segments): Likewise.
	(ForeverStack::SegIterator): Change type alias.
	* resolve/rust-forever-stack.hxx (check_leading_kw_at_start):
	Change function signature.
	(ForeverStack::find_starting_point): Likewise.
	(ForeverStack::resolve_segments): Likewise.
	(ForeverStack::resolve_path): Likewise.
	* resolve/rust-name-resolution-context.h: Tweak include guard,
	include "rust-name-resolution.h".
	(NameResolutionContext::resolve_path): Use ResolutionPath and
	ResolutionBuilder.
	(class NameResolutionContext::ResolutionBuilder): New class.
	(class Usage): Move this...
	(class Definition): ...and this...
	* resolve/rust-name-resolution.h: ...to new file.
	* util/rust-unwrap-segment.h: Add include guard.

Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: https://github.com/Rust-GCC/gccrs/commit/6e42e123e67a7b77266987b9a75cdb47d052bc3c

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4428

 gcc/rust/resolve/rust-forever-stack.h         | 103 ++++++--
 gcc/rust/resolve/rust-forever-stack.hxx       | 186 +++++++-------
 .../resolve/rust-name-resolution-context.h    | 240 +++++++++++-------
 gcc/rust/resolve/rust-name-resolution.h       |  50 ++++
 gcc/rust/util/rust-unwrap-segment.h           |   5 +
 5 files changed, 385 insertions(+), 199 deletions(-)
 create mode 100644 gcc/rust/resolve/rust-name-resolution.h

diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index 309a0ccd6..f6e351a1c 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -25,6 +25,8 @@
 #include "rust-path.h"
 #include "optional.h"
 #include "expected.h"
+#include "rust-name-resolution.h"
+#include "rust-unwrap-segment.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -550,6 +552,74 @@ enum class ResolutionMode
   FromExtern, // extern prelude
 };
 
+class ResolutionPath
+{
+public:
+  template <typename T>
+  ResolutionPath (const std::vector<T> &segments_in, NodeId node_id)
+    : node_id (node_id)
+  {
+    segments.clear ();
+    segments.reserve (segments_in.size ());
+    for (auto &outer_seg : segments_in)
+      {
+	if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
+	  {
+	    rust_assert (!lang_prefix.has_value ());
+	    lang_prefix = std::make_pair (lang_item.value (),
+					  unwrap_segment_node_id (outer_seg));
+	    continue;
+	  }
+
+	auto &seg = unwrap_type_segment (outer_seg);
+
+	Segment new_seg;
+	new_seg.name = seg.as_string ();
+	new_seg.node_id = unwrap_segment_node_id (outer_seg);
+	new_seg.locus = seg.get_locus ();
+	segments.push_back (std::move (new_seg));
+      }
+  }
+
+  ResolutionPath () : node_id (UNKNOWN_NODEID) {}
+
+  struct Segment
+  {
+    std::string name;
+    NodeId node_id;
+    location_t locus;
+
+    bool is_super_path_seg () const { return name.compare ("super") == 0; }
+    bool is_crate_path_seg () const { return name.compare ("crate") == 0; }
+    bool is_lower_self_seg () const { return name.compare ("self") == 0; }
+    bool is_big_self_seg () const { return name.compare ("Self") == 0; }
+  };
+
+  tl::optional<std::pair<LangItem::Kind, NodeId>> get_lang_prefix () const
+  {
+    return lang_prefix;
+  }
+
+  const std::vector<Segment> &get_segments () const { return segments; }
+
+  NodeId get_node_id () const { return node_id; }
+
+  std::string as_string () const
+  {
+    std::string ret;
+    if (lang_prefix)
+      ret = "#[lang]::";
+    for (auto &seg : segments)
+      ret += "::" + seg.name;
+    return ret;
+  }
+
+private:
+  tl::optional<std::pair<LangItem::Kind, NodeId>> lang_prefix;
+  std::vector<Segment> segments;
+  NodeId node_id;
+};
+
 template <Namespace N> class ForeverStack
 {
 public:
@@ -687,15 +757,13 @@ public:
    * @return a valid option with the Definition if the path is present in the
    *         current map, an empty one otherwise.
    */
-  template <typename S>
   tl::optional<Rib::Definition> resolve_path (
-    const std::vector<S> &segments, ResolutionMode mode,
-    std::function<void (const S &, NodeId)> insert_segment_resolution,
+    const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
     std::vector<Error> &collect_errors);
-  template <typename S>
   tl::optional<Rib::Definition> resolve_path (
-    const std::vector<S> &segments, ResolutionMode mode,
-    std::function<void (const S &, NodeId)> insert_segment_resolution,
+    const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
     std::vector<Error> &collect_errors, NodeId starting_point_id);
 
   // FIXME: Documentation
@@ -764,10 +832,9 @@ private:
 
   tl::optional<Rib::Definition> get (Node &start, const Identifier &name);
 
-  template <typename S>
   tl::optional<Rib::Definition> resolve_path (
-    const std::vector<S> &segments, ResolutionMode mode,
-    std::function<void (const S &, NodeId)> insert_segment_resolution,
+    const ResolutionPath &path, ResolutionMode mode,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
     std::vector<Error> &collect_errors,
     std::reference_wrapper<Node> starting_point);
 
@@ -817,23 +884,21 @@ private:
 
   /* Helper types and functions for `resolve_path` */
 
-  template <typename S>
-  using SegIterator = typename std::vector<S>::const_iterator;
+  using SegIterator =
+    typename std::vector<ResolutionPath::Segment>::const_iterator;
 
   Node &find_closest_module (Node &starting_point);
 
-  template <typename S>
-  tl::optional<SegIterator<S>> find_starting_point (
-    const std::vector<S> &segments,
+  tl::optional<SegIterator> find_starting_point (
+    const std::vector<ResolutionPath::Segment> &segments,
     std::reference_wrapper<Node> &starting_point,
-    std::function<void (const S &, NodeId)> insert_segment_resolution,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
     std::vector<Error> &collect_errors);
 
-  template <typename S>
   tl::optional<Node &> resolve_segments (
-    Node &starting_point, const std::vector<S> &segments,
-    SegIterator<S> iterator,
-    std::function<void (const S &, NodeId)> insert_segment_resolution,
+    Node &starting_point, const std::vector<ResolutionPath::Segment> &segments,
+    SegIterator iterator,
+    std::function<void (Usage, Definition)> insert_segment_resolution,
     std::vector<Error> &collect_errors);
 
   tl::optional<Rib::Definition> resolve_final_segment (Node &final_node,
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index 0f92a7f33..c7c5c9439 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -431,16 +431,15 @@ ForeverStack<N>::find_closest_module (Node &starting_point)
 
 /* If a the given condition is met, emit an error about misused leading path
  * segments */
-template <typename S>
 static inline bool
-check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
+check_leading_kw_at_start (std::vector<Error> &collect_errors,
+			   const ResolutionPath::Segment &segment,
 			   bool condition)
 {
   if (condition)
     collect_errors.emplace_back (
-      segment.get_locus (), ErrorCode::E0433,
-      "%qs in paths can only be used in start position",
-      segment.as_string ().c_str ());
+      segment.locus, ErrorCode::E0433,
+      "%qs in paths can only be used in start position", segment.name.c_str ());
 
   return condition;
 }
@@ -451,23 +450,19 @@ check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
 // `super` segment, we go back to the cursor's parent until we reach the
 // correct one or the root.
 template <Namespace N>
-template <typename S>
-tl::optional<typename std::vector<S>::const_iterator>
+tl::optional<typename std::vector<ResolutionPath::Segment>::const_iterator>
 ForeverStack<N>::find_starting_point (
-  const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
-  std::function<void (const S &, NodeId)> insert_segment_resolution,
+  const std::vector<ResolutionPath::Segment> &segments,
+  std::reference_wrapper<Node> &starting_point,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
   std::vector<Error> &collect_errors)
 {
   auto iterator = segments.begin ();
 
   for (; !is_last (iterator, segments); iterator++)
     {
-      auto &outer_seg = *iterator;
+      auto &seg = *iterator;
 
-      if (unwrap_segment_get_lang_item (outer_seg).has_value ())
-	break;
-
-      auto &seg = unwrap_type_segment (outer_seg);
       bool is_self_or_crate
 	= seg.is_crate_path_seg () || seg.is_lower_self_seg ();
 
@@ -481,7 +476,8 @@ ForeverStack<N>::find_starting_point (
       if (seg.is_crate_path_seg ())
 	{
 	  starting_point = root;
-	  insert_segment_resolution (outer_seg, starting_point.get ().id);
+	  insert_segment_resolution (Usage (seg.node_id),
+				     Definition (starting_point.get ().id));
 	  iterator++;
 	  break;
 	}
@@ -489,7 +485,8 @@ ForeverStack<N>::find_starting_point (
 	{
 	  // insert segment resolution and exit
 	  starting_point = find_closest_module (starting_point);
-	  insert_segment_resolution (outer_seg, starting_point.get ().id);
+	  insert_segment_resolution (Usage (seg.node_id),
+				     Definition (starting_point.get ().id));
 	  iterator++;
 	  break;
 	}
@@ -499,7 +496,7 @@ ForeverStack<N>::find_starting_point (
 	  if (starting_point.get ().is_root ())
 	    {
 	      collect_errors.emplace_back (
-		seg.get_locus (), ErrorCode::E0433,
+		seg.locus, ErrorCode::E0433,
 		"too many leading %<super%> keywords");
 	      return tl::nullopt;
 	    }
@@ -507,7 +504,8 @@ ForeverStack<N>::find_starting_point (
 	  starting_point
 	    = find_closest_module (starting_point.get ().parent.value ());
 
-	  insert_segment_resolution (outer_seg, starting_point.get ().id);
+	  insert_segment_resolution (Usage (seg.node_id),
+				     Definition (starting_point.get ().id));
 	  continue;
 	}
 
@@ -521,31 +519,19 @@ ForeverStack<N>::find_starting_point (
 }
 
 template <Namespace N>
-template <typename S>
 tl::optional<typename ForeverStack<N>::Node &>
 ForeverStack<N>::resolve_segments (
-  Node &starting_point, const std::vector<S> &segments,
-  typename std::vector<S>::const_iterator iterator,
-  std::function<void (const S &, NodeId)> insert_segment_resolution,
+  Node &starting_point, const std::vector<ResolutionPath::Segment> &segments,
+  typename std::vector<ResolutionPath::Segment>::const_iterator iterator,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
   std::vector<Error> &collect_errors)
 {
   Node *current_node = &starting_point;
   for (; !is_last (iterator, segments); iterator++)
     {
-      auto &outer_seg = *iterator;
-
-      if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
-	{
-	  NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
-	    lang_item.value ());
-	  current_node = &dfs_node (root, seg_id).value ();
+      auto &seg = *iterator;
 
-	  insert_segment_resolution (outer_seg, seg_id);
-	  continue;
-	}
-
-      auto &seg = unwrap_type_segment (outer_seg);
-      std::string str = seg.as_string ();
+      std::string str = seg.name;
       rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
 
       // check that we don't encounter *any* leading keywords afterwards
@@ -607,7 +593,7 @@ ForeverStack<N>::resolve_segments (
 	      break;
 	    }
 
-	  auto rib_lookup = current_node->rib.get (seg.as_string ());
+	  auto rib_lookup = current_node->rib.get (seg.name);
 	  if (rib_lookup && !rib_lookup->is_ambiguous ())
 	    {
 	      if (Analysis::Mappings::get ()
@@ -619,8 +605,9 @@ ForeverStack<N>::resolve_segments (
 		}
 	      else
 		{
-		  insert_segment_resolution (outer_seg,
-					     rib_lookup->get_node_id ());
+		  insert_segment_resolution (Usage (seg.node_id),
+					     Definition (
+					       rib_lookup->get_node_id ()));
 		  return tl::nullopt;
 		}
 	    }
@@ -645,7 +632,8 @@ ForeverStack<N>::resolve_segments (
       // if child didn't point to a value
       // the while loop above would have returned or kept looping
       current_node = &child->get ();
-      insert_segment_resolution (outer_seg, current_node->id);
+      insert_segment_resolution (Usage (seg.node_id),
+				 Definition (current_node->id));
     }
 
   return *current_node;
@@ -672,11 +660,10 @@ ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
 }
 
 template <Namespace N>
-template <typename S>
 tl::optional<Rib::Definition>
 ForeverStack<N>::resolve_path (
-  const std::vector<S> &segments, ResolutionMode mode,
-  std::function<void (const S &, NodeId)> insert_segment_resolution,
+  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);
@@ -686,34 +673,56 @@ ForeverStack<N>::resolve_path (
   if (!starting_point)
     return tl::nullopt;
 
-  return resolve_path (segments, mode, insert_segment_resolution,
-		       collect_errors, *starting_point);
+  return resolve_path (path, mode, insert_segment_resolution, collect_errors,
+		       *starting_point);
 }
 
 template <Namespace N>
-template <typename S>
 tl::optional<Rib::Definition>
 ForeverStack<N>::resolve_path (
-  const std::vector<S> &segments, ResolutionMode mode,
-  std::function<void (const S &, NodeId)> insert_segment_resolution,
+  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 (segments, mode, insert_segment_resolution,
-		       collect_errors, starting_point);
+  return resolve_path (path, mode, insert_segment_resolution, collect_errors,
+		       starting_point);
 }
 
 template <Namespace N>
-template <typename S>
 tl::optional<Rib::Definition>
 ForeverStack<N>::resolve_path (
-  const std::vector<S> &segments, ResolutionMode mode,
-  std::function<void (const S &, NodeId)> insert_segment_resolution,
+  const ResolutionPath &path, ResolutionMode mode,
+  std::function<void (Usage, Definition)> insert_segment_resolution,
   std::vector<Error> &collect_errors,
   std::reference_wrapper<Node> starting_point)
 {
-  rust_assert (!segments.empty ());
+  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
+    {
+      rust_assert (!path.get_segments ().empty ());
+    }
 
   switch (mode)
     {
@@ -729,40 +738,31 @@ ForeverStack<N>::resolve_path (
       rust_unreachable ();
     }
 
+  auto &segments = path.get_segments ();
+
   // if there's only one segment, we just use `get`
-  if (segments.size () == 1)
+  if (can_descend && segments.size () == 1)
     {
-      auto &outer_seg = segments.front ();
-      if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
-	{
-	  NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
-	    lang_item.value ());
-
-	  insert_segment_resolution (outer_seg, seg_id);
-	  // TODO: does NonShadowable matter?
-	  return Rib::Definition::NonShadowable (seg_id);
-	}
+      auto &seg = segments.front ();
 
-      auto &seg = unwrap_type_segment (outer_seg);
-
-      tl::optional<Rib::Definition> res
-	= get (starting_point.get (), seg.as_string ());
+      tl::optional<Rib::Definition> res = get (starting_point.get (), seg.name);
 
       if (!res)
-	res = get_lang_prelude (seg.as_string ());
+	res = get_lang_prelude (seg.name);
 
       if (N == Namespace::Types && !res)
 	{
 	  if (seg.is_crate_path_seg ())
 	    {
-	      insert_segment_resolution (outer_seg, root.id);
+	      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 (outer_seg, id);
+	      insert_segment_resolution (Usage (seg.node_id), Definition (id));
 	      // TODO: does NonShadowable matter?
 	      return Rib::Definition::NonShadowable (id);
 	    }
@@ -772,14 +772,14 @@ ForeverStack<N>::resolve_path (
 		= find_closest_module (starting_point.get ());
 	      if (closest_module.is_root ())
 		{
-		  rust_error_at (seg.get_locus (), ErrorCode::E0433,
+		  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 (outer_seg, id);
+	      insert_segment_resolution (Usage (seg.node_id), Definition (id));
 	      // TODO: does NonShadowable matter?
 	      return Rib::Definition::NonShadowable (id);
 	    }
@@ -794,11 +794,12 @@ ForeverStack<N>::resolve_path (
 		  if (link.path.map_or (
 			[&seg] (Identifier path) {
 			  auto &path_str = path.as_string ();
-			  return path_str == seg.as_string ();
+			  return path_str == seg.name;
 			},
 			false))
 		    {
-		      insert_segment_resolution (outer_seg, kv.second.id);
+		      insert_segment_resolution (Usage (seg.node_id),
+						 Definition (kv.second.id));
 		      return Rib::Definition::NonShadowable (kv.second.id);
 		    }
 		}
@@ -806,28 +807,33 @@ ForeverStack<N>::resolve_path (
 	}
 
       if (res && !res->is_ambiguous ())
-	insert_segment_resolution (outer_seg, res->get_node_id ());
+	insert_segment_resolution (Usage (seg.node_id),
+				   Definition (res->get_node_id ()));
       return res;
     }
 
-  return find_starting_point (segments, starting_point,
-			      insert_segment_resolution, collect_errors)
-    .and_then (
-      [this, &segments, &starting_point, &insert_segment_resolution,
-       &collect_errors] (typename std::vector<S>::const_iterator iterator) {
-	return resolve_segments (starting_point.get (), segments, iterator,
-				 insert_segment_resolution, collect_errors);
-      })
+  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 = unwrap_type_segment (segments.back ());
-      std::string seg_name = seg.as_string ();
+      auto &seg = segments.back ();
+      std::string seg_name = seg.name;
 
-      // assuming this can't be a lang item segment
       tl::optional<Rib::Definition> res
 	= resolve_final_segment (final_node, seg_name,
 				 seg.is_lower_self_seg ());
@@ -849,14 +855,16 @@ ForeverStack<N>::resolve_path (
 		    },
 		    false))
 		{
-		  insert_segment_resolution (segments.back (), kv.second.id);
+		  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 (segments.back (), res->get_node_id ());
+	insert_segment_resolution (Usage (seg.node_id),
+				   Definition (res->get_node_id ()));
 
       return res;
     });
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h
index 2d1ce3117..91eb0dcde 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -16,8 +16,8 @@
 // along with GCC; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-#ifndef RUST_NAME_RESOLVER_2_0_H
-#define RUST_NAME_RESOLVER_2_0_H
+#ifndef RUST_NAME_RESOLVER_2_0_CTX_H
+#define RUST_NAME_RESOLVER_2_0_CTX_H
 
 #include "optional.h"
 #include "rust-forever-stack.h"
@@ -25,6 +25,7 @@
 #include "rust-rib.h"
 #include "rust-stacked-contexts.h"
 #include "rust-item.h"
+#include "rust-name-resolution.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -136,28 +137,6 @@ change?
 correct
 */
 
-// FIXME: Documentation
-class Usage
-{
-public:
-  explicit Usage (NodeId id) : id (id) {}
-
-  // TODO: move to name-resolution-ctx.cc
-  // storing it as a key in a map
-  bool operator< (const Usage other) const { return other.id < id; }
-
-  NodeId id;
-};
-
-// FIXME: Documentation
-class Definition
-{
-public:
-  explicit Definition (NodeId id) : id (id) {}
-
-  NodeId id;
-};
-
 struct IdentifierMode
 {
   bool is_ref;
@@ -549,16 +528,14 @@ public:
     return canonical_ctx.get_path (id);
   }
 
-  template <typename S>
   tl::optional<Rib::Definition>
-  resolve_path (const std::vector<S> &segments, ResolutionMode mode,
+  resolve_path (const ResolutionPath &path, ResolutionMode mode,
 		std::vector<Error> &collect_errors, Namespace ns)
   {
-    std::function<void (const S &, NodeId)> insert_segment_resolution
-      = [this] (const S &seg, NodeId id) {
-	  auto seg_id = unwrap_segment_node_id (seg);
-	  if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
-	    map_usage (Usage (seg_id), Definition (id));
+    std::function<void (Usage, Definition)> insert_segment_resolution
+      = [this] (Usage seg_id, Definition id) {
+	  if (resolved_nodes.find (seg_id) == resolved_nodes.end ())
+	    map_usage (seg_id, id);
 	};
 
     tl::optional<Rib::Definition> resolved = tl::nullopt;
@@ -566,24 +543,20 @@ public:
     switch (ns)
       {
       case Namespace::Values:
-	resolved
-	  = values.resolve_path (segments, mode, insert_segment_resolution,
-				 collect_errors);
+	resolved = values.resolve_path (path, mode, insert_segment_resolution,
+					collect_errors);
 	break;
       case Namespace::Types:
-	resolved
-	  = types.resolve_path (segments, mode, insert_segment_resolution,
-				collect_errors);
+	resolved = types.resolve_path (path, mode, insert_segment_resolution,
+				       collect_errors);
 	break;
       case Namespace::Macros:
-	resolved
-	  = macros.resolve_path (segments, mode, insert_segment_resolution,
-				 collect_errors);
+	resolved = macros.resolve_path (path, mode, insert_segment_resolution,
+					collect_errors);
 	break;
       case Namespace::Labels:
-	resolved
-	  = labels.resolve_path (segments, mode, insert_segment_resolution,
-				 collect_errors);
+	resolved = labels.resolve_path (path, mode, insert_segment_resolution,
+					collect_errors);
 	break;
       default:
 	rust_unreachable ();
@@ -596,20 +569,16 @@ public:
 	switch (ns)
 	  {
 	  case Namespace::Values:
-	    return values.resolve_path (segments, mode,
-					insert_segment_resolution,
+	    return values.resolve_path (path, mode, insert_segment_resolution,
 					collect_errors, *prelude);
 	  case Namespace::Types:
-	    return types.resolve_path (segments, mode,
-				       insert_segment_resolution,
+	    return types.resolve_path (path, mode, insert_segment_resolution,
 				       collect_errors, *prelude);
 	  case Namespace::Macros:
-	    return macros.resolve_path (segments, mode,
-					insert_segment_resolution,
+	    return macros.resolve_path (path, mode, insert_segment_resolution,
 					collect_errors, *prelude);
 	  case Namespace::Labels:
-	    return labels.resolve_path (segments, mode,
-					insert_segment_resolution,
+	    return labels.resolve_path (path, mode, insert_segment_resolution,
 					collect_errors, *prelude);
 	  default:
 	    rust_unreachable ();
@@ -619,37 +588,122 @@ public:
     return resolved;
   }
 
+  class ResolutionBuilder
+  {
+  public:
+    ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}
+
+    template <typename S>
+    void set_path (const std::vector<S> &path_segments, NodeId node_id,
+		   bool has_opening_scope)
+    {
+      path = ResolutionPath (path_segments, node_id);
+      mode = ResolutionMode::Normal;
+      if (has_opening_scope)
+	{
+	  if (get_rust_edition () == Edition::E2015)
+	    mode = ResolutionMode::FromRoot;
+	  else
+	    mode = ResolutionMode::FromExtern;
+	}
+      has_path_set = true;
+    }
+
+    template <typename S>
+    void set_path (const std::vector<S> &path_segments, NodeId node_id,
+		   ResolutionMode mode)
+    {
+      path = ResolutionPath (path_segments, node_id);
+      this->mode = mode;
+      has_path_set = true;
+    }
+
+    void set_path (const AST::SimplePath &path)
+    {
+      set_path (path.get_segments (), path.get_node_id (),
+		path.has_opening_scope_resolution ());
+    }
+
+    void set_path (const AST::PathInExpression &path)
+    {
+      set_path (path.get_segments (), path.get_node_id (),
+		path.opening_scope_resolution ());
+    }
+
+    void set_path (const AST::TypePath &path)
+    {
+      set_path (path.get_segments (), path.get_node_id (),
+		path.has_opening_scope_resolution_op ());
+    }
+
+    void set_mode (ResolutionMode mode) { this->mode = mode; }
+
+    void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }
+
+    template <typename... Args> void add_namespaces (Namespace ns, Args... rest)
+    {
+      add_namespaces (ns);
+      add_namespaces (rest...);
+    }
+
+    void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)
+    {
+      this->collect_errors = collect_errors;
+    }
+
+    tl::optional<Rib::Definition> resolve ()
+    {
+      rust_assert (has_path_set);
+
+      for (auto ns : namespace_list)
+	{
+	  std::vector<Error> collect_errors_inner;
+	  if (auto ret
+	      = ctx->resolve_path (path, mode, collect_errors_inner, ns))
+	    return ret;
+	  if (!collect_errors_inner.empty ())
+	    {
+	      if (collect_errors.has_value ())
+		{
+		  std::move (collect_errors_inner.begin (),
+			     collect_errors_inner.end (),
+			     std::back_inserter (collect_errors.value ()));
+		}
+	      else
+		{
+		  for (auto &e : collect_errors_inner)
+		    e.emit ();
+		}
+	    }
+	}
+
+      return tl::nullopt;
+    }
+
+  private:
+    ResolutionPath path;
+    ResolutionMode mode;
+    bool has_path_set;
+
+    std::vector<Namespace> namespace_list;
+
+    tl::optional<std::vector<Error> &> collect_errors;
+
+    NameResolutionContext *ctx;
+  };
+
   template <typename S, typename... Args>
   tl::optional<Rib::Definition>
-  resolve_path (const std::vector<S> &segments, ResolutionMode mode,
+  resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
 		tl::optional<std::vector<Error> &> collect_errors,
 		Namespace ns_first, Args... ns_args)
   {
-    std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
+    ResolutionBuilder builder (*this);
+    builder.set_path (path_segments, UNKNOWN_NODEID, mode);
+    builder.add_namespaces (ns_first, ns_args...);
+    builder.set_collect_errors (collect_errors);
 
-    for (auto ns : namespaces)
-      {
-	std::vector<Error> collect_errors_inner;
-	if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns))
-	  return ret;
-	if (!collect_errors_inner.empty ())
-	  {
-	    if (collect_errors.has_value ())
-	      {
-		std::move (collect_errors_inner.begin (),
-			   collect_errors_inner.end (),
-			   std::back_inserter (collect_errors.value ()));
-	      }
-	    else
-	      {
-		for (auto &e : collect_errors_inner)
-		  e.emit ();
-	      }
-	    return tl::nullopt;
-	  }
-      }
-
-    return tl::nullopt;
+    return builder.resolve ();
   }
 
   template <typename S, typename... Args>
@@ -659,16 +713,13 @@ public:
 		tl::optional<std::vector<Error> &> collect_errors,
 		Namespace ns_first, Args... ns_args)
   {
-    auto mode = ResolutionMode::Normal;
-    if (has_opening_scope_resolution)
-      {
-	if (get_rust_edition () == Edition::E2015)
-	  mode = ResolutionMode::FromRoot;
-	else
-	  mode = ResolutionMode::FromExtern;
-      }
-    return resolve_path (path_segments, mode, collect_errors, ns_first,
-			 ns_args...);
+    ResolutionBuilder builder (*this);
+    builder.set_path (path_segments, UNKNOWN_NODEID,
+		      has_opening_scope_resolution);
+    builder.add_namespaces (ns_first, ns_args...);
+    builder.set_collect_errors (collect_errors);
+
+    return builder.resolve ();
   }
 
   template <typename S, typename... Args>
@@ -677,8 +728,12 @@ public:
 		bool has_opening_scope_resolution, Namespace ns_first,
 		Args... ns_args)
   {
-    return resolve_path (path_segments, has_opening_scope_resolution,
-			 tl::nullopt, ns_first, ns_args...);
+    ResolutionBuilder builder (*this);
+    builder.set_path (path_segments, UNKNOWN_NODEID,
+		      has_opening_scope_resolution);
+    builder.add_namespaces (ns_first, ns_args...);
+
+    return builder.resolve ();
   }
 
   template <typename S, typename... Args>
@@ -686,8 +741,11 @@ public:
   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,
 		Namespace ns_first, Args... ns_args)
   {
-    return resolve_path (path_segments, mode, tl::nullopt, ns_first,
-			 ns_args...);
+    ResolutionBuilder builder (*this);
+    builder.set_path (path_segments, UNKNOWN_NODEID, mode);
+    builder.add_namespaces (ns_first, ns_args...);
+
+    return builder.resolve ();
   }
 
   template <typename... Args>
@@ -727,4 +785,4 @@ private:
 } // namespace Resolver2_0
 } // namespace Rust
 
-#endif // ! RUST_NAME_RESOLVER_2_0_H
+#endif // ! RUST_NAME_RESOLVER_2_0_CTX_H
diff --git a/gcc/rust/resolve/rust-name-resolution.h b/gcc/rust/resolve/rust-name-resolution.h
new file mode 100644
index 000000000..6d5b4ec87
--- /dev/null
+++ b/gcc/rust/resolve/rust-name-resolution.h
@@ -0,0 +1,50 @@
+// 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/>.
+
+#ifndef RUST_NAME_RESOLVER_2_0_H
+#define RUST_NAME_RESOLVER_2_0_H
+
+namespace Rust {
+namespace Resolver2_0 {
+
+// FIXME: Documentation
+class Usage
+{
+public:
+  explicit Usage (NodeId id) : id (id) {}
+
+  // TODO: move to name-resolution-ctx.cc
+  // storing it as a key in a map
+  bool operator< (const Usage other) const { return other.id < id; }
+
+  NodeId id;
+};
+
+// FIXME: Documentation
+class Definition
+{
+public:
+  explicit Definition (NodeId id) : id (id) {}
+
+  NodeId id;
+};
+
+} // namespace Resolver2_0
+} // namespace Rust
+
+#endif // RUST_NAME_RESOLVER_2_0_H
diff --git a/gcc/rust/util/rust-unwrap-segment.h b/gcc/rust/util/rust-unwrap-segment.h
index 7181bd253..0bebe2871 100644
--- a/gcc/rust/util/rust-unwrap-segment.h
+++ b/gcc/rust/util/rust-unwrap-segment.h
@@ -16,6 +16,9 @@
 // along with GCC; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+#ifndef RUST_UNWRAP_SEGMENT_H
+#define RUST_UNWRAP_SEGMENT_H
+
 #include "rust-system.h"
 #include "optional.h"
 #include "rust-lang-item.h"
@@ -136,3 +139,5 @@ unwrap_segment_error_string (const AST::PathInExpression &path)
 }
 
 } // namespace Rust
+
+#endif // RUST_UNWRAP_SEGMENT_H

base-commit: 5d80c76a57265bc7183af4a6040104fdca371702
-- 
2.53.0



More information about the Gcc-rust mailing list