@@ -7,7 +7,7 @@ use rustc_middle::{
7
7
ty:: {
8
8
self ,
9
9
layout:: { FnAbiOf , IntegerExt , LayoutOf , TyAndLayout } ,
10
- Instance , Ty ,
10
+ AdtDef , Instance , Ty ,
11
11
} ,
12
12
} ;
13
13
use rustc_span:: sym;
@@ -261,9 +261,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
261
261
/// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
262
262
///
263
263
/// We work with `TyAndLayout` here since that makes it much easier to iterate over all fields.
264
- fn unfold_transparent ( & self , layout : TyAndLayout < ' tcx > ) -> TyAndLayout < ' tcx > {
264
+ fn unfold_transparent (
265
+ & self ,
266
+ layout : TyAndLayout < ' tcx > ,
267
+ may_unfold : impl Fn ( AdtDef < ' tcx > ) -> bool ,
268
+ ) -> TyAndLayout < ' tcx > {
265
269
match layout. ty . kind ( ) {
266
- ty:: Adt ( adt_def, _) if adt_def. repr ( ) . transparent ( ) => {
270
+ ty:: Adt ( adt_def, _) if adt_def. repr ( ) . transparent ( ) && may_unfold ( * adt_def ) => {
267
271
assert ! ( !adt_def. is_enum( ) ) ;
268
272
// Find the non-1-ZST field.
269
273
let mut non_1zst_fields = ( 0 ..layout. fields . count ( ) ) . filter_map ( |idx| {
@@ -277,7 +281,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
277
281
) ;
278
282
279
283
// Found it!
280
- self . unfold_transparent ( first)
284
+ self . unfold_transparent ( first, may_unfold )
281
285
}
282
286
// Not a transparent type, no further unfolding.
283
287
_ => layout,
@@ -287,7 +291,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
287
291
/// Unwrap types that are guaranteed a null-pointer-optimization
288
292
fn unfold_npo ( & self , ty : Ty < ' tcx > ) -> InterpResult < ' tcx , Ty < ' tcx > > {
289
293
// Check if this is `Option` wrapping some type.
290
- let inner_ty = match ty. kind ( ) {
294
+ let inner = match ty. kind ( ) {
291
295
ty:: Adt ( def, args) if self . tcx . is_diagnostic_item ( sym:: Option , def. did ( ) ) => {
292
296
args[ 0 ] . as_type ( ) . unwrap ( )
293
297
}
@@ -297,16 +301,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
297
301
}
298
302
} ;
299
303
// Check if the inner type is one of the NPO-guaranteed ones.
300
- Ok ( match inner_ty. kind ( ) {
304
+ // For that we first unpeel transparent *structs* (but not unions).
305
+ let is_npo = |def : AdtDef < ' tcx > | {
306
+ self . tcx . has_attr ( def. did ( ) , sym:: rustc_nonnull_optimization_guaranteed)
307
+ } ;
308
+ let inner = self . unfold_transparent ( self . layout_of ( inner) ?, /* may_unfold */ |def| {
309
+ // Stop at NPO tpyes so that we don't miss that attribute in the check below!
310
+ def. is_struct ( ) && !is_npo ( def)
311
+ } ) ;
312
+ Ok ( match inner. ty . kind ( ) {
301
313
ty:: Ref ( ..) | ty:: FnPtr ( ..) => {
302
314
// Option<&T> behaves like &T, and same for fn()
303
- inner_ty
315
+ inner . ty
304
316
}
305
- ty:: Adt ( def, _)
306
- if self . tcx . has_attr ( def. did ( ) , sym:: rustc_nonnull_optimization_guaranteed) =>
307
- {
308
- // For non-null-guaranteed structs, unwrap newtypes.
309
- self . unfold_transparent ( self . layout_of ( inner_ty) ?) . ty
317
+ ty:: Adt ( def, _) if is_npo ( * def) => {
318
+ // Once we found a `nonnull_optimization_guaranteed` type, further strip off
319
+ // newtype structs from it to find the underlying ABI type.
320
+ self . unfold_transparent ( inner, /* may_unfold */ |def| def. is_struct ( ) ) . ty
310
321
}
311
322
_ => {
312
323
// Everything else we do not unfold.
@@ -332,8 +343,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
332
343
return Ok ( caller_layout. is_1zst ( ) && callee_layout. is_1zst ( ) ) ;
333
344
}
334
345
// Unfold newtypes and NPO optimizations.
335
- let caller_ty = self . unfold_npo ( self . unfold_transparent ( caller_layout) . ty ) ?;
336
- let callee_ty = self . unfold_npo ( self . unfold_transparent ( callee_layout) . ty ) ?;
346
+ let caller_ty =
347
+ self . unfold_npo ( self . unfold_transparent ( caller_layout, /* may_unfold */ |_| true ) . ty ) ?;
348
+ let callee_ty =
349
+ self . unfold_npo ( self . unfold_transparent ( callee_layout, /* may_unfold */ |_| true ) . ty ) ?;
337
350
// Now see if these inner types are compatible.
338
351
339
352
// Compatible pointer types.
0 commit comments