From: Utkarsh Bahuguna <[email protected]>
TypeBoundsProbe::scan added every auto trait to every probe, and checking
an auto trait on an ADT probes each of its fields again, so a bound check
on nested structs took time and memory exponential in the nesting depth.
libcore never finished type checking because of it. Callers that probe for
a specific trait only look at that trait in the result, and an auto trait
has no supertraits, so only add the requested one.
Fixes Rust-GCC/gccrs#4971
Assisted-by: Claude Opus 5.5 (Anthropic)
gcc/rust/ChangeLog:
* typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::scan): Only add the
requested auto trait when probing for a specific trait.
gcc/testsuite/ChangeLog:
* rust/compile/auto-trait-nested-negative.rs: New test.
* rust/compile/issues/issue-4971.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/c8ddc01dca52f9494c2ae12524b89425528efb16
The commit has been mentioned in the following issue(s):
- Rust-GCC/gccrs#4971: https://github.com/Rust-GCC/gccrs/issues/4971
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4972
gcc/rust/typecheck/rust-tyty-bounds.cc | 5 +--
.../compile/auto-trait-nested-negative.rs | 35 +++++++++++++++++++
.../rust/compile/issues/issue-4971.rs | 35 +++++++++++++++++++
3 files changed, 73 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/auto-trait-nested-negative.rs
create mode 100644 gcc/testsuite/rust/compile/issues/issue-4971.rs
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 1f908cb6d..69ffe0e30 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -120,9 +120,10 @@ TypeBoundsProbe::scan ()
// marker traits...
assemble_marker_builtins ();
- // add auto trait bounds
+ // add auto trait bounds, only the requested one when probing for a trait
for (auto *auto_trait : mappings.get_auto_traits ())
- add_trait_bound (auto_trait);
+ if (specified_trait == nullptr || specified_trait == auto_trait)
+ add_trait_bound (auto_trait);
}
void
diff --git a/gcc/testsuite/rust/compile/auto-trait-nested-negative.rs
b/gcc/testsuite/rust/compile/auto-trait-nested-negative.rs
new file mode 100644
index 000000000..99c88d556
--- /dev/null
+++ b/gcc/testsuite/rust/compile/auto-trait-nested-negative.rs
@@ -0,0 +1,35 @@
+#![feature(no_core, lang_items, optin_builtin_traits, negative_impls)]
+#![no_core]
+
+// An auto trait bound on nested structs is still checked through every
+// field, so a negative impl deep inside makes the outer struct fail it.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub unsafe auto trait Send {}
+pub unsafe auto trait Sync {}
+
+pub struct Ok;
+pub struct NotSend;
+impl !Send for NotSend {}
+
+pub struct A1(Ok, Ok);
+pub struct A2(A1, A1);
+pub struct A3(A2, A2);
+pub struct A4(A3, A3);
+
+pub struct B1(Ok, NotSend);
+pub struct B2(A1, B1);
+pub struct B3(A2, B2);
+pub struct B4(A3, B3);
+
+fn need_send<X: Send>(_x: X) {}
+
+pub fn ok(x: A4) {
+ need_send(x);
+}
+
+pub fn not_send(x: B4) {
+ need_send(x); // { dg-error "bounds not satisfied for B4 .Send. is not
satisfied .E0277." }
+}
diff --git a/gcc/testsuite/rust/compile/issues/issue-4971.rs
b/gcc/testsuite/rust/compile/issues/issue-4971.rs
new file mode 100644
index 000000000..7ffdc594e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-4971.rs
@@ -0,0 +1,35 @@
+#![feature(no_core, lang_items, optin_builtin_traits)]
+#![no_core]
+
+// Rust-GCC/gccrs#4971: checking a bound on a struct whose fields are structs
+// used to take time and memory exponential in the nesting depth, because every
+// probe added every auto trait and checked each of them on every field.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub unsafe auto trait Send {}
+pub unsafe auto trait Sync {}
+
+pub struct L0;
+pub struct L1(L0, L0);
+pub struct L2(L1, L1);
+pub struct L3(L2, L2);
+pub struct L4(L3, L3);
+pub struct L5(L4, L4);
+pub struct L6(L5, L5);
+pub struct L7(L6, L6);
+pub struct L8(L7, L7);
+pub struct L9(L8, L8);
+pub struct L10(L9, L9);
+pub struct L11(L10, L10);
+pub struct L12(L11, L11);
+
+pub trait T {}
+impl T for L12 {}
+
+pub fn need<X: T>(_x: X) {}
+
+pub fn f(x: L12) {
+ need(x);
+}
base-commit: 7db682a89f216f2ee95989cc486505969a164169
--
2.55.0