@@ -8,7 +8,7 @@ use rustc_middle::{
8
8
ty:: { self , Ty } ,
9
9
} ;
10
10
use rustc_target:: abi;
11
- use rustc_target:: abi:: call:: { ArgAbi , FnAbi , PassMode } ;
11
+ use rustc_target:: abi:: call:: { ArgAbi , ArgAttribute , ArgAttributes , FnAbi , PassMode } ;
12
12
use rustc_target:: spec:: abi:: Abi ;
13
13
14
14
use super :: {
@@ -199,41 +199,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
199
199
}
200
200
} ;
201
201
// Padding must be fully equal.
202
- let pad_compat = || {
203
- if caller_abi. pad != callee_abi. pad {
204
- trace ! (
205
- "check_argument_compat: incompatible pad: {:?} != {:?}" ,
206
- caller_abi. pad,
207
- callee_abi. pad
208
- ) ;
202
+ let pad_compat = || caller_abi. pad == callee_abi. pad ;
203
+ // When comparing the PassMode, we have to be smart about comparing the attributes.
204
+ let arg_attr_compat = |a1 : ArgAttributes , a2 : ArgAttributes | {
205
+ // There's only one regular attribute that matters for the call ABI: InReg.
206
+ // Everything else is things like noalias, dereferencable, nonnull, ...
207
+ // (This also applies to pointee_size, pointee_align.)
208
+ if a1. regular . contains ( ArgAttribute :: InReg ) != a2. regular . contains ( ArgAttribute :: InReg )
209
+ {
210
+ return false ;
211
+ }
212
+ // We also compare the sign extension mode -- this could let the callee make assumptions
213
+ // about bits that conceptually were not even passed.
214
+ if a1. arg_ext != a2. arg_ext {
209
215
return false ;
210
216
}
211
217
return true ;
212
218
} ;
213
- // For comparing the PassMode, we allow the attributes to differ
214
- // (e.g., it is okay for NonNull to differ between caller and callee).
215
- // FIXME: Are there attributes (`call::ArgAttributes`) that do need to be checked?
216
- let mode_compat = || {
217
- match ( caller_abi. mode , callee_abi. mode ) {
218
- ( PassMode :: Ignore , PassMode :: Ignore ) => return true ,
219
- ( PassMode :: Direct ( _) , PassMode :: Direct ( _) ) => return true ,
220
- ( PassMode :: Pair ( _, _) , PassMode :: Pair ( _, _) ) => return true ,
221
- ( PassMode :: Cast ( c1) , PassMode :: Cast ( c2) ) if c1 == c2 => return true ,
222
- (
223
- PassMode :: Indirect { attrs : _, extra_attrs : e1, on_stack : s1 } ,
224
- PassMode :: Indirect { attrs : _, extra_attrs : e2, on_stack : s2 } ,
225
- ) if e1. is_some ( ) == e2. is_some ( ) && s1 == s2 => return true ,
226
- _ => { }
219
+ let mode_compat = || match ( caller_abi. mode , callee_abi. mode ) {
220
+ ( PassMode :: Ignore , PassMode :: Ignore ) => true ,
221
+ ( PassMode :: Direct ( a1) , PassMode :: Direct ( a2) ) => arg_attr_compat ( a1, a2) ,
222
+ ( PassMode :: Pair ( a1, b1) , PassMode :: Pair ( a2, b2) ) => {
223
+ arg_attr_compat ( a1, a2) && arg_attr_compat ( b1, b2)
227
224
}
228
- trace ! (
229
- "check_argument_compat: incompatible modes:\n caller: {:?}\n callee: {:?}" ,
230
- caller_abi. mode,
231
- callee_abi. mode
232
- ) ;
233
- return false ;
225
+ ( PassMode :: Cast ( c1) , PassMode :: Cast ( c2) ) => c1 == c2,
226
+ (
227
+ PassMode :: Indirect { attrs : a1, extra_attrs : None , on_stack : s1 } ,
228
+ PassMode :: Indirect { attrs : a2, extra_attrs : None , on_stack : s2 } ,
229
+ ) => arg_attr_compat ( a1, a2) && s1 == s2,
230
+ (
231
+ PassMode :: Indirect { attrs : a1, extra_attrs : Some ( e1) , on_stack : s1 } ,
232
+ PassMode :: Indirect { attrs : a2, extra_attrs : Some ( e2) , on_stack : s2 } ,
233
+ ) => arg_attr_compat ( a1, a2) && arg_attr_compat ( e1, e2) && s1 == s2,
234
+ _ => false ,
234
235
} ;
235
236
236
- layout_compat ( ) && pad_compat ( ) && mode_compat ( )
237
+ if layout_compat ( ) && pad_compat ( ) && mode_compat ( ) {
238
+ return true ;
239
+ }
240
+ trace ! (
241
+ "check_argument_compat: incompatible ABIs:\n caller: {:?}\n callee: {:?}" ,
242
+ caller_abi,
243
+ callee_abi
244
+ ) ;
245
+ return false ;
237
246
}
238
247
239
248
/// Initialize a single callee argument, checking the types for compatibility.
0 commit comments