@@ -25,11 +25,26 @@ pub enum Representability {
2525pub fn ty_is_representable < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , sp : Span ) -> Representability {
2626 debug ! ( "is_type_representable: {:?}" , ty) ;
2727 // To avoid a stack overflow when checking an enum variant or struct that
28- // contains a different, structurally recursive type, maintain a stack
29- // of seen types and check recursion for each of them (issues #3008, #3779).
28+ // contains a different, structurally recursive type, maintain a stack of
29+ // seen types and check recursion for each of them (issues #3008, #3779,
30+ // #74224, #84611). `shadow_seen` contains the full stack and `seen` only
31+ // the one for the current type (e.g. if we have structs A and B, B contains
32+ // a field of type A, and we're currently looking at B, then `seen` will be
33+ // cleared when recursing to check A, but `shadow_seen` won't, so that we
34+ // can catch cases of mutual recursion where A also contains B).
3035 let mut seen: Vec < Ty < ' _ > > = Vec :: new ( ) ;
36+ let mut shadow_seen: Vec < & ' tcx ty:: AdtDef > = Vec :: new ( ) ;
3137 let mut representable_cache = FxHashMap :: default ( ) ;
32- let r = is_type_structurally_recursive ( tcx, sp, & mut seen, & mut representable_cache, ty) ;
38+ let mut force_result = false ;
39+ let r = is_type_structurally_recursive (
40+ tcx,
41+ sp,
42+ & mut seen,
43+ & mut shadow_seen,
44+ & mut representable_cache,
45+ ty,
46+ & mut force_result,
47+ ) ;
3348 debug ! ( "is_type_representable: {:?} is {:?}" , ty, r) ;
3449 r
3550}
@@ -48,21 +63,38 @@ fn are_inner_types_recursive<'tcx>(
4863 tcx : TyCtxt < ' tcx > ,
4964 sp : Span ,
5065 seen : & mut Vec < Ty < ' tcx > > ,
66+ shadow_seen : & mut Vec < & ' tcx ty:: AdtDef > ,
5167 representable_cache : & mut FxHashMap < Ty < ' tcx > , Representability > ,
5268 ty : Ty < ' tcx > ,
69+ force_result : & mut bool ,
5370) -> Representability {
71+ debug ! ( "are_inner_types_recursive({:?}, {:?}, {:?})" , ty, seen, shadow_seen) ;
5472 match ty. kind ( ) {
5573 ty:: Tuple ( ..) => {
5674 // Find non representable
57- fold_repr (
58- ty. tuple_fields ( ) . map ( |ty| {
59- is_type_structurally_recursive ( tcx, sp, seen, representable_cache, ty)
60- } ) ,
61- )
75+ fold_repr ( ty. tuple_fields ( ) . map ( |ty| {
76+ is_type_structurally_recursive (
77+ tcx,
78+ sp,
79+ seen,
80+ shadow_seen,
81+ representable_cache,
82+ ty,
83+ force_result,
84+ )
85+ } ) )
6286 }
6387 // Fixed-length vectors.
6488 // FIXME(#11924) Behavior undecided for zero-length vectors.
65- ty:: Array ( ty, _) => is_type_structurally_recursive ( tcx, sp, seen, representable_cache, ty) ,
89+ ty:: Array ( ty, _) => is_type_structurally_recursive (
90+ tcx,
91+ sp,
92+ seen,
93+ shadow_seen,
94+ representable_cache,
95+ ty,
96+ force_result,
97+ ) ,
6698 ty:: Adt ( def, substs) => {
6799 // Find non representable fields with their spans
68100 fold_repr ( def. all_fields ( ) . map ( |field| {
@@ -76,12 +108,128 @@ fn are_inner_types_recursive<'tcx>(
76108 Some ( hir:: Node :: Field ( field) ) => field. ty . span ,
77109 _ => sp,
78110 } ;
79- match is_type_structurally_recursive ( tcx, span, seen, representable_cache, ty) {
80- Representability :: SelfRecursive ( _) => {
81- Representability :: SelfRecursive ( vec ! [ span] )
111+
112+ let mut result = None ;
113+
114+ // First, we check whether the field type per se is representable.
115+ // This catches cases as in #74224 and #84611. There is a special
116+ // case related to mutual recursion, though; consider this example:
117+ //
118+ // struct A<T> {
119+ // z: T,
120+ // x: B<T>,
121+ // }
122+ //
123+ // struct B<T> {
124+ // y: A<T>
125+ // }
126+ //
127+ // Here, without the following special case, both A and B are
128+ // ContainsRecursive, which is a problem because we only report
129+ // errors for SelfRecursive. We fix this by detecting this special
130+ // case (shadow_seen.first() is the type we are originally
131+ // interested in, and if we ever encounter the same AdtDef again,
132+ // we know that it must be SelfRecursive) and "forcibly" returning
133+ // SelfRecursive (by setting force_result, which tells the calling
134+ // invocations of are_inner_types_representable to forward the
135+ // result without adjusting).
136+ if shadow_seen. len ( ) > seen. len ( ) && shadow_seen. first ( ) == Some ( def) {
137+ * force_result = true ;
138+ result = Some ( Representability :: SelfRecursive ( vec ! [ span] ) ) ;
139+ }
140+
141+ if result == None {
142+ result = Some ( Representability :: Representable ) ;
143+
144+ // Now, we check whether the field types per se are representable, e.g.
145+ // for struct Foo { x: Option<Foo> }, we first check whether Option<_>
146+ // by itself is representable (which it is), and the nesting of Foo
147+ // will be detected later. This is necessary for #74224 and #84611.
148+
149+ // If we have encountered an ADT definition that we have not seen
150+ // before (no need to check them twice), recurse to see whether that
151+ // definition is SelfRecursive. If so, we must be ContainsRecursive.
152+ if shadow_seen. len ( ) > 1
153+ && !shadow_seen
154+ . iter ( )
155+ . take ( shadow_seen. len ( ) - 1 )
156+ . any ( |seen_def| seen_def == def)
157+ {
158+ let adt_def_id = def. did ;
159+ let raw_adt_ty = tcx. type_of ( adt_def_id) ;
160+ debug ! ( "are_inner_types_recursive: checking nested type: {:?}" , raw_adt_ty) ;
161+
162+ // Check independently whether the ADT is SelfRecursive. If so,
163+ // we must be ContainsRecursive (except for the special case
164+ // mentioned above).
165+ let mut nested_seen: Vec < Ty < ' _ > > = vec ! [ ] ;
166+ result = Some (
167+ match is_type_structurally_recursive (
168+ tcx,
169+ span,
170+ & mut nested_seen,
171+ shadow_seen,
172+ representable_cache,
173+ raw_adt_ty,
174+ force_result,
175+ ) {
176+ Representability :: SelfRecursive ( _) => {
177+ if * force_result {
178+ Representability :: SelfRecursive ( vec ! [ span] )
179+ } else {
180+ Representability :: ContainsRecursive
181+ }
182+ }
183+ x => x,
184+ } ,
185+ ) ;
186+ }
187+
188+ // We only enter the following block if the type looks representable
189+ // so far. This is necessary for cases such as this one (#74224):
190+ //
191+ // struct A<T> {
192+ // x: T,
193+ // y: A<A<T>>,
194+ // }
195+ //
196+ // struct B {
197+ // z: A<usize>
198+ // }
199+ //
200+ // When checking B, we recurse into A and check field y of type
201+ // A<A<usize>>. We haven't seen this exact type before, so we recurse
202+ // into A<A<usize>>, which contains, A<A<A<usize>>>, and so forth,
203+ // ad infinitum. We can prevent this from happening by first checking
204+ // A separately (the code above) and only checking for nested Bs if
205+ // A actually looks representable (which it wouldn't in this example).
206+ if result == Some ( Representability :: Representable ) {
207+ // Now, even if the type is representable (e.g. Option<_>),
208+ // it might still contribute to a recursive type, e.g.:
209+ // struct Foo { x: Option<Option<Foo>> }
210+ // These cases are handled by passing the full `seen`
211+ // stack to is_type_structurally_recursive (instead of the
212+ // empty `nested_seen` above):
213+ result = Some (
214+ match is_type_structurally_recursive (
215+ tcx,
216+ span,
217+ seen,
218+ shadow_seen,
219+ representable_cache,
220+ ty,
221+ force_result,
222+ ) {
223+ Representability :: SelfRecursive ( _) => {
224+ Representability :: SelfRecursive ( vec ! [ span] )
225+ }
226+ x => x,
227+ } ,
228+ ) ;
82229 }
83- x => x,
84230 }
231+
232+ result. unwrap ( )
85233 } ) )
86234 }
87235 ty:: Closure ( ..) => {
@@ -106,8 +254,10 @@ fn is_type_structurally_recursive<'tcx>(
106254 tcx : TyCtxt < ' tcx > ,
107255 sp : Span ,
108256 seen : & mut Vec < Ty < ' tcx > > ,
257+ shadow_seen : & mut Vec < & ' tcx ty:: AdtDef > ,
109258 representable_cache : & mut FxHashMap < Ty < ' tcx > , Representability > ,
110259 ty : Ty < ' tcx > ,
260+ force_result : & mut bool ,
111261) -> Representability {
112262 debug ! ( "is_type_structurally_recursive: {:?} {:?}" , ty, sp) ;
113263 if let Some ( representability) = representable_cache. get ( ty) {
@@ -118,8 +268,15 @@ fn is_type_structurally_recursive<'tcx>(
118268 return representability. clone ( ) ;
119269 }
120270
121- let representability =
122- is_type_structurally_recursive_inner ( tcx, sp, seen, representable_cache, ty) ;
271+ let representability = is_type_structurally_recursive_inner (
272+ tcx,
273+ sp,
274+ seen,
275+ shadow_seen,
276+ representable_cache,
277+ ty,
278+ force_result,
279+ ) ;
123280
124281 representable_cache. insert ( ty, representability. clone ( ) ) ;
125282 representability
@@ -129,12 +286,16 @@ fn is_type_structurally_recursive_inner<'tcx>(
129286 tcx : TyCtxt < ' tcx > ,
130287 sp : Span ,
131288 seen : & mut Vec < Ty < ' tcx > > ,
289+ shadow_seen : & mut Vec < & ' tcx ty:: AdtDef > ,
132290 representable_cache : & mut FxHashMap < Ty < ' tcx > , Representability > ,
133291 ty : Ty < ' tcx > ,
292+ force_result : & mut bool ,
134293) -> Representability {
135294 match ty. kind ( ) {
136295 ty:: Adt ( def, _) => {
137296 {
297+ debug ! ( "is_type_structurally_recursive_inner: adt: {:?}, seen: {:?}" , ty, seen) ;
298+
138299 // Iterate through stack of previously seen types.
139300 let mut iter = seen. iter ( ) ;
140301
@@ -158,8 +319,10 @@ fn is_type_structurally_recursive_inner<'tcx>(
158319 // will recurse infinitely for some inputs.
159320 //
160321 // It is important that we DO take generic parameters into account
161- // here, so that code like this is considered SelfRecursive, not
162- // ContainsRecursive:
322+ // here, because nesting e.g. Options is allowed (as long as the
323+ // definition of Option doesn't itself include an Option field, which
324+ // would be a case of SelfRecursive above). The following, too, counts
325+ // as SelfRecursive:
163326 //
164327 // struct Foo { Option<Option<Foo>> }
165328
@@ -174,13 +337,31 @@ fn is_type_structurally_recursive_inner<'tcx>(
174337 // For structs and enums, track all previously seen types by pushing them
175338 // onto the 'seen' stack.
176339 seen. push ( ty) ;
177- let out = are_inner_types_recursive ( tcx, sp, seen, representable_cache, ty) ;
340+ shadow_seen. push ( def) ;
341+ let out = are_inner_types_recursive (
342+ tcx,
343+ sp,
344+ seen,
345+ shadow_seen,
346+ representable_cache,
347+ ty,
348+ force_result,
349+ ) ;
350+ shadow_seen. pop ( ) ;
178351 seen. pop ( ) ;
179352 out
180353 }
181354 _ => {
182355 // No need to push in other cases.
183- are_inner_types_recursive ( tcx, sp, seen, representable_cache, ty)
356+ are_inner_types_recursive (
357+ tcx,
358+ sp,
359+ seen,
360+ shadow_seen,
361+ representable_cache,
362+ ty,
363+ force_result,
364+ )
184365 }
185366 }
186367}
0 commit comments