xref: /llvm-project/clang/test/SemaCXX/constant-expression-cxx2b.cpp (revision dbe308c000f3401cbf6bb55f2b8d606fe091dcfe)
1 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx2a %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wno-c++23-extensions
2 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,cxx23 %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wpre-c++23-compat
3 
4 struct NonLiteral { // cxx2a-note {{'NonLiteral' is not literal}} \
5                     // cxx23-note 2{{'NonLiteral' is not literal}}
6   NonLiteral() {} // cxx23-note 2{{declared here}}
7 };
8 
9 struct Constexpr{};
10 
11 #if __cplusplus > 202002L
12 
13 constexpr int f(int n) {  // cxx2a-error {{constexpr function never produces a constant expression}}
14   static const int m = n; // cxx2a-note {{control flows through the definition of a static variable}} \
15                           // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
16   return m;
17 }
18 constexpr int g(int n) {        // cxx2a-error {{constexpr function never produces a constant expression}}
19   thread_local const int m = n; // cxx2a-note {{control flows through the definition of a thread_local variable}} \
20                                 // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
21   return m;
22 }
23 
24 constexpr int c_thread_local(int n) { // cxx2a-error {{constexpr function never produces a constant expression}}
25   static _Thread_local int m = 0;     // cxx2a-note {{control flows through the definition of a thread_local variable}} \
26                                       // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
27   return m;
28 }
29 
30 constexpr int gnu_thread_local(int n) { // cxx2a-error {{constexpr function never produces a constant expression}}
31   static __thread int m = 0;            // cxx2a-note {{control flows through the definition of a thread_local variable}} \
32                                         // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
33   return m;
34 }
35 
36 constexpr int h(int n) {  // cxx2a-error {{constexpr function never produces a constant expression}}
37   static const int m = n; // cxx2a-note {{control flows through the definition of a static variable}} \
38                           // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
39   return &m - &m;
40 }
41 constexpr int i(int n) {        // cxx2a-error {{constexpr function never produces a constant expression}}
42   thread_local const int m = n; // cxx2a-note {{control flows through the definition of a thread_local variable}} \
43                                  // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
44   return &m - &m;
45 }
46 
47 constexpr int j(int n) {
48   if (!n)
49     return 0;
50   static const int m = n; // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
51   return m;
52 }
53 constexpr int j0 = j(0);
54 
55 constexpr int k(int n) {
56   if (!n)
57     return 0;
58   thread_local const int m = n; // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
59 
60   return m;
61 }
62 constexpr int k0 = k(0);
63 
64 constexpr int j_evaluated(int n) {
65   if (!n)
66     return 0;
67   static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
68                           // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
69   return m;
70 }
71 
72 constexpr int je = j_evaluated(1); // expected-error {{constexpr variable 'je' must be initialized by a constant expression}}  \
73                                    // expected-note {{in call}}
74 
75 constexpr int k_evaluated(int n) {
76   if (!n)
77     return 0;
78   thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
79                                 // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
80 
81   return m;
82 }
83 
84 constexpr int ke = k_evaluated(1); // expected-error {{constexpr variable 'ke' must be initialized by a constant expression}} \
85                                    // expected-note {{in call}}
86 
87 constexpr int static_constexpr() {
88   static constexpr int m = 42;     // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
89   static constexpr Constexpr foo; // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
90   return m;
91 }
92 
93 constexpr int thread_local_constexpr() {
94   thread_local constexpr int m = 42; // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
95   thread_local constexpr Constexpr foo; // cxx23-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++23}}
96   return m;
97 }
98 
99 constexpr int non_literal(bool b) {
100   if (!b)
101     return 0;
102   NonLiteral n; // cxx23-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++23}}
103 }
104 
105 constexpr int non_literal_1 = non_literal(false);
106 
107 namespace eval_goto {
108 
109 constexpr int f(int x) {
110   if (x) {
111     return 0;
112   } else {
113     goto test; // expected-note {{subexpression not valid in a constant expression}} \
114                // cxx23-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++23}}
115   }
116 test:
117   return 0;
118 }
119 
120 int a = f(0);
121 constexpr int b = f(0); // expected-error {{must be initialized by a constant expression}} \
122                         // expected-note {{in call to 'f(0)'}}
123 constexpr int c = f(1);
124 
125 constexpr int label() {
126 
127 test: // cxx23-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++23}}
128   return 0;
129 }
130 
131 constexpr int d = label();
132 
133 } // namespace eval_goto
134 
135 #endif
136 
137 // Test that explicitly constexpr lambdas behave correctly,
138 // This is to be contrasted with the test for implicitly constexpr lambdas below.
139 int test_in_lambdas() {
140   auto a = []() constexpr {
141     static const int m = 32; // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
142     return m;
143   };
144 
145   auto b = [](int n) constexpr {
146     if (!n)
147       return 0;
148     static const int m = n; // cxx23-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++23}}
149     return m;
150   }
151   (1);
152 
153   auto c = [](int n) constexpr {
154     if (!n)
155       return 0;
156     else
157       goto test; // expected-note {{subexpression not valid in a constant expression}} \
158                  // cxx23-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++23}}
159   test:
160     return 1;
161   };
162   c(0);
163   constexpr auto c_error = c(1); // expected-error {{constexpr variable 'c_error' must be initialized by a constant expression}} \
164                                  // expected-note {{in call to}}
165 
166   auto non_literal = [](bool b) constexpr {
167     if (!b)
168       NonLiteral n; // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++23}} \
169                     // cxx23-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++23}} \
170 		    // cxx23-note {{non-constexpr constructor 'NonLiteral' cannot be used in a constant expression}}
171     return 0;
172   };
173 
174 #if __cplusplus > 202002L
175   constexpr auto non_literal_ko = non_literal(false); // cxx23-error {{constexpr variable 'non_literal_ko' must be initialized by a constant expression}} \
176                                                       // cxx23-note {{in call}}
177 
178   constexpr auto non_literal_ok = non_literal(true);
179 #endif
180 }
181 
182 // Test whether lambdas are correctly treated as implicitly constexpr under the
183 // relaxed C++23 rules (and similarly as not implicitly constexpr under the
184 // C++20 rules).
185 int test_lambdas_implicitly_constexpr() {
186 
187   auto b = [](int n) { // cxx2a-note 2{{declared here}}
188     if (!n)
189       return 0;
190     static const int m = n; // cxx23-note {{control flows through the definition of a static variable}}
191     return m;
192   };
193 
194   auto b1 = b(1);
195   constexpr auto b2 = b(0); // cxx2a-error {{must be initialized by a constant expression}} \
196                             // cxx2a-note {{non-constexpr function}}
197 
198   constexpr auto b3 = b(1); // expected-error{{constexpr variable 'b3' must be initialized by a constant expression}} \
199                             // cxx2a-note {{non-constexpr function}} \
200                             // cxx23-note {{in call}}
201 
202   auto c = [](int n) { // cxx2a-note 2{{declared here}}
203     if (!n)
204       return 0;
205     else
206       goto test; // cxx23-note {{subexpression not valid in a constant expression}}
207   test:
208     return 1;
209   };
210   c(0);
211   constexpr auto c_ok = c(0); // cxx2a-error {{must be initialized by a constant expression}} \
212                               // cxx2a-note {{non-constexpr function}}
213 
214   constexpr auto c_error = c(1); // expected-error {{constexpr variable 'c_error' must be initialized by a constant expression}} \
215                                  // cxx2a-note {{non-constexpr function}} \
216                                  // cxx23-note {{in call to}}
217 
218   auto non_literal = [](bool b) { // cxx2a-note 2{{declared here}}
219     if (b)
220       NonLiteral n; // cxx23-note {{non-constexpr constructor 'NonLiteral' cannot be used in a constant expression}}
221     return 0;
222   };
223 
224   constexpr auto non_literal_ko = non_literal(true); // expected-error {{constexpr variable 'non_literal_ko' must be initialized by a constant expression}} \
225                                                      // cxx2a-note {{non-constexpr function}} \
226                                                      // cxx23-note {{in call}}
227 
228   constexpr auto non_literal_ok = non_literal(false); // cxx2a-error {{must be initialized by a constant expression}} \
229                                                       // cxx2a-note {{non-constexpr function}}
230 }
231 
232 template <typename T>
233 constexpr auto dependent_var_def_lambda() {
234   return [](bool b) { // cxx2a-note {{declared here}}
235     if (!b)
236       T t;
237     return 0;
238   };
239 }
240 
241 constexpr auto non_literal_valid_in_cxx23 = dependent_var_def_lambda<NonLiteral>()(true); // \
242     // cxx2a-error {{constexpr variable 'non_literal_valid_in_cxx23' must be initialized by a constant expression}} \
243     // cxx2a-note {{non-constexpr function}}
244 
245 
246 constexpr double evaluate_static_constexpr() {
247   struct Constexpr{
248     constexpr double f() const {
249       return 42;
250     }
251   };
252   thread_local constexpr Constexpr t; // cxx23-warning {{before C++23}}
253   static constexpr Constexpr s; // cxx23-warning {{before C++23}}
254   return t.f() + s.f();
255 }
256 static_assert(evaluate_static_constexpr() == 84);
257