rust/tests/codegen/repr/transparent.rs
Jubilee Young 20ebbf467d Replace ignore-everything with only-arch
Combining revisions with only-arch allows specifying
that a test only applies to a handful of targets.
This allows removing a large amount of repetition
in the test suite for tests that do not benefit.
The revisions are suboptimal for this for some tests,
so they aren't preferred in those cases.
2023-07-29 15:49:07 -07:00

175 lines
5.4 KiB
Rust

// compile-flags: -O -C no-prepopulate-passes
// ignore-riscv64 riscv64 has an i128 type used with test_Vector
// ignore-s390x s390x with default march passes vector types per reference
// ignore-loongarch64 see codegen/loongarch-abi for loongarch function call tests
// This codegen test embeds assumptions about how certain "C" psABIs are handled
// so it doesn't apply to all architectures or even all OS
// For RISCV: see codegen/riscv-abi
// For LoongArch: see codegen/loongarch-abi
#![crate_type="lib"]
#![feature(repr_simd, transparent_unions)]
use std::marker::PhantomData;
#[derive(Copy, Clone)]
pub struct Zst1;
#[derive(Copy, Clone)]
pub struct Zst2(());
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct F32(f32);
// CHECK: define{{.*}}float @test_F32(float noundef %_1)
#[no_mangle]
pub extern "C" fn test_F32(_: F32) -> F32 { loop {} }
#[repr(transparent)]
pub struct Ptr(*mut u8);
// CHECK: define{{.*}}ptr @test_Ptr(ptr noundef %_1)
#[no_mangle]
pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { loop {} }
#[repr(transparent)]
pub struct WithZst(u64, Zst1);
// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1)
#[no_mangle]
pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
#[repr(transparent)]
pub struct WithZeroSizedArray(*const f32, [i8; 0]);
// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
// CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1)
#[no_mangle]
pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
#[repr(transparent)]
pub struct Generic<T>(T);
// CHECK: define{{.*}}double @test_Generic(double noundef %_1)
#[no_mangle]
pub extern "C" fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
#[repr(transparent)]
pub struct GenericPlusZst<T>(T, Zst2);
#[repr(u8)]
pub enum Bool { True, False, FileNotFound }
// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
#[no_mangle]
pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }
#[repr(transparent)]
pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
// CHECK: define{{.*}}ptr @test_LifetimePhantom(ptr noundef %_1)
#[no_mangle]
pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
// This works despite current alignment resrictions because PhantomData is always align(1)
#[repr(transparent)]
pub struct UnitPhantom<T, U> { val: T, unit: PhantomData<U> }
pub struct Px;
// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1)
#[no_mangle]
pub extern "C" fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
#[repr(transparent)]
pub struct TwoZsts(Zst1, i8, Zst2);
// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1)
#[no_mangle]
pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
#[repr(transparent)]
pub struct Nested1(Zst2, Generic<f64>);
// CHECK: define{{.*}}double @test_Nested1(double noundef %_1)
#[no_mangle]
pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
#[repr(transparent)]
pub struct Nested2(Nested1, Zst1);
// CHECK: define{{.*}}double @test_Nested2(double noundef %_1)
#[no_mangle]
pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
#[repr(simd)]
struct f32x4(f32, f32, f32, f32);
#[repr(transparent)]
pub struct Vector(f32x4);
// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
#[no_mangle]
pub extern "C" fn test_Vector(_: Vector) -> Vector { loop {} }
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
#[repr(transparent)]
pub struct StructWithProjection(<f32 as Mirror>::It);
// CHECK: define{{.*}}float @test_Projection(float noundef %_1)
#[no_mangle]
pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
#[repr(transparent)]
pub enum EnumF32 {
Variant(F32)
}
// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1)
#[no_mangle]
pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
#[repr(transparent)]
pub enum EnumF32WithZsts {
Variant(Zst1, F32, Zst2)
}
// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1)
#[no_mangle]
pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
#[repr(transparent)]
pub union UnionF32 {
field: F32,
}
// CHECK: define{{.*}} float @test_UnionF32(float %_1)
#[no_mangle]
pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
#[repr(transparent)]
pub union UnionF32WithZsts {
zst1: Zst1,
field: F32,
zst2: Zst2,
}
// CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1)
#[no_mangle]
pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
// All that remains to be tested are aggregates. They are tested in separate files called
// transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR
// function signatures vary so much that it's not reasonably possible to cover all of them with a
// single CHECK line.
//
// You may be wondering why we don't just compare the return types and argument types for equality
// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes
// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of
// pointee types yet, the IR function signature will be syntactically different (%Foo* vs
// %FooWrapper*).