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

Reply via email to