https://gcc.gnu.org/g:e84bd344499c534c84b5b0c72632caa9fea84dc1

commit r17-5707-ge84bd344499c534c84b5b0c72632caa9fea84dc1
Author: Utkarsh Bahuguna <[email protected]>
Date:   Thu Oct 8 15:35:39 2026 +0530

    gccrs: Only add the requested auto trait when probing for a trait
    
    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]>

Diff:
---
 gcc/rust/typecheck/rust-tyty-bounds.cc             |  5 ++--
 .../rust/compile/auto-trait-nested-negative.rs     | 35 ++++++++++++++++++++++
 gcc/testsuite/rust/compile/issues/issue-4971.rs    | 35 ++++++++++++++++++++++
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc 
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 1f908cb6de29..69ffe0e3048d 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 000000000000..99c88d556f7e
--- /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 000000000000..7ffdc594e70d
--- /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);
+}

Reply via email to