@@ -11,7 +11,7 @@ use rustc_middle::{
1111 } ,
1212} ;
1313use rustc_span:: sym;
14- use rustc_target:: abi:: FieldIdx ;
14+ use rustc_target:: abi:: { self , FieldIdx } ;
1515use rustc_target:: abi:: {
1616 call:: { ArgAbi , FnAbi , PassMode } ,
1717 Integer ,
@@ -289,39 +289,40 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
289289 }
290290
291291 /// Unwrap types that are guaranteed a null-pointer-optimization
292- fn unfold_npo ( & self , ty : Ty < ' tcx > ) -> InterpResult < ' tcx , Ty < ' tcx > > {
292+ fn unfold_npo ( & self , layout : TyAndLayout < ' tcx > ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > {
293293 // Check if this is `Option` wrapping some type.
294- let inner = match ty. kind ( ) {
294+ let inner = match layout . ty . kind ( ) {
295295 ty:: Adt ( def, args) if self . tcx . is_diagnostic_item ( sym:: Option , def. did ( ) ) => {
296296 args[ 0 ] . as_type ( ) . unwrap ( )
297297 }
298298 _ => {
299299 // Not an `Option`.
300- return Ok ( ty ) ;
300+ return Ok ( layout ) ;
301301 }
302302 } ;
303+ let inner = self . layout_of ( inner) ?;
303304 // Check if the inner type is one of the NPO-guaranteed ones.
304305 // For that we first unpeel transparent *structs* (but not unions).
305306 let is_npo = |def : AdtDef < ' tcx > | {
306307 self . tcx . has_attr ( def. did ( ) , sym:: rustc_nonnull_optimization_guaranteed)
307308 } ;
308- let inner = self . unfold_transparent ( self . layout_of ( inner) ? , /* may_unfold */ |def| {
309+ let inner = self . unfold_transparent ( inner, /* may_unfold */ |def| {
309310 // Stop at NPO tpyes so that we don't miss that attribute in the check below!
310311 def. is_struct ( ) && !is_npo ( def)
311312 } ) ;
312313 Ok ( match inner. ty . kind ( ) {
313314 ty:: Ref ( ..) | ty:: FnPtr ( ..) => {
314315 // Option<&T> behaves like &T, and same for fn()
315- inner. ty
316+ inner
316317 }
317318 ty:: Adt ( def, _) if is_npo ( * def) => {
318319 // Once we found a `nonnull_optimization_guaranteed` type, further strip off
319320 // newtype structs from it to find the underlying ABI type.
320- self . unfold_transparent ( inner, /* may_unfold */ |def| def. is_struct ( ) ) . ty
321+ self . unfold_transparent ( inner, /* may_unfold */ |def| def. is_struct ( ) )
321322 }
322323 _ => {
323324 // Everything else we do not unfold.
324- ty
325+ layout
325326 }
326327 } )
327328 }
@@ -331,28 +332,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
331332 /// that only checking the `PassMode` is insufficient.)
332333 fn layout_compat (
333334 & self ,
334- caller_layout : TyAndLayout < ' tcx > ,
335- callee_layout : TyAndLayout < ' tcx > ,
335+ caller : TyAndLayout < ' tcx > ,
336+ callee : TyAndLayout < ' tcx > ,
336337 ) -> InterpResult < ' tcx , bool > {
337338 // Fast path: equal types are definitely compatible.
338- if caller_layout . ty == callee_layout . ty {
339+ if caller . ty == callee . ty {
339340 return Ok ( true ) ;
340341 }
341342 // 1-ZST are compatible with all 1-ZST (and with nothing else).
342- if caller_layout . is_1zst ( ) || callee_layout . is_1zst ( ) {
343- return Ok ( caller_layout . is_1zst ( ) && callee_layout . is_1zst ( ) ) ;
343+ if caller . is_1zst ( ) || callee . is_1zst ( ) {
344+ return Ok ( caller . is_1zst ( ) && callee . is_1zst ( ) ) ;
344345 }
345346 // Unfold newtypes and NPO optimizations.
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 ) ?;
347+ let unfold = |layout : TyAndLayout < ' tcx > | {
348+ self . unfold_npo ( self . unfold_transparent ( layout, /* may_unfold */ |_def| true ) )
349+ } ;
350+ let caller = unfold ( caller) ?;
351+ let callee = unfold ( callee) ?;
350352 // Now see if these inner types are compatible.
351353
352- // Compatible pointer types.
353- let pointee_ty = |ty : Ty < ' tcx > | {
354+ // Compatible pointer types. For thin pointers, we have to accept even non-`repr(transparent)`
355+ // things as compatible due to `DispatchFromDyn`. For instance, `Rc<i32>` and `*mut i32`
356+ // must be compatible. So we just accept everything with Pointer ABI as compatible,
357+ // even if this will accept some code that is not stably guaranteed to work.
358+ // This also handles function pointers.
359+ let thin_pointer = |layout : TyAndLayout < ' tcx > | match layout. abi {
360+ abi:: Abi :: Scalar ( s) => match s. primitive ( ) {
361+ abi:: Primitive :: Pointer ( addr_space) => Some ( addr_space) ,
362+ _ => None ,
363+ } ,
364+ _ => None ,
365+ } ;
366+ if let ( Some ( caller) , Some ( callee) ) = ( thin_pointer ( caller) , thin_pointer ( callee) ) {
367+ return Ok ( caller == callee) ;
368+ }
369+ // For wide pointers we have to get the pointee type.
370+ let pointee_ty = |ty : Ty < ' tcx > | -> InterpResult < ' tcx , Option < Ty < ' tcx > > > {
354371 // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`.
355- Some ( match ty. kind ( ) {
372+ Ok ( Some ( match ty. kind ( ) {
356373 ty:: Ref ( _, ty, _) => * ty,
357374 ty:: RawPtr ( mt) => mt. ty ,
358375 // We should only accept `Box` with the default allocator.
@@ -363,10 +380,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
363380 {
364381 args[ 0 ] . expect_ty ( )
365382 }
366- _ => return None ,
367- } )
383+ _ => return Ok ( None ) ,
384+ } ) )
368385 } ;
369- if let ( Some ( left ) , Some ( right ) ) = ( pointee_ty ( caller_ty ) , pointee_ty ( callee_ty ) ) {
386+ if let ( Some ( caller ) , Some ( callee ) ) = ( pointee_ty ( caller . ty ) ? , pointee_ty ( callee . ty ) ? ) {
370387 // This is okay if they have the same metadata type.
371388 let meta_ty = |ty : Ty < ' tcx > | {
372389 let ( meta, only_if_sized) = ty. ptr_metadata_ty ( * self . tcx , |ty| ty) ;
@@ -376,12 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
376393 ) ;
377394 meta
378395 } ;
379- return Ok ( meta_ty ( left) == meta_ty ( right) ) ;
380- }
381-
382- // Compatible function pointer types.
383- if let ( ty:: FnPtr ( ..) , ty:: FnPtr ( ..) ) = ( caller_ty. kind ( ) , callee_ty. kind ( ) ) {
384- return Ok ( true ) ;
396+ return Ok ( meta_ty ( caller) == meta_ty ( callee) ) ;
385397 }
386398
387399 // Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
@@ -392,14 +404,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
392404 _ => return None ,
393405 } )
394406 } ;
395- if let ( Some ( left ) , Some ( right ) ) = ( int_ty ( caller_ty ) , int_ty ( callee_ty ) ) {
407+ if let ( Some ( caller ) , Some ( callee ) ) = ( int_ty ( caller . ty ) , int_ty ( callee . ty ) ) {
396408 // This is okay if they are the same integer type.
397- return Ok ( left == right ) ;
409+ return Ok ( caller == callee ) ;
398410 }
399411
400412 // Fall back to exact equality.
401413 // FIXME: We are missing the rules for "repr(C) wrapping compatible types".
402- Ok ( caller_ty == callee_ty )
414+ Ok ( caller == callee )
403415 }
404416
405417 fn check_argument_compat (
0 commit comments