compare calling convention instead of call ABI
This commit is contained in:
parent
fcc5fd6135
commit
b5c7530fcf
3 changed files with 11 additions and 39 deletions
|
@ -274,9 +274,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
|
|
||||||
/// Call this function -- pushing the stack frame and initializing the arguments.
|
/// Call this function -- pushing the stack frame and initializing the arguments.
|
||||||
///
|
///
|
||||||
/// For now, we require *both* the `Abi` and `FnAbi` of the caller. In principle, however,
|
/// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
|
||||||
/// `FnAbi` should be enough -- if they are sufficiently compatible, it's probably okay for
|
/// However, we also need `caller_abi` to determine if we need to do untupling of arguments.
|
||||||
/// `Abi` to differ.
|
|
||||||
///
|
///
|
||||||
/// `with_caller_location` indicates whether the caller passed a caller location. Miri
|
/// `with_caller_location` indicates whether the caller passed a caller location. Miri
|
||||||
/// implements caller locations without argument passing, but to match `FnAbi` we need to know
|
/// implements caller locations without argument passing, but to match `FnAbi` we need to know
|
||||||
|
@ -299,40 +298,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
|
|
||||||
ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
|
|
||||||
// Even after lowering closures and generators away, the *callee* can still have this
|
|
||||||
// kind of type.
|
|
||||||
ty::Closure(..) => Abi::RustCall,
|
|
||||||
ty::Generator(..) => Abi::Rust,
|
|
||||||
_ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
|
|
||||||
};
|
|
||||||
|
|
||||||
// ABI check
|
|
||||||
let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
|
|
||||||
let normalize_abi = |abi| match abi {
|
|
||||||
Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
|
|
||||||
// These are all the same ABI, really.
|
|
||||||
{
|
|
||||||
Abi::Rust
|
|
||||||
}
|
|
||||||
abi => abi,
|
|
||||||
};
|
|
||||||
if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
|
|
||||||
throw_ub_format!(
|
|
||||||
"calling a function with ABI {} using caller ABI {}",
|
|
||||||
callee_abi.name(),
|
|
||||||
caller_abi.name()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
match instance.def {
|
match instance.def {
|
||||||
ty::InstanceDef::Intrinsic(..) => {
|
ty::InstanceDef::Intrinsic(..) => {
|
||||||
if M::enforce_abi(self) {
|
|
||||||
check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
|
|
||||||
}
|
|
||||||
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
|
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
|
||||||
// caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
|
// caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
|
||||||
M::call_intrinsic(self, instance, args, ret, unwind)
|
M::call_intrinsic(self, instance, args, ret, unwind)
|
||||||
|
@ -353,14 +320,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
|
|
||||||
// Compute callee information using the `instance` returned by
|
// Compute callee information using the `instance` returned by
|
||||||
// `find_mir_or_eval_fn`.
|
// `find_mir_or_eval_fn`.
|
||||||
let callee_abi = get_abi(self, instance.ty(*self.tcx, self.param_env));
|
|
||||||
// FIXME: for variadic support, do we have to somehow determine calle's extra_args?
|
// FIXME: for variadic support, do we have to somehow determine calle's extra_args?
|
||||||
let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
|
let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
|
||||||
assert!(!callee_fn_abi.c_variadic);
|
assert!(!callee_fn_abi.c_variadic);
|
||||||
assert!(!caller_fn_abi.c_variadic);
|
assert!(!caller_fn_abi.c_variadic);
|
||||||
|
|
||||||
if M::enforce_abi(self) {
|
if M::enforce_abi(self) {
|
||||||
check_abi(callee_abi)?;
|
if caller_fn_abi.conv != callee_fn_abi.conv {
|
||||||
|
throw_ub_format!(
|
||||||
|
"calling a function with calling convention {:?} using calling convention {:?}",
|
||||||
|
callee_fn_abi.conv,
|
||||||
|
caller_fn_abi.conv
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
|
if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
|
||||||
|
|
|
@ -9,7 +9,7 @@ const extern "C" fn c_fn() {}
|
||||||
const fn call_rust_fn(my_fn: extern "Rust" fn()) {
|
const fn call_rust_fn(my_fn: extern "Rust" fn()) {
|
||||||
my_fn();
|
my_fn();
|
||||||
//~^ ERROR could not evaluate static initializer
|
//~^ ERROR could not evaluate static initializer
|
||||||
//~| NOTE calling a function with ABI C using caller ABI Rust
|
//~| NOTE calling a function with calling convention C using calling convention Rust
|
||||||
//~| NOTE inside `call_rust_fn`
|
//~| NOTE inside `call_rust_fn`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ error[E0080]: could not evaluate static initializer
|
||||||
LL | my_fn();
|
LL | my_fn();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
| |
|
| |
|
||||||
| calling a function with ABI C using caller ABI Rust
|
| calling a function with calling convention C using calling convention Rust
|
||||||
| inside `call_rust_fn` at $DIR/abi-mismatch.rs:10:5
|
| inside `call_rust_fn` at $DIR/abi-mismatch.rs:10:5
|
||||||
...
|
...
|
||||||
LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) });
|
LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue