From: Utkarsh Bahuguna <[email protected]>

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]>
---
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/682a2f6d13127471160723d58a3d59bea69841eb

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#3764: https://github.com/Rust-GCC/gccrs/issues/3764

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4953

 gcc/rust/resolve/rust-forever-stack.h          | 18 +++++++++++++-----
 .../resolve/rust-late-name-resolver-2.0.cc     | 10 ++++++++--
 gcc/testsuite/rust/compile/issue-3764.rs       |  7 +++++++
 3 files changed, 28 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-3764.rs

diff --git a/gcc/rust/resolve/rust-forever-stack.h 
b/gcc/rust/resolve/rust-forever-stack.h
index 3e18fea86..80ac7a45e 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 b568b19b0..dfcf6b283 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 000000000..626e3330a
--- /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);

base-commit: 7f128423f45f90bd44460ef9f7616b7a4b14138c
-- 
2.55.0

Reply via email to