From d199424948e4da142dfe299966131401c5dbf21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 7 Nov 2025 23:29:54 +0000 Subject: [PATCH] Avoid infinite cycle in `coerce_unsized_old_solver` when encountering invalid recursive struct definition If an obligation's nested obligations expands to itself, do not add it to the working queue. --- compiler/rustc_hir_typeck/src/coercion.rs | 11 +++++++- .../148653-recursive-struct-infinte-cycle.rs | 11 ++++++++ ...8653-recursive-struct-infinte-cycle.stderr | 27 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.rs create mode 100644 tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 857e4f66489ab..3c4eb99b5a885 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -792,7 +792,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.fcx.set_tainted_by_errors(guar); } } - Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), + Ok(Some(impl_source)) => { + let nested = impl_source.nested_obligations(); + if nested.len() == 1 && &obligation == &nested[0] { + // Avoid hang when expanding the current obligation to the same obligation. + // This doesn't occur under normal circumstances, only on incorrect + // recursive type definitions. Issue #148653. + } else { + queue.extend(nested); + } + } } } diff --git a/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.rs b/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.rs new file mode 100644 index 0000000000000..1ef6754e3589e --- /dev/null +++ b/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.rs @@ -0,0 +1,11 @@ +// Issue #148653. +struct Vec { //~ ERROR recursive type `Vec` has infinite size + data: Vec, //~ ERROR type parameter `T` is only used recursively +} +impl Vec { + pub fn push(&mut self) -> &mut Self { + self + } +} + +fn main() {} diff --git a/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.stderr b/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.stderr new file mode 100644 index 0000000000000..b0f02f1ba0838 --- /dev/null +++ b/tests/ui/traits/solver-cycles/148653-recursive-struct-infinte-cycle.stderr @@ -0,0 +1,27 @@ +error: type parameter `T` is only used recursively + --> $DIR/148653-recursive-struct-infinte-cycle.rs:3:15 + | +LL | struct Vec { + | - type parameter must be used non-recursively in the definition +LL | data: Vec, + | ^ + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = note: all type parameters must be used in a non-recursive way in order to constrain their variance + +error[E0072]: recursive type `Vec` has infinite size + --> $DIR/148653-recursive-struct-infinte-cycle.rs:2:1 + | +LL | struct Vec { + | ^^^^^^^^^^^^^ +LL | data: Vec, + | ------ recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | data: Box>, + | ++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0072`.