[clang] [Clang] Implement P2747 constexpr placement new (PR #104586)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 16 08:19:41 PDT 2024
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/104586
>From 36eb12a12db45ca345fe9a3945431c19eff2a6cf Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Jul 2024 08:37:18 +0200
Subject: [PATCH 1/2] [Clang] Implement P2747 constexpr placement new
In C++26 and as an extension in C++20
---
clang/docs/LanguageExtensions.rst | 1 +
clang/docs/ReleaseNotes.rst | 5 +-
.../include/clang/Basic/DiagnosticASTKinds.td | 2 +-
clang/lib/AST/ExprConstant.cpp | 55 +++++++------
clang/lib/Frontend/InitPreprocessor.cpp | 2 +-
clang/test/AST/Interp/new-delete.cpp | 4 +-
clang/test/CXX/drs/cwg29xx.cpp | 26 ++++++
clang/test/Lexer/cxx-features.cpp | 2 +-
.../SemaCXX/constant-expression-cxx2a.cpp | 2 +-
.../test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | 82 ++++++++++++++++++-
clang/www/cxx_dr_status.html | 2 +-
clang/www/cxx_status.html | 2 +-
12 files changed, 151 insertions(+), 34 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 114e742f3561b7..296bb85f5e72b2 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1506,6 +1506,7 @@ Attributes on Structured Bindings __cpp_structured_bindings C+
Pack Indexing __cpp_pack_indexing C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
Variadic Friends __cpp_variadic_friend C++26 C++03
+``constexpr`` placement new __cpp_constexpr C++26 C++20
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ffdd063ec99037..22864062fba7fd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -73,7 +73,7 @@ C++ Specific Potentially Breaking Changes
template <> // error: extraneous template head
template <typename T>
void f();
-
+
ABI Changes in This Version
---------------------------
@@ -131,6 +131,9 @@ C++2c Feature Support
- Implemented `P2893R3 Variadic Friends <https://wg21.link/P2893>`_
+- Implemented `P2747R2 constexpr placement new <https://wg21.link/P2747R2>`_.
+
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index f317c5ac44f32b..569d2cc20a526c 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -335,7 +335,7 @@ def note_constexpr_new_non_replaceable : Note<
def note_constexpr_new_placement : Note<
"this placement new expression is not yet supported in constant expressions">;
def note_constexpr_placement_new_wrong_type : Note<
- "placement new would change type of storage from %0 to %1">;
+ "placement new would change type of storage from %0 to %1">;
def note_constexpr_new_negative : Note<
"cannot allocate array; evaluated array bound %0 is negative">;
def note_constexpr_new_too_large : Note<
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 09edbb6641650a..20c1fd6747d582 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6691,7 +6691,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
if (Size && Size > Value.getArrayInitializedElts())
expandArray(Value, Value.getArraySize() - 1);
- for (; Size != 0; --Size) {
+ for (Size = Value.getArraySize(); Size != 0; --Size) {
APValue &Elem = Value.getArrayInitializedElt(Size - 1);
if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, -1) ||
!HandleDestructionImpl(Info, CallRange, ElemLV, Elem, ElemT))
@@ -10003,23 +10003,14 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
return false;
FunctionDecl *OperatorNew = E->getOperatorNew();
+ QualType AllocType = E->getAllocatedType();
+ QualType TargetType = AllocType;
bool IsNothrow = false;
bool IsPlacement = false;
- if (OperatorNew->isReservedGlobalPlacementOperator() &&
- Info.CurrentCall->isStdFunction() && !E->isArray()) {
- // FIXME Support array placement new.
- assert(E->getNumPlacementArgs() == 1);
- if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
- return false;
- if (Result.Designator.Invalid)
- return false;
- IsPlacement = true;
- } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
- Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
- << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
- return false;
- } else if (E->getNumPlacementArgs()) {
+
+ if (E->getNumPlacementArgs() && E->getNumPlacementArgs() == 1 &&
+ E->getPlacementArg(0)->getType()->isNothrowT()) {
// The only new-placement list we support is of the form (std::nothrow).
//
// FIXME: There is no restriction on this, but it's not clear that any
@@ -10030,14 +10021,25 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
// (which should presumably be valid only if N is a multiple of
// alignof(int), and in any case can't be deallocated unless N is
// alignof(X) and X has new-extended alignment).
- if (E->getNumPlacementArgs() != 1 ||
- !E->getPlacementArg(0)->getType()->isNothrowT())
- return Error(E, diag::note_constexpr_new_placement);
-
LValue Nothrow;
if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
return false;
IsNothrow = true;
+ } else if (OperatorNew->isReservedGlobalPlacementOperator()) {
+ if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
+ return false;
+ if (Result.Designator.Invalid)
+ return false;
+ /// if(!lifetimeStartedInEvaluation(Info, Result.getLValueBase()))
+ // return false;
+ TargetType = E->getPlacementArg(0)->getType();
+ IsPlacement = true;
+ } else if (E->getNumPlacementArgs()) {
+ return Error(E, diag::note_constexpr_new_placement);
+ } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
+ return false;
}
const Expr *Init = E->getInitializer();
@@ -10045,7 +10047,6 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
const CXXConstructExpr *ResizedArrayCCE = nullptr;
bool ValueInit = false;
- QualType AllocType = E->getAllocatedType();
if (std::optional<const Expr *> ArraySize = E->getArraySize()) {
const Expr *Stripped = *ArraySize;
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
@@ -10139,9 +10140,17 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool found(APValue &Subobj, QualType SubobjType) {
// FIXME: Reject the cases where [basic.life]p8 would not permit the
// old name of the object to be used to name the new object.
- if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) {
- Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) <<
- SubobjType << AllocType;
+ unsigned SubobjectSize = 1;
+ unsigned AllocSize = 1;
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
+ AllocSize = CAT->getZExtSize();
+ if (auto *CAT = dyn_cast<ConstantArrayType>(SubobjType))
+ SubobjectSize = CAT->getZExtSize();
+ if (SubobjectSize < AllocSize ||
+ !Info.Ctx.hasSimilarType(Info.Ctx.getBaseElementType(SubobjType),
+ Info.Ctx.getBaseElementType(AllocType))) {
+ Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type)
+ << SubobjType << AllocType;
return false;
}
Value = &Subobj;
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 4f2856dd2247f8..61260a3379828d 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -660,7 +660,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_unicode_literals", "200710L");
Builder.defineMacro("__cpp_user_defined_literals", "200809L");
Builder.defineMacro("__cpp_lambdas", "200907L");
- Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus26 ? "202306L"
+ Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus26 ? "202406L"
: LangOpts.CPlusPlus23 ? "202211L"
: LangOpts.CPlusPlus20 ? "201907L"
: LangOpts.CPlusPlus17 ? "201603L"
diff --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp
index 6bb30bc19f110c..0c823e7000f853 100644
--- a/clang/test/AST/Interp/new-delete.cpp
+++ b/clang/test/AST/Interp/new-delete.cpp
@@ -245,7 +245,7 @@ namespace std {
namespace PlacementNew {
constexpr int foo() { // both-error {{never produces a constant expression}}
char c[sizeof(int)];
- new (c) int{12}; // ref-note {{call to placement 'operator new'}} \
+ new (c) int{12}; // ref-note {{placement new would change type of storage from 'char' to 'int'}} \
// expected-note {{subexpression not valid in a constant expression}}
return 0;
}
@@ -309,7 +309,7 @@ namespace placement_new_delete {
constexpr bool bad(int which) {
switch (which) {
case 0:
- delete new (placement_new_arg{}) int; // ref-note {{call to placement 'operator new'}} \
+ delete new (placement_new_arg{}) int; // ref-note {{this placement new expression is not yet supported in constant expression}} \
// expected-note {{subexpression not valid in a constant expression}}
break;
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index 8cac9f283980b6..7e04aa0c3a4942 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -23,3 +23,29 @@ struct S {
friend class C<Ts>::Nested...; // expected-error {{friend declaration expands pack 'Ts' that is declared it its own template parameter list}}
};
} // namespace cwg2917
+
+#if __cplusplus >= 202002
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+};
+void *operator new(std::size_t, void *p) { return p; }
+void* operator new[] (std::size_t, void* p) {return p;}
+
+
+namespace cwg2922 { // cwg2922: 20 open 2024-07-10
+union U { int a, b; };
+constexpr U nondeterministic(bool i) {
+ if(i) {
+ U u;
+ new (&u) int();
+ // expected-note at -1 {{placement new would change type of storage from 'U' to 'int'}}
+ return u;
+ }
+ return {};
+}
+constexpr U _ = nondeterministic(true);
+// expected-error at -1 {{constexpr variable '_' must be initialized by a constant expression}} \
+// expected-note at -1 {{in call to 'nondeterministic(true)'}}
+}
+#endif
diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp
index 1c51013ca06f77..4a06d29ae9dbc6 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -317,7 +317,7 @@
#error "wrong value for __cpp_lambdas"
#endif
-#if check(constexpr, 0, 200704, 201304, 201603, 201907, 202211, 202306)
+#if check(constexpr, 0, 200704, 201304, 201603, 201907, 202211, 202406L)
#error "wrong value for __cpp_constexpr"
#endif
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index e4d97dcb73562d..b8cbf723a96a76 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -994,7 +994,7 @@ namespace placement_new_delete {
constexpr bool bad(int which) {
switch (which) {
case 0:
- delete new (placement_new_arg{}) int; // expected-note {{call to placement 'operator new'}}
+ delete new (placement_new_arg{}) int; // expected-note {{this placement new expression is not yet supported in constant expressions}}
break;
case 1:
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
index 357dc67bd5ad22..b02c90b88d1ac6 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
@@ -90,9 +90,10 @@ constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&
// expected-note at -2 {{declared here}}
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}}
+void* operator new[] (std::size_t, void* p) {return p;}
+constexpr bool no_placement_new_in_user_code() {
int a;
- new (&a) int(42); // expected-note {{call to placement 'operator new'}}
+ new (&a) int(42);
return a == 42;
}
@@ -239,3 +240,80 @@ void f() {
}
}
+
+namespace placement_new {
+
+template <typename T, typename U>
+constexpr void f(T* t, U u) {
+ new (t) U(u);
+}
+
+consteval int ok() {
+ int i;
+ new (&i) int(0);
+ new (&i) int[1]{1};
+ new (static_cast<void*>(&i)) int(0);
+ return 0;
+}
+
+consteval int conversion() { // expected-error {{consteval function never produces a constant expression}}
+ int i;
+ new (static_cast<void*>(&i)) float(0);
+ // expected-note at -1 {{placement new would change type of storage from 'int' to 'float'}}
+ return 0;
+}
+
+consteval int indeterminate() {
+ int * indeterminate;
+ new (indeterminate) int(0);
+ // expected-note at -1 {{read of uninitialized object is not allowed in a constant expression}}
+ return 0;
+}
+
+consteval int array1() {
+ int i[2];
+ new (&i) int[]{1,2};
+ new (&i) int[]{1};
+ new (&i) int(0);
+ new (static_cast<void*>(&i)) int[]{1,2};
+ new (static_cast<void*>(&i)) int[]{1};
+ return 0;
+}
+
+consteval int array2() { // expected-error {{consteval function never produces a constant expression}}
+ int i[1];
+ new (&i) int[2];
+ //expected-note at -1 {{placement new would change type of storage from 'int[1]' to 'int[2]'}}
+ return 0;
+}
+
+struct S{
+ int* i;
+ constexpr S() : i(new int(42)) {} // expected-note {{allocation performed here was not deallocated}}
+ constexpr ~S() {delete i;}
+};
+
+consteval void alloc() {
+ S* s = new S();
+ s->~S();
+ new (s) S();
+ delete s;
+}
+
+
+consteval void alloc_err() {
+ S* s = new S();
+ new (s) S();
+ delete s;
+}
+
+
+
+int a = ok();
+int c = indeterminate(); // expected-error {{call to consteval function 'placement_new::indeterminate' is not a constant expression}} \
+ // expected-note {{in call to 'indeterminate()'}}
+int d = array1();
+int alloc1 = (alloc(), 0);
+int alloc2 = (alloc_err(), 0); // expected-error {{call to consteval function 'placement_new::alloc_err' is not a constant expression}}
+
+}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index c901e1ce0e15b3..de84d94c20a152 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -17348,7 +17348,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2922.html">2922</a></td>
<td>open</td>
<td>constexpr placement-new is too permissive</td>
- <td align="center">Not resolved</td>
+ <td title="Clang 20 implements 2024-07-10 resolution" align="center">Not Resolved*</td>
</tr></table>
</div>
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index faee8b578b6242..58bbb12a76dd75 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -208,7 +208,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td><tt>constexpr</tt> placement new</td>
<td><a href="https://wg21.link/P2747R2">P2747R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 20</td>
</tr>
<tr>
<td>Deleting a Pointer to an Incomplete Type Should be Ill-formed</td>
>From 073e2e5878d3c7cdbd54a5d2f32e8fb59e732d0e Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 16 Aug 2024 17:18:51 +0200
Subject: [PATCH 2/2] Do not make it an extension as there is no good way to
introduce a warning for it
---
clang/docs/LanguageExtensions.rst | 1 -
clang/lib/AST/ExprConstant.cpp | 4 +-
clang/test/AST/Interp/new-delete.cpp | 2 +-
clang/test/CXX/drs/cwg29xx.cpp | 2 +-
.../test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | 88 ++-----------------
.../SemaCXX/cxx2c-constexpr-placement-new.cpp | 78 ++++++++++++++++
6 files changed, 89 insertions(+), 86 deletions(-)
create mode 100644 clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 296bb85f5e72b2..114e742f3561b7 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1506,7 +1506,6 @@ Attributes on Structured Bindings __cpp_structured_bindings C+
Pack Indexing __cpp_pack_indexing C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
Variadic Friends __cpp_variadic_friend C++26 C++03
-``constexpr`` placement new __cpp_constexpr C++26 C++20
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 20c1fd6747d582..138269043c1790 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10025,7 +10025,9 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
return false;
IsNothrow = true;
- } else if (OperatorNew->isReservedGlobalPlacementOperator()) {
+ } else if (OperatorNew->isReservedGlobalPlacementOperator() &&
+ (Info.CurrentCall->isStdFunction() ||
+ Info.getLangOpts().CPlusPlus26)) {
if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
return false;
if (Result.Designator.Invalid)
diff --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp
index 0c823e7000f853..7f135d94919cc6 100644
--- a/clang/test/AST/Interp/new-delete.cpp
+++ b/clang/test/AST/Interp/new-delete.cpp
@@ -245,7 +245,7 @@ namespace std {
namespace PlacementNew {
constexpr int foo() { // both-error {{never produces a constant expression}}
char c[sizeof(int)];
- new (c) int{12}; // ref-note {{placement new would change type of storage from 'char' to 'int'}} \
+ new (c) int{12}; // ref-note {{this placement new expression is not yet supported in constant expressions}} \
// expected-note {{subexpression not valid in a constant expression}}
return 0;
}
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index 7e04aa0c3a4942..2515785f47bf19 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -24,7 +24,7 @@ struct S {
};
} // namespace cwg2917
-#if __cplusplus >= 202002
+#if __cplusplus >= 202400L
namespace std {
using size_t = decltype(sizeof(0));
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
index b02c90b88d1ac6..c84678137479fc 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -std=c++2a -verify %s -DNEW=__builtin_operator_new -DDELETE=__builtin_operator_delete
-// RUN: %clang_cc1 -std=c++2a -verify %s "-DNEW=operator new" "-DDELETE=operator delete"
-// RUN: %clang_cc1 -std=c++2a -verify %s "-DNEW=::operator new" "-DDELETE=::operator delete"
+// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s -DNEW=__builtin_operator_new -DDELETE=__builtin_operator_delete
+// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=operator new" "-DDELETE=operator delete"
+// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=::operator new" "-DDELETE=::operator delete"
+// RUN: %clang_cc1 -std=c++2c -verify=expected,cxx26 %s "-DNEW=::operator new" "-DDELETE=::operator delete"
constexpr bool alloc_from_user_code() {
void *p = NEW(sizeof(int)); // expected-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator<T>::allocate'}}
@@ -91,9 +92,9 @@ constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&
void *operator new(std::size_t, void *p) { return p; }
void* operator new[] (std::size_t, void* p) {return p;}
-constexpr bool no_placement_new_in_user_code() {
+constexpr bool no_placement_new_in_user_code() { // cxx20-error {{constexpr function never produces a constant expression}}
int a;
- new (&a) int(42);
+ new (&a) int(42); // cxx20-note {{this placement new expression is not yet supported in constant expressions}}
return a == 42;
}
@@ -240,80 +241,3 @@ void f() {
}
}
-
-namespace placement_new {
-
-template <typename T, typename U>
-constexpr void f(T* t, U u) {
- new (t) U(u);
-}
-
-consteval int ok() {
- int i;
- new (&i) int(0);
- new (&i) int[1]{1};
- new (static_cast<void*>(&i)) int(0);
- return 0;
-}
-
-consteval int conversion() { // expected-error {{consteval function never produces a constant expression}}
- int i;
- new (static_cast<void*>(&i)) float(0);
- // expected-note at -1 {{placement new would change type of storage from 'int' to 'float'}}
- return 0;
-}
-
-consteval int indeterminate() {
- int * indeterminate;
- new (indeterminate) int(0);
- // expected-note at -1 {{read of uninitialized object is not allowed in a constant expression}}
- return 0;
-}
-
-consteval int array1() {
- int i[2];
- new (&i) int[]{1,2};
- new (&i) int[]{1};
- new (&i) int(0);
- new (static_cast<void*>(&i)) int[]{1,2};
- new (static_cast<void*>(&i)) int[]{1};
- return 0;
-}
-
-consteval int array2() { // expected-error {{consteval function never produces a constant expression}}
- int i[1];
- new (&i) int[2];
- //expected-note at -1 {{placement new would change type of storage from 'int[1]' to 'int[2]'}}
- return 0;
-}
-
-struct S{
- int* i;
- constexpr S() : i(new int(42)) {} // expected-note {{allocation performed here was not deallocated}}
- constexpr ~S() {delete i;}
-};
-
-consteval void alloc() {
- S* s = new S();
- s->~S();
- new (s) S();
- delete s;
-}
-
-
-consteval void alloc_err() {
- S* s = new S();
- new (s) S();
- delete s;
-}
-
-
-
-int a = ok();
-int c = indeterminate(); // expected-error {{call to consteval function 'placement_new::indeterminate' is not a constant expression}} \
- // expected-note {{in call to 'indeterminate()'}}
-int d = array1();
-int alloc1 = (alloc(), 0);
-int alloc2 = (alloc_err(), 0); // expected-error {{call to consteval function 'placement_new::alloc_err' is not a constant expression}}
-
-}
diff --git a/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp b/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp
new file mode 100644
index 00000000000000..55ebc37b700983
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -std=c++2c -verify %s
+
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+}
+
+void *operator new(std::size_t, void *p) { return p; }
+void* operator new[] (std::size_t, void* p) {return p;}
+
+
+consteval int ok() {
+ int i;
+ new (&i) int(0);
+ new (&i) int[1]{1};
+ new (static_cast<void*>(&i)) int(0);
+ return 0;
+}
+
+consteval int conversion() { // expected-error {{consteval function never produces a constant expression}}
+ int i;
+ new (static_cast<void*>(&i)) float(0);
+ // expected-note at -1 {{placement new would change type of storage from 'int' to 'float'}}
+ return 0;
+}
+
+consteval int indeterminate() {
+ int * indeterminate;
+ new (indeterminate) int(0);
+ // expected-note at -1 {{read of uninitialized object is not allowed in a constant expression}}
+ return 0;
+}
+
+consteval int array1() {
+ int i[2];
+ new (&i) int[]{1,2};
+ new (&i) int[]{1};
+ new (&i) int(0);
+ new (static_cast<void*>(&i)) int[]{1,2};
+ new (static_cast<void*>(&i)) int[]{1};
+ return 0;
+}
+
+consteval int array2() { // expected-error {{consteval function never produces a constant expression}}
+ int i[1];
+ new (&i) int[2];
+ //expected-note at -1 {{placement new would change type of storage from 'int[1]' to 'int[2]'}}
+ return 0;
+}
+
+struct S{
+ int* i;
+ constexpr S() : i(new int(42)) {} // expected-note {{allocation performed here was not deallocated}}
+ constexpr ~S() {delete i;}
+};
+
+consteval void alloc() {
+ S* s = new S();
+ s->~S();
+ new (s) S();
+ delete s;
+}
+
+
+consteval void alloc_err() {
+ S* s = new S();
+ new (s) S();
+ delete s;
+}
+
+
+
+int a = ok();
+int c = indeterminate(); // expected-error {{call to consteval function 'placement_new::indeterminate' is not a constant expression}} \
+ // expected-note {{in call to 'indeterminate()'}}
+int d = array1();
+int alloc1 = (alloc(), 0);
+int alloc2 = (alloc_err(), 0); // expected-error {{call to consteval function 'placement_new::alloc_err' is not a constant expression}}
More information about the cfe-commits
mailing list