summaryrefslogtreecommitdiffstats
path: root/tests/ui/abi
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/abi')
-rw-r--r--tests/ui/abi/compatibility.rs354
-rw-r--r--tests/ui/abi/debug.rs53
-rw-r--r--tests/ui/abi/debug.stderr959
-rw-r--r--tests/ui/abi/explicit_repr_rust.rs12
-rw-r--r--tests/ui/abi/relocation_model_pic.rs3
5 files changed, 1379 insertions, 2 deletions
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
new file mode 100644
index 000000000..1f049b178
--- /dev/null
+++ b/tests/ui/abi/compatibility.rs
@@ -0,0 +1,354 @@
+// check-pass
+// revisions: host
+// revisions: arm
+//[arm] compile-flags: --target arm-unknown-linux-gnueabi
+//[arm] needs-llvm-components: arm
+// revisions: aarch64
+//[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//[aarch64] needs-llvm-components: aarch64
+// revisions: s390x
+//[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//[s390x] needs-llvm-components: systemz
+// revisions: mips
+//[mips] compile-flags: --target mips-unknown-linux-gnu
+//[mips] needs-llvm-components: mips
+// revisions: mips64
+//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
+//[mips64] needs-llvm-components: mips
+// revisions: sparc
+//[sparc] compile-flags: --target sparc-unknown-linux-gnu
+//[sparc] needs-llvm-components: sparc
+// revisions: sparc64
+//[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//[sparc64] needs-llvm-components: sparc
+// revisions: powerpc64
+//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//[powerpc64] needs-llvm-components: powerpc
+// revisions: riscv
+//[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
+//[riscv] needs-llvm-components: riscv
+// revisions: loongarch64
+//[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//[loongarch64] needs-llvm-components: loongarch
+// revisions: wasm
+//[wasm] compile-flags: --target wasm32-unknown-unknown
+//[wasm] needs-llvm-components: webassembly
+// revisions: wasi
+//[wasi] compile-flags: --target wasm32-wasi
+//[wasi] needs-llvm-components: webassembly
+// revisions: nvptx64
+//[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
+//[nvptx64] needs-llvm-components: nvptx
+#![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)]
+
+// 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 {
+ use super::*;
+ // Declaring a `type` doesn't even check well-formedness, so we also declare a function.
+ fn check_wf(_x: $t1, _y: $t2) {}
+ // Test argument and return value, `Rust` and `C` ABIs.
+ #[rustc_abi(assert_eq)]
+ type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2);
+ #[rustc_abi(assert_eq)]
+ type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2);
+ }
+ };
+}
+
+struct Zst;
+impl Copy for Zst {}
+impl Clone for Zst {
+ fn clone(&self) -> Self {
+ Zst
+ }
+}
+
+#[repr(C)]
+struct ReprC1<T: ?Sized>(T);
+#[repr(C)]
+struct ReprC2Int<T>(i32, T);
+#[repr(C)]
+struct ReprC2Float<T>(f32, T);
+#[repr(C)]
+struct ReprC4<T>(T, Vec<i32>, Zst, T);
+#[repr(C)]
+struct ReprC4Mixed<T>(T, f32, i32, T);
+#[repr(C)]
+enum ReprCEnum<T> {
+ Variant1,
+ Variant2(T),
+}
+#[repr(C)]
+union ReprCUnion<T> {
+ nothing: (),
+ something: ManuallyDrop<T>,
+}
+
+macro_rules! test_abi_compatible {
+ ($name:ident, $t1:ty, $t2:ty) => {
+ mod $name {
+ use super::*;
+ assert_abi_compatible!(plain, $t1, $t2);
+ // We also do some tests with differences in fields of `repr(C)` types.
+ assert_abi_compatible!(repr_c_1, ReprC1<$t1>, ReprC1<$t2>);
+ assert_abi_compatible!(repr_c_2_int, ReprC2Int<$t1>, ReprC2Int<$t2>);
+ assert_abi_compatible!(repr_c_2_float, ReprC2Float<$t1>, ReprC2Float<$t2>);
+ assert_abi_compatible!(repr_c_4, ReprC4<$t1>, ReprC4<$t2>);
+ assert_abi_compatible!(repr_c_4mixed, ReprC4Mixed<$t1>, ReprC4Mixed<$t2>);
+ assert_abi_compatible!(repr_c_enum, ReprCEnum<$t1>, ReprCEnum<$t2>);
+ assert_abi_compatible!(repr_c_union, ReprCUnion<$t1>, ReprCUnion<$t2>);
+ }
+ };
+}
+
+// Compatibility of pointers is probably de-facto guaranteed,
+// but that does not seem to be documented.
+test_abi_compatible!(ptr_mut, *const i32, *mut i32);
+test_abi_compatible!(ptr_pointee, *const i32, *const Vec<i32>);
+test_abi_compatible!(ref_mut, &i32, &mut i32);
+test_abi_compatible!(ref_ptr, &i32, *const i32);
+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);
+
+// Some further guarantees we will likely (have to) make.
+test_abi_compatible!(zst_unit, Zst, ());
+#[cfg(not(any(target_arch = "sparc64")))]
+test_abi_compatible!(zst_array, Zst, [u8; 0]);
+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, Rc<i32>, *mut i32);
+test_abi_compatible!(arc, Arc<i32>, *mut i32);
+
+// `repr(transparent)` compatibility.
+#[repr(transparent)]
+struct Wrapper1<T: ?Sized>(T);
+#[repr(transparent)]
+struct Wrapper2<T: ?Sized>((), Zst, T);
+#[repr(transparent)]
+struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
+#[repr(transparent)]
+union WrapperUnion<T> {
+ nothing: (),
+ something: ManuallyDrop<T>,
+}
+
+macro_rules! test_transparent {
+ ($name:ident, $t:ty) => {
+ mod $name {
+ use super::*;
+ test_abi_compatible!(wrap1, $t, Wrapper1<$t>);
+ test_abi_compatible!(wrap2, $t, Wrapper2<$t>);
+ test_abi_compatible!(wrap3, $t, Wrapper3<$t>);
+ test_abi_compatible!(wrap4, $t, WrapperUnion<$t>);
+ }
+ };
+}
+
+test_transparent!(simple, i32);
+test_transparent!(reference, &'static i32);
+test_transparent!(zst, Zst);
+test_transparent!(unit, ());
+test_transparent!(enum_, Option<i32>);
+test_transparent!(enum_niched, Option<&'static i32>);
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod tuples {
+ use super::*;
+ // mixing in some floats since they often get special treatment
+ test_transparent!(pair, (i32, f32));
+ // chosen to fit into 64bit
+ test_transparent!(triple, (i8, i16, f32));
+ // Pure-float types that are not ScalarPair seem to be tricky.
+ test_transparent!(triple_f32, (f32, f32, f32));
+ test_transparent!(triple_f64, (f64, f64, f64));
+ // and also something that's larger than 2 pointers
+ test_transparent!(tuple, (i32, f32, i64, f64));
+}
+// Some targets have special rules for arrays.
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod arrays {
+ use super::*;
+ test_transparent!(empty_array, [u32; 0]);
+ test_transparent!(empty_1zst_array, [u8; 0]);
+ test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
+ test_transparent!(large_array, [i32; 16]);
+}
+
+// Some tests with unsized types (not all wrappers are compatible with that).
+macro_rules! test_transparent_unsized {
+ ($name:ident, $t:ty) => {
+ mod $name {
+ use super::*;
+ assert_abi_compatible!(wrap1, $t, Wrapper1<$t>);
+ assert_abi_compatible!(wrap1_reprc, ReprC1<$t>, ReprC1<Wrapper1<$t>>);
+ assert_abi_compatible!(wrap2, $t, Wrapper2<$t>);
+ assert_abi_compatible!(wrap2_reprc, ReprC1<$t>, ReprC1<Wrapper2<$t>>);
+ }
+ };
+}
+
+#[cfg(not(any(target_arch = "mips64", target_arch = "sparc64")))]
+mod unsized_ {
+ use super::*;
+ test_transparent_unsized!(str_, str);
+ test_transparent_unsized!(slice, [u8]);
+ test_transparent_unsized!(dyn_trait, dyn Any);
+}
+
+// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
+macro_rules! test_nonnull {
+ ($name:ident, $t:ty) => {
+ mod $name {
+ use super::*;
+ test_abi_compatible!(option, Option<$t>, $t);
+ test_abi_compatible!(result_err_unit, Result<$t, ()>, $t);
+ test_abi_compatible!(result_ok_unit, Result<(), $t>, $t);
+ test_abi_compatible!(result_err_zst, Result<$t, Zst>, $t);
+ test_abi_compatible!(result_ok_zst, Result<Zst, $t>, $t);
+ test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t);
+ test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t);
+ }
+ }
+}
+
+test_nonnull!(ref_, &i32);
+test_nonnull!(mut_, &mut i32);
+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 Any>);
+test_nonnull!(non_zero, NonZeroI32);
+
+fn main() {}
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
new file mode 100644
index 000000000..77715ee40
--- /dev/null
+++ b/tests/ui/abi/debug.rs
@@ -0,0 +1,53 @@
+// normalize-stderr-test "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
+// normalize-stderr-test "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
+// normalize-stderr-test "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL"
+// normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
+// This pattern is prepared for when we account for alignment in the niche.
+// normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL"
+// Some attributes are only computed for release builds:
+// compile-flags: -O
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+
+struct S(u16);
+
+#[rustc_abi(debug)]
+fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi
+
+#[rustc_abi(debug)]
+type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi
+
+#[rustc_abi(debug)]
+fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi
+
+#[rustc_abi(debug)]
+const C: () = (); //~ ERROR: can only be applied to
+
+impl S {
+ #[rustc_abi(debug)]
+ const C: () = (); //~ ERROR: can only be applied to
+}
+
+impl S {
+ #[rustc_abi(debug)]
+ fn assoc_test(&self) { } //~ ERROR: fn_abi
+}
+
+#[rustc_abi(assert_eq)]
+type TestAbiEq = (fn(bool), fn(bool));
+
+#[rustc_abi(assert_eq)]
+type TestAbiNe = (fn(u8), fn(u32)); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiNeFloat = (fn(f32), fn(u32)); //~ ERROR: ABIs are not compatible
+
+// Sign matters on some targets (such as s390x), so let's make sure we never accept this.
+#[rustc_abi(assert_eq)]
+type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible
+
+#[rustc_abi(assert_eq)]
+type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
new file mode 100644
index 000000000..00fc7d1ec
--- /dev/null
+++ b/tests/ui/abi/debug.stderr
@@ -0,0 +1,959 @@
+error: fn_abi_of(test) = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: u8,
+ layout: Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: bool,
+ layout: Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: Zext,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:15:1
+ |
+LL | fn test(_x: u8) -> bool { true }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: fn_abi_of(TestFnPtr) = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: bool,
+ layout: Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: Zext,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: u8,
+ layout: Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:18:1
+ |
+LL | type TestFnPtr = fn(bool) -> u8;
+ | ^^^^^^^^^^^^^^
+
+error: fn_abi_of(test_generic) = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: *const T,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Pointer(
+ AddressSpace(
+ 0,
+ ),
+ ),
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:21:1
+ |
+LL | fn test_generic<T>(_x: *const T) { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+ --> $DIR/debug.rs:24:1
+ |
+LL | const C: () = ();
+ | ^^^^^^^^^^^
+
+error: ABIs are not compatible
+ left ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: u8,
+ layout: Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ right ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: u32,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:40:1
+ |
+LL | type TestAbiNe = (fn(u8), fn(u32));
+ | ^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+ left ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: [u8; 32],
+ layout: Layout {
+ size: Size(32 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Array {
+ stride: Size(1 bytes),
+ count: 32,
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Indirect {
+ attrs: ArgAttributes {
+ regular: NoAlias | NoCapture | NonNull | NoUndef,
+ arg_ext: None,
+ pointee_size: Size(32 bytes),
+ pointee_align: Some(
+ Align(1 bytes),
+ ),
+ },
+ meta_attrs: None,
+ on_stack: false,
+ },
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ right ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: [u32; 32],
+ layout: Layout {
+ size: Size(128 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Array {
+ stride: Size(4 bytes),
+ count: 32,
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Indirect {
+ attrs: ArgAttributes {
+ regular: NoAlias | NoCapture | NonNull | NoUndef,
+ arg_ext: None,
+ pointee_size: Size(128 bytes),
+ pointee_align: Some(
+ Align(4 bytes),
+ ),
+ },
+ meta_attrs: None,
+ on_stack: false,
+ },
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:43:1
+ |
+LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+ left ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: f32,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: F32,
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ right ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: u32,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:46:1
+ |
+LL | type TestAbiNeFloat = (fn(f32), fn(u32));
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: ABIs are not compatible
+ left ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: i32,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ right ABI = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: u32,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: $FULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoUndef,
+ arg_ext: None,
+ pointee_size: Size(0 bytes),
+ pointee_align: None,
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:50:1
+ |
+LL | type TestAbiNeSign = (fn(i32), fn(u32));
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/debug.rs:53:46
+ |
+LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
+ | ^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
+ --> $DIR/debug.rs:28:5
+ |
+LL | const C: () = ();
+ | ^^^^^^^^^^^
+
+error: fn_abi_of(assoc_test) = FnAbi {
+ args: [
+ ArgAbi {
+ layout: TyAndLayout {
+ ty: &S,
+ layout: Layout {
+ size: $SOME_SIZE,
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Pointer(
+ AddressSpace(
+ 0,
+ ),
+ ),
+ valid_range: $NON_NULL,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Pointer(
+ AddressSpace(
+ 0,
+ ),
+ ),
+ valid_range: $NON_NULL,
+ },
+ ),
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Direct(
+ ArgAttributes {
+ regular: NoAlias | NonNull | ReadOnly | NoUndef,
+ arg_ext: None,
+ pointee_size: Size(2 bytes),
+ pointee_align: Some(
+ Align(2 bytes),
+ ),
+ },
+ ),
+ },
+ ],
+ ret: ArgAbi {
+ layout: TyAndLayout {
+ ty: (),
+ layout: Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: $SOME_ALIGN,
+ pref: $SOME_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: $SOME_ALIGN,
+ },
+ },
+ mode: Ignore,
+ },
+ c_variadic: false,
+ fixed_count: 1,
+ conv: Rust,
+ can_unwind: $SOME_BOOL,
+ }
+ --> $DIR/debug.rs:33:5
+ |
+LL | fn assoc_test(&self) { }
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/abi/explicit_repr_rust.rs b/tests/ui/abi/explicit_repr_rust.rs
new file mode 100644
index 000000000..4f8cab3bf
--- /dev/null
+++ b/tests/ui/abi/explicit_repr_rust.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#[repr(Rust)]
+struct A;
+
+#[repr(Rust, align(16))]
+struct B;
+
+#[repr(Rust, packed)]
+struct C;
+
+fn main() {}
diff --git a/tests/ui/abi/relocation_model_pic.rs b/tests/ui/abi/relocation_model_pic.rs
index 0cfc44cd0..cca2e8db7 100644
--- a/tests/ui/abi/relocation_model_pic.rs
+++ b/tests/ui/abi/relocation_model_pic.rs
@@ -1,7 +1,6 @@
// run-pass
// compile-flags: -C relocation-model=pic
-// ignore-emscripten no pic
-// ignore-wasm
+// needs-relocation-model-pic
#![feature(cfg_relocation_model)]