@@ -332,9 +332,38 @@ impl<'tcx> SizeSkeleton<'tcx> {
332332 ty : Ty < ' tcx > ,
333333 tcx : TyCtxt < ' tcx > ,
334334 typing_env : ty:: TypingEnv < ' tcx > ,
335+ span : Span ,
336+ ) -> Result < SizeSkeleton < ' tcx > , & ' tcx LayoutError < ' tcx > > {
337+ Self :: compute_inner ( ty, tcx, typing_env, span, 0 )
338+ }
339+
340+ fn compute_inner (
341+ ty : Ty < ' tcx > ,
342+ tcx : TyCtxt < ' tcx > ,
343+ typing_env : ty:: TypingEnv < ' tcx > ,
344+ span : Span ,
345+ depth : usize ,
335346 ) -> Result < SizeSkeleton < ' tcx > , & ' tcx LayoutError < ' tcx > > {
336347 debug_assert ! ( !ty. has_non_region_infer( ) ) ;
337348
349+ // Bail out if we've recursed too deeply (issue #156137); a cyclic type
350+ // alias can otherwise blow the stack here. Using `>=` rather than `>`
351+ // means we fire exactly at the limit, which lets us report the
352+ // cycle-root type (`Thing<T>`) instead of an innocent field type.
353+ let recursion_limit = tcx. recursion_limit ( ) ;
354+ if depth >= recursion_limit. 0 {
355+ let suggested_limit = match recursion_limit {
356+ hir:: limit:: Limit ( 0 ) => hir:: limit:: Limit ( 2 ) ,
357+ limit => limit * 2 ,
358+ } ;
359+ let reported = tcx. dcx ( ) . emit_err ( crate :: error:: RecursionLimitReachedSizeSkeleton {
360+ span,
361+ ty,
362+ suggested_limit,
363+ } ) ;
364+ return Err ( tcx. arena . alloc ( LayoutError :: ReferencesError ( reported) ) ) ;
365+ }
366+
338367 // First try computing a static layout.
339368 let err = match tcx. layout_of ( typing_env. as_query_input ( ty) ) {
340369 Ok ( layout) => {
@@ -407,7 +436,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
407436 return Ok ( SizeSkeleton :: Known ( Size :: from_bytes ( 0 ) , None ) ) ;
408437 }
409438
410- match SizeSkeleton :: compute ( inner, tcx, typing_env) ? {
439+ match SizeSkeleton :: compute_inner ( inner, tcx, typing_env, span , depth + 1 ) ? {
411440 // This may succeed because the multiplication of two types may overflow
412441 // but a single size of a nested array will not.
413442 SizeSkeleton :: Known ( s, a) => {
@@ -434,10 +463,15 @@ impl<'tcx> SizeSkeleton<'tcx> {
434463 // Get a zero-sized variant or a pointer newtype.
435464 let zero_or_ptr_variant = |i| {
436465 let i = VariantIdx :: from_usize ( i) ;
437- let fields =
438- def. variant ( i) . fields . iter ( ) . map ( |field| {
439- SizeSkeleton :: compute ( field. ty ( tcx, args) , tcx, typing_env)
440- } ) ;
466+ let fields = def. variant ( i) . fields . iter ( ) . map ( |field| {
467+ SizeSkeleton :: compute_inner (
468+ field. ty ( tcx, args) ,
469+ tcx,
470+ typing_env,
471+ span,
472+ depth + 1 ,
473+ )
474+ } ) ;
441475 let mut ptr = None ;
442476 for field in fields {
443477 let field = field?;
@@ -487,13 +521,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
487521 if ty == normalized {
488522 Err ( err)
489523 } else {
490- SizeSkeleton :: compute ( normalized, tcx, typing_env)
524+ SizeSkeleton :: compute_inner ( normalized, tcx, typing_env, span , depth + 1 )
491525 }
492526 }
493527
494528 ty:: Pat ( base, pat) => {
495529 // Pattern types are always the same size as their base.
496- let base = SizeSkeleton :: compute ( base, tcx, typing_env) ;
530+ let base = SizeSkeleton :: compute_inner ( base, tcx, typing_env, span , depth + 1 ) ;
497531 match * pat {
498532 ty:: PatternKind :: Range { .. } | ty:: PatternKind :: Or ( _) => base,
499533 // But in the case of `!null` patterns we need to note that in the
0 commit comments