From: Owen Avery <[email protected]>

gcc/rust/ChangeLog:

        * Make-lang.in (GRS_OBJS): Add rust-identifier-path.o.
        * resolve/rust-early-name-resolver-2.0.cc: Include
        "rust-identifier-path.h".
        (Early::go): Use IdentifierPathPass.
        (Early::visit): Handle identifier patterns which should be path
        patterns.
        * resolve/rust-early-name-resolver-2.0.h: Include
        "rust-pattern.h".
        (Early::visit): Add visiting function declaration for
        IdentifierPattern.
        (Early::ident_path_to_convert): New member variable.
        * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit):
        Call Mappings::add_function_node.
        * util/rust-hir-map.cc (Mappings::add_function_node): New
        member function definition.
        (Mappings::is_function_node): Likewise.
        * util/rust-hir-map.h (Mappings::add_function_node): New
        member function declaration.
        (Mappings::is_function_node): Likewise.
        (Mappings::function_nodes): New member variable.
        * resolve/rust-identifier-path.cc: New file.
        * resolve/rust-identifier-path.h: New file.

gcc/testsuite/ChangeLog:

        * rust/execute/ident_pat_vs_path_1.rs: New test.
        * rust/execute/ident_pat_vs_path_2.rs: New test.

Signed-off-by: Owen Avery <[email protected]>
---
 gcc/rust/Make-lang.in                         |  1 +
 .../resolve/rust-early-name-resolver-2.0.cc   | 28 +++++++++
 .../resolve/rust-early-name-resolver-2.0.h    |  6 ++
 gcc/rust/resolve/rust-identifier-path.cc      | 61 +++++++++++++++++++
 gcc/rust/resolve/rust-identifier-path.h       | 50 +++++++++++++++
 .../rust-toplevel-name-resolver-2.0.cc        |  2 +
 gcc/rust/util/rust-hir-map.cc                 | 12 ++++
 gcc/rust/util/rust-hir-map.h                  |  5 ++
 .../rust/execute/ident_pat_vs_path_1.rs       | 27 ++++++++
 .../rust/execute/ident_pat_vs_path_2.rs       | 18 ++++++
 10 files changed, 210 insertions(+)
 create mode 100644 gcc/rust/resolve/rust-identifier-path.cc
 create mode 100644 gcc/rust/resolve/rust-identifier-path.h
 create mode 100644 gcc/testsuite/rust/execute/ident_pat_vs_path_1.rs
 create mode 100644 gcc/testsuite/rust/execute/ident_pat_vs_path_2.rs

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index bd5646f7c37..4c394d39c0b 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -146,6 +146,7 @@ GRS_OBJS = \
        rust/rust-finalize-imports-2.0.o \
        rust/rust-ice-finalizer.o \
     rust/rust-late-name-resolver-2.0.o \
+    rust/rust-identifier-path.o \
        rust/rust-immutable-name-resolution-context.o \
     rust/rust-name-resolver.o \
     rust/rust-resolve-builtins.o \
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index df29a55c8fb..91ad82c8966 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -27,6 +27,7 @@
 #include "rust-attributes.h"
 #include "rust-finalize-imports-2.0.h"
 #include "rust-attribute-values.h"
+#include "rust-identifier-path.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -70,6 +71,9 @@ Early::go (AST::Crate &crate)
   visit (crate);
 
   textual_scope.pop ();
+
+  // handle IdentifierPattern vs PathInExpression disambiguation
+  IdentifierPathPass::go (crate, ctx, std::move (ident_path_to_convert));
 }
 
 bool
@@ -543,5 +547,29 @@ Early::visit (AST::UseTreeList &use_list)
   DefaultResolver::visit (use_list);
 }
 
+void
+Early::visit (AST::IdentifierPattern &identifier)
+{
+  // check if this is *really* a path pattern
+  if (!identifier.get_is_ref () && !identifier.get_is_mut ()
+      && !identifier.has_subpattern ())
+    {
+      auto res = ctx.values.get (identifier.get_ident ());
+      if (res)
+       {
+         if (res->is_ambiguous ())
+           rust_error_at (identifier.get_locus (), ErrorCode::E0659,
+                          "%qs is ambiguous",
+                          identifier.get_ident ().as_string ().c_str ());
+         else
+           {
+             // HACK: bail out if the definition is a function
+             if (!ctx.mappings.is_function_node (res->get_node_id ()))
+               ident_path_to_convert.insert (identifier.get_node_id ());
+           }
+       }
+    }
+}
+
 } // namespace Resolver2_0
 } // namespace Rust
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h 
b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
index bd9ccf66dec..0fdf1436cbd 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -26,6 +26,7 @@
 #include "rust-default-resolver.h"
 #include "rust-rib.h"
 #include "rust-toplevel-name-resolver-2.0.h"
+#include "rust-pattern.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -67,6 +68,8 @@ public:
 
   void visit (AST::Attribute &) override;
 
+  void visit (AST::IdentifierPattern &) override;
+
   struct ImportData
   {
     enum class Kind
@@ -266,6 +269,9 @@ private:
                             const Early::ImportPair &mapping);
 
   void finalize_rebind_import (const Early::ImportPair &mapping);
+
+  /* used to help conversion from IdentifierPattern to PathInExpression */
+  std::set<NodeId> ident_path_to_convert;
 };
 
 } // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-identifier-path.cc 
