https://gcc.gnu.org/g:f4fede6edba2bbb51f7ec00f60565db9156796c8
commit r17-5443-gf4fede6edba2bbb51f7ec00f60565db9156796c8 Author: Utkarsh Bahuguna <[email protected]> Date: Sat Oct 3 13:46:35 2026 +0530 gccrs: Reject type param defaults using later params The forward declaration check only caught a default naming its own param, so `struct Foo<T = U, U = ()>` was accepted. Flag later params too, skipping a trait's implicit Self. Fixes Rust-GCC/gccrs#3764 gcc/rust/ChangeLog: * resolve/rust-forever-stack.h (ForeverStack::forward_declared): Also flag params declared after the current one. * resolve/rust-late-name-resolver-2.0.cc (resolve_type_path_like): Skip the check for Self. gcc/testsuite/ChangeLog: * rust/compile/issue-3764.rs: New test. Signed-off-by: Utkarsh Bahuguna <[email protected]> Diff: --- gcc/rust/resolve/rust-forever-stack.h | 18 +++++++++++++----- gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 10 ++++++++-- gcc/testsuite/rust/compile/issue-3764.rs | 7 +++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 3e18fea869f8..80ac7a45e5a6 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -806,13 +806,21 @@ public: if (peek ().kind != Rib::Kind::ForwardTypeParamBan) return false; - const auto &definition_rib = dfs_rib (cursor (), definition); - - if (!definition_rib) + // Each type param has a ban rib keyed by its NodeId, and those ribs are + // siblings ordered by NodeId, i.e. by declaration order. A default may + // only use params declared before its own. + auto ¤t = cursor (); + if (definition == current.id) + return true; + if (!current.parent) return false; - return (definition_rib - && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan); + for (auto &child : current.parent.value ().children) + if (child.second.id == definition) + return definition > current.id + && child.second.rib (N).kind == Rib::Kind::ForwardTypeParamBan; + + return false; } void map_usage (Usage usage, Definition definition) 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 b568b19b0e51..dfcf6b283ea5 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -537,8 +537,14 @@ resolve_type_path_like (NameResolutionContext &ctx, bool block_big_self, return; } - if (ctx.types.forward_declared (resolved->definition.get_node_id (), - type.get_node_id ())) + // a trait's implicit Self is always in scope, even in its generic defaults + bool is_self + = !unwrap_segment_get_lang_item (type.get_segments ().front ()).has_value () + && unwrap_type_segment (type.get_segments ().front ()).is_big_self_seg (); + + if (!is_self + && ctx.types.forward_declared (resolved->definition.get_node_id (), + type.get_node_id ())) { rust_error_at (type.get_locus (), ErrorCode::E0128, "type parameters with a default cannot use forward " diff --git a/gcc/testsuite/rust/compile/issue-3764.rs b/gcc/testsuite/rust/compile/issue-3764.rs new file mode 100644 index 000000000000..626e3330aa35 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3764.rs @@ -0,0 +1,7 @@ +#![feature(no_core)] +#![no_core] + +struct Foo<T = U, U = ()>(T, U); +// { dg-error "type parameters with a default cannot use forward declared identifiers" "" { target *-*-* } .-1 } + +struct Bar<T, U = T>(T, U);
