@@ -8,7 +8,7 @@ use rustc_middle::{
88 ty:: { self , Ty } ,
99} ;
1010use rustc_target:: abi;
11- use rustc_target:: abi:: call:: { ArgAbi , FnAbi , PassMode } ;
11+ use rustc_target:: abi:: call:: { ArgAbi , ArgAttribute , ArgAttributes , FnAbi , PassMode } ;
1212use rustc_target:: spec:: abi:: Abi ;
1313
1414use super :: {
@@ -199,41 +199,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
199199 }
200200 } ;
201201 // 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 {
209215 return false ;
210216 }
211217 return true ;
212218 } ;
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)
227224 }
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 ,
234235 } ;
235236
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 ;
237246 }
238247
239248 /// Initialize a single callee argument, checking the types for compatibility.
0 commit comments