diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e23c3f51967..25787f005aa 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; use std::{cmp, fmt}; @@ -221,7 +221,13 @@ impl<'tcx> TyCtxt<'tcx> { mut ty: Ty<'tcx>, normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { - loop { + for iteration in 0.. { + if !self.sess.recursion_limit().value_within_limit(iteration) { + return self.ty_error_with_message( + DUMMY_SP, + &format!("reached the recursion limit finding the struct tail for {}", ty), + ); + } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs new file mode 100644 index 00000000000..70a203ea6e8 --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.rs @@ -0,0 +1,10 @@ +struct Take(Take); +//~^ ERROR has infinite size +//~| ERROR cycle detected + +// check that we don't hang trying to find the tail of a recursive struct (#79437) +fn foo() -> Take { + Take(loop {}) +} + +fn main() {} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr new file mode 100644 index 00000000000..d180670e38f --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -0,0 +1,27 @@ +error[E0072]: recursive type `Take` has infinite size + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^----^^ + | | | + | | recursive without indirection + | recursive type has infinite size + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable + | +LL | struct Take(Box); + | ^^^^ ^ + +error[E0391]: cycle detected when computing drop-check constraints for `Take` + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`.