526 lines · cpp
1// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s -DBYTECODE2// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -verify=ref,both %s3 4typedef __INT64_TYPE__ int64_t;5namespace std {6 using size_t = decltype(sizeof(0));7 template<typename T> struct allocator {8 constexpr T *allocate(size_t N) {9 return (T*)operator new(sizeof(T) * N);10 }11 constexpr void deallocate(void *p) {12 operator delete(p);13 }14 };15 template<typename T, typename ...Args>16 constexpr void construct_at(void *p, Args &&...args) {17 new (p) T((Args&&)args...); // both-note {{in call to}} \18 // both-note {{placement new would change type of storage from 'int' to 'float'}} \19 // both-note {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}} \20 // both-note {{construction of temporary is not allowed}} \21 // both-note {{construction of heap allocated object that has been deleted}} \22 // both-note {{construction of subobject of object outside its lifetime is not allowed in a constant expression}}23 }24}25 26void *operator new(std::size_t, void *p) { return p; }27void* operator new[] (std::size_t, void* p) {return p;}28 29constexpr int no_lifetime_start = (*std::allocator<int>().allocate(1) = 1); // both-error {{constant expression}} \30 // both-note {{assignment to object outside its lifetime}}31 32consteval auto ok1() {33 bool b;34 new (&b) bool(true);35 return b;36}37static_assert(ok1());38 39consteval auto ok2() {40 int b;41 new (&b) int(12);42 return b;43}44static_assert(ok2() == 12);45 46 47consteval auto ok3() {48 float b;49 new (&b) float(12.0);50 return b;51}52static_assert(ok3() == 12.0);53 54 55consteval auto ok4() {56 _BitInt(11) b;57 new (&b) _BitInt(11)(37);58 return b;59}60static_assert(ok4() == 37);61 62consteval int ok5() {63 int i;64 new (&i) int[1]{1};65 66 struct S {67 int a; int b;68 } s;69 new (&s) S[1]{{12, 13}};70 71 return 25;72 // return s.a + s.b; FIXME: Broken in the current interpreter.73}74static_assert(ok5() == 25);75 76/// FIXME: Broken in both interpreters.77#if 078consteval int ok5() {79 int i;80 new (&i) int[1]{1}; // expected-note {{assignment to dereferenced one-past-the-end pointer}}81 return i;82}83static_assert(ok5() == 1); // expected-error {{not an integral constant expression}} \84 // expected-note {{in call to}}85#endif86 87/// FIXME: Crashes the current interpreter.88#if 089consteval int ok6() {90 int i[2];91 new (&i) int(100);92 return i[0];93}94static_assert(ok6() == 100);95#endif96 97consteval int ok6() {98 int i[2];99 new (i) int(100);100 new (i + 1) int(200);101 return i[0] + i[1];102}103static_assert(ok6() == 300);104 105 106consteval auto fail1() {107 int b;108 new (&b) float(1.0); // both-note {{placement new would change type of storage from 'int' to 'float'}}109 return b;110}111static_assert(fail1() == 0); // both-error {{not an integral constant expression}} \112 // both-note {{in call to}}113 114consteval int fail2() {115 int i;116 new (static_cast<void*>(&i)) float(0); // both-note {{placement new would change type of storage from 'int' to 'float'}}117 return 0;118}119static_assert(fail2() == 0); // both-error {{not an integral constant expression}} \120 // both-note {{in call to}}121 122consteval int indeterminate() {123 int * indeterminate;124 new (indeterminate) int(0); // both-note {{read of uninitialized object is not allowed in a constant expression}}125 return 0;126}127static_assert(indeterminate() == 0); // both-error {{not an integral constant expression}} \128 // both-note {{in call to}}129 130consteval int array1() {131 int i[2];132 new (&i) int[]{1,2};133 return i[0] + i[1];134}135static_assert(array1() == 3);136 137consteval int array2() {138 int i[2];139 new (static_cast<void*>(&i)) int[]{1,2};140 return i[0] + i[1];141}142static_assert(array2() == 3);143 144consteval int array3() {145 int i[1];146 new (&i) int[2]; // both-note {{placement new would change type of storage from 'int[1]' to 'int[2]'}}147 return 0;148}149static_assert(array3() == 0); // both-error {{not an integral constant expression}} \150 // both-note {{in call to}}151 152consteval int array4() {153 int i[2];154 new (&i) int[]{12};155 return i[0];156}157static_assert(array4() == 12);158 159constexpr int *intptr() {160 return new int;161}162constexpr bool yay() {163 int *ptr = new (intptr()) int(42);164 bool ret = *ptr == 42;165 delete ptr;166 return ret;167}168static_assert(yay());169 170 171constexpr bool blah() {172 int *ptr = new (intptr()) int[3]{ 1, 2, 3 }; // both-note {{placement new would change type of storage from 'int' to 'int[3]'}}173 bool ret = ptr[0] == 1 && ptr[1] == 2 && ptr[2] == 3;174 delete [] ptr;175 return ret;176}177static_assert(blah()); // both-error {{not an integral constant expression}} \178 // both-note {{in call to 'blah()'}}179 180 181constexpr int *get_indeterminate() {182 int *evil;183 return evil; // both-note {{read of uninitialized object is not allowed in a constant expression}}184}185 186constexpr bool bleh() {187 int *ptr = new (get_indeterminate()) int; // both-note {{in call to 'get_indeterminate()'}}188 return true;189}190static_assert(bleh()); // both-error {{not an integral constant expression}} \191 // both-note {{in call to 'bleh()'}}192 193namespace records {194 class S {195 public:196 float f;197 };198 199 constexpr bool record1() {200 S s(13);201 new (&s) S(42);202 return s.f == 42;203 }204 static_assert(record1());205 206 S GlobalS;207 constexpr bool record2() {208 new (&GlobalS) S(42); // both-note {{a constant expression cannot modify an object that is visible outside that expression}}209 return GlobalS.f == 42;210 }211 static_assert(record2()); // both-error {{not an integral constant expression}} \212 // both-note {{in call to}}213 214 215 constexpr bool record3() {216 S ss[3];217 218 new (&ss) S[]{{1}, {2}, {3}};219 220 return ss[0].f == 1 && ss[1].f == 2 && ss[2].f == 3;221 }222 static_assert(record3());223 224 struct F {225 float f;226 };227 struct R {228 F f;229 int a;230 };231 constexpr bool record4() {232 R r;233 new (&r.f) F{42.0};234 new (&r.a) int(12);235 236 return r.f.f == 42.0 && r.a == 12;237 }238 static_assert(record4());239 240 /// Destructor is NOT called.241 struct A {242 bool b;243 constexpr ~A() { if (b) throw; }244 };245 246 constexpr int foo() {247 A a;248 new (&a) A(true);249 new (&a) A(false);250 return 0;251 }252 static_assert(foo() == 0);253}254 255namespace ConstructAt {256 struct S {257 int a = 10;258 float b = 1.0;259 };260 261 constexpr bool ok1() {262 S s;263 264 std::construct_at<S>(&s);265 return s.a == 10 && s.b == 1.0;266 }267 static_assert(ok1());268 269 struct S2 {270 constexpr S2() {271 (void)(1/0); // both-note {{division by zero}} \272 // both-warning {{division by zero is undefined}}273 }274 };275 276 constexpr bool ctorFail() { //277 S2 *s = std::allocator<S2>().allocate(1);278 std::construct_at<S2>(s); // both-note {{in call to}}279 280 return true;281 }282 static_assert(ctorFail()); // both-error {{not an integral constant expression}} \283 // both-note {{in call to 'ctorFail()'}}284 285 286 constexpr bool bad_construct_at_type() {287 int a;288 std::construct_at<float>(&a, 1.0f); // both-note {{in call to}}289 return true;290 }291 static_assert(bad_construct_at_type()); // both-error {{not an integral constant expression}} \292 // both-note {{in call}}293 294 constexpr bool bad_construct_at_subobject() {295 struct X { int a, b; };296 union A {297 int a;298 X x;299 };300 A a = {1};301 std::construct_at<int>(&a.x.a, 1); // both-note {{in call}}302 return true;303 }304 static_assert(bad_construct_at_subobject()); // both-error{{not an integral constant expression}} \305 // both-note {{in call}}306}307 308namespace UsedToCrash {309 struct S {310 int* i;311 constexpr S() : i(new int(42)) {} // #no-deallocation312 constexpr ~S() {delete i;}313 };314 consteval void alloc() {315 S* s = new S();316 s->~S();317 new (s) S();318 delete s;319 }320 int alloc1 = (alloc(), 0);321}322 323constexpr bool change_union_member() {324 union U {325 int a;326 int b;327 };328 U u = {.a = 1};329 std::construct_at<int>(&u.b, 2);330 return u.b == 2;331}332static_assert(change_union_member());333 334namespace PR48606 {335 struct A { mutable int n = 0; };336 337 constexpr bool f() {338 A a;339 A *p = &a;340 p->~A();341 std::construct_at<A>(p);342 return true;343 }344 static_assert(f());345}346 347/// This used to crash because of an assertion in the implementation348/// of the This instruction.349namespace ExplicitThisOnArrayElement {350 struct S {351 int a = 12;352 constexpr S(int a) {353 this->a = a;354 }355 };356 357 template <class _Tp, class... _Args>358 constexpr void construct_at(_Tp *__location, _Args &&...__args) {359 new (__location) _Tp(__args...);360 }361 362 constexpr bool foo() {363 auto *M = std::allocator<S>().allocate(13); // both-note {{allocation performed here was not deallocated}}364 construct_at(M, 12);365 return true;366 }367 368 static_assert(foo()); // both-error {{not an integral constant expression}}369}370 371#ifdef BYTECODE372constexpr int N = [] // expected-error {{must be initialized by a constant expression}} \373 // expected-note {{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \374 // expected-note {{in call to}}375{376 struct S {377 int a[1];378 };379 S s;380 ::new (s.a) int[1][2][3][4]();381 return s.a[0];382}();383#endif384 385namespace MemMove {386 constexpr int foo() {387 int *a = std::allocator<int>{}.allocate(1);388 new(a) int{123};389 390 int b;391 __builtin_memmove(&b, a, sizeof(int));392 393 std::allocator<int>{}.deallocate(a);394 return b;395 }396 397 static_assert(foo() == 123);398}399 400namespace Temp {401 constexpr int &&temporary = 0; // both-note {{created here}}402 static_assert((std::construct_at<int>(&temporary, 1), true)); // both-error{{not an integral constant expression}} \403 // both-note {{in call}}404}405 406namespace PlacementNewAfterDelete {407 constexpr bool construct_after_lifetime() {408 int *p = new int;409 delete p;410 std::construct_at<int>(p); // both-note {{in call}}411 return true;412 }413 static_assert(construct_after_lifetime()); // both-error {{}} \414 // both-note {{in call}}415}416 417namespace SubObj {418 constexpr bool construct_after_lifetime_2() {419 struct A { struct B {} b; };420 A a;421 a.~A();422 std::construct_at<A::B>(&a.b); // both-note {{in call}}423 return true;424 }425 static_assert(construct_after_lifetime_2()); // both-error {{}} both-note {{in call}}426}427 428namespace RecursiveLifetimeStart {429 struct B {430 int b;431 };432 433 struct A {434 B b;435 int a;436 };437 438 constexpr int foo() {439 A a;440 a.~A();441 442 new (&a) A();443 a.a = 10;444 a.b.b = 12;445 return a.a;446 }447 static_assert(foo() == 10);448}449 450namespace ArrayRoot {451 struct S {452 int a;453 };454 constexpr int foo() {455 S* ss = std::allocator<S>().allocate(2);456 new (ss) S{};457 new (ss + 1) S{};458 459 S* ps = &ss[2];460 ps = ss;461 ps->~S();462 463 std::allocator<S>().deallocate(ss);464 return 0;465 }466 467 static_assert(foo() == 0);468}469 470namespace bitcast {471 template <typename F, typename T>472 constexpr T bit_cast(const F &f) {473 return __builtin_bit_cast(T, f);474 }475 constexpr int foo() {476 double *d = std::allocator<double>{}.allocate(2);477 std::construct_at<double>(d, 0);478 479 double &dd = *d;480 481 int64_t i = bit_cast<double, int64_t>(*d);482 483 484 std::allocator<double>{}.deallocate(d);485 return i;486 }487 static_assert(foo() == 0);488}489 490constexpr int modify_const_variable() {491 const int a = 10;492 new ((int *)&a) int(12); // both-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}493 return a;494}495static_assert(modify_const_variable()); // both-error {{not an integral constant expression}} \496 // both-note {{in call to}}497 498constexpr int nullDest() {499 new (nullptr) int{12}; // both-note {{construction of dereferenced null pointer}}500 return 0;501}502static_assert(nullDest() == 0); // both-error {{not an integral constant expression}} \503 // both-note {{in call to}}504 505constexpr int nullArrayDest() {506 new (nullptr) int{12}; // both-note {{construction of dereferenced null pointer}}507 return 0;508}509static_assert(nullArrayDest() == 0); // both-error {{not an integral constant expression}} \510 // both-note {{in call to}}511 512constexpr int intDest() {513 new ((void*)2) int{3}; // both-note {{cast that performs the conversions of a reinterpret_cast}}514 return 0;515}516static_assert(intDest() == 0); // both-error {{not an integral constant expression}} \517 // both-note {{in call to}}518 519constexpr int intDestArray() {520 new ((void*)2) int[4]; // both-note {{cast that performs the conversions of a reinterpret_cast}}521 return 0;522}523static_assert(intDestArray() == 0); // both-error {{not an integral constant expression}} \524 // both-note {{in call to}}525 526