diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 48c0c830325c4..7bb62c843d637 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2460,16 +2460,34 @@ impl LayoutData { /// aggregates are passed via `PassMode::Indirect`, `PassMode::IndirectUnsized` or /// `PassMode::Cast`; more strict checks would otherwise be required. pub fn eq_abi(&self, other: &Self) -> bool { + let LayoutData { + size, + align, + backend_repr, + // We assume aggregates are passed via `Cast` or `Indirect*` so their details either + // do not matter or they are checked by `PassMode::eq_abi`. + fields: _, + variants: _, + // Inhabitedness and niches are not ABI-relevant. + largest_niche: _, + uninhabited: _, + // max_repr_align, unadjusted_abi_align, repr_c are not read directly by codegen + // backends. They are only used to compute `PassMode`. So we can ignore them here, any + // differences they may cause are picked up by the `PassMode` check. + max_repr_align: _, + unadjusted_abi_align: _, + repr_c: _, + // The seed does not affect the ABI. + randomization_seed: _, + } = self; // The one thing that we are not capturing here is that for unsized types, the metadata must // also have the same ABI, and moreover that the same metadata leads to the same size. The // 2nd point is quite hard to check though. - self.size == other.size - && self.is_sized() == other.is_sized() - && self.backend_repr.eq_up_to_validity(&other.backend_repr) - && self.backend_repr.is_bool() == other.backend_repr.is_bool() - && self.align.abi == other.align.abi - && self.max_repr_align == other.max_repr_align - && self.unadjusted_abi_align == other.unadjusted_abi_align + *size == other.size + && *align == other.align + && backend_repr.eq_up_to_validity(&other.backend_repr) + // `is_bool` checks validity and is ABI-relevant, so we need to consider it. + && backend_repr.is_bool() == other.backend_repr.is_bool() } } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 27239ce58a9ea..4627d4cba28f5 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -389,7 +389,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if self.layout_compat(caller_abi.layout, callee_abi.layout)? { // Ensure that our checks imply actual ABI compatibility for this concrete call. // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.) - assert!(caller_abi.eq_abi(callee_abi)); + assert!( + caller_abi.eq_abi(callee_abi), + "these types were deemed ABI-compatible but do not actually have compatible `FnAbi`:\ncaller: {caller_abi:#?}\ncallee: {callee_abi:#?}" + ); interp_ok(true) } else { trace!( diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index bb9dd84962060..635f4e5b0e226 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -613,21 +613,9 @@ impl<'a, Ty> ArgAbi<'a, Ty> { where Ty: PartialEq, { - // Ideally we'd just compare the `mode`, but that is not enough -- for some modes LLVM will look - // at the type. - self.layout.eq_abi(&other.layout) && self.mode.eq_abi(&other.mode) && { - // `fn_arg_sanity_check` accepts `PassMode::Direct` for some aggregates. - // That elevates any type difference to an ABI difference since we just use the - // full Rust type as the LLVM argument/return type. - if matches!(self.mode, PassMode::Direct(..)) - && matches!(self.layout.backend_repr, BackendRepr::Memory { .. }) - { - // For aggregates in `Direct` mode to be compatible, the types need to be equal. - self.layout.ty == other.layout.ty - } else { - true - } - } + // Ideally we'd just compare the `mode`, but that is not enough -- for some modes LLVM will + // look at the type. + self.layout.eq_abi(&other.layout) && self.mode.eq_abi(&other.mode) } } diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index e78c49457280f..a763c300cc1a6 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -6,6 +6,14 @@ use std::{mem, num, ptr}; #[derive(Copy, Clone, Default)] struct Zst; +#[derive(Copy, Clone, Default)] +#[repr(align(1))] +struct ReprAlignZst; + +#[derive(Copy, Clone, Default)] +#[repr(C)] +struct ReprCZst; + #[repr(transparent)] #[derive(Copy, Clone)] struct Wrapper(T); @@ -124,6 +132,8 @@ fn main() { test_abi_compat(main as fn(), id:: as fn(i32) -> i32); // - trivial-ABI types test_abi_compat((), [(); 0]); + test_abi_compat((), Zst); + test_abi_compat((), ReprAlignZst); // Guaranteed null-pointer-layout optimizations: // - Guaranteed Option null-pointer-optimizations (RFC 3391). @@ -157,6 +167,8 @@ fn main() { // with the wrapped field. test_abi_newtype::<()>(); test_abi_newtype::(); + test_abi_newtype::(); + test_abi_newtype::(); test_abi_newtype::(); test_abi_newtype::(); test_abi_newtype::<(u8, u16, f32)>(); @@ -179,5 +191,6 @@ fn main() { let non_capturing_closure = || {}; test_abi_compat(non_capturing_closure.clone(), Wrapper(non_capturing_closure)); + // Check that we take the CFI tag into account. test_abi_cfi_encoding(); }