xref: /llvm-project/clang/test/AST/ByteCode/arrays.cpp (revision a0bd40e5a3df94229ec06243f2958289071ca75c)
1 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
2 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,both %s
3 // RUN: %clang_cc1 -verify=ref,both %s
4 // RUN: %clang_cc1 -verify=ref,both -std=c++20 %s
5 
6 constexpr int m = 3;
7 constexpr const int *foo[][5] = {
8   {nullptr, &m, nullptr, nullptr, nullptr},
9   {nullptr, nullptr, &m, nullptr, nullptr},
10   {nullptr, nullptr, nullptr, &m, nullptr},
11 };
12 
13 static_assert(foo[0][0] == nullptr, "");
14 static_assert(foo[0][1] == &m, "");
15 static_assert(foo[0][2] == nullptr, "");
16 static_assert(foo[0][3] == nullptr, "");
17 static_assert(foo[0][4] == nullptr, "");
18 static_assert(foo[1][0] == nullptr, "");
19 static_assert(foo[1][1] == nullptr, "");
20 static_assert(foo[1][2] == &m, "");
21 static_assert(foo[1][3] == nullptr, "");
22 static_assert(foo[1][4] == nullptr, "");
23 static_assert(foo[2][0] == nullptr, "");
24 static_assert(foo[2][1] == nullptr, "");
25 static_assert(foo[2][2] == nullptr, "");
26 static_assert(foo[2][3] == &m, "");
27 static_assert(foo[2][4] == nullptr, "");
28 
29 constexpr int afterEnd[] = {1,2,3};
30 static_assert(&afterEnd[3] == afterEnd + 3, "");
31 
32 constexpr int ZeroSizeArray[] = {};
33 
34 constexpr int SomeInt[] = {1};
35 constexpr int getSomeInt() { return *SomeInt; }
36 static_assert(getSomeInt() == 1, "");
37 
38 /// A init list for a primitive value.
39 constexpr int f{5};
40 static_assert(f == 5, "");
41 
42 
43 constexpr int getElement(int i) {
44   int values[] = {1, 4, 9, 16, 25, 36};
45   return values[i];
46 }
47 static_assert(getElement(1) == 4, "");
48 static_assert(getElement(5) == 36, "");
49 
50 constexpr int data[] = {5, 4, 3, 2, 1};
51 constexpr int getElement(const int *Arr, int index) {
52   return *(Arr + index);
53 }
54 
55 constexpr int derefPtr(const int *d) {
56   return *d;
57 }
58 static_assert(derefPtr(data) == 5, "");
59 
60 /// Make sure we can refer to the one-past-the-end element
61 /// and then return back to the end of the array.
62 static_assert((&data[5])[-1] == 1, "");
63 
64 constexpr int storePtr() {
65   int b[] = {1,2,3,4};
66   int *c = b;
67 
68   *c = 4;
69   return *c;
70 }
71 static_assert(storePtr() == 4, "");
72 
73 
74 static_assert(getElement(data, 1) == 4, "");
75 static_assert(getElement(data, 4) == 1, "");
76 
77 constexpr int getElementFromEnd(const int *Arr, int size, int index) {
78   return *(Arr + size - index - 1);
79 }
80 static_assert(getElementFromEnd(data, 5, 0) == 1, "");
81 static_assert(getElementFromEnd(data, 5, 4) == 5, "");
82 
83 constexpr int getFirstElem(const int *a) {
84   return a[0]; // both-note {{read of dereferenced null pointer}}
85 }
86 static_assert(getFirstElem(nullptr) == 1, ""); // both-error {{not an integral constant expression}} \
87                                                // both-note {{in call to}}
88 
89 constexpr static int arr[2] = {1,2};
90 constexpr static int arr2[2] = {3,4};
91 constexpr int *p1 = nullptr;
92 constexpr int *p2 = p1 + 1; // both-error {{must be initialized by a constant expression}} \
93                             // both-note {{cannot perform pointer arithmetic on null pointer}}
94 constexpr int *p3 = p1 + 0;
95 constexpr int *p4 = p1 - 0;
96 constexpr int *p5 =  0 + p1;
97 constexpr int *p6 =  0 - p1; // both-error {{invalid operands to binary expression}}
98 
99 constexpr int const * ap1 = &arr[0];
100 constexpr int const * ap2 = ap1 + 3; // both-error {{must be initialized by a constant expression}} \
101                                      // both-note {{cannot refer to element 3 of array of 2}}
102 
103 constexpr auto ap3 = arr - 1; // both-error {{must be initialized by a constant expression}} \
104                               // both-note {{cannot refer to element -1}}
105 constexpr int k1 = &arr[1] - &arr[0];
106 static_assert(k1 == 1, "");
107 static_assert((&arr[0] - &arr[1]) == -1, "");
108 
109 constexpr int k2 = &arr2[1] - &arr[0]; // both-error {{must be initialized by a constant expression}}
110 
111 static_assert((arr + 0) == arr, "");
112 static_assert(&arr[0] == arr, "");
113 static_assert(*(&arr[0]) == 1, "");
114 static_assert(*(&arr[1]) == 2, "");
115 
116 constexpr const int *OOB = (arr + 3) - 3; // both-error {{must be initialized by a constant expression}} \
117                                           // both-note {{cannot refer to element 3 of array of 2 elements}}
118 
119 template<typename T>
120 constexpr T getElementOf(T* array, int i) {
121   return array[i];
122 }
123 static_assert(getElementOf(foo[0], 1) == &m, "");
124 
125 
126 template <typename T, int N>
127 constexpr T& getElementOfArray(T (&array)[N], int I) {
128   return array[I];
129 }
130 static_assert(getElementOfArray(foo[2], 3) == &m, "");
131 
132 
133 static_assert(data[0] == 4, ""); // both-error{{failed}} \
134                                  // both-note{{5 == 4}}
135 
136 constexpr int dynamic[] = {
137   f, 3, 2 + 5, data[3], *getElementOf(foo[2], 3)
138 };
139 static_assert(dynamic[0] == f, "");
140 static_assert(dynamic[3] == 2, "");
141 
142 
143 constexpr int dependent[4] = {
144   0, 1, dependent[0], dependent[1]
145 };
146 static_assert(dependent[2] == dependent[0], "");
147 static_assert(dependent[3] == dependent[1], "");
148 
149 union { char x[]; } r = {0};
150 
151 #pragma clang diagnostic push
152 #pragma clang diagnostic ignored "-Wc99-extensions"
153 #pragma clang diagnostic ignored "-Winitializer-overrides"
154 constexpr int DI[] = {
155   [0] = 10,
156   [1] = 20,
157   30,
158   40,
159   [1] = 50
160 };
161 static_assert(DI[0] == 10, "");
162 static_assert(DI[1] == 50, "");
163 static_assert(DI[2] == 30, "");
164 static_assert(DI[3] == 40, "");
165 
166 constexpr int addThreeElements(const int v[3]) {
167   return v[0] + v[1] + v[2];
168 }
169 constexpr int is[] = {10, 20, 30 };
170 static_assert(addThreeElements(is) == 60, "");
171 
172 struct fred {
173   char s [6];
174   int n;
175 };
176 
177 struct fred y [] = { [0] = { .s[0] = 'q' } };
178 #pragma clang diagnostic pop
179 
180 namespace indices {
181   constexpr int first[] = {1};
182   constexpr int firstValue = first[2]; // both-error {{must be initialized by a constant expression}} \
183                                        // both-note {{cannot refer to element 2 of array of 1}}
184 
185   constexpr int second[10] = {17};
186   constexpr int secondValue = second[10];// both-error {{must be initialized by a constant expression}} \
187                                          // both-note {{read of dereferenced one-past-the-end pointer}} \
188 
189   constexpr int negative = second[-2]; // both-error {{must be initialized by a constant expression}} \
190                                        // both-note {{cannot refer to element -2 of array of 10}}
191 };
192 
193 namespace DefaultInit {
194   template <typename T, unsigned N>
195   struct B {
196     T a[N];
197   };
198 
199   int f() {
200      constexpr B<int,10> arr = {};
201      constexpr int x = arr.a[0];
202   }
203 };
204 
205 class A {
206 public:
207   int a;
208   constexpr A(int m = 2) : a(10 + m) {}
209 };
210 class AU {
211 public:
212   int a;
213   constexpr AU() : a(5 / 0) {} // both-warning {{division by zero is undefined}} \
214                                // both-note 2{{division by zero}} \
215                                // both-error {{never produces a constant expression}}
216 };
217 class B {
218 public:
219   A a[2];
220   constexpr B() {}
221 };
222 constexpr B b;
223 static_assert(b.a[0].a == 12, "");
224 static_assert(b.a[1].a == 12, "");
225 
226 class BU {
227 public:
228   AU a[2];
229   constexpr BU() {} // both-note {{in call to 'AU()'}}
230 };
231 constexpr BU bu; // both-error {{must be initialized by a constant expression}} \
232                  // both-note {{in call to 'BU()'}}
233 
234 namespace IncDec {
235   constexpr int getNextElem(const int *A, int I) {
236     const int *B = (A + I);
237     ++B;
238     return *B;
239   }
240   constexpr int E[] = {1,2,3,4};
241 
242   static_assert(getNextElem(E, 1) == 3, "");
243 
244   constexpr int getFirst() {
245     const int *e = E;
246     return *(e++);
247   }
248   static_assert(getFirst() == 1, "");
249 
250   constexpr int getFirst2() {
251     const int *e = E;
252     e++;
253     return *e;
254   }
255   static_assert(getFirst2() == 2, "");
256 
257   constexpr int getSecond() {
258     const int *e = E;
259     return *(++e);
260   }
261   static_assert(getSecond() == 2, "");
262 
263   constexpr int getSecond2() {
264     const int *e = E;
265     ++e;
266     return *e;
267   }
268   static_assert(getSecond2() == 2, "");
269 
270   constexpr int getLast() {
271     const int *e = E + 3;
272     return *(e--);
273   }
274   static_assert(getLast() == 4, "");
275 
276   constexpr int getLast2() {
277     const int *e = E + 3;
278     e--;
279     return *e;
280   }
281   static_assert(getLast2() == 3, "");
282 
283   constexpr int getSecondToLast() {
284     const int *e = E + 3;
285     return *(--e);
286   }
287   static_assert(getSecondToLast() == 3, "");
288 
289   constexpr int getSecondToLast2() {
290     const int *e = E + 3;
291     --e;
292     return *e;
293   }
294   static_assert(getSecondToLast2() == 3, "");
295 
296   constexpr int bad1() { // both-error {{never produces a constant expression}}
297     const int *e =  E + 3;
298     e++; // This is fine because it's a one-past-the-end pointer
299     return *e; // both-note 2{{read of dereferenced one-past-the-end pointer}}
300   }
301   static_assert(bad1() == 0, ""); // both-error {{not an integral constant expression}} \
302                                   // both-note {{in call to}}
303 
304   constexpr int bad2() { // both-error {{never produces a constant expression}}
305     const int *e = E + 4;
306     e++; // both-note 2{{cannot refer to element 5 of array of 4 elements}}
307     return *e; // This is UB as well
308   }
309   static_assert(bad2() == 0, ""); // both-error {{not an integral constant expression}} \
310                                   // both-note {{in call to}}
311 
312   constexpr int bad3() { // both-error {{never produces a constant expression}}
313     const int *e = E;
314     e--; // both-note 2{{cannot refer to element -1 of array of 4 elements}}
315     return *e; // This is UB as well
316   }
317    static_assert(bad3() == 0, ""); // both-error {{not an integral constant expression}} \
318                                    // both-note {{in call to}}
319 
320   constexpr int nullptr1(bool Pre) {
321     int *a = nullptr;
322     if (Pre)
323       ++a; // both-note {{arithmetic on null pointer}}
324     else
325       a++; // both-note {{arithmetic on null pointer}}
326     return 1;
327   }
328   static_assert(nullptr1(true) == 1, ""); // both-error {{not an integral constant expression}} \
329                                           // both-note {{in call to}}
330 
331   static_assert(nullptr1(false) == 1, ""); // both-error {{not an integral constant expression}} \
332                                            // both-note {{in call to}}
333 };
334 
335 namespace ZeroInit {
336   struct A {
337     int *p[2];
338   };
339   constexpr A a = {};
340   static_assert(a.p[0] == nullptr, "");
341   static_assert(a.p[1] == nullptr, "");
342 
343   struct B {
344     double f[2];
345   };
346   constexpr B b = {};
347   static_assert(b.f[0] == 0.0, "");
348   static_assert(b.f[1] == 0.0, "");
349 }
350 
351 namespace ArrayInitLoop {
352   struct X {
353       int arr[3];
354   };
355   constexpr X f(int &r) {
356       return {++r, ++r, ++r};
357   }
358   constexpr int g() {
359       int n = 0;
360       auto [a, b, c] = f(n).arr;
361       return a + b + c;
362   }
363   static_assert(g() == 6, "");
364 }
365 
366 namespace StringZeroFill {
367   struct A {
368     char c[6];
369   };
370   constexpr A a = { "abc" };
371   static_assert(a.c[0] == 'a', "");
372   static_assert(a.c[1] == 'b', "");
373   static_assert(a.c[2] == 'c', "");
374   static_assert(a.c[3] == '\0', "");
375   static_assert(a.c[4] == '\0', "");
376   static_assert(a.c[5] == '\0', "");
377 
378   constexpr char b[6] = "foo";
379   static_assert(b[0] == 'f', "");
380   static_assert(b[1] == 'o', "");
381   static_assert(b[2] == 'o', "");
382   static_assert(b[3] == '\0', "");
383   static_assert(b[4] == '\0', "");
384   static_assert(b[5] == '\0', "");
385 }
386 
387 namespace NoInitMapLeak {
388 #pragma clang diagnostic push
389 #pragma clang diagnostic ignored "-Wdivision-by-zero"
390 #pragma clang diagnostic ignored "-Wc++20-extensions"
391   constexpr int testLeak() { // both-error {{never produces a constant expression}}
392     int a[2];
393     a[0] = 1;
394     // interrupts interpretation.
395     (void)(1 / 0); // both-note 2{{division by zero}}
396 
397     return 1;
398   }
399 #pragma clang diagnostic pop
400   static_assert(testLeak() == 1, ""); // both-error {{not an integral constant expression}} \
401                                       // both-note {{in call to 'testLeak()'}}
402 
403   constexpr int a[] = {1,2,3,4/0,5}; // both-error {{must be initialized by a constant expression}} \
404                                      // both-note {{division by zero}} \
405                                      // ref-note {{declared here}}
406 
407   /// FIXME: This should fail in the new interpreter as well.
408   constexpr int b = a[0]; // ref-error {{must be initialized by a constant expression}} \
409                           // ref-note {{is not a constant expression}} \
410                           // ref-note {{declared here}}
411   static_assert(b == 1, ""); // ref-error {{not an integral constant expression}} \
412                              // ref-note {{not a constant expression}}
413 
414   constexpr int f() { // both-error {{never produces a constant expression}}
415     int a[] = {19,2,3/0,4}; // both-note 2{{division by zero}} \
416                             // both-warning {{is undefined}}
417     return 1;
418   }
419   static_assert(f() == 1, ""); // both-error {{not an integral constant expression}} \
420                                // both-note {{in call to}}
421 }
422 
423 namespace Incomplete {
424   struct Foo {
425     char c;
426     int a[];
427   };
428 
429   constexpr Foo F{};
430   constexpr const int *A = F.a; // both-error {{must be initialized by a constant expression}} \
431                                 // both-note {{array-to-pointer decay of array member without known bound}}
432 
433   constexpr const int *B = F.a + 1; // both-error {{must be initialized by a constant expression}} \
434                                     // both-note {{array-to-pointer decay of array member without known bound}}
435 
436   constexpr int C = *F.a; // both-error {{must be initialized by a constant expression}} \
437                           // both-note {{array-to-pointer decay of array member without known bound}}
438 
439   struct X {
440     int a;
441     int b[];
442   };
443   extern X x;
444   constexpr int *xb = x.b; // both-error {{must be initialized by a constant expression}} \
445                            // both-note {{array-to-pointer decay of array member without known bound}}
446 
447 
448   /// These are from test/SemaCXX/constant-expression-cxx11.cpp
449   extern int arr[];
450   constexpr int *c = &arr[1]; // both-error  {{must be initialized by a constant expression}} \
451                               // both-note {{indexing of array without known bound}}
452   constexpr int *d = &arr[1]; // both-error  {{must be initialized by a constant expression}} \
453                               // both-note {{indexing of array without known bound}}
454   constexpr int *e = arr + 1; // both-error  {{must be initialized by a constant expression}} \
455                               // both-note {{indexing of array without known bound}}
456 }
457 
458 namespace GH69115 {
459   /// This used to crash because we were trying to emit destructors for the
460   /// array.
461   constexpr int foo() {
462     int arr[2][2] = {1, 2, 3, 4};
463     return 0;
464   }
465   static_assert(foo() == 0, "");
466 
467   /// Test that we still emit the destructors for multi-dimensional
468   /// composite arrays.
469 #if __cplusplus >= 202002L
470   constexpr void assert(bool C) {
471     if (C)
472       return;
473     // Invalid in constexpr.
474     (void)(1 / 0); // both-warning {{undefined}}
475   }
476 
477   class F {
478   public:
479     int a;
480     int *dtor;
481     int &idx;
482     constexpr F(int a, int *dtor, int &idx) : a(a), dtor(dtor), idx(idx) {}
483     constexpr ~F() noexcept(false){
484       dtor[idx] = a;
485       ++idx;
486     }
487   };
488   constexpr int foo2() {
489     int dtorIndices[] = {0, 0, 0, 0};
490     int idx = 0;
491 
492     {
493       F arr[2][2] = {F(1, dtorIndices, idx),
494                      F(2, dtorIndices, idx),
495                      F(3, dtorIndices, idx),
496                      F(4, dtorIndices, idx)};
497     }
498 
499     /// Reverse-reverse order.
500     assert(idx == 4);
501     assert(dtorIndices[0] == 4);
502     assert(dtorIndices[1] == 3);
503     assert(dtorIndices[2] == 2);
504     assert(dtorIndices[3] == 1);
505 
506     return 0;
507   }
508   static_assert(foo2() == 0, "");
509 #endif
510 }
511 
512 namespace NonConstReads {
513 #if __cplusplus >= 202002L
514   void *p = nullptr; // both-note {{declared here}}
515 
516   int arr[!p]; // both-error {{not allowed at file scope}} \
517                // both-warning {{variable length arrays}} \
518                // both-note {{read of non-constexpr variable 'p'}}
519   int z; // both-note {{declared here}}
520   int a[z]; // both-error {{not allowed at file scope}} \
521             // both-warning {{variable length arrays}} \
522             // both-note {{read of non-const variable 'z'}}
523 #else
524   void *p = nullptr;
525   int arr[!p]; // both-error {{not allowed at file scope}}
526   int z;
527   int a[z]; // both-error {{not allowed at file scope}}
528 #endif
529 
530   const int y = 0;
531   int yy[y];
532 }
533 
534 namespace SelfComparison {
535   struct S {
536     int field;
537     static int static_field;
538     int array[4];
539   };
540 
541   struct T {
542     int field;
543     static int static_field;
544     int array[4];
545     S s;
546   };
547 
548   int struct_test(S s1, S s2, S *s3, T t) {
549     return s3->array[t.field] == s3->array[t.field];  // both-warning {{self-comparison always evaluates to true}}
550   };
551 }
552 
553 namespace LocalIndex {
554   void test() {
555     const int const_subscript = 3;
556     int array[2]; // both-note {{declared here}}
557     array[const_subscript] = 0;  // both-warning {{array index 3 is past the end of the array (that has type 'int[2]')}}
558   }
559 }
560 
561 namespace LocalVLA {
562   struct Foo {
563     int x;
564     Foo(int x) : x(x) {}
565   };
566   struct Elidable {
567     Elidable();
568   };
569 
570   void foo(int size) {
571     Elidable elidableDynArray[size];
572 #if __cplusplus >= 202002L
573      // both-note@-3 {{declared here}}
574      // both-warning@-3 {{variable length array}}
575      // both-note@-4 {{function parameter 'size' with unknown value}}
576 #endif
577   }
578 
579   void f (unsigned int m) {
580     int e[2][m];
581 #if __cplusplus >= 202002L
582      // both-note@-3 {{declared here}}
583      // both-warning@-3 2{{variable length array}}
584      // both-note@-4 {{function parameter 'm' with unknown value}}
585 #endif
586     e[0][0] = 0;
587   }
588 }
589 
590 char melchizedek[2];
591 typedef decltype(melchizedek[1] - melchizedek[0]) ptrdiff_t;
592 constexpr ptrdiff_t d1 = &melchizedek[1] - &melchizedek[0]; // ok
593 constexpr ptrdiff_t d3 = &melchizedek[0] - &melchizedek[1]; // ok
594 
595 /// GH#88018
596 const int SZA[] = {};
597 void testZeroSizedArrayAccess() { unsigned c = SZA[4]; }
598 
599 #if __cplusplus >= 202002L
600 constexpr int test_multiarray2() { // both-error {{never produces a constant expression}}
601   int multi2[2][1]; // both-note {{declared here}}
602   return multi2[2][0]; // both-note {{cannot access array element of pointer past the end of object}} \
603                        // both-warning {{array index 2 is past the end of the array (that has type 'int[2][1]')}}
604 }
605 
606 /// Same but with a dummy pointer.
607 int multi22[2][2]; // both-note {{declared here}}
608 int test_multiarray22() {
609   return multi22[2][0]; // both-warning {{array index 2 is past the end of the array (that has type 'int[2][2]')}}
610 }
611 
612 #endif
613 
614 namespace ArrayMemberAccess {
615   struct A {
616     int x;
617   };
618   void f(const A (&a)[]) {
619     bool cond = a->x;
620   }
621 }
622 
623 namespace OnePastEndSub {
624   struct A {};
625   constexpr A a[3][3];
626   constexpr int diff2 = &a[1][3] - &a[1][0]; /// Used to crash.
627 }
628 
629 static int same_entity_2[3];
630 constexpr int *get2() {
631   // This is a redeclaration of the same entity, even though it doesn't
632   // inherit the type of the prior declaration.
633   extern int same_entity_2[];
634   return same_entity_2;
635 }
636 static_assert(get2() == same_entity_2, "failed to find previous decl");
637 
638 constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
639 constexpr int fail(const int &p) {
640   return (&p)[64]; // both-note {{cannot refer to element 64 of array of 2 elements}}
641 }
642 static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // both-error {{not an integral constant expression}} \
643                                                                                     // both-note {{in call to}}
644 
645 namespace ZeroSizeTypes {
646   constexpr int (*p1)[0] = 0, (*p2)[0] = 0;
647   constexpr int k = p2 - p1; // both-error {{constexpr variable 'k' must be initialized by a constant expression}} \
648                              // both-note {{subtraction of pointers to type 'int[0]' of zero size}} \
649                              // both-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}}
650 
651   int arr[5][0];
652   constexpr int f() { // both-error {{never produces a constant expression}}
653     return &arr[3] - &arr[0]; // both-note {{subtraction of pointers to type 'int[0]' of zero size}} \
654                               // both-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}}
655   }
656 }
657