xref: /llvm-project/clang/test/CodeGenCXX/cxx2a-consteval.cpp (revision a024a0ceedae886c254b496c9321f9ef253cd7f8)
1 // RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
2 // RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s
3 // RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s
4 // RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s
5 //
6 // RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
7 // RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s
8 
9 // RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter
10 // RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s
11 // RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s
12 // RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s
13 //
14 // RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter
15 // RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s
16 
17 // there is two version of symbol checks to ensure
18 // that the symbol we are looking for are correct
19 // EVAL-NOT: @__cxx_global_var_init()
20 // EXPR: @__cxx_global_var_init()
21 
22 // EVAL-NOT: @_Z4ret7v()
23 // EXPR: @_Z4ret7v()
24 consteval int ret7() {
25   return 7;
26 }
27 
28 // EVAL-FN-LABEL: @_Z9test_ret7v(
29 // EVAL-FN-NEXT:  entry:
30 // EVAL-FN-NEXT:    [[I:%.*]] = alloca i32, align 4
31 // EVAL-FN-NEXT:    store i32 7, ptr [[I]], align 4
32 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
33 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
34 //
35 int test_ret7() {
36   int i = ret7();
37   return i;
38 }
39 
40 int global_i = ret7();
41 
42 constexpr int i_const = 5;
43 
44 // EVAL-NOT: @_Z4retIv()
45 // EXPR: @_Z4retIv()
46 consteval const int &retI() {
47   return i_const;
48 }
49 
50 // EVAL-FN-LABEL: @_Z12test_retRefIv(
51 // EVAL-FN-NEXT:  entry:
52 // EVAL-FN-NEXT:    ret ptr @_ZL7i_const
53 //
54 const int &test_retRefI() {
55   return retI();
56 }
57 
58 // EVAL-FN-LABEL: @_Z9test_retIv(
59 // EVAL-FN-NEXT:  entry:
60 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4
61 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
62 //
63 int test_retI() {
64   return retI();
65 }
66 
67 // EVAL-NOT: @_Z4retIv()
68 // EXPR: @_Z4retIv()
69 consteval const int *retIPtr() {
70   return &i_const;
71 }
72 
73 // EVAL-FN-LABEL: @_Z12test_retIPtrv(
74 // EVAL-FN-NEXT:  entry:
75 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4
76 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
77 //
78 int test_retIPtr() {
79   return *retIPtr();
80 }
81 
82 // EVAL-FN-LABEL: @_Z13test_retPIPtrv(
83 // EVAL-FN-NEXT:  entry:
84 // EVAL-FN-NEXT:    ret ptr @_ZL7i_const
85 //
86 const int *test_retPIPtr() {
87   return retIPtr();
88 }
89 
90 // EVAL-NOT: @_Z4retIv()
91 // EXPR: @_Z4retIv()
92 consteval const int &&retIRRef() {
93   return static_cast<const int &&>(i_const);
94 }
95 
96 // EVAL-FN-LABEL: @_Z13test_retIRRefv(
97 // EVAL-FN-NEXT:  entry:
98 // EVAL-FN-NEXT:    ret ptr @_ZL7i_const
99 //
100 const int &&test_retIRRef() {
101   return static_cast<const int &&>(retIRRef());
102 }
103 
104 // EVAL-FN-LABEL: @_Z14test_retIRRefIv(
105 // EVAL-FN-NEXT:  entry:
106 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4
107 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
108 //
109 int test_retIRRefI() {
110   return retIRRef();
111 }
112 
113 struct Agg {
114   int a;
115   long b;
116 };
117 
118 // EVAL-NOT: @_Z6retAggv()
119 // EXPR: @_Z6retAggv()
120 consteval Agg retAgg() {
121   return {13, 17};
122 }
123 
124 // EVAL-FN-LABEL: @_Z11test_retAggv(
125 // EVAL-FN-NEXT:  entry:
126 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
127 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
128 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0
129 // EVAL-FN-NEXT:    store i32 13, ptr [[TMP0]], align 8
130 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1
131 // EVAL-FN-NEXT:    store i64 17, ptr [[TMP1]], align 8
132 // EVAL-FN-NEXT:    store i64 17, ptr [[B]], align 8
133 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, ptr [[B]], align 8
134 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
135 //
136 long test_retAgg() {
137   long b = retAgg().b;
138   return b;
139 }
140 
141 // EVAL-STATIC: @A ={{.*}} global %struct.Agg { i32 13, i64 17 }, align 8
142 Agg A = retAgg();
143 
144 // EVAL-NOT: @_Z9retRefAggv()
145 // EXPR: @_Z9retRefAggv()
146 consteval const Agg &retRefAgg() {
147   const Agg &tmp = A;
148   return A;
149 }
150 
151 // EVAL-FN-LABEL: @_Z14test_retRefAggv(
152 // EVAL-FN-NEXT:  entry:
153 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
154 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
155 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0
156 // EVAL-FN-NEXT:    store i32 13, ptr [[TMP0]], align 8
157 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1
158 // EVAL-FN-NEXT:    store i64 17, ptr [[TMP1]], align 8
159 // EVAL-FN-NEXT:    store i64 17, ptr [[B]], align 8
160 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, ptr [[B]], align 8
161 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
162 //
163 long test_retRefAgg() {
164   long b = retAgg().b;
165   return b;
166 }
167 
168 // EVAL-NOT: @_Z8is_constv()
169 // EXPR: @_Z8is_constv()
170 consteval Agg is_const() {
171   return {5, 19 * __builtin_is_constant_evaluated()};
172 }
173 
174 // EVAL-FN-LABEL: @_Z13test_is_constv(
175 // EVAL-FN-NEXT:  entry:
176 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
177 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
178 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0
179 // EVAL-FN-NEXT:    store i32 5, ptr [[TMP0]], align 8
180 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1
181 // EVAL-FN-NEXT:    store i64 19, ptr [[TMP1]], align 8
182 // EVAL-FN-NEXT:    store i64 19, ptr [[B]], align 8
183 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, ptr [[B]], align 8
184 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
185 //
186 long test_is_const() {
187   long b = is_const().b;
188   return b;
189 }
190 
191 // EVAL-NOT: @_ZN7AggCtorC
192 // EXPR: @_ZN7AggCtorC
193 struct AggCtor {
194   consteval AggCtor(int a = 3, long b = 5) : a(a * a), b(a * b) {}
195   int a;
196   long b;
197 };
198 
199 // EVAL-FN-LABEL: @_Z12test_AggCtorv(
200 // EVAL-FN-NEXT:  entry:
201 // EVAL-FN-NEXT:    [[I:%.*]] = alloca i32, align 4
202 // EVAL-FN-NEXT:    [[C:%.*]] = alloca [[STRUCT_AGGCTOR:%.*]], align 8
203 // EVAL-FN-NEXT:    store i32 2, ptr [[I]], align 4
204 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 0
205 // EVAL-FN-NEXT:    store i32 4, ptr [[TMP0]], align 8
206 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 1
207 // EVAL-FN-NEXT:    store i64 10, ptr [[TMP1]], align 8
208 // EVAL-FN-NEXT:    [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 0
209 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A]], align 8
210 // EVAL-FN-NEXT:    [[CONV:%.*]] = sext i32 [[TMP2]] to i64
211 // EVAL-FN-NEXT:    [[B:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 1
212 // EVAL-FN-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B]], align 8
213 // EVAL-FN-NEXT:    [[ADD:%.*]] = add nsw i64 [[CONV]], [[TMP3]]
214 // EVAL-FN-NEXT:    ret i64 [[ADD]]
215 //
216 long test_AggCtor() {
217   const int i = 2;
218   AggCtor C(i);
219   return C.a + C.b;
220 }
221 
222 struct UserConv {
223   consteval operator int() const noexcept { return 42; }
224 };
225 
226 // EVAL-FN-LABEL: @_Z13test_UserConvv(
227 // EVAL-FN-NEXT:  entry:
228 // EVAL-FN-NEXT:    ret i32 42
229 //
230 int test_UserConv() {
231   return UserConv();
232 }
233 
234 // EVAL-FN-LABEL: @_Z28test_UserConvOverload_helperi(
235 // EVAL-FN-NEXT:  entry:
236 // EVAL-FN-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
237 // EVAL-FN-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
238 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
239 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
240 //
241 int test_UserConvOverload_helper(int a) { return a; }
242 
243 // EVAL-FN-LABEL: @_Z21test_UserConvOverloadv(
244 // EVAL-FN-NEXT:  entry:
245 // EVAL-FN-NEXT:    [[CALL:%.*]] = call noundef i32 @_Z28test_UserConvOverload_helperi(i32 noundef 42)
246 // EVAL-FN-NEXT:    ret i32 [[CALL]]
247 //
248 int test_UserConvOverload() {
249   return test_UserConvOverload_helper(UserConv());
250 }
251 
252 consteval int test_UserConvOverload_helper_ceval(int a) { return a; }
253 
254 // EVAL-FN-LABEL: @_Z27test_UserConvOverload_cevalv(
255 // EVAL-FN-NEXT:  entry:
256 // EVAL-FN-NEXT:    ret i32 42
257 //
258 int test_UserConvOverload_ceval() {
259   return test_UserConvOverload_helper_ceval(UserConv());
260 }
261 
262 consteval void void_test() {}
263 void void_call() { // EVAL-FN-LABEL: define {{.*}} @_Z9void_call
264   // EVAL-FN-NOT: call
265   void_test();
266   // EVAL-FN: {{^}}}
267 }
268 
269 
270 namespace GH82154 {
271 struct S1 { consteval S1(int) {} };
272 struct S3 { constexpr S3(int) {} };
273 
274 void f() {
275     struct S2 {
276         S1 s = 0;
277         S3 s2 = 0;
278     };
279     S2 s;
280     // EVAL-FN-LABEL: define {{.*}} void @_ZZN7GH821541fEvEN2S2C2Ev
281     // EVAL-FN-NOT: call void @_ZN7GH821542S1C2Ei
282     // EVAL-FN:     call void @_ZN7GH821542S3C2Ei
283 }
284 }
285 
286 namespace GH93040 {
287 struct C { char c = 1; };
288 struct Empty { consteval Empty() {} };
289 struct Empty2 { consteval Empty2() {} };
290 struct Test : C, Empty {
291   [[no_unique_address]] Empty2 e;
292 };
293 static_assert(sizeof(Test) == 1);
294 void f() {
295   Test test;
296 
297 // Make sure we don't overwrite the initialization of c.
298 
299 // EVAL-FN-LABEL: define {{.*}} void @_ZN7GH930404TestC2Ev
300 // EVAL-FN: entry:
301 // EVAL-FN-NEXT:  [[THIS_ADDR:%.*]] = alloca ptr, align 8
302 // EVAL-FN-NEXT:  store ptr {{.*}}, ptr [[THIS_ADDR]], align 8
303 // EVAL-FN-NEXT:  [[THIS:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
304 // EVAL-FN-NEXT:  call void @_ZN7GH930401CC2Ev(ptr noundef nonnull align 1 dereferenceable(1) [[THIS]])
305 // EVAL-FN-NEXT:  ret void
306 }
307 }
308