1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2 // RUN: %clang_cc1 -no-opaque-pointers -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
3 // RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s
4 // RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s
5 // RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s
6 //
7 // RUN: %clang_cc1 -no-opaque-pointers -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
8 // RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s
9 
10 // there is two version of symbol checks to ensure
11 // that the symbol we are looking for are correct
12 // EVAL-NOT: @__cxx_global_var_init()
13 // EXPR: @__cxx_global_var_init()
14 
15 // EVAL-NOT: @_Z4ret7v()
16 // EXPR: @_Z4ret7v()
ret7()17 consteval int ret7() {
18   return 7;
19 }
20 
21 // EVAL-FN-LABEL: @_Z9test_ret7v(
22 // EVAL-FN-NEXT:  entry:
23 // EVAL-FN-NEXT:    [[I:%.*]] = alloca i32, align 4
24 // EVAL-FN-NEXT:    store i32 7, i32* [[I]], align 4
25 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, i32* [[I]], align 4
26 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
27 //
test_ret7()28 int test_ret7() {
29   int i = ret7();
30   return i;
31 }
32 
33 int global_i = ret7();
34 
35 constexpr int i_const = 5;
36 
37 // EVAL-NOT: @_Z4retIv()
38 // EXPR: @_Z4retIv()
retI()39 consteval const int &retI() {
40   return i_const;
41 }
42 
43 // EVAL-FN-LABEL: @_Z12test_retRefIv(
44 // EVAL-FN-NEXT:  entry:
45 // EVAL-FN-NEXT:    ret i32* @_ZL7i_const
46 //
test_retRefI()47 const int &test_retRefI() {
48   return retI();
49 }
50 
51 // EVAL-FN-LABEL: @_Z9test_retIv(
52 // EVAL-FN-NEXT:  entry:
53 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4
54 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
55 //
test_retI()56 int test_retI() {
57   return retI();
58 }
59 
60 // EVAL-NOT: @_Z4retIv()
61 // EXPR: @_Z4retIv()
retIPtr()62 consteval const int *retIPtr() {
63   return &i_const;
64 }
65 
66 // EVAL-FN-LABEL: @_Z12test_retIPtrv(
67 // EVAL-FN-NEXT:  entry:
68 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4
69 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
70 //
test_retIPtr()71 int test_retIPtr() {
72   return *retIPtr();
73 }
74 
75 // EVAL-FN-LABEL: @_Z13test_retPIPtrv(
76 // EVAL-FN-NEXT:  entry:
77 // EVAL-FN-NEXT:    ret i32* @_ZL7i_const
78 //
test_retPIPtr()79 const int *test_retPIPtr() {
80   return retIPtr();
81 }
82 
83 // EVAL-NOT: @_Z4retIv()
84 // EXPR: @_Z4retIv()
retIRRef()85 consteval const int &&retIRRef() {
86   return static_cast<const int &&>(i_const);
87 }
88 
89 // EVAL-FN-LABEL: @_Z13test_retIRRefv(
90 // EVAL-FN-NEXT:  entry:
91 // EVAL-FN-NEXT:    ret i32* @_ZL7i_const
92 //
test_retIRRef()93 const int &&test_retIRRef() {
94   return static_cast<const int &&>(retIRRef());
95 }
96 
97 // EVAL-FN-LABEL: @_Z14test_retIRRefIv(
98 // EVAL-FN-NEXT:  entry:
99 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4
100 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
101 //
test_retIRRefI()102 int test_retIRRefI() {
103   return retIRRef();
104 }
105 
106 struct Agg {
107   int a;
108   long b;
109 };
110 
111 // EVAL-NOT: @_Z6retAggv()
112 // EXPR: @_Z6retAggv()
retAgg()113 consteval Agg retAgg() {
114   return {13, 17};
115 }
116 
117 // EVAL-FN-LABEL: @_Z11test_retAggv(
118 // EVAL-FN-NEXT:  entry:
119 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
120 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
121 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0
122 // EVAL-FN-NEXT:    store i32 13, i32* [[TMP0]], align 8
123 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1
124 // EVAL-FN-NEXT:    store i64 17, i64* [[TMP1]], align 8
125 // EVAL-FN-NEXT:    store i64 17, i64* [[B]], align 8
126 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, i64* [[B]], align 8
127 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
128 //
test_retAgg()129 long test_retAgg() {
130   long b = retAgg().b;
131   return b;
132 }
133 
134 // EVAL-STATIC: @A ={{.*}} global %struct.Agg { i32 13, i64 17 }, align 8
135 Agg A = retAgg();
136 
137 // EVAL-NOT: @_Z9retRefAggv()
138 // EXPR: @_Z9retRefAggv()
retRefAgg()139 consteval const Agg &retRefAgg() {
140   const Agg &tmp = A;
141   return A;
142 }
143 
144 // EVAL-FN-LABEL: @_Z14test_retRefAggv(
145 // EVAL-FN-NEXT:  entry:
146 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
147 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
148 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0
149 // EVAL-FN-NEXT:    store i32 13, i32* [[TMP0]], align 8
150 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1
151 // EVAL-FN-NEXT:    store i64 17, i64* [[TMP1]], align 8
152 // EVAL-FN-NEXT:    store i64 17, i64* [[B]], align 8
153 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, i64* [[B]], align 8
154 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
155 //
test_retRefAgg()156 long test_retRefAgg() {
157   long b = retAgg().b;
158   return b;
159 }
160 
161 // EVAL-NOT: @_Z8is_constv()
162 // EXPR: @_Z8is_constv()
is_const()163 consteval Agg is_const() {
164   return {5, 19 * __builtin_is_constant_evaluated()};
165 }
166 
167 // EVAL-FN-LABEL: @_Z13test_is_constv(
168 // EVAL-FN-NEXT:  entry:
169 // EVAL-FN-NEXT:    [[B:%.*]] = alloca i64, align 8
170 // EVAL-FN-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8
171 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0
172 // EVAL-FN-NEXT:    store i32 5, i32* [[TMP0]], align 8
173 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1
174 // EVAL-FN-NEXT:    store i64 19, i64* [[TMP1]], align 8
175 // EVAL-FN-NEXT:    store i64 19, i64* [[B]], align 8
176 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i64, i64* [[B]], align 8
177 // EVAL-FN-NEXT:    ret i64 [[TMP2]]
178 //
test_is_const()179 long test_is_const() {
180   long b = is_const().b;
181   return b;
182 }
183 
184 // EVAL-NOT: @_ZN7AggCtorC
185 // EXPR: @_ZN7AggCtorC
186 struct AggCtor {
AggCtorAggCtor187   consteval AggCtor(int a = 3, long b = 5) : a(a * a), b(a * b) {}
188   int a;
189   long b;
190 };
191 
192 // EVAL-FN-LABEL: @_Z12test_AggCtorv(
193 // EVAL-FN-NEXT:  entry:
194 // EVAL-FN-NEXT:    [[I:%.*]] = alloca i32, align 4
195 // EVAL-FN-NEXT:    [[C:%.*]] = alloca [[STRUCT_AGGCTOR:%.*]], align 8
196 // EVAL-FN-NEXT:    store i32 2, i32* [[I]], align 4
197 // EVAL-FN-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 0
198 // EVAL-FN-NEXT:    store i32 4, i32* [[TMP0]], align 8
199 // EVAL-FN-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 1
200 // EVAL-FN-NEXT:    store i64 10, i64* [[TMP1]], align 8
201 // EVAL-FN-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 0
202 // EVAL-FN-NEXT:    [[TMP2:%.*]] = load i32, i32* [[A]], align 8
203 // EVAL-FN-NEXT:    [[CONV:%.*]] = sext i32 [[TMP2]] to i64
204 // EVAL-FN-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 1
205 // EVAL-FN-NEXT:    [[TMP3:%.*]] = load i64, i64* [[B]], align 8
206 // EVAL-FN-NEXT:    [[ADD:%.*]] = add nsw i64 [[CONV]], [[TMP3]]
207 // EVAL-FN-NEXT:    ret i64 [[ADD]]
208 //
test_AggCtor()209 long test_AggCtor() {
210   const int i = 2;
211   AggCtor C(i);
212   return C.a + C.b;
213 }
214 
215 struct UserConv {
operator intUserConv216   consteval operator int() const noexcept { return 42; }
217 };
218 
219 // EVAL-FN-LABEL: @_Z13test_UserConvv(
220 // EVAL-FN-NEXT:  entry:
221 // EVAL-FN-NEXT:    ret i32 42
222 //
test_UserConv()223 int test_UserConv() {
224   return UserConv();
225 }
226 
227 // EVAL-FN-LABEL: @_Z28test_UserConvOverload_helperi(
228 // EVAL-FN-NEXT:  entry:
229 // EVAL-FN-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
230 // EVAL-FN-NEXT:    store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
231 // EVAL-FN-NEXT:    [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
232 // EVAL-FN-NEXT:    ret i32 [[TMP0]]
233 //
test_UserConvOverload_helper(int a)234 int test_UserConvOverload_helper(int a) { return a; }
235 
236 // EVAL-FN-LABEL: @_Z21test_UserConvOverloadv(
237 // EVAL-FN-NEXT:  entry:
238 // EVAL-FN-NEXT:    [[CALL:%.*]] = call noundef i32 @_Z28test_UserConvOverload_helperi(i32 noundef 42)
239 // EVAL-FN-NEXT:    ret i32 [[CALL]]
240 //
test_UserConvOverload()241 int test_UserConvOverload() {
242   return test_UserConvOverload_helper(UserConv());
243 }
244 
test_UserConvOverload_helper_ceval(int a)245 consteval int test_UserConvOverload_helper_ceval(int a) { return a; }
246 
247 // EVAL-FN-LABEL: @_Z27test_UserConvOverload_cevalv(
248 // EVAL-FN-NEXT:  entry:
249 // EVAL-FN-NEXT:    ret i32 42
250 //
test_UserConvOverload_ceval()251 int test_UserConvOverload_ceval() {
252   return test_UserConvOverload_helper_ceval(UserConv());
253 }
254 
void_test()255 consteval void void_test() {}
void_call()256 void void_call() { // EVAL-FN-LABEL: define {{.*}} @_Z9void_call
257   // EVAL-FN-NOT: call
258   void_test();
259   // EVAL-FN: {{^}}}
260 }
261