]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Improve path resolution
authorOwen Avery <powerboat9.gamer@gmail.com>
Sat, 7 Feb 2026 01:11:20 +0000 (20:11 -0500)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 14 Apr 2026 21:48:35 +0000 (23:48 +0200)
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>
gcc/rust/resolve/rust-forever-stack.h
gcc/rust/resolve/rust-forever-stack.hxx
gcc/rust/resolve/rust-name-resolution-context.h
gcc/rust/resolve/rust-name-resolution.h [new file with mode: 0644]
gcc/rust/util/rust-unwrap-segment.h

index 309a0ccd6309c6ff40d8ff893ff33e3bb6ab5273..f6e351a1c4f725b4d9f9d8c2394d96794c088001 100644 (file)
@@ -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,
index 0f92a7f332ad489c97346124daccd53fe87afb71..c7c5c9439e46428a1807a534c409e22ff8ad7963 100644 (file)
@@ -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;
     });
index 2d1ce3117b574976c95dace847ca3efbf6c83c39..91eb0dcde759ec0cb8dbf05079ca3e02dd41562c 100644 (file)
@@ -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 (file)
index 0000000..6d5b4ec
--- /dev/null
@@ -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
index 7181bd2537984d6e9fa662044a7a01ba4f0d6a7b..0bebe287152de5ea95060bcc4b4776dae1102d2b 100644 (file)
@@ -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