Auto merge of #118032 - RalfJung:char-u32, r=Mark-Simulacrum
guarantee that char and u32 are ABI-compatible In https://github.com/rust-lang/rust/pull/116894 we added a guarantee that `char` has the same alignment as `u32`, but there is still one axis where these types could differ: function call ABI. So let's nail that down as well: in a function signature, `char` and `u32` are completely equivalent. This is a new stable guarantee, so it will need t-lang approval.
This commit is contained in:
commit
e299752868
@ -384,10 +384,12 @@ fn layout_compat(
|
||||
}
|
||||
|
||||
// Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
|
||||
// `char` counts as `u32.`
|
||||
let int_ty = |ty: Ty<'tcx>| {
|
||||
Some(match ty.kind() {
|
||||
ty::Int(ity) => (Integer::from_int_ty(&self.tcx, *ity), /* signed */ true),
|
||||
ty::Uint(uty) => (Integer::from_uint_ty(&self.tcx, *uty), /* signed */ false),
|
||||
ty::Char => (Integer::I32, /* signed */ false),
|
||||
_ => return None,
|
||||
})
|
||||
};
|
||||
|
@ -330,7 +330,7 @@ mod prim_never {}
|
||||
/// the future ("reserved"); some will never be a character ("noncharacters"); and some may be given
|
||||
/// different meanings by different users ("private use").
|
||||
///
|
||||
/// `char` is guaranteed to have the same size and alignment as `u32` on all
|
||||
/// `char` is guaranteed to have the same size, alignment, and function call ABI as `u32` on all
|
||||
/// platforms.
|
||||
/// ```
|
||||
/// use std::alloc::Layout;
|
||||
@ -1557,6 +1557,7 @@ mod prim_ref {}
|
||||
/// Pointee>::Metadata`).
|
||||
/// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is
|
||||
/// ABI-compatible with the `iN` integer type of the same size.
|
||||
/// - `char` is ABI-compatible with `u32`.
|
||||
/// - Any two `fn` (function pointer) types are ABI-compatible with each other if they have the same
|
||||
/// ABI string or the ABI string only differs in a trailing `-unwind`, independent of the rest of
|
||||
/// their signature. (This means you can pass `fn()` to a function expecting `fn(i32)`, and the
|
||||
@ -1585,9 +1586,9 @@ mod prim_ref {}
|
||||
/// since it is not portable and not a stable guarantee.
|
||||
///
|
||||
/// Noteworthy cases of types *not* being ABI-compatible in general are:
|
||||
/// * `bool` vs `u8`, and `i32` vs `u32`: on some targets, the calling conventions for these types
|
||||
/// differ in terms of what they guarantee for the remaining bits in the register that are not
|
||||
/// used by the value.
|
||||
/// * `bool` vs `u8`, `i32` vs `u32`, `char` vs `i32`: on some targets, the calling conventions for
|
||||
/// these types differ in terms of what they guarantee for the remaining bits in the register that
|
||||
/// are not used by the value.
|
||||
/// * `i32` vs `f32` are not compatible either, as has already been mentioned above.
|
||||
/// * `struct Foo(u32)` and `u32` are not compatible (without `repr(transparent)`) since structs are
|
||||
/// aggregate types and often passed in a different way than primitives like `i32`.
|
||||
|
@ -71,6 +71,8 @@ fn main() {
|
||||
test_abi_compat(0isize, 0i64);
|
||||
}
|
||||
test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
|
||||
// - `char` and `u32`.
|
||||
test_abi_compat(42u32, 'x');
|
||||
// - Reference/pointer types with the same pointee.
|
||||
test_abi_compat(&0u32, &0u32 as *const u32);
|
||||
test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32));
|
||||
@ -81,7 +83,7 @@ fn main() {
|
||||
test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
|
||||
// - 1-ZST
|
||||
test_abi_compat((), [0u8; 0]);
|
||||
// - Guaranteed null-pointer-optimizations.
|
||||
// - Guaranteed null-pointer-optimizations (RFC 3391).
|
||||
test_abi_compat(&0u32 as *const u32, Some(&0u32));
|
||||
test_abi_compat(main as fn(), Some(main as fn()));
|
||||
test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
|
||||
@ -103,6 +105,8 @@ fn main() {
|
||||
test_abi_newtype::<Option<num::NonZeroU32>>();
|
||||
|
||||
// Extra test for assumptions made by arbitrary-self-dyn-receivers.
|
||||
// This is interesting since these types are not `repr(transparent)`. So this is not part of our
|
||||
// public ABI guarantees, but is relied on by the compiler.
|
||||
let rc = Rc::new(0);
|
||||
let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) };
|
||||
test_abi_compat(rc, rc_ptr);
|
||||
|
@ -263,6 +263,13 @@ mod $name {
|
||||
test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
|
||||
test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32);
|
||||
|
||||
// Compatibility of integer types.
|
||||
test_abi_compatible!(char_uint, char, u32);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
test_abi_compatible!(isize_int, isize, i32);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
test_abi_compatible!(isize_int, isize, i64);
|
||||
|
||||
// Compatibility of 1-ZST.
|
||||
test_abi_compatible!(zst_unit, Zst, ());
|
||||
#[cfg(not(any(target_arch = "sparc64")))]
|
||||
|
Loading…
Reference in New Issue
Block a user