// RUN: %clang_cc1 -std=c++20 -verify -fconstexpr-steps=1024 -Wvla %s namespace std { using size_t = decltype(sizeof(0)); } void *operator new(std::size_t, void *p) { return p; } namespace std { template struct allocator { constexpr T *allocate(size_t N) { return (T*)operator new(sizeof(T) * N); // #alloc } constexpr void deallocate(void *p) { operator delete(p); } }; template constexpr void construct_at(void *p, Args &&...args) { // #construct new (p) T((Args&&)args...); } } namespace GH63562 { template struct S { constexpr S(unsigned long long N) : data(nullptr){ data = alloc.allocate(N); // #call for(std::size_t i = 0; i < N; i ++) std::construct_at(data + i, i); // #construct_call } constexpr T operator[](std::size_t i) const { return data[i]; } constexpr ~S() { alloc.deallocate(data); } std::allocator alloc; T* data; }; // Only run these tests on 64 bits platforms #if __LP64__ constexpr std::size_t s = S(~0UL)[42]; // expected-error {{constexpr variable 's' must be initialized by a constant expression}} \ // expected-note-re@#call {{in call to 'this->alloc.allocate({{.*}})'}} \ // expected-note-re@#alloc {{cannot allocate array; evaluated array bound {{.*}} is too large}} \ // expected-note-re {{in call to 'S({{.*}})'}} #endif // Check that we do not try to fold very large arrays std::size_t s2 = S(~0UL)[42]; std::size_t s3 = S(~0ULL)[42]; // We can allocate and initialize a small array constexpr std::size_t ssmall = S(100)[42]; // We can allocate this array but we hikt the number of steps constexpr std::size_t s4 = S(1024)[42]; // expected-error {{constexpr variable 's4' must be initialized by a constant expression}} \ // expected-note@#construct {{constexpr evaluation hit maximum step limit; possible infinite loop?}} \ // expected-note@#construct_call {{in call}} \ // expected-note {{in call}} constexpr std::size_t s5 = S(1025)[42]; // expected-error{{constexpr variable 's5' must be initialized by a constant expression}} \ // expected-note@#alloc {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}} \ // expected-note@#call {{in call to 'this->alloc.allocate(1025)'}} \ // expected-note {{in call}} // Check we do not perform constant initialization in the presence // of very large arrays (this used to crash) template constexpr int stack_array() { [[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}} return BIG[N-1]; } int a = stack_array<~0U>(); int c = stack_array<1024>(); int d = stack_array<1025>(); constexpr int e = stack_array<1024>(); constexpr int f = stack_array<1025>(); // expected-error {{constexpr variable 'f' must be initialized by a constant expression}} \ // expected-note {{in call}} void ohno() { int bar[stack_array<1024>()]; int foo[stack_array<1025>()]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \ // expected-note {{in call to 'stack_array<1025>()'}} constexpr int foo[stack_array<1025>()]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \ // expected-error {{constexpr variable cannot have non-literal type 'const int[stack_array<1025>()]'}} \ // expected-note {{in call to 'stack_array<1025>()'}} } }