diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-10-03 00:39:35 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-10-03 00:39:35 +0000 |
commit | b542602c5f351d66b0a4213f537fd6fb8dde8dcd (patch) | |
tree | 0c4be96a0f3b7a5e94398fee08c980c9f187a371 /clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | |
parent | 19ad5239713ce0f2742ca2f9e30ff4663ee5ad90 (diff) | |
download | bcm5719-llvm-b542602c5f351d66b0a4213f537fd6fb8dde8dcd.tar.gz bcm5719-llvm-b542602c5f351d66b0a4213f537fd6fb8dde8dcd.zip |
For P0784R7: support placement new-expressions in constant evaluation.
For now, we restrict this support to use from within the standard
library implementation, since we're required to make parts of the
standard library that use placement new work, but not permitted to
make uses of placement new from user code work.
llvm-svn: 373547
Diffstat (limited to 'clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp')
-rw-r--r-- | clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp index 5a39b33a87c..23582f2e302 100644 --- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp +++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp @@ -83,3 +83,86 @@ static_assert(mismatched(2, 2)); constexpr int *escape = std::allocator<int>().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}} constexpr int leak = (std::allocator<int>().allocate(3), 0); // expected-error {{constant expression}} constexpr int no_lifetime_start = (*std::allocator<int>().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}} + +void *operator new(std::size_t, void *p) { return p; } +constexpr bool no_placement_new_in_user_code() { // expected-error {{never produces a constant expression}} + int a; + new (&a) int(42); // expected-note {{call to placement 'operator new'}} + return a == 42; +} + +namespace std { + constexpr bool placement_new_in_stdlib() { + int a; + new (&a) int(42); + return a == 42; + } +} +static_assert(std::placement_new_in_stdlib()); + +namespace std { + template<typename T, typename ...Args> + constexpr void construct_at(void *p, Args &&...args) { + new (p) T((Args&&)args...); // #new + } +} + +constexpr bool call_std_construct_at() { + int *p = std::allocator<int>().allocate(3); + std::construct_at<int>(p, 1); + std::construct_at<int>(p + 1, 2); + std::construct_at<int>(p + 2, 3); + bool good = p[0] + p[1] + p[2] == 6; + std::allocator<int>().deallocate(p); + return good; +} +static_assert(call_std_construct_at()); + +constexpr bool bad_construct_at_type() { + int a; + // expected-note@#new {{placement new would change type of storage from 'int' to 'float'}} + std::construct_at<float>(&a, 1.0f); // expected-note {{in call}} + return true; +} +static_assert(bad_construct_at_type()); // expected-error{{}} expected-note {{in call}} + +constexpr bool bad_construct_at_subobject() { + struct X { int a, b; }; + union A { + int a; + X x; + }; + A a = {1}; + // expected-note@#new {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}} + std::construct_at<int>(&a.x.a, 1); // expected-note {{in call}} + return true; +} +static_assert(bad_construct_at_subobject()); // expected-error{{}} expected-note {{in call}} + +constexpr bool change_union_member() { + union U { + int a; + int b; + }; + U u = {.a = 1}; + std::construct_at<int>(&u.b, 2); + return u.b == 2; +} +static_assert(change_union_member()); + +int external; +// expected-note@#new {{visible outside}} +static_assert((std::construct_at<int>(&external, 1), true)); // expected-error{{}} expected-note {{in call}} + +constexpr int &&temporary = 0; // expected-note {{created here}} +// expected-note@#new {{construction of temporary is not allowed in a constant expression outside the expression that created the temporary}} +static_assert((std::construct_at<int>(&temporary, 1), true)); // expected-error{{}} expected-note {{in call}} + +constexpr bool construct_after_lifetime() { + int *p = new int; + delete p; + // expected-note@#new {{construction of heap allocated object that has been deleted}} + std::construct_at<int>(p); // expected-note {{in call}} + return true; +} +static_assert(construct_after_lifetime()); // expected-error {{}} expected-note {{in call}} |