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]>
---
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/de7dffce247c236349b418215c820ecb8965b090
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4455
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 bd5646f7c..4c394d39c 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 df29a55c8..91ad82c89 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 bd9ccf66d..0fdf1436c 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 000000000..30223a7b3
--- /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 000000000..5363a5e87
--- /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 2002df545..630b5ab8b 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 a58fef00d..89b956478 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 c04e2efb7..7012dd5c2 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 000000000..479e8700b
--- /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 000000000..bb6841f0a
--- /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
+ }
+}
base-commit: bde2985a486cf5f5c000fc186f508471cdf20d12
--
2.53.0