b/gcc/rust/resolve/rust-identifier-path.cc
new file mode 100644
index 00000000000..30223a7b3d6
--- /dev/null
+++ b/gcc/rust/resolve/rust-identifier-path.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-system.h"
+#include "rust-identifier-path.h"
+#include "rust-pattern.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+IdentifierPathPass::IdentifierPathPass (NameResolutionContext &ctx,
+                                       std::set<NodeId> ident_path_to_convert)
+  : ctx (&ctx), ident_path_to_convert (std::move (ident_path_to_convert))
+{}
+
+void
+IdentifierPathPass::go (AST::Crate &crate, NameResolutionContext &ctx,
+                       std::set<NodeId> ident_path_to_convert)
+{
+  IdentifierPathPass pass (ctx, std::move (ident_path_to_convert));
+  pass.visit (crate);
+}
+
+void
+IdentifierPathPass::reseat (std::unique_ptr<AST::Pattern> &ptr)
+{
+  AST::IdentifierPattern *ident_pat;
+  if (ptr->get_pattern_kind () == AST::Pattern::Kind::Identifier)
+    ident_pat = static_cast<AST::IdentifierPattern *> (ptr.get ());
+  else
+    return;
+
+  if (ident_path_to_convert.find (ident_pat->get_node_id ())
+      != ident_path_to_convert.end ())
+    {
+      std::vector<AST::PathExprSegment> segments;
+      segments.emplace_back (ident_pat->get_ident ().as_string (),
+                            ident_pat->get_locus ());
+      ptr = std::make_unique<AST::PathInExpression> (
+       std::move (segments), std::vector<AST::Attribute> (),
+       ident_pat->get_locus ());
+    }
+}
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-identifier-path.h 
b/gcc/rust/resolve/rust-identifier-path.h
new file mode 100644
index 00000000000..5363a5e87ef
--- /dev/null
+++ b/gcc/rust/resolve/rust-identifier-path.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_RESOLVE_IDENTIFIER_PATH_H
+#define RUST_RESOLVE_IDENTIFIER_PATH_H
+
+#include "rust-ast-pointer-visitor.h"
+#include "rust-name-resolution-context.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+// changes IdentifierPattern instances to PathInExpression instances
+class IdentifierPathPass : public AST::PointerVisitor
+{
+public:
+  IdentifierPathPass (NameResolutionContext &ctx,
+                     std::set<NodeId> ident_path_to_convert);
+
+  static void go (AST::Crate &crate, NameResolutionContext &ctx,
+                 std::set<NodeId> ident_path_to_convert);
+
+  using AST::PointerVisitor::reseat;
+
+  void reseat (std::unique_ptr<AST::Pattern> &ptr) override;
+
+private:
+  NameResolutionContext *ctx;
+  std::set<NodeId> ident_path_to_convert;
+};
+
+} // namespace Resolver2_0
+} // namespace Rust
+
+#endif // ! RUST_RESOLVE_IDENTIFIER_PATH_H
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 2002df54596..630b5ab8b95 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -241,6 +241,8 @@ TopLevel::visit (AST::Function &function)
   insert_or_error_out (function.get_function_name (), function,
                       Namespace::Values);
 
+  Analysis::Mappings::get ().add_function_node (function.get_node_id ());
+
   DefaultResolver::visit (function);
 }
 
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index a58fef00d46..89b95647861 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -1382,5 +1382,17 @@ Mappings::is_derived_node (NodeId node_id)
   return derived_nodes.find (node_id) != derived_nodes.end ();
 }
 
+void
+Mappings::add_function_node (NodeId node_id)
+{
+  function_nodes.insert (node_id);
+}
+
+bool
+Mappings::is_function_node (NodeId node_id)
+{
+  return function_nodes.find (node_id) != function_nodes.end ();
+}
+
 } // namespace Analysis
 } // namespace Rust
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index c04e2efb7a4..7012dd5c2e0 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -353,6 +353,9 @@ public:
   void add_derived_node (NodeId node_id);
   bool is_derived_node (NodeId node_id);
 
+  void add_function_node (NodeId node_id);
+  bool is_function_node (NodeId node_id);
+
 private:
   Mappings ();
 
@@ -450,6 +453,8 @@ private:
   std::unordered_map<NodeId, std::vector<NodeId>> captures;
 
   std::set<NodeId> derived_nodes;
+
+  std::set<NodeId> function_nodes;
 };
 
 } // namespace Analysis
diff --git a/gcc/testsuite/rust/execute/ident_pat_vs_path_1.rs 
b/gcc/testsuite/rust/execute/ident_pat_vs_path_1.rs
new file mode 100644
index 00000000000..479e8700bac
--- /dev/null
+++ b/gcc/testsuite/rust/execute/ident_pat_vs_path_1.rs
@@ -0,0 +1,27 @@
+// { dg-additional-options "-w" }
+#![feature(no_core)]
+#![no_core]
+
+enum E {
+    A,
+    B,
+    C
+}
+
+fn main() -> i32 {
+    use E::C;
+
+    let v1 = match E::A {
+        C => 1,
+        E::A => 0,
+        E::B => 1
+    };
+
+    let v2 = match E::A {
+        B => 0,
+        E::A => 1,
+        C => 1
+    };
+
+    v1 + v2
+}
diff --git a/gcc/testsuite/rust/execute/ident_pat_vs_path_2.rs 
b/gcc/testsuite/rust/execute/ident_pat_vs_path_2.rs
new file mode 100644
index 00000000000..bb6841f0ae4
--- /dev/null
+++ b/gcc/testsuite/rust/execute/ident_pat_vs_path_2.rs
@@ -0,0 +1,18 @@
+// { dg-additional-options "-w" }
+#![feature(no_core)]
+#![no_core]
+
+enum E {
+    A,
+    B,
+    C
+}
+
+fn main() -> i32 {
+    use E::*;
+
+    match A {
+        C => 1,
+        _ => 0
+    }
+}
-- 
2.50.1

Reply via email to