guarantee that char and u32 are ABI-compatible
This commit is contained in:
parent
e6dade96f4
commit
b4f3f2aeac
@ -384,10 +384,12 @@ fn layout_compat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
|
// Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
|
||||||
|
// `char` counts as `u32.`
|
||||||
let int_ty = |ty: Ty<'tcx>| {
|
let int_ty = |ty: Ty<'tcx>| {
|
||||||
Some(match ty.kind() {
|
Some(match ty.kind() {
|
||||||
ty::Int(ity) => (Integer::from_int_ty(&self.tcx, *ity), /* signed */ true),
|
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::Uint(uty) => (Integer::from_uint_ty(&self.tcx, *uty), /* signed */ false),
|
||||||
|
ty::Char => (Integer::I32, /* signed */ false),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -330,7 +330,7 @@ mod prim_never {}
|
|||||||
/// the future ("reserved"); some will never be a character ("noncharacters"); and some may be given
|
/// the future ("reserved"); some will never be a character ("noncharacters"); and some may be given
|
||||||
/// different meanings by different users ("private use").
|
/// 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.
|
/// platforms.
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::alloc::Layout;
|
/// use std::alloc::Layout;
|
||||||
@ -1557,6 +1557,7 @@ mod prim_ref {}
|
|||||||
/// Pointee>::Metadata`).
|
/// Pointee>::Metadata`).
|
||||||
/// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is
|
/// - `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.
|
/// 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
|
/// - 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
|
/// 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
|
/// 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.
|
/// since it is not portable and not a stable guarantee.
|
||||||
///
|
///
|
||||||
/// Noteworthy cases of types *not* being ABI-compatible in general are:
|
/// 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
|
/// * `bool` vs `u8`, `i32` vs `u32`, `char` vs `i32`: on some targets, the calling conventions for
|
||||||
/// differ in terms of what they guarantee for the remaining bits in the register that are not
|
/// these types differ in terms of what they guarantee for the remaining bits in the register that
|
||||||
/// used by the value.
|
/// are not used by the value.
|
||||||
/// * `i32` vs `f32` are not compatible either, as has already been mentioned above.
|
/// * `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
|
/// * `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`.
|
/// 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(0isize, 0i64);
|
||||||
}
|
}
|
||||||
test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
|
test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
|
||||||
|
// - `char` and `u32`.
|
||||||
|
test_abi_compat(42u32, 'x');
|
||||||
// - Reference/pointer types with the same pointee.
|
// - Reference/pointer types with the same pointee.
|
||||||
test_abi_compat(&0u32, &0u32 as *const u32);
|
test_abi_compat(&0u32, &0u32 as *const u32);
|
||||||
test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32));
|
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);
|
test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
|
||||||
// - 1-ZST
|
// - 1-ZST
|
||||||
test_abi_compat((), [0u8; 0]);
|
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(&0u32 as *const u32, Some(&0u32));
|
||||||
test_abi_compat(main as fn(), Some(main as fn()));
|
test_abi_compat(main as fn(), Some(main as fn()));
|
||||||
test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
|
test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
|
||||||
@ -103,6 +105,8 @@ fn main() {
|
|||||||
test_abi_newtype::<Option<num::NonZeroU32>>();
|
test_abi_newtype::<Option<num::NonZeroU32>>();
|
||||||
|
|
||||||
// Extra test for assumptions made by arbitrary-self-dyn-receivers.
|
// 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 = Rc::new(0);
|
||||||
let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) };
|
let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) };
|
||||||
test_abi_compat(rc, rc_ptr);
|
test_abi_compat(rc, rc_ptr);
|
||||||
|
@ -240,6 +240,13 @@ mod $name {
|
|||||||
test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
|
test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
|
||||||
test_abi_compatible!(fn_fn, fn(), fn(i32) -> 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.
|
// Compatibility of 1-ZST.
|
||||||
test_abi_compatible!(zst_unit, Zst, ());
|
test_abi_compatible!(zst_unit, Zst, ());
|
||||||
#[cfg(not(any(target_arch = "sparc64")))]
|
#[cfg(not(any(target_arch = "sparc64")))]
|
||||||
|
Loading…
Reference in New Issue
Block a user