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); +}
