xref: /llvm-project/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp (revision 84a3aadf0f2483dde0acfc4e79f2a075a5f35bd1)
1 // RUN: %clang_cc1 -std=c++20 -verify -fconstexpr-steps=1024 -Wvla %s
2 
3 namespace std {
4   using size_t = decltype(sizeof(0));
5 }
6 
operator new(std::size_t,void * p)7 void *operator new(std::size_t, void *p) { return p; }
8 
9 namespace std {
10   template<typename T> struct allocator {
allocatestd::allocator11     constexpr T *allocate(size_t N) {
12       return (T*)operator new(sizeof(T) * N); // #alloc
13     }
deallocatestd::allocator14     constexpr void deallocate(void *p) {
15       operator delete(p);
16     }
17   };
18   template<typename T, typename ...Args>
construct_at(void * p,Args &&...args)19   constexpr void construct_at(void *p, Args &&...args) { // #construct
20     new (p) T((Args&&)args...);
21   }
22 }
23 
24 namespace GH63562 {
25 
26 template <typename T>
27 struct S {
SGH63562::S28     constexpr S(unsigned long long N)
29     : data(nullptr){
30         data = alloc.allocate(N);  // #call
31         for(std::size_t i = 0; i < N; i ++)
32             std::construct_at<T>(data + i, i); // #construct_call
33     }
operator []GH63562::S34     constexpr T operator[](std::size_t i) const {
35       return data[i];
36     }
37 
~SGH63562::S38     constexpr ~S() {
39         alloc.deallocate(data);
40     }
41     std::allocator<T> alloc;
42     T* data;
43 };
44 
45 // Only run these tests on 64 bits platforms
46 #if __LP64__
47 constexpr std::size_t s = S<std::size_t>(~0UL)[42]; // expected-error {{constexpr variable 's' must be initialized by a constant expression}} \
48                                            // expected-note-re@#call {{in call to 'this->alloc.allocate({{.*}})'}} \
49                                            // expected-note-re@#alloc {{cannot allocate array; evaluated array bound {{.*}} is too large}} \
50                                            // expected-note-re {{in call to 'S({{.*}})'}}
51 #endif
52 // Check that we do not try to fold very large arrays
53 std::size_t s2 = S<std::size_t>(~0UL)[42];
54 std::size_t s3 = S<std::size_t>(~0ULL)[42];
55 
56 // We can allocate and initialize a small array
57 constexpr std::size_t ssmall = S<std::size_t>(100)[42];
58 
59 // We can allocate this array but we hikt the number of steps
60 constexpr std::size_t s4 = S<std::size_t>(1024)[42]; // expected-error {{constexpr variable 's4' must be initialized by a constant expression}} \
61                                    // expected-note@#construct {{constexpr evaluation hit maximum step limit; possible infinite loop?}} \
62                                    // expected-note@#construct_call {{in call}} \
63                                    // expected-note {{in call}}
64 
65 
66 
67 constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // expected-error{{constexpr variable 's5' must be initialized by a constant expression}} \
68                                    // expected-note@#alloc {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}} \
69                                    // expected-note@#call {{in call to 'this->alloc.allocate(1025)'}} \
70                                    // expected-note {{in call}}
71 
72 
73 // Check we do not perform constant initialization in the presence
74 // of very large arrays (this used to crash)
75 
76 template <auto N>
stack_array()77 constexpr int stack_array() {
78     [[maybe_unused]] char BIG[N] = {1};  // expected-note  3{{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}}
79     return BIG[N-1];
80 }
81 
82 int a = stack_array<~0U>();
83 int c = stack_array<1024>();
84 int d = stack_array<1025>();
85 constexpr int e = stack_array<1024>();
86 constexpr int f = stack_array<1025>(); // expected-error {{constexpr variable 'f' must be initialized by a constant expression}} \
87                                        //  expected-note {{in call}}
ohno()88 void ohno() {
89   int bar[stack_array<1024>()];
90   int foo[stack_array<1025>()]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \
91                                 // expected-note {{in call to 'stack_array<1025>()'}}
92 
93   constexpr int foo[stack_array<1025>()]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \
94                                           // expected-error {{constexpr variable cannot have non-literal type 'const int[stack_array<1025>()]'}} \
95                                           // expected-note {{in call to 'stack_array<1025>()'}}
96 }
97 
98 }
99