Move the callee "can unwind" check to the right place
This commit is contained in:
parent
7b3e10c751
commit
da0abad492
2 changed files with 37 additions and 38 deletions
|
@ -819,19 +819,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
StackPopCleanup::Goto { ret, unwind } => (
|
StackPopCleanup::Goto { ret, unwind } => (
|
||||||
true,
|
true,
|
||||||
Some(if unwinding {
|
Some(if unwinding {
|
||||||
let def_id = frame.body.source.def_id();
|
|
||||||
match unwind {
|
match unwind {
|
||||||
StackPopUnwind::Cleanup(unwind)
|
StackPopUnwind::Cleanup(unwind) => unwind,
|
||||||
// `fn_sig()` can't be used on closures, but closures always have
|
StackPopUnwind::NotAllowed => {
|
||||||
// "rust-call" ABI, which always allows unwinding anyway.
|
|
||||||
if self.tcx.is_closure(def_id) || self.fn_can_unwind(
|
|
||||||
self.tcx.codegen_fn_attrs(def_id).flags,
|
|
||||||
self.tcx.fn_sig(def_id).abi(),
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
unwind
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
throw_ub_format!("unwind past a frame that does not allow unwinding")
|
throw_ub_format!("unwind past a frame that does not allow unwinding")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
pub(super) fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
|
fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
|
||||||
layout::fn_can_unwind(
|
layout::fn_can_unwind(
|
||||||
self.tcx.sess.panic_strategy(),
|
self.tcx.sess.panic_strategy(),
|
||||||
attrs,
|
attrs,
|
||||||
|
@ -247,37 +247,38 @@ 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(),
|
||||||
|
ty::Closure(..) => Abi::RustCall,
|
||||||
|
ty::Generator(..) => Abi::Rust,
|
||||||
|
_ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
|
||||||
|
};
|
||||||
|
|
||||||
// ABI check
|
// ABI check
|
||||||
let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
|
let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
|
||||||
if M::enforce_abi(this) {
|
let normalize_abi = |abi| match abi {
|
||||||
let callee_abi = match instance_ty.kind() {
|
Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
|
||||||
ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
|
// These are all the same ABI, really.
|
||||||
ty::Closure(..) => Abi::RustCall,
|
{
|
||||||
ty::Generator(..) => Abi::Rust,
|
Abi::Rust
|
||||||
_ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
|
|
||||||
};
|
|
||||||
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()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
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(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
match instance.def {
|
match instance.def {
|
||||||
ty::InstanceDef::Intrinsic(..) => {
|
ty::InstanceDef::Intrinsic(..) => {
|
||||||
check_abi(self, instance.ty(*self.tcx, self.param_env))?;
|
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);
|
||||||
M::call_intrinsic(self, instance, args, ret, unwind)
|
M::call_intrinsic(self, instance, args, ret, unwind)
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
|
// Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
|
||||||
// these can differ when `find_mir_or_eval_fn` does something clever like resolve
|
// these can differ when `find_mir_or_eval_fn` does something clever like resolve
|
||||||
// exported symbol names).
|
// exported symbol names).
|
||||||
check_abi(self, self.tcx.type_of(body.source.def_id()))?;
|
let callee_def_id = body.source.def_id();
|
||||||
|
let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
|
||||||
|
|
||||||
|
if M::enforce_abi(self) {
|
||||||
|
check_abi(callee_abi)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let callee_can_unwind =
|
||||||
|
self.fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi);
|
||||||
|
|
||||||
self.push_stack_frame(
|
self.push_stack_frame(
|
||||||
instance,
|
instance,
|
||||||
|
@ -306,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
ret.map(|p| p.0),
|
ret.map(|p| p.0),
|
||||||
StackPopCleanup::Goto {
|
StackPopCleanup::Goto {
|
||||||
ret: ret.map(|p| p.1),
|
ret: ret.map(|p| p.1),
|
||||||
unwind: if can_unwind {
|
unwind: if can_unwind && callee_can_unwind {
|
||||||
StackPopUnwind::Cleanup(unwind)
|
StackPopUnwind::Cleanup(unwind)
|
||||||
} else {
|
} else {
|
||||||
StackPopUnwind::NotAllowed
|
StackPopUnwind::NotAllowed
|
||||||
|
|
Loading…
Add table
Reference in a new issue