@@ -255,6 +255,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
255
255
caller_abi : & ArgAbi < ' tcx , Ty < ' tcx > > ,
256
256
callee_abi : & ArgAbi < ' tcx , Ty < ' tcx > > ,
257
257
) -> bool {
258
+ let primitive_abi_compat = |a1 : abi:: Primitive , a2 : abi:: Primitive | -> bool {
259
+ match ( a1, a2) {
260
+ // For integers, ignore the sign.
261
+ ( abi:: Primitive :: Int ( int_ty1, _sign1) , abi:: Primitive :: Int ( int_ty2, _sign2) ) => {
262
+ int_ty1 == int_ty2
263
+ }
264
+ // For everything else we require full equality.
265
+ _ => a1 == a2,
266
+ }
267
+ } ;
258
268
// Heuristic for type comparison.
259
269
let layout_compat = || {
260
270
if caller_abi. layout . ty == callee_abi. layout . ty {
@@ -267,28 +277,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
267
277
// then who knows what happens.
268
278
return false ;
269
279
}
270
- if caller_abi. layout . size != callee_abi. layout . size
271
- || caller_abi. layout . align . abi != callee_abi. layout . align . abi
272
- {
273
- // This cannot go well...
274
- return false ;
275
- }
276
- // The rest *should* be okay, but we are extra conservative.
280
+ // This is tricky. Some ABIs split aggregates up into multiple registers etc, so we have
281
+ // to be super careful here. For the scalar ABIs we conveniently already have all the
282
+ // newtypes unwrapped etc, so in those cases we can just compare the scalar components.
283
+ // Everything else we just reject for now.
277
284
match ( caller_abi. layout . abi , callee_abi. layout . abi ) {
278
- // Different valid ranges are okay (once we enforce validity,
279
- // that will take care to make it UB to leave the range, just
280
- // like for transmute).
285
+ // Different valid ranges are okay (the validity check will complain if this leads
286
+ // to invalid transmutes).
281
287
( abi:: Abi :: Scalar ( caller) , abi:: Abi :: Scalar ( callee) ) => {
282
- caller. primitive ( ) == callee. primitive ( )
288
+ primitive_abi_compat ( caller. primitive ( ) , callee. primitive ( ) )
283
289
}
284
290
(
285
291
abi:: Abi :: ScalarPair ( caller1, caller2) ,
286
292
abi:: Abi :: ScalarPair ( callee1, callee2) ,
287
293
) => {
288
- caller1. primitive ( ) == callee1. primitive ( )
289
- && caller2. primitive ( ) == callee2. primitive ( )
294
+ primitive_abi_compat ( caller1. primitive ( ) , callee1. primitive ( ) )
295
+ && primitive_abi_compat ( caller2. primitive ( ) , callee2. primitive ( ) )
290
296
}
291
- // Be conservative
297
+ // Be conservative.
292
298
_ => false ,
293
299
}
294
300
} ;
@@ -309,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
309
315
return true ;
310
316
} ;
311
317
let mode_compat = || match ( & caller_abi. mode , & callee_abi. mode ) {
312
- ( PassMode :: Ignore , PassMode :: Ignore ) => true ,
318
+ ( PassMode :: Ignore , PassMode :: Ignore ) => true , // can still be reached for the return type
313
319
( PassMode :: Direct ( a1) , PassMode :: Direct ( a2) ) => arg_attr_compat ( a1, a2) ,
314
320
( PassMode :: Pair ( a1, b1) , PassMode :: Pair ( a2, b2) ) => {
315
321
arg_attr_compat ( a1, a2) && arg_attr_compat ( b1, b2)
@@ -326,7 +332,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
326
332
_ => false ,
327
333
} ;
328
334
335
+ // We have to check both. `layout_compat` is needed to reject e.g. `i32` vs `f32`,
336
+ // which is not reflected in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`,
337
+ // which have the same `abi::Primitive` but different `arg_ext`.
329
338
if layout_compat ( ) && mode_compat ( ) {
339
+ // Something went very wrong if our checks don't even imply that the layout is the same.
340
+ assert ! (
341
+ caller_abi. layout. size == callee_abi. layout. size
342
+ && caller_abi. layout. align. abi == callee_abi. layout. align. abi
343
+ ) ;
330
344
return true ;
331
345
}
332
346
trace ! (
0 commit comments