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 &current = 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);

Reply via email to