Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / AST / Interp / functions.cpp
blob4bef9c2f7c0d1fa6ef78ca572d3e72bca74fb35f
1 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
2 // RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify %s
3 // RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify %s
4 // RUN: %clang_cc1 -verify=ref %s
5 // RUN: %clang_cc1 -std=c++14 -verify=ref %s
6 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
8 constexpr void doNothing() {}
9 constexpr int gimme5() {
10 doNothing();
11 return 5;
13 static_assert(gimme5() == 5, "");
16 template<typename T> constexpr T identity(T t) {
17 static_assert(true, "");
18 return t;
20 static_assert(identity(true), "");
21 static_assert(identity(true), ""); /// Compiled bytecode should be cached
22 static_assert(!identity(false), "");
24 template<typename A, typename B>
25 constexpr bool sameSize() {
26 static_assert(sizeof(A) == sizeof(B), ""); // expected-error {{static assertion failed}} \
27 // ref-error {{static assertion failed}} \
28 // expected-note {{evaluates to}} \
29 // ref-note {{evaluates to}}
30 return true;
32 static_assert(sameSize<int, int>(), "");
33 static_assert(sameSize<unsigned int, int>(), "");
34 static_assert(sameSize<char, long>(), ""); // expected-note {{in instantiation of function template specialization}} \
35 // ref-note {{in instantiation of function template specialization}}
38 constexpr auto add(int a, int b) -> int {
39 return identity(a) + identity(b);
42 constexpr int sub(int a, int b) {
43 return a - b;
45 static_assert(sub(5, 2) == 3, "");
46 static_assert(sub(0, 5) == -5, "");
48 constexpr int norm(int n) {
49 if (n >= 0) {
50 return identity(n);
52 return -identity(n);
54 static_assert(norm(5) == norm(-5), "");
56 constexpr int square(int n) {
57 return norm(n) * norm(n);
59 static_assert(square(2) == 4, "");
61 constexpr int add_second(int a, int b, bool doAdd = true) {
62 if (doAdd)
63 return a + b;
64 return a;
66 static_assert(add_second(10, 3, true) == 13, "");
67 static_assert(add_second(10, 3) == 13, "");
68 static_assert(add_second(300, -20, false) == 300, "");
71 constexpr int sub(int a, int b, int c) {
72 return a - b - c;
74 static_assert(sub(10, 8, 2) == 0, "");
77 constexpr int recursion(int i) {
78 doNothing();
79 i = i - 1;
80 if (i == 0)
81 return identity(0);
83 return recursion(i);
85 static_assert(recursion(10) == 0, "");
87 template<int N = 5>
88 constexpr decltype(N) getNum() {
89 return N;
91 static_assert(getNum<-2>() == -2, "");
92 static_assert(getNum<10>() == 10, "");
93 static_assert(getNum() == 5, "");
95 constexpr int f(); // expected-note {{declared here}} \
96 // ref-note {{declared here}}
97 static_assert(f() == 5, ""); // expected-error {{not an integral constant expression}} \
98 // expected-note {{undefined function 'f'}} \
99 // ref-error {{not an integral constant expression}} \
100 // ref-note {{undefined function 'f'}}
101 constexpr int a() {
102 return f();
104 constexpr int f() {
105 return 5;
107 static_assert(a() == 5, "");
109 constexpr int invalid() {
110 // Invalid expression in visit().
111 while(huh) {} // expected-error {{use of undeclared identifier}} \
112 // ref-error {{use of undeclared identifier}}
114 return 0;
117 constexpr void invalid2() {
118 int i = 0;
119 // Invalid expression in discard().
120 huh(); // expected-error {{use of undeclared identifier}} \
121 // ref-error {{use of undeclared identifier}}
124 namespace FunctionPointers {
125 constexpr int add(int a, int b) {
126 return a + b;
129 struct S { int a; };
130 constexpr S getS() {
131 return S{12};
134 constexpr int applyBinOp(int a, int b, int (*op)(int, int)) {
135 return op(a, b);
137 static_assert(applyBinOp(1, 2, add) == 3, "");
139 constexpr int ignoreReturnValue() {
140 int (*foo)(int, int) = add;
142 foo(1, 2);
143 return 1;
145 static_assert(ignoreReturnValue() == 1, "");
147 constexpr int createS(S (*gimme)()) {
148 gimme(); // Ignored return value
149 return gimme().a;
151 static_assert(createS(getS) == 12, "");
153 namespace FunctionReturnType {
154 typedef int (*ptr)(int*);
155 typedef ptr (*pm)();
157 constexpr int fun1(int* y) {
158 return *y + 10;
160 constexpr ptr fun() {
161 return &fun1;
163 static_assert(fun() == nullptr, ""); // expected-error {{static assertion failed}} \
164 // ref-error {{static assertion failed}}
166 constexpr int foo() {
167 int (*f)(int *) = fun();
168 int m = 0;
170 m = f(&m);
172 return m;
174 static_assert(foo() == 10, "");
176 struct S {
177 int i;
178 void (*fp)();
181 constexpr S s{ 12 };
182 static_assert(s.fp == nullptr, ""); // zero-initialized function pointer.
184 constexpr int (*op)(int, int) = add;
185 constexpr bool b = op;
186 static_assert(op, "");
187 static_assert(!!op, "");
188 constexpr int (*op2)(int, int) = nullptr;
189 static_assert(!op2, "");
192 namespace Comparison {
193 void f(), g();
194 constexpr void (*pf)() = &f, (*pg)() = &g;
196 constexpr bool u13 = pf < pg; // ref-warning {{ordered comparison of function pointers}} \
197 // ref-error {{must be initialized by a constant expression}} \
198 // ref-note {{comparison between '&f' and '&g' has unspecified value}} \
199 // expected-warning {{ordered comparison of function pointers}} \
200 // expected-error {{must be initialized by a constant expression}} \
201 // expected-note {{comparison between '&f' and '&g' has unspecified value}}
203 constexpr bool u14 = pf < (void(*)())nullptr; // ref-warning {{ordered comparison of function pointers}} \
204 // ref-error {{must be initialized by a constant expression}} \
205 // ref-note {{comparison between '&f' and 'nullptr' has unspecified value}} \
206 // expected-warning {{ordered comparison of function pointers}} \
207 // expected-error {{must be initialized by a constant expression}} \
208 // expected-note {{comparison between '&f' and 'nullptr' has unspecified value}}
212 static_assert(pf != pg, "");
213 static_assert(pf == &f, "");
214 static_assert(pg == &g, "");
219 struct F {
220 constexpr bool ok() const {
221 return okRecurse();
223 constexpr bool okRecurse() const {
224 return true;
228 struct BodylessMemberFunction {
229 constexpr int first() const {
230 return second();
232 constexpr int second() const {
233 return 1;
237 constexpr int nyd(int m);
238 constexpr int doit() { return nyd(10); }
239 constexpr int nyd(int m) { return m; }
240 static_assert(doit() == 10, "");
242 namespace InvalidCall {
243 struct S {
244 constexpr int a() const { // expected-error {{never produces a constant expression}} \
245 // ref-error {{never produces a constant expression}}
246 return 1 / 0; // expected-note 2{{division by zero}} \
247 // expected-warning {{is undefined}} \
248 // ref-note 2{{division by zero}} \
249 // ref-warning {{is undefined}}
252 constexpr S s;
253 static_assert(s.a() == 1, ""); // expected-error {{not an integral constant expression}} \
254 // expected-note {{in call to}} \
255 // ref-error {{not an integral constant expression}} \
256 // ref-note {{in call to}}
258 /// This used to cause an assertion failure in the new constant interpreter.
259 constexpr void func(); // expected-note {{declared here}} \
260 // ref-note {{declared here}}
261 struct SS {
262 constexpr SS() { func(); } // expected-note {{undefined function }} \
263 // ref-note {{undefined function}}
265 constexpr SS ss; // expected-error {{must be initialized by a constant expression}} \
266 // expected-note {{in call to 'SS()'}} \
267 // ref-error {{must be initialized by a constant expression}} \
268 // ref-note {{in call to 'SS()'}}
272 namespace CallWithArgs {
273 /// This used to call problems during checkPotentialConstantExpression() runs.
274 constexpr void g(int a) {}
275 constexpr void f() {
276 g(0);
280 namespace ReturnLocalPtr {
281 constexpr int *p() {
282 int a = 12;
283 return &a; // ref-warning {{address of stack memory}} \
284 // expected-warning {{address of stack memory}}
287 /// GCC rejects the expression below, just like the new interpreter. The current interpreter
288 /// however accepts it and only warns about the function above returning an address to stack
289 /// memory. If we change the condition to 'p() != nullptr', it even succeeds.
290 static_assert(p() == nullptr, ""); // ref-error {{static assertion failed}} \
291 // expected-error {{not an integral constant expression}}
293 /// FIXME: The current interpreter emits diagnostics in the reference case below, but the
294 /// new one does not.
295 constexpr const int &p2() {
296 int a = 12; // ref-note {{declared here}}
297 return a; // ref-warning {{reference to stack memory associated with local variable}} \
298 // expected-warning {{reference to stack memory associated with local variable}}
301 static_assert(p2() == 12, ""); // ref-error {{not an integral constant expression}} \
302 // ref-note {{read of variable whose lifetime has ended}} \
303 // expected-error {{not an integral constant expression}}
306 namespace VoidReturn {
307 /// ReturnStmt with an expression in a void function used to cause problems.
308 constexpr void bar() {}
309 constexpr void foo() {
310 return bar();
312 static_assert((foo(),1) == 1, "");
315 namespace InvalidReclRefs {
316 void param(bool b) { // ref-note {{declared here}} \
317 // expected-note {{declared here}}
318 static_assert(b, ""); // ref-error {{not an integral constant expression}} \
319 // ref-note {{function parameter 'b' with unknown value}} \
320 // expected-error {{not an integral constant expression}} \
321 // expected-note {{function parameter 'b' with unknown value}}
322 static_assert(true ? true : b, "");
325 #if __cplusplus >= 202002L
326 consteval void param2(bool b) { // ref-note {{declared here}} \
327 // expected-note {{declared here}}
328 static_assert(b, ""); // ref-error {{not an integral constant expression}} \
329 // ref-note {{function parameter 'b' with unknown value}} \
330 // expected-error {{not an integral constant expression}} \
331 // expected-note {{function parameter 'b' with unknown value}}
333 #endif
336 namespace TemplateUndefined {
337 template<typename T> constexpr int consume(T);
338 // ok, not a constant expression.
339 const int k = consume(0);
341 template<typename T> constexpr int consume(T) { return 0; }
342 // ok, constant expression.
343 constexpr int l = consume(0);
344 static_assert(l == 0, "");
347 namespace PtrReturn {
348 constexpr void *a() {
349 return nullptr;
351 static_assert(a() == nullptr, "");
354 namespace Variadic {
355 struct S { int a; bool b; };
357 constexpr void variadic_function(int a, ...) {}
358 constexpr int f1() {
359 variadic_function(1, S{'a', false});
360 return 1;
362 static_assert(f1() == 1, "");
364 constexpr int variadic_function2(...) {
365 return 12;
367 static_assert(variadic_function2() == 12, "");
368 static_assert(variadic_function2(1, 2, 3, 4, 5) == 12, "");
369 static_assert(variadic_function2(1, variadic_function2()) == 12, "");
371 constexpr int (*VFP)(...) = variadic_function2;
372 static_assert(VFP() == 12, "");