From 4709749d7f053b29dbee1c1b3f7631521d370e53 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Fri, 4 Apr 2025 15:35:15 +0200 Subject: [PATCH 1/8] Add fn_once and Sized lang items to the test gcc/testsuite/ChangeLog: * rust/compile/multiple_bindings1.rs: Add missing lang items. Signed-off-by: Pierre-Emmanuel Patry --- .../rust/compile/multiple_bindings1.rs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/gcc/testsuite/rust/compile/multiple_bindings1.rs b/gcc/testsuite/rust/compile/multiple_bindings1.rs index e73dc2ae7d94..8a2e18c27b1b 100644 --- a/gcc/testsuite/rust/compile/multiple_bindings1.rs +++ b/gcc/testsuite/rust/compile/multiple_bindings1.rs @@ -1,29 +1,38 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +trait FnOnce { + type Output; + + fn call_once(self, args: Args) -> Self::Output; +} + fn f1(i: i32, i: i32) {} // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } trait Foo { - fn f2(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f2(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } trait Bar { - fn f3(i: i32, j: i32) {} + fn f3(i: i32, j: i32) {} } struct S; impl S { - fn f4(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f4(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } impl Bar for S { - fn f3(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f3(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } fn main() { - let _ = |i, i| {}; - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + let _ = |i, i| {}; + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } - From 974a706860c4a997d9dab8317a6b7698b3439622 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 01:43:20 +0200 Subject: [PATCH 2/8] Add equality operator for identifiers gcc/rust/ChangeLog: * ast/rust-ast.h: Add equality operator. Signed-off-by: Pierre-Emmanuel Patry --- gcc/rust/ast/rust-ast.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 52379fae5b2e..5f302bc80d31 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -57,6 +57,11 @@ class Identifier bool empty () const { return ident.empty (); } + bool operator== (const Identifier &other) const + { + return ident == other.ident; + } + private: std::string ident; location_t loc; From 228a971c8056308cd9cce46f9b8870436ef13012 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 01:44:18 +0200 Subject: [PATCH 3/8] Add hash function for Identifiers gcc/rust/ChangeLog: * ast/rust-ast.h: Add hash function. Signed-off-by: Pierre-Emmanuel Patry --- gcc/rust/ast/rust-ast.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 5f302bc80d31..9581dd57b739 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -2102,6 +2102,19 @@ template <> struct less return lhs.as_string () < rhs.as_string (); } }; + +template <> struct hash +{ + std::size_t operator() (const Rust::Identifier &k) const + { + using std::hash; + using std::size_t; + using std::string; + + return hash () (k.as_string ()) ^ (hash () (k.get_locus ())); + } +}; + } // namespace std #endif From dbc1ea13da0afcdb457e3d3ed0dbe862f2beb310 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 17:09:42 +0200 Subject: [PATCH 4/8] Add binding context class We need to differentiate bindings types, so the same binding cannot be reused multiple time in a product binding. gcc/rust/ChangeLog: * resolve/rust-name-resolution-context.h (struct Binding): Add Binding struct to differentiate Or and Product bindings in patterns. (enum class): Add Binding kind. (class BindingContext): Add binding context with Binding stack. Signed-off-by: Pierre-Emmanuel Patry --- .../resolve/rust-name-resolution-context.h | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 3ba93bd82bf7..cb2df64274b6 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -156,6 +156,87 @@ class Definition NodeId id; }; +struct Binding +{ + enum class Kind + { + Product, + Or, + } kind; + + std::unordered_set set; + + Binding (Binding::Kind kind) : kind (kind) {} +}; + +enum class BindingSource +{ + Match, + Let, + For, + Param +}; + +class BindingContext +{ + // FIXME: Use std::vector> to handle nested patterns + std::vector bindings; + + BindingSource source; + + bool bind_test (Identifier ident, Binding::Kind kind) + { + for (auto &bind : bindings) + { + if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + { + return true; + } + } + return false; + } + +public: + bool and_binded (Identifier ident) + { + return bind_test (ident, Binding::Kind::Product); + } + + bool or_binded (Identifier ident) + { + return bind_test (ident, Binding::Kind::Or); + } + + void insert_ident (Identifier ident) { bindings.back ().set.insert (ident); } + + void push (Binding::Kind kind) { bindings.push_back (Binding (kind)); } + + void new_binding (BindingSource source) + { + rust_assert (bindings.size () == 0); + this->source = source; + push (Binding::Kind::Product); + } + + void clear () + { + rust_assert (bindings.size () == 1); + bindings.clear (); + } + + void merge () + { + auto last_binding = bindings.back (); + bindings.pop_back (); + for (auto &value : last_binding.set) + { + bindings.back ().set.insert (value); + } + } + + BindingSource get_source () const { return source; } +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { From c2a0871d23e459cd2ea2c1a549c6fb1b3a9e4202 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 18:17:41 +0200 Subject: [PATCH 5/8] Add pattern bindings gcc/rust/ChangeLog: * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add binding creation in visitor. * resolve/rust-late-name-resolver-2.0.h: Add function prototypes. * resolve/rust-name-resolution-context.h: Add binding context. Signed-off-by: Pierre-Emmanuel Patry --- .../resolve/rust-late-name-resolver-2.0.cc | 155 +++++++++++++++++- .../resolve/rust-late-name-resolver-2.0.h | 5 + .../resolve/rust-name-resolution-context.h | 1 + 3 files changed, 156 insertions(+), 5 deletions(-) diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index a86f196a16a6..a452d44a0b4a 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -128,6 +128,54 @@ Late::new_label (Identifier name, NodeId id) rust_assert (ok); } +void +Late::visit (AST::ForLoopExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.new_binding (BindingSource::For); + + visit (expr.get_pattern ()); + + ctx.bindings.clear (); + + visit (expr.get_iterator_expr ()); + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); +} + +void +Late::visit (AST::IfLetExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.new_binding (BindingSource::Let); + + for (auto &pattern : expr.get_patterns ()) + visit (pattern); + + ctx.bindings.clear (); + + visit (expr.get_value_expr ()); + visit (expr.get_if_block ()); +} + +void +Late::visit (AST::MatchArm &arm) +{ + visit_outer_attrs (arm); + + ctx.bindings.new_binding (BindingSource::Match); + + for (auto &pattern : arm.get_patterns ()) + visit (pattern); + + ctx.bindings.clear (); + + if (arm.has_match_arm_guard ()) + visit (arm.get_guard_expr ()); +} + void Late::visit (AST::LetStmt &let) { @@ -138,8 +186,13 @@ Late::visit (AST::LetStmt &let) // this makes variable shadowing work properly if (let.has_init_expr ()) visit (let.get_init_expr ()); + + ctx.bindings.new_binding (BindingSource::Let); + visit (let.get_pattern ()); + ctx.bindings.clear (); + if (let.has_else_expr ()) visit (let.get_init_expr ()); @@ -167,9 +220,80 @@ Late::visit (AST::IdentifierPattern &identifier) // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + if (ctx.bindings.and_binded (identifier.get_ident ())) + { + if (ctx.bindings.get_source () == BindingSource::Param) + rust_error_at ( + identifier.get_locus (), ErrorCode::E0415, + "identifier %qs is bound more than once in the same parameter list", + identifier.as_string ().c_str ()); + else + rust_error_at ( + identifier.get_locus (), ErrorCode::E0416, + "identifier %qs is bound more than once in the same pattern", + identifier.as_string ().c_str ()); + return; + } + + ctx.bindings.insert_ident (identifier.get_ident ()); + + if (ctx.bindings.or_binded (identifier.get_ident ())) + { + // FIXME: map usage instead + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } + else + { + // We do want to ignore duplicated data because some situations rely on + // it. + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } +} + +void +Late::visit (AST::AltPattern &pattern) +{ + ctx.bindings.push (Binding::Kind::Or); + for (auto &alt : pattern.get_alts ()) + { + ctx.bindings.push (Binding::Kind::Product); + visit (alt); + ctx.bindings.merge (); + } + ctx.bindings.merge (); +} + +void +Late::visit (AST::Function &function) +{ + auto def_fn = [this, &function] () { + visit_outer_attrs (function); + visit (function.get_visibility ()); + visit (function.get_qualifiers ()); + for (auto &generic : function.get_generic_params ()) + visit (generic); + + // We only care about params + ctx.bindings.new_binding (BindingSource::Param); + + for (auto ¶m : function.get_function_params ()) + visit (param); + + ctx.bindings.clear (); + + // Back to regular visit + + if (function.has_return_type ()) + visit (function.get_return_type ()); + if (function.has_where_clause ()) + visit (function.get_where_clause ()); + if (function.has_body ()) + visit (*function.get_definition ()); + }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); } void @@ -525,14 +649,35 @@ void Late::visit (AST::ClosureExprInner &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.new_binding (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.clear (); + + visit (closure.get_definition_expr ()); } void Late::visit (AST::ClosureExprInnerTyped &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.new_binding (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.clear (); + + visit (closure.get_return_type ()); + visit (closure.get_definition_block ()); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 34f3c28fee4f..90113f2277f4 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -43,7 +43,12 @@ class Late : public DefaultResolver // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; void visit (AST::StructPatternFieldIdent &) override; + void visit (AST::AltPattern &) override; + void visit (AST::Function &) override; void visit (AST::SelfParam &) override; + void visit (AST::MatchArm &) override; + void visit (AST::ForLoopExpr &) override; + void visit (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index cb2df64274b6..10318b1283dd 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -293,6 +293,7 @@ class NameResolutionContext ForeverStack labels; Analysis::Mappings &mappings; + BindingContext bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition From 4056b8cc372dad1d4e766d71e44b30d5341b67f9 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 18:49:11 +0200 Subject: [PATCH 6/8] Use stacked context for nested bindings. Binding context may be stacked when a new binding group is introduced within a const expression. gcc/rust/ChangeLog: * resolve/rust-name-resolution-context.h: Use BindingLayer instead. * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer): Add new constructor for binding layer. (BindingLayer::bind_test): Add a function to test a binding constraint. (BindingLayer::push): Push a new binding group. (BindingLayer::and_binded): Add function to test and-binding constraint. (BindingLayer::or_binded): Add function to test or-binding constraints. (BindingLayer::insert_ident): Insert a new identifier in the current binding group. (BindingLayer::merge): Merge current binding group with it's parent. (BindingLayer::get_source): Get the source of the current binding group. * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for binding group. * util/rust-stacked-contexts.h: Add mutable peek function. Signed-off-by: Pierre-Emmanuel Patry --- .../resolve/rust-late-name-resolver-2.0.cc | 44 ++++++------ .../resolve/rust-name-resolution-context.cc | 59 +++++++++++++++ .../resolve/rust-name-resolution-context.h | 72 +++++++------------ gcc/rust/util/rust-stacked-contexts.h | 9 ++- 4 files changed, 113 insertions(+), 71 deletions(-) diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index a452d44a0b4a..5ee3fa2dae35 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -133,11 +133,11 @@ Late::visit (AST::ForLoopExpr &expr) { visit_outer_attrs (expr); - ctx.bindings.new_binding (BindingSource::For); + ctx.bindings.enter (BindingSource::For); visit (expr.get_pattern ()); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (expr.get_iterator_expr ()); visit (expr.get_loop_label ()); @@ -149,12 +149,12 @@ Late::visit (AST::IfLetExpr &expr) { visit_outer_attrs (expr); - ctx.bindings.new_binding (BindingSource::Let); + ctx.bindings.enter (BindingSource::Let); for (auto &pattern : expr.get_patterns ()) visit (pattern); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (expr.get_value_expr ()); visit (expr.get_if_block ()); @@ -165,12 +165,12 @@ Late::visit (AST::MatchArm &arm) { visit_outer_attrs (arm); - ctx.bindings.new_binding (BindingSource::Match); + ctx.bindings.enter (BindingSource::Match); for (auto &pattern : arm.get_patterns ()) visit (pattern); - ctx.bindings.clear (); + ctx.bindings.exit (); if (arm.has_match_arm_guard ()) visit (arm.get_guard_expr ()); @@ -187,11 +187,11 @@ Late::visit (AST::LetStmt &let) if (let.has_init_expr ()) visit (let.get_init_expr ()); - ctx.bindings.new_binding (BindingSource::Let); + ctx.bindings.enter (BindingSource::Let); visit (let.get_pattern ()); - ctx.bindings.clear (); + ctx.bindings.exit (); if (let.has_else_expr ()) visit (let.get_init_expr ()); @@ -220,9 +220,9 @@ Late::visit (AST::IdentifierPattern &identifier) // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - if (ctx.bindings.and_binded (identifier.get_ident ())) + if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) { - if (ctx.bindings.get_source () == BindingSource::Param) + if (ctx.bindings.peek ().get_source () == BindingSource::Param) rust_error_at ( identifier.get_locus (), ErrorCode::E0415, "identifier %qs is bound more than once in the same parameter list", @@ -235,9 +235,9 @@ Late::visit (AST::IdentifierPattern &identifier) return; } - ctx.bindings.insert_ident (identifier.get_ident ()); + ctx.bindings.peek ().insert_ident (identifier.get_ident ()); - if (ctx.bindings.or_binded (identifier.get_ident ())) + if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) { // FIXME: map usage instead std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), @@ -255,14 +255,14 @@ Late::visit (AST::IdentifierPattern &identifier) void Late::visit (AST::AltPattern &pattern) { - ctx.bindings.push (Binding::Kind::Or); + ctx.bindings.peek ().push (Binding::Kind::Or); for (auto &alt : pattern.get_alts ()) { - ctx.bindings.push (Binding::Kind::Product); + ctx.bindings.peek ().push (Binding::Kind::Product); visit (alt); - ctx.bindings.merge (); + ctx.bindings.peek ().merge (); } - ctx.bindings.merge (); + ctx.bindings.peek ().merge (); } void @@ -276,12 +276,12 @@ Late::visit (AST::Function &function) visit (generic); // We only care about params - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : function.get_function_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); // Back to regular visit @@ -652,12 +652,12 @@ Late::visit (AST::ClosureExprInner &closure) visit_outer_attrs (closure); - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : closure.get_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (closure.get_definition_expr ()); } @@ -669,12 +669,12 @@ Late::visit (AST::ClosureExprInnerTyped &closure) visit_outer_attrs (closure); - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : closure.get_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (closure.get_return_type ()); visit (closure.get_definition_block ()); diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 35befc1da8a2..7f47e85204a8 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -23,6 +23,65 @@ namespace Rust { namespace Resolver2_0 { +BindingLayer::BindingLayer (BindingSource source) : source (source) +{ + push (Binding::Kind::Product); +} + +bool +BindingLayer::bind_test (Identifier ident, Binding::Kind kind) +{ + for (auto &bind : bindings) + { + if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + { + return true; + } + } + return false; +} + +void +BindingLayer::push (Binding::Kind kind) +{ + bindings.push_back (Binding (kind)); +} + +bool +BindingLayer::is_and_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Product); +} + +bool +BindingLayer::is_or_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Or); +} + +void +BindingLayer::insert_ident (Identifier ident) +{ + bindings.back ().set.insert (ident); +} + +void +BindingLayer::merge () +{ + auto last_binding = bindings.back (); + bindings.pop_back (); + for (auto &value : last_binding.set) + { + bindings.back ().set.insert (value); + } +} + +BindingSource +BindingLayer::get_source () const +{ + return source; +} + NameResolutionContext::NameResolutionContext () : mappings (Analysis::Mappings::get ()) {} diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 10318b1283dd..aab04ccc18eb 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -23,6 +23,7 @@ #include "rust-forever-stack.h" #include "rust-hir-map.h" #include "rust-rib.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace Resolver2_0 { @@ -169,72 +170,47 @@ struct Binding Binding (Binding::Kind kind) : kind (kind) {} }; +/** + * Used to identify the source of a binding, and emit the correct error message. + */ enum class BindingSource { Match, Let, For, + /* Closure param or function param */ Param }; -class BindingContext +class BindingLayer { - // FIXME: Use std::vector> to handle nested patterns - std::vector bindings; - BindingSource source; + std::vector bindings; - bool bind_test (Identifier ident, Binding::Kind kind) - { - for (auto &bind : bindings) - { - if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) - { - return true; - } - } - return false; - } + bool bind_test (Identifier ident, Binding::Kind kind); public: - bool and_binded (Identifier ident) - { - return bind_test (ident, Binding::Kind::Product); - } + void push (Binding::Kind kind); - bool or_binded (Identifier ident) - { - return bind_test (ident, Binding::Kind::Or); - } + BindingLayer (BindingSource source); - void insert_ident (Identifier ident) { bindings.back ().set.insert (ident); } + /** + * Identifies if the identifier has been used in a product binding context. + * eg. `let (a, a) = test();` + */ + bool is_and_bound (Identifier ident); - void push (Binding::Kind kind) { bindings.push_back (Binding (kind)); } + /** + * Identifies if the identifier has been used in a or context. + * eg. `let (a, 1) | (a, 2) = test()` + */ + bool is_or_bound (Identifier ident); - void new_binding (BindingSource source) - { - rust_assert (bindings.size () == 0); - this->source = source; - push (Binding::Kind::Product); - } + void insert_ident (Identifier ident); - void clear () - { - rust_assert (bindings.size () == 1); - bindings.clear (); - } - - void merge () - { - auto last_binding = bindings.back (); - bindings.pop_back (); - for (auto &value : last_binding.set) - { - bindings.back ().set.insert (value); - } - } + void merge (); - BindingSource get_source () const { return source; } + BindingSource get_source () const; }; // Now our resolver, which keeps track of all the `ForeverStack`s we could want @@ -293,7 +269,7 @@ class NameResolutionContext ForeverStack labels; Analysis::Mappings &mappings; - BindingContext bindings; + StackedContexts bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h index d537d6ec451b..cabc65df4b01 100644 --- a/gcc/rust/util/rust-stacked-contexts.h +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -71,7 +71,14 @@ template class StackedContexts return last; } - const T &peek () + const T &peek () const + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + + T &peek () { rust_assert (!stack.empty ()); From 8ce5a6971086dc1e47266883a99c51247a20cfb5 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sun, 6 Apr 2025 19:54:06 +0200 Subject: [PATCH 7/8] Remove passing test from exclusion list gcc/testsuite/ChangeLog: * rust/compile/nr2/exclude: Remove passing test from exclusion list. Signed-off-by: Pierre-Emmanuel Patry --- gcc/testsuite/rust/compile/nr2/exclude | 2 -- 1 file changed, 2 deletions(-) diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index 2c116be13491..b47ea09fe258 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -1,7 +1,5 @@ canonical_paths1.rs issue-3315-2.rs -multiple_bindings1.rs -multiple_bindings2.rs privacy5.rs privacy8.rs pub_restricted_1.rs From 7134a116477bd59b2b1427480f2dd61ee0655e15 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Sat, 19 Apr 2025 14:14:25 +0200 Subject: [PATCH 8/8] Use specialized param visit function for params This commit introduce a new public function to visit function parameters in the default visitor. It allows visitors derived from DefaultVisitor to override only a small part of the default visitor. gcc/rust/ChangeLog: * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit_function_params): Add specialized function to visit function parameters. (DefaultASTVisitor::visit): Remove parameter visit and call specialized function instead. * ast/rust-ast-visitor.h: Add function prototye. * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove function. (Late::visit_function_params): Override specialized visit function. * resolve/rust-late-name-resolver-2.0.h: Add overriden function prototype. Signed-off-by: Pierre-Emmanuel Patry --- gcc/rust/ast/rust-ast-visitor.cc | 12 ++++++-- gcc/rust/ast/rust-ast-visitor.h | 2 ++ .../resolve/rust-late-name-resolver-2.0.cc | 30 ++++--------------- .../resolve/rust-late-name-resolver-2.0.h | 4 ++- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index 70580accb368..563bf7de959c 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -831,6 +831,13 @@ DefaultASTVisitor::visit (AST::UseDeclaration &use_decl) visit (use_decl.get_tree ()); } +void +DefaultASTVisitor::visit_function_params (AST::Function &function) +{ + for (auto ¶m : function.get_function_params ()) + visit (param); +} + void DefaultASTVisitor::visit (AST::Function &function) { @@ -839,8 +846,9 @@ DefaultASTVisitor::visit (AST::Function &function) visit (function.get_qualifiers ()); for (auto &generic : function.get_generic_params ()) visit (generic); - for (auto ¶m : function.get_function_params ()) - visit (param); + + visit_function_params (function); + if (function.has_return_type ()) visit (function.get_return_type ()); if (function.has_where_clause ()) diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 50cf1bf81482..dca8cbc645b4 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -242,6 +242,8 @@ class ASTVisitor class DefaultASTVisitor : public ASTVisitor { public: + virtual void visit_function_params (AST::Function &function); + virtual void visit (AST::Crate &crate); virtual void visit (AST::Token &tok) override; diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 5ee3fa2dae35..5f215db0a72b 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -266,34 +266,14 @@ Late::visit (AST::AltPattern &pattern) } void -Late::visit (AST::Function &function) +Late::visit_function_params (AST::Function &function) { - auto def_fn = [this, &function] () { - visit_outer_attrs (function); - visit (function.get_visibility ()); - visit (function.get_qualifiers ()); - for (auto &generic : function.get_generic_params ()) - visit (generic); - - // We only care about params - ctx.bindings.enter (BindingSource::Param); - - for (auto ¶m : function.get_function_params ()) - visit (param); - - ctx.bindings.exit (); - - // Back to regular visit + ctx.bindings.enter (BindingSource::Param); - if (function.has_return_type ()) - visit (function.get_return_type ()); - if (function.has_where_clause ()) - visit (function.get_where_clause ()); - if (function.has_body ()) - visit (*function.get_definition ()); - }; + for (auto ¶m : function.get_function_params ()) + visit (param); - ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); + ctx.bindings.exit (); } void diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 90113f2277f4..896b72ce4399 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -37,6 +37,9 @@ class Late : public DefaultResolver void new_label (Identifier name, NodeId id); + // Specialized visit bits + void visit_function_params (AST::Function &function) override; + // some more label declarations void visit (AST::LetStmt &) override; // TODO: Do we need this? @@ -44,7 +47,6 @@ class Late : public DefaultResolver void visit (AST::IdentifierPattern &) override; void visit (AST::StructPatternFieldIdent &) override; void visit (AST::AltPattern &) override; - void visit (AST::Function &) override; void visit (AST::SelfParam &) override; void visit (AST::MatchArm &) override; void visit (AST::ForLoopExpr &) override;