{"id":2223274,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2223274/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260414231905.191063-2-arthur.cohen@embecosm.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20260414231905.191063-2-arthur.cohen@embecosm.com>","date":"2026-04-14T23:18:23","name":"[COMMITTED,02/43] gccrs: Improve path resolution","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"33489c25c4de83f09cae00a07433e37fa2e17b9b","submitter":{"id":83476,"url":"http://patchwork.ozlabs.org/api/1.1/people/83476/?format=json","name":"Arthur Cohen","email":"arthur.cohen@embecosm.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260414231905.191063-2-arthur.cohen@embecosm.com/mbox/","series":[{"id":499900,"url":"http://patchwork.ozlabs.org/api/1.1/series/499900/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=499900","date":"2026-04-14T23:18:24","name":"[COMMITTED,01/43] gccrs: testsuite:Add a testcase for setup_associated_types","version":1,"mbox":"http://patchwork.ozlabs.org/series/499900/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2223274/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2223274/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=embecosm.com header.i=@embecosm.com header.a=rsa-sha256\n header.s=google header.b=Q0+defBm;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=embecosm.com header.i=@embecosm.com header.a=rsa-sha256\n header.s=google header.b=Q0+defBm","sourceware.org;\n dmarc=none (p=none dis=none) header.from=embecosm.com","sourceware.org; spf=pass smtp.mailfrom=embecosm.com","server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.128.67"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fwKtt1GKhz1yHc\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 15 Apr 2026 09:17:42 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 5CCA14BA23C3\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 14 Apr 2026 23:17:40 +0000 (GMT)","from mail-wm1-f67.google.com (mail-wm1-f67.google.com\n [209.85.128.67])\n by sourceware.org (Postfix) with ESMTPS id CCF4C4BA2E07\n for <gcc-patches@gcc.gnu.org>; Tue, 14 Apr 2026 23:14:12 +0000 (GMT)","by mail-wm1-f67.google.com with SMTP id\n 5b1f17b1804b1-4888375f735so60516025e9.3\n for <gcc-patches@gcc.gnu.org>; Tue, 14 Apr 2026 16:14:12 -0700 (PDT)","from platypus.localdomain (176-147-231-59.abo.bbox.fr.\n [176.147.231.59]) by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-488f1dd8806sm3325945e9.3.2026.04.14.16.14.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 14 Apr 2026 16:14:10 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 5CCA14BA23C3","OpenDKIM Filter v2.11.0 sourceware.org CCF4C4BA2E07"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org CCF4C4BA2E07","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org CCF4C4BA2E07","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776208453; cv=none;\n b=wNV6zheBhbyE1/NjHxNmY4bWuFVmFaVQ5QC9dRT+3y5BCj8tmP0f4ed3SO2GDn0v5iWht45/GTgZ40IoLHiSn/xYffUQQDZxmh69EspSP5DQAcN1irkZ/FAOSY9EskEcw3u7YGqucyD0hEeCUBSlOCIreEzmHydEEPbJd3vuyIs=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776208453; c=relaxed/simple;\n bh=9Q/+I7F/D4UrpQA+X8NTXv5hUYu4Ibr52xBPUKLg7ZA=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=Tul+g30hdOHjjw/XqKQAYpTrlsjgaVdWzKrpgOJlsERa4Ks9gaaruI7l3whAj9So968yPOJc+mkIOoNWj0s4tCc1bnlSfqETMyACDNFyJuHS76TMy/mF0n0xk/N2Cm95tSYmU8CDWpxDqdckt/ECdKVUwtJoD39DauNJSUuZCg4=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=embecosm.com; s=google; t=1776208451; x=1776813251; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=DpCCzydQ4EB2cGFazRaAI6jwq9Sau9s2lROJfIbZ+po=;\n b=Q0+defBmqoRxsCz/AQdAFnoFwUsLN2E/Ygk1ZvF6rs8TaoyazwMtJgtsW8G8BRYGD0\n KsHYF5R8e18IS2F6ErAXBhKPU3gu1bsL3hr/BxCfmqC0L5lGVPVULUbI3X/6xi0slbue\n fp4wKHzDU9VoP1ecBTxLxLB0uHuGPGsnt0yFjdpB9hoNcRJedQ0di9+8r4tIWYtD7ROt\n QUvyUdHNYCFiy/Q/o14WKpfYT9CX/mHL9uBscr74cjrR4PTxKL/XVKv+oLV9AS6b8LjJ\n JqGxHqn4SKFPU23NqYy7T2OyuZT4b03W/e+cC097+aP2ueR1MGbWhHX54eKtexNnN3ns\n y26w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776208451; x=1776813251;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=DpCCzydQ4EB2cGFazRaAI6jwq9Sau9s2lROJfIbZ+po=;\n b=peuhUVKMX1wxsscQ2KiAg5AEIYK4V84M52F8037dU1jQ4BWRP7eJUfIJsNCs9wGcnO\n 2BPyd/FOlhOmztFkrmzckecpgmtqNVwGy+i9r/aqj8DOgJNLwsT4KwjC4kQ95Y5lru8J\n ogl++PNOEQxvZyKlk2v8MzvmLXBT9SUGC9fjE4I4utH7fp20XG18MDIoLgxKGfrsnnai\n XRJdudyGK2gOrvEsHGm63liG40oq0aA+/ALo5q2MWXFC5oOFwOKYvG4wrOms3nN6tIVy\n XxUKBLLmbQlN1CuwBGv5jyHdiyoLcS4pt+2Glf+hk4dDbJ5RFNroy1jc7JZTALr+wuU3\n qVHw==","X-Gm-Message-State":"AOJu0YwPq4RH4AuVQ+x9JQtZu4RiB36Ph+MeyMPtFDjrwJj3D/62cRUW\n bV+MHGtNxbKN26Eemawyf2zagrwxl2ijkrSr2yE/iw1XfnzrwS1AZf/pTKaLkLM/L0AkiH3MHZq\n uggsatRS3","X-Gm-Gg":"AeBDievNH6n74Uga6v7jQ0KE8dqpkPGiTbGhzs8yPNrT7o/CMqElJgP2C6DSN2WtIiY\n HDrJMAFpH5Arvr2sHhcLnDvtlTYldy5BgOWNc9bZFOyytvBkxP3Fb4JuVRY+bW5S6kIve5etYpQ\n /Swv3GMAo1Migu5QGmW+jNbkcCEb1jCXWyxN/SMnkr5dflqnl0kYKBrE/hirAasog1cgDFwnSdA\n GW2w0TDZYHWkJLt9+AV0vnLctbuPqNdXel605NEBYIpcdP9X9eiFGW32CmXsK7Z0AroyGPvfrw+\n rVwrMApr/IDr3ankT38G13odbcoTwkU9cHnfeeR5hlZBypfUZVgpV09T8CHFIz0pgjKrVJ89WHT\n D//hRYzRFPED8p9FoBDGvqpH84iwOMsGL+y8AWsR7OeRPfaAK/cMfujj5PJC0EhO2mi8gRX8wPd\n dkowcxPr+7D7vIuZNYRDl+CTQQ+19EaUpJV7UsUc1fDeHg7p/tq+62yd1Wts27wKmuaCNucrscj\n 1oENA==","X-Received":"by 2002:a05:600c:c0c8:b0:488:af14:f1de with SMTP id\n 5b1f17b1804b1-488d67b8de8mr194529085e9.4.1776208450985;\n Tue, 14 Apr 2026 16:14:10 -0700 (PDT)","From":"arthur.cohen@embecosm.com","To":"gcc-patches@gcc.gnu.org","Cc":"gcc-rust@gcc.gnu.org,\n\tOwen Avery <powerboat9.gamer@gmail.com>","Subject":"[COMMITTED 02/43] gccrs: Improve path resolution","Date":"Wed, 15 Apr 2026 01:18:23 +0200","Message-ID":"<20260414231905.191063-2-arthur.cohen@embecosm.com>","X-Mailer":"git-send-email 2.50.1","In-Reply-To":"<20260414231905.191063-1-arthur.cohen@embecosm.com>","References":"<20260414231905.191063-1-arthur.cohen@embecosm.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"From: Owen Avery <powerboat9.gamer@gmail.com>\n\nThis makes path resolution less dependent on templates for path\nhandling.\n\ngcc/rust/ChangeLog:\n\n\t* resolve/rust-forever-stack.h: Include more headers.\n\t(class ResolutionPath): New class for representing paths.\n\t(ForeverStack::resolve_path): Change function signature.\n\t(ForeverStack::find_starting_point): Likewise.\n\t(ForeverStack::resolve_segments): Likewise.\n\t(ForeverStack::SegIterator): Change type alias.\n\t* resolve/rust-forever-stack.hxx (check_leading_kw_at_start):\n\tChange function signature.\n\t(ForeverStack::find_starting_point): Likewise.\n\t(ForeverStack::resolve_segments): Likewise.\n\t(ForeverStack::resolve_path): Likewise.\n\t* resolve/rust-name-resolution-context.h: Tweak include guard,\n\tinclude \"rust-name-resolution.h\".\n\t(NameResolutionContext::resolve_path): Use ResolutionPath and\n\tResolutionBuilder.\n\t(class NameResolutionContext::ResolutionBuilder): New class.\n\t(class Usage): Move this...\n\t(class Definition): ...and this...\n\t* resolve/rust-name-resolution.h: ...to new file.\n\t* util/rust-unwrap-segment.h: Add include guard.\n\nSigned-off-by: Owen Avery <powerboat9.gamer@gmail.com>\n---\n gcc/rust/resolve/rust-forever-stack.h         | 103 ++++++--\n gcc/rust/resolve/rust-forever-stack.hxx       | 186 +++++++-------\n .../resolve/rust-name-resolution-context.h    | 240 +++++++++++-------\n gcc/rust/resolve/rust-name-resolution.h       |  50 ++++\n gcc/rust/util/rust-unwrap-segment.h           |   5 +\n 5 files changed, 385 insertions(+), 199 deletions(-)\n create mode 100644 gcc/rust/resolve/rust-name-resolution.h","diff":"diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h\nindex 309a0ccd630..f6e351a1c4f 100644\n--- a/gcc/rust/resolve/rust-forever-stack.h\n+++ b/gcc/rust/resolve/rust-forever-stack.h\n@@ -25,6 +25,8 @@\n #include \"rust-path.h\"\n #include \"optional.h\"\n #include \"expected.h\"\n+#include \"rust-name-resolution.h\"\n+#include \"rust-unwrap-segment.h\"\n \n namespace Rust {\n namespace Resolver2_0 {\n@@ -550,6 +552,74 @@ enum class ResolutionMode\n   FromExtern, // extern prelude\n };\n \n+class ResolutionPath\n+{\n+public:\n+  template <typename T>\n+  ResolutionPath (const std::vector<T> &segments_in, NodeId node_id)\n+    : node_id (node_id)\n+  {\n+    segments.clear ();\n+    segments.reserve (segments_in.size ());\n+    for (auto &outer_seg : segments_in)\n+      {\n+\tif (auto lang_item = unwrap_segment_get_lang_item (outer_seg))\n+\t  {\n+\t    rust_assert (!lang_prefix.has_value ());\n+\t    lang_prefix = std::make_pair (lang_item.value (),\n+\t\t\t\t\t  unwrap_segment_node_id (outer_seg));\n+\t    continue;\n+\t  }\n+\n+\tauto &seg = unwrap_type_segment (outer_seg);\n+\n+\tSegment new_seg;\n+\tnew_seg.name = seg.as_string ();\n+\tnew_seg.node_id = unwrap_segment_node_id (outer_seg);\n+\tnew_seg.locus = seg.get_locus ();\n+\tsegments.push_back (std::move (new_seg));\n+      }\n+  }\n+\n+  ResolutionPath () : node_id (UNKNOWN_NODEID) {}\n+\n+  struct Segment\n+  {\n+    std::string name;\n+    NodeId node_id;\n+    location_t locus;\n+\n+    bool is_super_path_seg () const { return name.compare (\"super\") == 0; }\n+    bool is_crate_path_seg () const { return name.compare (\"crate\") == 0; }\n+    bool is_lower_self_seg () const { return name.compare (\"self\") == 0; }\n+    bool is_big_self_seg () const { return name.compare (\"Self\") == 0; }\n+  };\n+\n+  tl::optional<std::pair<LangItem::Kind, NodeId>> get_lang_prefix () const\n+  {\n+    return lang_prefix;\n+  }\n+\n+  const std::vector<Segment> &get_segments () const { return segments; }\n+\n+  NodeId get_node_id () const { return node_id; }\n+\n+  std::string as_string () const\n+  {\n+    std::string ret;\n+    if (lang_prefix)\n+      ret = \"#[lang]::\";\n+    for (auto &seg : segments)\n+      ret += \"::\" + seg.name;\n+    return ret;\n+  }\n+\n+private:\n+  tl::optional<std::pair<LangItem::Kind, NodeId>> lang_prefix;\n+  std::vector<Segment> segments;\n+  NodeId node_id;\n+};\n+\n template <Namespace N> class ForeverStack\n {\n public:\n@@ -687,15 +757,13 @@ public:\n    * @return a valid option with the Definition if the path is present in the\n    *         current map, an empty one otherwise.\n    */\n-  template <typename S>\n   tl::optional<Rib::Definition> resolve_path (\n-    const std::vector<S> &segments, ResolutionMode mode,\n-    std::function<void (const S &, NodeId)> insert_segment_resolution,\n+    const ResolutionPath &path, ResolutionMode mode,\n+    std::function<void (Usage, Definition)> insert_segment_resolution,\n     std::vector<Error> &collect_errors);\n-  template <typename S>\n   tl::optional<Rib::Definition> resolve_path (\n-    const std::vector<S> &segments, ResolutionMode mode,\n-    std::function<void (const S &, NodeId)> insert_segment_resolution,\n+    const ResolutionPath &path, ResolutionMode mode,\n+    std::function<void (Usage, Definition)> insert_segment_resolution,\n     std::vector<Error> &collect_errors, NodeId starting_point_id);\n \n   // FIXME: Documentation\n@@ -764,10 +832,9 @@ private:\n \n   tl::optional<Rib::Definition> get (Node &start, const Identifier &name);\n \n-  template <typename S>\n   tl::optional<Rib::Definition> resolve_path (\n-    const std::vector<S> &segments, ResolutionMode mode,\n-    std::function<void (const S &, NodeId)> insert_segment_resolution,\n+    const ResolutionPath &path, ResolutionMode mode,\n+    std::function<void (Usage, Definition)> insert_segment_resolution,\n     std::vector<Error> &collect_errors,\n     std::reference_wrapper<Node> starting_point);\n \n@@ -817,23 +884,21 @@ private:\n \n   /* Helper types and functions for `resolve_path` */\n \n-  template <typename S>\n-  using SegIterator = typename std::vector<S>::const_iterator;\n+  using SegIterator =\n+    typename std::vector<ResolutionPath::Segment>::const_iterator;\n \n   Node &find_closest_module (Node &starting_point);\n \n-  template <typename S>\n-  tl::optional<SegIterator<S>> find_starting_point (\n-    const std::vector<S> &segments,\n+  tl::optional<SegIterator> find_starting_point (\n+    const std::vector<ResolutionPath::Segment> &segments,\n     std::reference_wrapper<Node> &starting_point,\n-    std::function<void (const S &, NodeId)> insert_segment_resolution,\n+    std::function<void (Usage, Definition)> insert_segment_resolution,\n     std::vector<Error> &collect_errors);\n \n-  template <typename S>\n   tl::optional<Node &> resolve_segments (\n-    Node &starting_point, const std::vector<S> &segments,\n-    SegIterator<S> iterator,\n-    std::function<void (const S &, NodeId)> insert_segment_resolution,\n+    Node &starting_point, const std::vector<ResolutionPath::Segment> &segments,\n+    SegIterator iterator,\n+    std::function<void (Usage, Definition)> insert_segment_resolution,\n     std::vector<Error> &collect_errors);\n \n   tl::optional<Rib::Definition> resolve_final_segment (Node &final_node,\ndiff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx\nindex 0f92a7f332a..c7c5c9439e4 100644\n--- a/gcc/rust/resolve/rust-forever-stack.hxx\n+++ b/gcc/rust/resolve/rust-forever-stack.hxx\n@@ -431,16 +431,15 @@ ForeverStack<N>::find_closest_module (Node &starting_point)\n \n /* If a the given condition is met, emit an error about misused leading path\n  * segments */\n-template <typename S>\n static inline bool\n-check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,\n+check_leading_kw_at_start (std::vector<Error> &collect_errors,\n+\t\t\t   const ResolutionPath::Segment &segment,\n \t\t\t   bool condition)\n {\n   if (condition)\n     collect_errors.emplace_back (\n-      segment.get_locus (), ErrorCode::E0433,\n-      \"%qs in paths can only be used in start position\",\n-      segment.as_string ().c_str ());\n+      segment.locus, ErrorCode::E0433,\n+      \"%qs in paths can only be used in start position\", segment.name.c_str ());\n \n   return condition;\n }\n@@ -451,23 +450,19 @@ check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,\n // `super` segment, we go back to the cursor's parent until we reach the\n // correct one or the root.\n template <Namespace N>\n-template <typename S>\n-tl::optional<typename std::vector<S>::const_iterator>\n+tl::optional<typename std::vector<ResolutionPath::Segment>::const_iterator>\n ForeverStack<N>::find_starting_point (\n-  const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,\n-  std::function<void (const S &, NodeId)> insert_segment_resolution,\n+  const std::vector<ResolutionPath::Segment> &segments,\n+  std::reference_wrapper<Node> &starting_point,\n+  std::function<void (Usage, Definition)> insert_segment_resolution,\n   std::vector<Error> &collect_errors)\n {\n   auto iterator = segments.begin ();\n \n   for (; !is_last (iterator, segments); iterator++)\n     {\n-      auto &outer_seg = *iterator;\n+      auto &seg = *iterator;\n \n-      if (unwrap_segment_get_lang_item (outer_seg).has_value ())\n-\tbreak;\n-\n-      auto &seg = unwrap_type_segment (outer_seg);\n       bool is_self_or_crate\n \t= seg.is_crate_path_seg () || seg.is_lower_self_seg ();\n \n@@ -481,7 +476,8 @@ ForeverStack<N>::find_starting_point (\n       if (seg.is_crate_path_seg ())\n \t{\n \t  starting_point = root;\n-\t  insert_segment_resolution (outer_seg, starting_point.get ().id);\n+\t  insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t     Definition (starting_point.get ().id));\n \t  iterator++;\n \t  break;\n \t}\n@@ -489,7 +485,8 @@ ForeverStack<N>::find_starting_point (\n \t{\n \t  // insert segment resolution and exit\n \t  starting_point = find_closest_module (starting_point);\n-\t  insert_segment_resolution (outer_seg, starting_point.get ().id);\n+\t  insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t     Definition (starting_point.get ().id));\n \t  iterator++;\n \t  break;\n \t}\n@@ -499,7 +496,7 @@ ForeverStack<N>::find_starting_point (\n \t  if (starting_point.get ().is_root ())\n \t    {\n \t      collect_errors.emplace_back (\n-\t\tseg.get_locus (), ErrorCode::E0433,\n+\t\tseg.locus, ErrorCode::E0433,\n \t\t\"too many leading %<super%> keywords\");\n \t      return tl::nullopt;\n \t    }\n@@ -507,7 +504,8 @@ ForeverStack<N>::find_starting_point (\n \t  starting_point\n \t    = find_closest_module (starting_point.get ().parent.value ());\n \n-\t  insert_segment_resolution (outer_seg, starting_point.get ().id);\n+\t  insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t     Definition (starting_point.get ().id));\n \t  continue;\n \t}\n \n@@ -521,31 +519,19 @@ ForeverStack<N>::find_starting_point (\n }\n \n template <Namespace N>\n-template <typename S>\n tl::optional<typename ForeverStack<N>::Node &>\n ForeverStack<N>::resolve_segments (\n-  Node &starting_point, const std::vector<S> &segments,\n-  typename std::vector<S>::const_iterator iterator,\n-  std::function<void (const S &, NodeId)> insert_segment_resolution,\n+  Node &starting_point, const std::vector<ResolutionPath::Segment> &segments,\n+  typename std::vector<ResolutionPath::Segment>::const_iterator iterator,\n+  std::function<void (Usage, Definition)> insert_segment_resolution,\n   std::vector<Error> &collect_errors)\n {\n   Node *current_node = &starting_point;\n   for (; !is_last (iterator, segments); iterator++)\n     {\n-      auto &outer_seg = *iterator;\n-\n-      if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))\n-\t{\n-\t  NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (\n-\t    lang_item.value ());\n-\t  current_node = &dfs_node (root, seg_id).value ();\n+      auto &seg = *iterator;\n \n-\t  insert_segment_resolution (outer_seg, seg_id);\n-\t  continue;\n-\t}\n-\n-      auto &seg = unwrap_type_segment (outer_seg);\n-      std::string str = seg.as_string ();\n+      std::string str = seg.name;\n       rust_debug (\"[ARTHUR]: resolving segment part: %s\", str.c_str ());\n \n       // check that we don't encounter *any* leading keywords afterwards\n@@ -607,7 +593,7 @@ ForeverStack<N>::resolve_segments (\n \t      break;\n \t    }\n \n-\t  auto rib_lookup = current_node->rib.get (seg.as_string ());\n+\t  auto rib_lookup = current_node->rib.get (seg.name);\n \t  if (rib_lookup && !rib_lookup->is_ambiguous ())\n \t    {\n \t      if (Analysis::Mappings::get ()\n@@ -619,8 +605,9 @@ ForeverStack<N>::resolve_segments (\n \t\t}\n \t      else\n \t\t{\n-\t\t  insert_segment_resolution (outer_seg,\n-\t\t\t\t\t     rib_lookup->get_node_id ());\n+\t\t  insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t\t     Definition (\n+\t\t\t\t\t       rib_lookup->get_node_id ()));\n \t\t  return tl::nullopt;\n \t\t}\n \t    }\n@@ -645,7 +632,8 @@ ForeverStack<N>::resolve_segments (\n       // if child didn't point to a value\n       // the while loop above would have returned or kept looping\n       current_node = &child->get ();\n-      insert_segment_resolution (outer_seg, current_node->id);\n+      insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t Definition (current_node->id));\n     }\n \n   return *current_node;\n@@ -672,11 +660,10 @@ ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,\n }\n \n template <Namespace N>\n-template <typename S>\n tl::optional<Rib::Definition>\n ForeverStack<N>::resolve_path (\n-  const std::vector<S> &segments, ResolutionMode mode,\n-  std::function<void (const S &, NodeId)> insert_segment_resolution,\n+  const ResolutionPath &path, ResolutionMode mode,\n+  std::function<void (Usage, Definition)> insert_segment_resolution,\n   std::vector<Error> &collect_errors, NodeId starting_point_id)\n {\n   auto starting_point = dfs_node (root, starting_point_id);\n@@ -686,34 +673,56 @@ ForeverStack<N>::resolve_path (\n   if (!starting_point)\n     return tl::nullopt;\n \n-  return resolve_path (segments, mode, insert_segment_resolution,\n-\t\t       collect_errors, *starting_point);\n+  return resolve_path (path, mode, insert_segment_resolution, collect_errors,\n+\t\t       *starting_point);\n }\n \n template <Namespace N>\n-template <typename S>\n tl::optional<Rib::Definition>\n ForeverStack<N>::resolve_path (\n-  const std::vector<S> &segments, ResolutionMode mode,\n-  std::function<void (const S &, NodeId)> insert_segment_resolution,\n+  const ResolutionPath &path, ResolutionMode mode,\n+  std::function<void (Usage, Definition)> insert_segment_resolution,\n   std::vector<Error> &collect_errors)\n {\n   std::reference_wrapper<Node> starting_point = cursor ();\n \n-  return resolve_path (segments, mode, insert_segment_resolution,\n-\t\t       collect_errors, starting_point);\n+  return resolve_path (path, mode, insert_segment_resolution, collect_errors,\n+\t\t       starting_point);\n }\n \n template <Namespace N>\n-template <typename S>\n tl::optional<Rib::Definition>\n ForeverStack<N>::resolve_path (\n-  const std::vector<S> &segments, ResolutionMode mode,\n-  std::function<void (const S &, NodeId)> insert_segment_resolution,\n+  const ResolutionPath &path, ResolutionMode mode,\n+  std::function<void (Usage, Definition)> insert_segment_resolution,\n   std::vector<Error> &collect_errors,\n   std::reference_wrapper<Node> starting_point)\n {\n-  rust_assert (!segments.empty ());\n+  bool can_descend = true;\n+\n+  rust_debug (\"resolving %s\", path.as_string ().c_str ());\n+\n+  if (auto lang_item = path.get_lang_prefix ())\n+    {\n+      NodeId seg_id\n+\t= Analysis::Mappings::get ().get_lang_item_node (lang_item->first);\n+\n+      insert_segment_resolution (Usage (lang_item->second),\n+\t\t\t\t Definition (seg_id));\n+\n+      if (path.get_segments ().empty ())\n+\treturn Rib::Definition::NonShadowable (seg_id);\n+\n+      auto new_start = dfs_node (root, seg_id);\n+      rust_assert (new_start.has_value ());\n+      starting_point = new_start.value ();\n+\n+      can_descend = false;\n+    }\n+  else\n+    {\n+      rust_assert (!path.get_segments ().empty ());\n+    }\n \n   switch (mode)\n     {\n@@ -729,40 +738,31 @@ ForeverStack<N>::resolve_path (\n       rust_unreachable ();\n     }\n \n+  auto &segments = path.get_segments ();\n+\n   // if there's only one segment, we just use `get`\n-  if (segments.size () == 1)\n+  if (can_descend && segments.size () == 1)\n     {\n-      auto &outer_seg = segments.front ();\n-      if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))\n-\t{\n-\t  NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (\n-\t    lang_item.value ());\n-\n-\t  insert_segment_resolution (outer_seg, seg_id);\n-\t  // TODO: does NonShadowable matter?\n-\t  return Rib::Definition::NonShadowable (seg_id);\n-\t}\n+      auto &seg = segments.front ();\n \n-      auto &seg = unwrap_type_segment (outer_seg);\n-\n-      tl::optional<Rib::Definition> res\n-\t= get (starting_point.get (), seg.as_string ());\n+      tl::optional<Rib::Definition> res = get (starting_point.get (), seg.name);\n \n       if (!res)\n-\tres = get_lang_prelude (seg.as_string ());\n+\tres = get_lang_prelude (seg.name);\n \n       if (N == Namespace::Types && !res)\n \t{\n \t  if (seg.is_crate_path_seg ())\n \t    {\n-\t      insert_segment_resolution (outer_seg, root.id);\n+\t      insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t\t Definition (root.id));\n \t      // TODO: does NonShadowable matter?\n \t      return Rib::Definition::NonShadowable (root.id);\n \t    }\n \t  else if (seg.is_lower_self_seg ())\n \t    {\n \t      NodeId id = find_closest_module (starting_point.get ()).id;\n-\t      insert_segment_resolution (outer_seg, id);\n+\t      insert_segment_resolution (Usage (seg.node_id), Definition (id));\n \t      // TODO: does NonShadowable matter?\n \t      return Rib::Definition::NonShadowable (id);\n \t    }\n@@ -772,14 +772,14 @@ ForeverStack<N>::resolve_path (\n \t\t= find_closest_module (starting_point.get ());\n \t      if (closest_module.is_root ())\n \t\t{\n-\t\t  rust_error_at (seg.get_locus (), ErrorCode::E0433,\n+\t\t  rust_error_at (seg.locus, ErrorCode::E0433,\n \t\t\t\t \"too many leading %<super%> keywords\");\n \t\t  return tl::nullopt;\n \t\t}\n \n \t      NodeId id\n \t\t= find_closest_module (closest_module.parent.value ()).id;\n-\t      insert_segment_resolution (outer_seg, id);\n+\t      insert_segment_resolution (Usage (seg.node_id), Definition (id));\n \t      // TODO: does NonShadowable matter?\n \t      return Rib::Definition::NonShadowable (id);\n \t    }\n@@ -794,11 +794,12 @@ ForeverStack<N>::resolve_path (\n \t\t  if (link.path.map_or (\n \t\t\t[&seg] (Identifier path) {\n \t\t\t  auto &path_str = path.as_string ();\n-\t\t\t  return path_str == seg.as_string ();\n+\t\t\t  return path_str == seg.name;\n \t\t\t},\n \t\t\tfalse))\n \t\t    {\n-\t\t      insert_segment_resolution (outer_seg, kv.second.id);\n+\t\t      insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t\t\t Definition (kv.second.id));\n \t\t      return Rib::Definition::NonShadowable (kv.second.id);\n \t\t    }\n \t\t}\n@@ -806,28 +807,33 @@ ForeverStack<N>::resolve_path (\n \t}\n \n       if (res && !res->is_ambiguous ())\n-\tinsert_segment_resolution (outer_seg, res->get_node_id ());\n+\tinsert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t   Definition (res->get_node_id ()));\n       return res;\n     }\n \n-  return find_starting_point (segments, starting_point,\n-\t\t\t      insert_segment_resolution, collect_errors)\n-    .and_then (\n-      [this, &segments, &starting_point, &insert_segment_resolution,\n-       &collect_errors] (typename std::vector<S>::const_iterator iterator) {\n-\treturn resolve_segments (starting_point.get (), segments, iterator,\n-\t\t\t\t insert_segment_resolution, collect_errors);\n-      })\n+  auto iterator = segments.begin ();\n+  if (can_descend)\n+    {\n+      if (auto res\n+\t  = find_starting_point (segments, starting_point,\n+\t\t\t\t insert_segment_resolution, collect_errors))\n+\titerator = *res;\n+      else\n+\treturn tl::nullopt;\n+    }\n+\n+  return resolve_segments (starting_point.get (), segments, iterator,\n+\t\t\t   insert_segment_resolution, collect_errors)\n     .and_then ([this, &segments, &insert_segment_resolution] (\n \t\t Node &final_node) -> tl::optional<Rib::Definition> {\n       // leave resolution within impl blocks to type checker\n       if (final_node.rib.kind == Rib::Kind::TraitOrImpl)\n \treturn tl::nullopt;\n \n-      auto &seg = unwrap_type_segment (segments.back ());\n-      std::string seg_name = seg.as_string ();\n+      auto &seg = segments.back ();\n+      std::string seg_name = seg.name;\n \n-      // assuming this can't be a lang item segment\n       tl::optional<Rib::Definition> res\n \t= resolve_final_segment (final_node, seg_name,\n \t\t\t\t seg.is_lower_self_seg ());\n@@ -849,14 +855,16 @@ ForeverStack<N>::resolve_path (\n \t\t    },\n \t\t    false))\n \t\t{\n-\t\t  insert_segment_resolution (segments.back (), kv.second.id);\n+\t\t  insert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t\t     Definition (kv.second.id));\n \t\t  return Rib::Definition::NonShadowable (kv.second.id);\n \t\t}\n \t    }\n \t}\n \n       if (res && !res->is_ambiguous ())\n-\tinsert_segment_resolution (segments.back (), res->get_node_id ());\n+\tinsert_segment_resolution (Usage (seg.node_id),\n+\t\t\t\t   Definition (res->get_node_id ()));\n \n       return res;\n     });\ndiff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h\nindex 2d1ce3117b5..91eb0dcde75 100644\n--- a/gcc/rust/resolve/rust-name-resolution-context.h\n+++ b/gcc/rust/resolve/rust-name-resolution-context.h\n@@ -16,8 +16,8 @@\n // along with GCC; see the file COPYING3.  If not see\n // <http://www.gnu.org/licenses/>.\n \n-#ifndef RUST_NAME_RESOLVER_2_0_H\n-#define RUST_NAME_RESOLVER_2_0_H\n+#ifndef RUST_NAME_RESOLVER_2_0_CTX_H\n+#define RUST_NAME_RESOLVER_2_0_CTX_H\n \n #include \"optional.h\"\n #include \"rust-forever-stack.h\"\n@@ -25,6 +25,7 @@\n #include \"rust-rib.h\"\n #include \"rust-stacked-contexts.h\"\n #include \"rust-item.h\"\n+#include \"rust-name-resolution.h\"\n \n namespace Rust {\n namespace Resolver2_0 {\n@@ -136,28 +137,6 @@ change?\n correct\n */\n \n-// FIXME: Documentation\n-class Usage\n-{\n-public:\n-  explicit Usage (NodeId id) : id (id) {}\n-\n-  // TODO: move to name-resolution-ctx.cc\n-  // storing it as a key in a map\n-  bool operator< (const Usage other) const { return other.id < id; }\n-\n-  NodeId id;\n-};\n-\n-// FIXME: Documentation\n-class Definition\n-{\n-public:\n-  explicit Definition (NodeId id) : id (id) {}\n-\n-  NodeId id;\n-};\n-\n struct IdentifierMode\n {\n   bool is_ref;\n@@ -549,16 +528,14 @@ public:\n     return canonical_ctx.get_path (id);\n   }\n \n-  template <typename S>\n   tl::optional<Rib::Definition>\n-  resolve_path (const std::vector<S> &segments, ResolutionMode mode,\n+  resolve_path (const ResolutionPath &path, ResolutionMode mode,\n \t\tstd::vector<Error> &collect_errors, Namespace ns)\n   {\n-    std::function<void (const S &, NodeId)> insert_segment_resolution\n-      = [this] (const S &seg, NodeId id) {\n-\t  auto seg_id = unwrap_segment_node_id (seg);\n-\t  if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())\n-\t    map_usage (Usage (seg_id), Definition (id));\n+    std::function<void (Usage, Definition)> insert_segment_resolution\n+      = [this] (Usage seg_id, Definition id) {\n+\t  if (resolved_nodes.find (seg_id) == resolved_nodes.end ())\n+\t    map_usage (seg_id, id);\n \t};\n \n     tl::optional<Rib::Definition> resolved = tl::nullopt;\n@@ -566,24 +543,20 @@ public:\n     switch (ns)\n       {\n       case Namespace::Values:\n-\tresolved\n-\t  = values.resolve_path (segments, mode, insert_segment_resolution,\n-\t\t\t\t collect_errors);\n+\tresolved = values.resolve_path (path, mode, insert_segment_resolution,\n+\t\t\t\t\tcollect_errors);\n \tbreak;\n       case Namespace::Types:\n-\tresolved\n-\t  = types.resolve_path (segments, mode, insert_segment_resolution,\n-\t\t\t\tcollect_errors);\n+\tresolved = types.resolve_path (path, mode, insert_segment_resolution,\n+\t\t\t\t       collect_errors);\n \tbreak;\n       case Namespace::Macros:\n-\tresolved\n-\t  = macros.resolve_path (segments, mode, insert_segment_resolution,\n-\t\t\t\t collect_errors);\n+\tresolved = macros.resolve_path (path, mode, insert_segment_resolution,\n+\t\t\t\t\tcollect_errors);\n \tbreak;\n       case Namespace::Labels:\n-\tresolved\n-\t  = labels.resolve_path (segments, mode, insert_segment_resolution,\n-\t\t\t\t collect_errors);\n+\tresolved = labels.resolve_path (path, mode, insert_segment_resolution,\n+\t\t\t\t\tcollect_errors);\n \tbreak;\n       default:\n \trust_unreachable ();\n@@ -596,20 +569,16 @@ public:\n \tswitch (ns)\n \t  {\n \t  case Namespace::Values:\n-\t    return values.resolve_path (segments, mode,\n-\t\t\t\t\tinsert_segment_resolution,\n+\t    return values.resolve_path (path, mode, insert_segment_resolution,\n \t\t\t\t\tcollect_errors, *prelude);\n \t  case Namespace::Types:\n-\t    return types.resolve_path (segments, mode,\n-\t\t\t\t       insert_segment_resolution,\n+\t    return types.resolve_path (path, mode, insert_segment_resolution,\n \t\t\t\t       collect_errors, *prelude);\n \t  case Namespace::Macros:\n-\t    return macros.resolve_path (segments, mode,\n-\t\t\t\t\tinsert_segment_resolution,\n+\t    return macros.resolve_path (path, mode, insert_segment_resolution,\n \t\t\t\t\tcollect_errors, *prelude);\n \t  case Namespace::Labels:\n-\t    return labels.resolve_path (segments, mode,\n-\t\t\t\t\tinsert_segment_resolution,\n+\t    return labels.resolve_path (path, mode, insert_segment_resolution,\n \t\t\t\t\tcollect_errors, *prelude);\n \t  default:\n \t    rust_unreachable ();\n@@ -619,37 +588,122 @@ public:\n     return resolved;\n   }\n \n+  class ResolutionBuilder\n+  {\n+  public:\n+    ResolutionBuilder (NameResolutionContext &ctx) : ctx (&ctx) {}\n+\n+    template <typename S>\n+    void set_path (const std::vector<S> &path_segments, NodeId node_id,\n+\t\t   bool has_opening_scope)\n+    {\n+      path = ResolutionPath (path_segments, node_id);\n+      mode = ResolutionMode::Normal;\n+      if (has_opening_scope)\n+\t{\n+\t  if (get_rust_edition () == Edition::E2015)\n+\t    mode = ResolutionMode::FromRoot;\n+\t  else\n+\t    mode = ResolutionMode::FromExtern;\n+\t}\n+      has_path_set = true;\n+    }\n+\n+    template <typename S>\n+    void set_path (const std::vector<S> &path_segments, NodeId node_id,\n+\t\t   ResolutionMode mode)\n+    {\n+      path = ResolutionPath (path_segments, node_id);\n+      this->mode = mode;\n+      has_path_set = true;\n+    }\n+\n+    void set_path (const AST::SimplePath &path)\n+    {\n+      set_path (path.get_segments (), path.get_node_id (),\n+\t\tpath.has_opening_scope_resolution ());\n+    }\n+\n+    void set_path (const AST::PathInExpression &path)\n+    {\n+      set_path (path.get_segments (), path.get_node_id (),\n+\t\tpath.opening_scope_resolution ());\n+    }\n+\n+    void set_path (const AST::TypePath &path)\n+    {\n+      set_path (path.get_segments (), path.get_node_id (),\n+\t\tpath.has_opening_scope_resolution_op ());\n+    }\n+\n+    void set_mode (ResolutionMode mode) { this->mode = mode; }\n+\n+    void add_namespaces (Namespace ns) { namespace_list.push_back (ns); }\n+\n+    template <typename... Args> void add_namespaces (Namespace ns, Args... rest)\n+    {\n+      add_namespaces (ns);\n+      add_namespaces (rest...);\n+    }\n+\n+    void set_collect_errors (tl::optional<std::vector<Error> &> collect_errors)\n+    {\n+      this->collect_errors = collect_errors;\n+    }\n+\n+    tl::optional<Rib::Definition> resolve ()\n+    {\n+      rust_assert (has_path_set);\n+\n+      for (auto ns : namespace_list)\n+\t{\n+\t  std::vector<Error> collect_errors_inner;\n+\t  if (auto ret\n+\t      = ctx->resolve_path (path, mode, collect_errors_inner, ns))\n+\t    return ret;\n+\t  if (!collect_errors_inner.empty ())\n+\t    {\n+\t      if (collect_errors.has_value ())\n+\t\t{\n+\t\t  std::move (collect_errors_inner.begin (),\n+\t\t\t     collect_errors_inner.end (),\n+\t\t\t     std::back_inserter (collect_errors.value ()));\n+\t\t}\n+\t      else\n+\t\t{\n+\t\t  for (auto &e : collect_errors_inner)\n+\t\t    e.emit ();\n+\t\t}\n+\t    }\n+\t}\n+\n+      return tl::nullopt;\n+    }\n+\n+  private:\n+    ResolutionPath path;\n+    ResolutionMode mode;\n+    bool has_path_set;\n+\n+    std::vector<Namespace> namespace_list;\n+\n+    tl::optional<std::vector<Error> &> collect_errors;\n+\n+    NameResolutionContext *ctx;\n+  };\n+\n   template <typename S, typename... Args>\n   tl::optional<Rib::Definition>\n-  resolve_path (const std::vector<S> &segments, ResolutionMode mode,\n+  resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,\n \t\ttl::optional<std::vector<Error> &> collect_errors,\n \t\tNamespace ns_first, Args... ns_args)\n   {\n-    std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};\n+    ResolutionBuilder builder (*this);\n+    builder.set_path (path_segments, UNKNOWN_NODEID, mode);\n+    builder.add_namespaces (ns_first, ns_args...);\n+    builder.set_collect_errors (collect_errors);\n \n-    for (auto ns : namespaces)\n-      {\n-\tstd::vector<Error> collect_errors_inner;\n-\tif (auto ret = resolve_path (segments, mode, collect_errors_inner, ns))\n-\t  return ret;\n-\tif (!collect_errors_inner.empty ())\n-\t  {\n-\t    if (collect_errors.has_value ())\n-\t      {\n-\t\tstd::move (collect_errors_inner.begin (),\n-\t\t\t   collect_errors_inner.end (),\n-\t\t\t   std::back_inserter (collect_errors.value ()));\n-\t      }\n-\t    else\n-\t      {\n-\t\tfor (auto &e : collect_errors_inner)\n-\t\t  e.emit ();\n-\t      }\n-\t    return tl::nullopt;\n-\t  }\n-      }\n-\n-    return tl::nullopt;\n+    return builder.resolve ();\n   }\n \n   template <typename S, typename... Args>\n@@ -659,16 +713,13 @@ public:\n \t\ttl::optional<std::vector<Error> &> collect_errors,\n \t\tNamespace ns_first, Args... ns_args)\n   {\n-    auto mode = ResolutionMode::Normal;\n-    if (has_opening_scope_resolution)\n-      {\n-\tif (get_rust_edition () == Edition::E2015)\n-\t  mode = ResolutionMode::FromRoot;\n-\telse\n-\t  mode = ResolutionMode::FromExtern;\n-      }\n-    return resolve_path (path_segments, mode, collect_errors, ns_first,\n-\t\t\t ns_args...);\n+    ResolutionBuilder builder (*this);\n+    builder.set_path (path_segments, UNKNOWN_NODEID,\n+\t\t      has_opening_scope_resolution);\n+    builder.add_namespaces (ns_first, ns_args...);\n+    builder.set_collect_errors (collect_errors);\n+\n+    return builder.resolve ();\n   }\n \n   template <typename S, typename... Args>\n@@ -677,8 +728,12 @@ public:\n \t\tbool has_opening_scope_resolution, Namespace ns_first,\n \t\tArgs... ns_args)\n   {\n-    return resolve_path (path_segments, has_opening_scope_resolution,\n-\t\t\t tl::nullopt, ns_first, ns_args...);\n+    ResolutionBuilder builder (*this);\n+    builder.set_path (path_segments, UNKNOWN_NODEID,\n+\t\t      has_opening_scope_resolution);\n+    builder.add_namespaces (ns_first, ns_args...);\n+\n+    return builder.resolve ();\n   }\n \n   template <typename S, typename... Args>\n@@ -686,8 +741,11 @@ public:\n   resolve_path (const std::vector<S> &path_segments, ResolutionMode mode,\n \t\tNamespace ns_first, Args... ns_args)\n   {\n-    return resolve_path (path_segments, mode, tl::nullopt, ns_first,\n-\t\t\t ns_args...);\n+    ResolutionBuilder builder (*this);\n+    builder.set_path (path_segments, UNKNOWN_NODEID, mode);\n+    builder.add_namespaces (ns_first, ns_args...);\n+\n+    return builder.resolve ();\n   }\n \n   template <typename... Args>\n@@ -727,4 +785,4 @@ private:\n } // namespace Resolver2_0\n } // namespace Rust\n \n-#endif // ! RUST_NAME_RESOLVER_2_0_H\n+#endif // ! RUST_NAME_RESOLVER_2_0_CTX_H\ndiff --git a/gcc/rust/resolve/rust-name-resolution.h b/gcc/rust/resolve/rust-name-resolution.h\nnew file mode 100644\nindex 00000000000..6d5b4ec874d\n--- /dev/null\n+++ b/gcc/rust/resolve/rust-name-resolution.h\n@@ -0,0 +1,50 @@\n+// Copyright (C) 2026 Free Software Foundation, Inc.\n+\n+// This file is part of GCC.\n+\n+// GCC is free software; you can redistribute it and/or modify it under\n+// the terms of the GNU General Public License as published by the Free\n+// Software Foundation; either version 3, or (at your option) any later\n+// version.\n+\n+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+// WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n+// for more details.\n+\n+// You should have received a copy of the GNU General Public License\n+// along with GCC; see the file COPYING3.  If not see\n+// <http://www.gnu.org/licenses/>.\n+\n+#ifndef RUST_NAME_RESOLVER_2_0_H\n+#define RUST_NAME_RESOLVER_2_0_H\n+\n+namespace Rust {\n+namespace Resolver2_0 {\n+\n+// FIXME: Documentation\n+class Usage\n+{\n+public:\n+  explicit Usage (NodeId id) : id (id) {}\n+\n+  // TODO: move to name-resolution-ctx.cc\n+  // storing it as a key in a map\n+  bool operator< (const Usage other) const { return other.id < id; }\n+\n+  NodeId id;\n+};\n+\n+// FIXME: Documentation\n+class Definition\n+{\n+public:\n+  explicit Definition (NodeId id) : id (id) {}\n+\n+  NodeId id;\n+};\n+\n+} // namespace Resolver2_0\n+} // namespace Rust\n+\n+#endif // RUST_NAME_RESOLVER_2_0_H\ndiff --git a/gcc/rust/util/rust-unwrap-segment.h b/gcc/rust/util/rust-unwrap-segment.h\nindex 7181bd25379..0bebe287152 100644\n--- a/gcc/rust/util/rust-unwrap-segment.h\n+++ b/gcc/rust/util/rust-unwrap-segment.h\n@@ -16,6 +16,9 @@\n // along with GCC; see the file COPYING3.  If not see\n // <http://www.gnu.org/licenses/>.\n \n+#ifndef RUST_UNWRAP_SEGMENT_H\n+#define RUST_UNWRAP_SEGMENT_H\n+\n #include \"rust-system.h\"\n #include \"optional.h\"\n #include \"rust-lang-item.h\"\n@@ -136,3 +139,5 @@ unwrap_segment_error_string (const AST::PathInExpression &path)\n }\n \n } // namespace Rust\n+\n+#endif // RUST_UNWRAP_SEGMENT_H\n","prefixes":["COMMITTED","02/43"]}