Skip to content

Commit

Permalink
run abi/compatibility test against a whole bunch of targets
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Sep 21, 2023
1 parent e4a361a commit 797d593
Showing 1 changed file with 158 additions and 10 deletions.
168 changes: 158 additions & 10 deletions tests/ui/abi/compatibility.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,159 @@
// check-pass
// revisions: host
// revisions: arm
//[arm] compile-flags: --target arm-unknown-linux-gnueabi
// revisions: aarch64
//[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
// revisions: s390x
//[s390x] compile-flags: --target s390x-unknown-linux-gnu
// revisions: mips
//[mips] compile-flags: --target mips-unknown-linux-gnu
// revisions: mips64
//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
// revisions: sparc
//[sparc] compile-flags: --target sparc-unknown-linux-gnu
// revisions: sparc64
//[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
// revisions: powerpc64
//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
// revisions: riscv
//[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
// revisions: loongarch64
//[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
// revisions: wasm
//[wasm] compile-flags: --target wasm32-unknown-unknown
// revisions: nvptx64
//[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
#![feature(rustc_attrs, unsized_fn_params, transparent_unions)]
#![cfg_attr(not(host), feature(no_core, lang_items), no_std, no_core)]
#![allow(unused, improper_ctypes_definitions, internal_features)]
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::num::NonZeroI32;
use std::ptr::NonNull;

// FIXME: a bunch of targets are broken in various ways.
// FIXME: some targets are broken in various ways.
// Hence there are `cfg` throughout this test to disable parts of it on those targets.
// sparc64: https://github.com/rust-lang/rust/issues/115336
// mips64: https://github.com/rust-lang/rust/issues/115404

#[cfg(host)]
use std::{
any::Any, marker::PhantomData, mem::ManuallyDrop, num::NonZeroI32, ptr::NonNull, rc::Rc,
sync::Arc,
};

/// To work cross-target this test must be no_core.
/// This little prelude supplies what we need.
#[cfg(not(host))]
mod prelude {
#[lang = "sized"]
pub trait Sized {}

#[lang = "receiver"]
pub trait Receiver {}
impl<T: ?Sized> Receiver for &T {}
impl<T: ?Sized> Receiver for &mut T {}

#[lang = "copy"]
pub trait Copy: Sized {}
impl Copy for i32 {}
impl Copy for f32 {}
impl<T: ?Sized> Copy for &T {}
impl<T: ?Sized> Copy for *const T {}
impl<T: ?Sized> Copy for *mut T {}

#[lang = "clone"]
pub trait Clone: Sized {
fn clone(&self) -> Self;
}

#[lang = "phantom_data"]
pub struct PhantomData<T: ?Sized>;
impl<T: ?Sized> Copy for PhantomData<T> {}

#[lang = "unsafe_cell"]
#[repr(transparent)]
pub struct UnsafeCell<T: ?Sized> {
value: T,
}

pub trait Any: 'static {}

pub enum Option<T> {
None,
Some(T),
}
impl<T: Copy> Copy for Option<T> {}

pub enum Result<T, E> {
Ok(T),
Err(E),
}
impl<T: Copy, E: Copy> Copy for Result<T, E> {}

#[lang = "manually_drop"]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
value: T,
}
impl<T: Copy + ?Sized> Copy for ManuallyDrop<T> {}

#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonNull<T: ?Sized> {
pointer: *const T,
}
impl<T: ?Sized> Copy for NonNull<T> {}

#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonZeroI32(i32);

// This just stands in for a non-trivial type.
pub struct Vec<T> {
ptr: NonNull<T>,
cap: usize,
len: usize,
}

pub struct Unique<T: ?Sized> {
pub pointer: NonNull<T>,
pub _marker: PhantomData<T>,
}

pub struct Global;

#[lang = "owned_box"]
pub struct Box<T: ?Sized, A = Global>(Unique<T>, A);

#[repr(C)]
struct RcBox<T: ?Sized> {
strong: UnsafeCell<usize>,
weak: UnsafeCell<usize>,
value: T,
}
pub struct Rc<T: ?Sized, A = Global> {
ptr: NonNull<RcBox<T>>,
phantom: PhantomData<RcBox<T>>,
alloc: A,
}

#[repr(C, align(8))]
struct AtomicUsize(usize);
#[repr(C)]
struct ArcInner<T: ?Sized> {
strong: AtomicUsize,
weak: AtomicUsize,
data: T,
}
pub struct Arc<T: ?Sized, A = Global> {
ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<ArcInner<T>>,
alloc: A,
}
}
#[cfg(not(host))]
use prelude::*;

macro_rules! assert_abi_compatible {
($name:ident, $t1:ty, $t2:ty) => {
mod $name {
Expand All @@ -26,8 +169,13 @@ macro_rules! assert_abi_compatible {
};
}

#[derive(Copy, Clone)]
struct Zst;
impl Copy for Zst {}
impl Clone for Zst {
fn clone(&self) -> Self {
Zst
}
}

#[repr(C)]
struct ReprC1<T: ?Sized>(T);
Expand Down Expand Up @@ -85,8 +233,8 @@ test_abi_compatible!(nonzero_int, NonZeroI32, i32);

// `DispatchFromDyn` relies on ABI compatibility.
// This is interesting since these types are not `repr(transparent)`.
test_abi_compatible!(rc, std::rc::Rc<i32>, *mut i32);
test_abi_compatible!(arc, std::sync::Arc<i32>, *mut i32);
test_abi_compatible!(rc, Rc<i32>, *mut i32);
test_abi_compatible!(arc, Arc<i32>, *mut i32);

// `repr(transparent)` compatibility.
#[repr(transparent)]
Expand Down Expand Up @@ -160,7 +308,7 @@ mod unsized_ {
use super::*;
test_transparent_unsized!(str_, str);
test_transparent_unsized!(slice, [u8]);
test_transparent_unsized!(dyn_trait, dyn std::any::Any);
test_transparent_unsized!(dyn_trait, dyn Any);
}

// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
Expand All @@ -185,7 +333,7 @@ test_nonnull!(ref_unsized, &[i32]);
test_nonnull!(mut_unsized, &mut [i32]);
test_nonnull!(fn_, fn());
test_nonnull!(nonnull, NonNull<i32>);
test_nonnull!(nonnull_unsized, NonNull<dyn std::fmt::Debug>);
test_nonnull!(nonnull_unsized, NonNull<dyn Any>);
test_nonnull!(non_zero, NonZeroI32);

fn main() {}

0 comments on commit 797d593

Please sign in to comment.