@@ -7,7 +7,7 @@ use rustc_middle::{
77 ty:: {
88 self ,
99 layout:: { FnAbiOf , IntegerExt , LayoutOf , TyAndLayout } ,
10- Instance , Ty ,
10+ AdtDef , Instance , Ty ,
1111 } ,
1212} ;
1313use rustc_span:: sym;
@@ -261,9 +261,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
261261 /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
262262 ///
263263 /// 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 > {
265269 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 ) => {
267271 assert ! ( !adt_def. is_enum( ) ) ;
268272 // Find the non-1-ZST field.
269273 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> {
277281 ) ;
278282
279283 // Found it!
280- self . unfold_transparent ( first)
284+ self . unfold_transparent ( first, may_unfold )
281285 }
282286 // Not a transparent type, no further unfolding.
283287 _ => layout,
@@ -287,7 +291,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
287291 /// Unwrap types that are guaranteed a null-pointer-optimization
288292 fn unfold_npo ( & self , ty : Ty < ' tcx > ) -> InterpResult < ' tcx , Ty < ' tcx > > {
289293 // Check if this is `Option` wrapping some type.
290- let inner_ty = match ty. kind ( ) {
294+ let inner = match ty. kind ( ) {
291295 ty:: Adt ( def, args) if self . tcx . is_diagnostic_item ( sym:: Option , def. did ( ) ) => {
292296 args[ 0 ] . as_type ( ) . unwrap ( )
293297 }
@@ -297,16 +301,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
297301 }
298302 } ;
299303 // 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 ( ) {
301313 ty:: Ref ( ..) | ty:: FnPtr ( ..) => {
302314 // Option<&T> behaves like &T, and same for fn()
303- inner_ty
315+ inner . ty
304316 }
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
310321 }
311322 _ => {
312323 // Everything else we do not unfold.
@@ -332,8 +343,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
332343 return Ok ( caller_layout. is_1zst ( ) && callee_layout. is_1zst ( ) ) ;
333344 }
334345 // 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 ) ?;
337350 // Now see if these inner types are compatible.
338351
339352 // Compatible pointer types.
0 commit comments