Make fn_abi_sanity_check a bit stricter

The Rust ABI must ignore all ZST arguments, all ignored arguments must
be either ZST or uninhabited. And finally ScalarPair should never be
passed as PassMode::Direct.
This commit is contained in:
bjorn3 2024-11-07 15:54:40 +00:00
parent fe43131683
commit c8f0b15a2d

View File

@ -463,43 +463,64 @@ fn fn_arg_sanity_check<'tcx>(
arg: &ArgAbi<'tcx, Ty<'tcx>>, arg: &ArgAbi<'tcx, Ty<'tcx>>,
) { ) {
let tcx = cx.tcx(); let tcx = cx.tcx();
if spec_abi == ExternAbi::Rust
|| spec_abi == ExternAbi::RustCall
|| spec_abi == ExternAbi::RustCold
{
if arg.layout.is_zst() {
// Casting closures to function pointers depends on ZST closure types being
// omitted entirely in the calling convention.
assert!(arg.is_ignore());
}
if let PassMode::Indirect { on_stack, .. } = arg.mode {
assert!(!on_stack, "rust abi shouldn't use on_stack");
}
}
match &arg.mode { match &arg.mode {
PassMode::Ignore => {} PassMode::Ignore => {
assert!(arg.layout.is_zst() || arg.layout.is_uninhabited());
}
PassMode::Direct(_) => { PassMode::Direct(_) => {
// Here the Rust type is used to determine the actual ABI, so we have to be very // Here the Rust type is used to determine the actual ABI, so we have to be very
// careful. Scalar/ScalarPair is fine, since backends will generally use // careful. Scalar/Vector is fine, since backends will generally use
// `layout.abi` and ignore everything else. We should just reject `Aggregate` // `layout.backend_repr` and ignore everything else. We should just reject
// entirely here, but some targets need to be fixed first. //`Aggregate` entirely here, but some targets need to be fixed first.
if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { match arg.layout.backend_repr {
// For an unsized type we'd only pass the sized prefix, so there is no universe BackendRepr::Uninhabited
// in which we ever want to allow this. | BackendRepr::Scalar(_)
assert!( | BackendRepr::Vector { .. } => {}
arg.layout.is_sized(), BackendRepr::ScalarPair(..) => {
"`PassMode::Direct` for unsized type in ABI: {:#?}", panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty)
fn_abi }
); BackendRepr::Memory { sized } => {
// This really shouldn't happen even for sized aggregates, since // For an unsized type we'd only pass the sized prefix, so there is no universe
// `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an // in which we ever want to allow this.
// LLVM type. This means all sorts of Rust type details leak into the ABI. assert!(sized, "`PassMode::Direct` for unsized type in ABI: {:#?}", fn_abi);
// However wasm sadly *does* currently use this mode so we have to allow it -- // This really shouldn't happen even for sized aggregates, since
// but we absolutely shouldn't let any more targets do that. // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an
// (Also see <https://github.com/rust-lang/rust/issues/115666>.) // LLVM type. This means all sorts of Rust type details leak into the ABI.
// // However wasm sadly *does* currently use this mode so we have to allow it --
// The unstable abi `PtxKernel` also uses Direct for now. // but we absolutely shouldn't let any more targets do that.
// It needs to switch to something else before stabilization can happen. // (Also see <https://github.com/rust-lang/rust/issues/115666>.)
// (See issue: https://github.com/rust-lang/rust/issues/117271) //
assert!( // The unstable abi `PtxKernel` also uses Direct for now.
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") // It needs to switch to something else before stabilization can happen.
|| matches!(spec_abi, ExternAbi::PtxKernel | ExternAbi::Unadjusted), // (See issue: https://github.com/rust-lang/rust/issues/117271)
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\ assert!(
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64")
|| matches!(spec_abi, ExternAbi::PtxKernel | ExternAbi::Unadjusted),
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
Problematic type: {:#?}", Problematic type: {:#?}",
arg.layout, arg.layout,
); );
}
} }
} }
PassMode::Pair(_, _) => { PassMode::Pair(_, _) => {
// Similar to `Direct`, we need to make sure that backends use `layout.abi` and // Similar to `Direct`, we need to make sure that backends use `layout.backend_repr`
// ignore the rest of the layout. // and ignore the rest of the layout.
assert!( assert!(
matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)), matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)),
"PassMode::Pair for type {}", "PassMode::Pair for type {}",