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 ¤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 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