1 // compile-flags: -O -C no-prepopulate-passes
3 // ignore-riscv64 riscv64 has an i128 type used with test_Vector
4 // see codegen/riscv-abi for riscv functiona call tests
7 #![feature(repr_simd, transparent_unions)]
9 use std
::marker
::PhantomData
;
11 #[derive(Copy, Clone)]
13 #[derive(Copy, Clone)]
16 #[derive(Copy, Clone)]
20 // CHECK: define{{.*}}float @test_F32(float %_1)
22 pub extern "C" fn test_F32(_
: F32
) -> F32 { loop {}
}
25 pub struct Ptr(*mut u8);
27 // CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} %_1)
29 pub extern "C" fn test_Ptr(_
: Ptr
) -> Ptr { loop {}
}
32 pub struct WithZst(u64, Zst1
);
34 // CHECK: define{{.*}}i64 @test_WithZst(i64 %_1)
36 pub extern "C" fn test_WithZst(_
: WithZst
) -> WithZst { loop {}
}
39 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
41 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
42 // CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} %_1)
44 pub extern "C" fn test_WithZeroSizedArray(_
: WithZeroSizedArray
) -> WithZeroSizedArray { loop {}
}
47 pub struct Generic
<T
>(T
);
49 // CHECK: define{{.*}}double @test_Generic(double %_1)
51 pub extern "C" fn test_Generic(_
: Generic
<f64>) -> Generic
<f64> { loop {}
}
54 pub struct GenericPlusZst
<T
>(T
, Zst2
);
57 pub enum Bool { True, False, FileNotFound }
59 // CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
61 pub extern "C" fn test_Gpz(_
: GenericPlusZst
<Bool
>) -> GenericPlusZst
<Bool
> { loop {}
}
64 pub struct LifetimePhantom
<'a
, T
: 'a
>(*const T
, PhantomData
<&'a T
>);
66 // CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} %_1)
68 pub extern "C" fn test_LifetimePhantom(_
: LifetimePhantom
<i16>) -> LifetimePhantom
<i16> { loop {}
}
70 // This works despite current alignment resrictions because PhantomData is always align(1)
72 pub struct UnitPhantom
<T
, U
> { val: T, unit: PhantomData<U> }
76 // CHECK: define{{.*}}float @test_UnitPhantom(float %_1)
78 pub extern "C" fn test_UnitPhantom(_
: UnitPhantom
<f32, Px
>) -> UnitPhantom
<f32, Px
> { loop {}
}
81 pub struct TwoZsts(Zst1
, i8, Zst2
);
83 // CHECK: define{{( dso_local)?}}{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1)
85 pub extern "C" fn test_TwoZsts(_
: TwoZsts
) -> TwoZsts { loop {}
}
88 pub struct Nested1(Zst2
, Generic
<f64>);
90 // CHECK: define{{.*}}double @test_Nested1(double %_1)
92 pub extern "C" fn test_Nested1(_
: Nested1
) -> Nested1 { loop {}
}
95 pub struct Nested2(Nested1
, Zst1
);
97 // CHECK: define{{.*}}double @test_Nested2(double %_1)
99 pub extern "C" fn test_Nested2(_
: Nested2
) -> Nested2 { loop {}
}
102 struct f32x4(f32, f32, f32, f32);
105 pub struct Vector(f32x4
);
107 // CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
109 pub extern "C" fn test_Vector(_
: Vector
) -> Vector { loop {}
}
111 trait Mirror { type It: ?Sized; }
112 impl<T
: ?Sized
> Mirror
for T { type It = Self; }
115 pub struct StructWithProjection(<f32 as Mirror
>::It
);
117 // CHECK: define{{.*}}float @test_Projection(float %_1)
119 pub extern "C" fn test_Projection(_
: StructWithProjection
) -> StructWithProjection { loop {}
}
126 // CHECK: define{{.*}}float @test_EnumF32(float %_1)
128 pub extern "C" fn test_EnumF32(_
: EnumF32
) -> EnumF32 { loop {}
}
131 pub enum EnumF32WithZsts
{
132 Variant(Zst1
, F32
, Zst2
)
135 // CHECK: define{{.*}}float @test_EnumF32WithZsts(float %_1)
137 pub extern "C" fn test_EnumF32WithZsts(_
: EnumF32WithZsts
) -> EnumF32WithZsts { loop {}
}
144 // CHECK: define{{.*}}float @test_UnionF32(float %_1)
146 pub extern "C" fn test_UnionF32(_
: UnionF32
) -> UnionF32 { loop {}
}
149 pub union UnionF32WithZsts
{
155 // CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1)
157 pub extern "C" fn test_UnionF32WithZsts(_
: UnionF32WithZsts
) -> UnionF32WithZsts { loop {}
}
160 // All that remains to be tested are aggregates. They are tested in separate files called repr-
161 // transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR
162 // function signatures vary so much that it's not reasonably possible to cover all of them with a
163 // single CHECK line.
165 // You may be wondering why we don't just compare the return types and argument types for equality
166 // with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes
167 // containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of
168 // pointee types yet, the IR function signature will be syntactically different (%Foo* vs