]> git.lizzy.rs Git - rust.git/blob - tests/codegen/repr-transparent.rs
Rollup merge of #106946 - dtolnay:hashlinecolumn, r=m-ou-se
[rust.git] / tests / codegen / repr-transparent.rs
1 // compile-flags: -O -C no-prepopulate-passes
2
3 // ignore-riscv64 riscv64 has an i128 type used with test_Vector
4 // see codegen/riscv-abi for riscv functiona call tests
5 // ignore-s390x s390x with default march passes vector types per reference
6
7 #![crate_type="lib"]
8 #![feature(repr_simd, transparent_unions)]
9
10 use std::marker::PhantomData;
11
12 #[derive(Copy, Clone)]
13 pub struct Zst1;
14 #[derive(Copy, Clone)]
15 pub struct Zst2(());
16
17 #[derive(Copy, Clone)]
18 #[repr(transparent)]
19 pub struct F32(f32);
20
21 // CHECK: define{{.*}}float @test_F32(float noundef %_1)
22 #[no_mangle]
23 pub extern "C" fn test_F32(_: F32) -> F32 { loop {} }
24
25 #[repr(transparent)]
26 pub struct Ptr(*mut u8);
27
28 // CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} noundef %_1)
29 #[no_mangle]
30 pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { loop {} }
31
32 #[repr(transparent)]
33 pub struct WithZst(u64, Zst1);
34
35 // CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1)
36 #[no_mangle]
37 pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
38
39 #[repr(transparent)]
40 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
41
42 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
43 // CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} noundef %_1)
44 #[no_mangle]
45 pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
46
47 #[repr(transparent)]
48 pub struct Generic<T>(T);
49
50 // CHECK: define{{.*}}double @test_Generic(double noundef %_1)
51 #[no_mangle]
52 pub extern "C" fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
53
54 #[repr(transparent)]
55 pub struct GenericPlusZst<T>(T, Zst2);
56
57 #[repr(u8)]
58 pub enum Bool { True, False, FileNotFound }
59
60 // CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
61 #[no_mangle]
62 pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }
63
64 #[repr(transparent)]
65 pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
66
67 // CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} noundef %_1)
68 #[no_mangle]
69 pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
70
71 // This works despite current alignment resrictions because PhantomData is always align(1)
72 #[repr(transparent)]
73 pub struct UnitPhantom<T, U> { val: T, unit: PhantomData<U> }
74
75 pub struct Px;
76
77 // CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1)
78 #[no_mangle]
79 pub extern "C" fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
80
81 #[repr(transparent)]
82 pub struct TwoZsts(Zst1, i8, Zst2);
83
84 // CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1)
85 #[no_mangle]
86 pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
87
88 #[repr(transparent)]
89 pub struct Nested1(Zst2, Generic<f64>);
90
91 // CHECK: define{{.*}}double @test_Nested1(double noundef %_1)
92 #[no_mangle]
93 pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
94
95 #[repr(transparent)]
96 pub struct Nested2(Nested1, Zst1);
97
98 // CHECK: define{{.*}}double @test_Nested2(double noundef %_1)
99 #[no_mangle]
100 pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
101
102 #[repr(simd)]
103 struct f32x4(f32, f32, f32, f32);
104
105 #[repr(transparent)]
106 pub struct Vector(f32x4);
107
108 // CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
109 #[no_mangle]
110 pub extern "C" fn test_Vector(_: Vector) -> Vector { loop {} }
111
112 trait Mirror { type It: ?Sized; }
113 impl<T: ?Sized> Mirror for T { type It = Self; }
114
115 #[repr(transparent)]
116 pub struct StructWithProjection(<f32 as Mirror>::It);
117
118 // CHECK: define{{.*}}float @test_Projection(float noundef %_1)
119 #[no_mangle]
120 pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
121
122 #[repr(transparent)]
123 pub enum EnumF32 {
124     Variant(F32)
125 }
126
127 // CHECK: define{{.*}}float @test_EnumF32(float noundef %_1)
128 #[no_mangle]
129 pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
130
131 #[repr(transparent)]
132 pub enum EnumF32WithZsts {
133     Variant(Zst1, F32, Zst2)
134 }
135
136 // CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1)
137 #[no_mangle]
138 pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
139
140 #[repr(transparent)]
141 pub union UnionF32 {
142     field: F32,
143 }
144
145 // CHECK: define{{.*}} float @test_UnionF32(float %_1)
146 #[no_mangle]
147 pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
148
149 #[repr(transparent)]
150 pub union UnionF32WithZsts {
151     zst1: Zst1,
152     field: F32,
153     zst2: Zst2,
154 }
155
156 // CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1)
157 #[no_mangle]
158 pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
159
160
161 // All that remains to be tested are aggregates. They are tested in separate files called repr-
162 // transparent-*.rs  with `only-*` or `ignore-*` directives, because the expected LLVM IR
163 // function signatures vary so much that it's not reasonably possible to cover all of them with a
164 // single CHECK line.
165 //
166 // You may be wondering why we don't just compare the return types and argument types for equality
167 // with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes
168 // containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of
169 // pointee types yet, the IR function signature will be syntactically different (%Foo* vs
170 // %FooWrapper*).