xref: /llvm-project/clang/test/AST/ByteCode/cxx23.cpp (revision a0bd40e5a3df94229ec06243f2958289071ca75c)
1 // UNSUPPORTED:  target={{.*}}-zos{{.*}}
2 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref,ref20,all,all20 %s
3 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=ref,ref23,all,all23 %s
4 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
5 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter
6 
7 constexpr int f(int n) {  // all20-error {{constexpr function never produces a constant expression}}
8   static const int m = n; // all-note {{control flows through the definition of a static variable}} \
9                           // all20-note {{control flows through the definition of a static variable}} \
10                           // all20-warning {{is a C++23 extension}}
11 
12   return m;
13 }
14 static_assert(f(0) == 0, ""); // all-error {{not an integral constant expression}} \
15                               // all-note {{in call to}}
16 
17 constexpr int g(int n) {        // all20-error {{constexpr function never produces a constant expression}}
18   thread_local const int m = n; // all-note {{control flows through the definition of a thread_local variable}} \
19                                 // all20-note {{control flows through the definition of a thread_local variable}} \
20                                 // all20-warning {{is a C++23 extension}}
21   return m;
22 }
23 static_assert(g(0) == 0, ""); // all-error {{not an integral constant expression}} \
24                               // all-note {{in call to}}
25 
26 constexpr int c_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}}
27   static _Thread_local int m = 0;     // all20-note 2{{control flows through the definition of a thread_local variable}} \
28                                       // all23-note {{control flows through the definition of a thread_local variable}} \
29                                       // all20-warning {{is a C++23 extension}}
30   return m;
31 }
32 static_assert(c_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \
33                                            // all-note {{in call to}}
34 
35 
36 constexpr int gnu_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}}
37   static __thread int m = 0;            // all20-note 2{{control flows through the definition of a thread_local variable}} \
38                                         // all23-note {{control flows through the definition of a thread_local variable}} \
39                                         // all20-warning {{is a C++23 extension}}
40   return m;
41 }
42 static_assert(gnu_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \
43                                              // all-note {{in call to}}
44 
45 constexpr int h(int n) {  // all20-error {{constexpr function never produces a constant expression}}
46   static const int m = n; // all20-note {{control flows through the definition of a static variable}} \
47                           // all20-warning {{is a C++23 extension}}
48   return &m - &m;
49 }
50 
51 constexpr int i(int n) {        // all20-error {{constexpr function never produces a constant expression}}
52   thread_local const int m = n; // all20-note {{control flows through the definition of a thread_local variable}} \
53                                 // all20-warning {{is a C++23 extension}}
54   return &m - &m;
55 }
56 
57 constexpr int j(int n) {
58   if (!n)
59     return 0;
60   static const int m = n; // ref20-warning {{is a C++23 extension}} \
61                           // expected20-warning {{is a C++23 extension}}
62   return m;
63 }
64 constexpr int j0 = j(0);
65 
66 constexpr int k(int n) {
67   if (!n)
68     return 0;
69   thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \
70                                 // expected20-warning {{is a C++23 extension}}
71 
72   return m;
73 }
74 constexpr int k0 = k(0);
75 
76 namespace StaticLambdas {
77   constexpr auto static_capture_constexpr() {
78     char n = 'n';
79     return [n] static { return n; }(); // expected23-error {{a static lambda cannot have any captures}} \
80                                        // expected20-error {{a static lambda cannot have any captures}} \
81                                        // expected20-warning {{are a C++23 extension}} \
82                                        // expected20-warning {{is a C++23 extension}} \
83                                        // ref23-error {{a static lambda cannot have any captures}} \
84                                        // ref20-error {{a static lambda cannot have any captures}} \
85                                        // ref20-warning {{are a C++23 extension}} \
86                                        // ref20-warning {{is a C++23 extension}}
87   }
88   static_assert(static_capture_constexpr()); // expected23-error {{static assertion expression is not an integral constant expression}} \
89                                              // expected20-error {{static assertion expression is not an integral constant expression}} \
90                                              // ref23-error {{static assertion expression is not an integral constant expression}} \
91                                              // ref20-error {{static assertion expression is not an integral constant expression}}
92 
93   constexpr auto capture_constexpr() {
94     char n = 'n';
95     return [n] { return n; }();
96   }
97   static_assert(capture_constexpr());
98 }
99 
100 namespace StaticOperators {
101   auto lstatic = []() static { return 3; };  // ref20-warning {{C++23 extension}} \
102                                              // expected20-warning {{C++23 extension}}
103   static_assert(lstatic() == 3, "");
104   constexpr int (*f2)(void) = lstatic;
105   static_assert(f2() == 3);
106 
107   struct S1 {
108     constexpr S1() { // all20-error {{never produces a constant expression}}
109       throw; // all-note {{not valid in a constant expression}} \
110              // all20-note {{not valid in a constant expression}}
111     }
112     static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \
113                                                     // expected20-warning {{C++23 extension}}
114   };
115   static_assert(S1{}() == 3, ""); // all-error {{not an integral constant expression}} \
116                                   // all-note {{in call to}}
117 
118 
119 
120 }
121 
122 int test_in_lambdas() {
123   auto c = [](int n) constexpr {
124     if (n == 0)
125       return 0;
126     else
127       goto test; // all-note {{subexpression not valid in a constant expression}} \
128                  // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}
129   test:
130     return 1;
131   };
132   c(0);
133   constexpr auto A = c(1); // all-error {{must be initialized by a constant expression}} \
134                            // all-note {{in call to}}
135   return 0;
136 }
137 
138 /// PackIndexExpr.
139 template <auto... p>
140 struct check_ice {
141     enum e {
142         x = p...[0] // all-warning {{is a C++2c extension}}
143     };
144 };
145 static_assert(check_ice<42>::x == 42);
146 
147 
148 namespace VirtualBases {
149   namespace One {
150     struct U { int n; };
151     struct V : U { int n; };
152     struct A : virtual V { int n; };
153     struct Aa { int n; };
154     struct B : virtual A, Aa {};
155     struct C : virtual A, Aa {};
156     struct D : B, C {};
157 
158     /// Calls the constructor of D.
159     D d;
160   }
161 
162 #if __cplusplus >= 202302L
163   struct VBase {};
164   struct HasVBase : virtual VBase {}; // all23-note 1{{virtual base class declared here}}
165   struct Derived : HasVBase {
166     constexpr Derived() {} // all23-error {{constexpr constructor not allowed in struct with virtual base class}}
167   };
168   template<typename T> struct DerivedFromVBase : T {
169     constexpr DerivedFromVBase();
170   };
171   constexpr int f(DerivedFromVBase<HasVBase>) {}
172   template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
173   constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // all23-error {{constant expression}} \
174                                                             // all23-note {{cannot construct object of type 'DerivedFromVBase<VirtualBases::HasVBase>' with virtual base class in a constant expression}}
175 #endif
176 }
177 
178 namespace LabelGoto {
179   constexpr int foo() { // all20-error {{never produces a constant expression}}
180     a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}
181     goto a; // all20-note 2{{subexpression not valid in a constant expression}} \
182             // ref23-note {{subexpression not valid in a constant expression}} \
183             // expected23-note {{subexpression not valid in a constant expression}}
184 
185     return 1;
186   }
187   static_assert(foo() == 1, ""); // all-error {{not an integral constant expression}} \
188                                  // all-note {{in call to}}
189 }
190 
191 namespace ExplicitLambdaThis {
192   constexpr auto f = [x = 3]<typename Self>(this Self self) { // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}}
193       return x;
194   };
195   static_assert(f());
196 }
197 
198 namespace std {
199   struct strong_ordering {
200     int n;
201     constexpr operator int() const { return n; }
202     static const strong_ordering less, equal, greater;
203   };
204   constexpr strong_ordering strong_ordering::less = {-1};
205   constexpr strong_ordering strong_ordering::equal = {0};
206   constexpr strong_ordering strong_ordering::greater = {1};
207 }
208 
209 namespace UndefinedThreeWay {
210   struct A {
211     friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default; // all-note {{declared here}}
212   };
213 
214   constexpr std::strong_ordering operator<=>(const A&, const A&) noexcept;
215   constexpr std::strong_ordering (*test_a_threeway)(const A&, const A&) = &operator<=>;
216   static_assert(!(*test_a_threeway)(A(), A())); // all-error {{static assertion expression is not an integral constant expression}} \
217                                                 // all-note {{undefined function 'operator<=>' cannot be used in a constant expression}}
218 }
219 
220 /// FIXME: The new interpreter is missing the "initializer of q is not a constant expression" diagnostics.a
221 /// That's because the cast from void* to int* is considered fine, but diagnosed. So we don't consider
222 /// q to be uninitialized.
223 namespace VoidCast {
224   constexpr void* p = nullptr;
225   constexpr int* q = static_cast<int*>(p); // all-error {{must be initialized by a constant expression}} \
226                                            // all-note {{cast from 'void *' is not allowed in a constant expression}} \
227                                            // ref-note {{declared here}}
228   static_assert(q == nullptr); // ref-error {{not an integral constant expression}} \
229                                // ref-note {{initializer of 'q' is not a constant expression}}
230 }
231 
232 namespace ExplicitLambdaInstancePointer {
233   struct C {
234       constexpr C(auto) { }
235   };
236   void foo() {
237       constexpr auto b = [](this C) { return 1; }; // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}}
238       constexpr int (*fp)(C) = b;
239       static_assert(fp(1) == 1, "");
240   }
241 }
242 
243 namespace TwosComplementShifts {
244   using uint32 = __UINT32_TYPE__;
245   using int32 = __INT32_TYPE__;
246   static_assert(uint32(int32(0x1234) << 16) == 0x12340000);
247   static_assert(uint32(int32(0x1234) << 19) == 0x91a00000);
248   static_assert(uint32(int32(0x1234) << 20) == 0x23400000);
249   static_assert(uint32(int32(0x1234) << 24) == 0x34000000);
250   static_assert(uint32(int32(-1) << 31) == 0x80000000);
251 
252   static_assert(-2 >> 1 == -1);
253   static_assert(-3 >> 1 == -2);
254   static_assert(-7 >> 1 == -4);
255 }
256 
257 namespace AnonUnionDtor {
258   struct A {
259     A ();
260     ~A();
261   };
262 
263   template <class T>
264   struct opt
265   {
266     union {
267       char c;
268       T data;
269     };
270 
271     constexpr opt() {}
272 
273     constexpr ~opt()  {
274      if (engaged)
275        data.~T();
276    }
277 
278     bool engaged = false;
279   };
280 
281   consteval void foo() {
282     opt<A> a;
283   }
284 
285   void bar() { foo(); }
286 }
287 
288 /// FIXME: The two interpreters disagree about there to diagnose the non-constexpr destructor call.
289 namespace NonLiteralDtorInParam {
290   class NonLiteral { // all20-note {{is not an aggregate and has no constexpr constructors other than copy or move constructors}}
291   public:
292     NonLiteral() {}
293     ~NonLiteral() {} // all23-note {{declared here}}
294   };
295   constexpr int F2(NonLiteral N) { // all20-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} \
296                                    // ref23-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}
297     return 8;
298   }
299 
300 
301   void test() {
302     NonLiteral L;
303     constexpr auto D = F2(L); // all23-error {{must be initialized by a constant expression}} \
304                               // expected23-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}
305   }
306 }
307