Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

guarantee that char and u32 are ABI-compatible #118032

Merged
merged 1 commit into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

// 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,
})
};
Expand Down
9 changes: 5 additions & 4 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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`.
Expand Down
6 changes: 5 additions & 1 deletion src/tools/miri/tests/pass/function_calls/abi_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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()));
Expand All @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/abi/compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ test_abi_compatible!(box_ptr, Box<i32>, *const i32);
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")))]
Expand Down
Loading