[clang] [Clang] Improve diagnostics for 'placement new' with const storage argument (PR #144270)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 22 13:07:24 PDT 2025
https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/144270
>From 07392e16740d3d89700da43e22b4d90197bb4d4a Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sun, 15 Jun 2025 19:56:05 +0300
Subject: [PATCH 1/3] [Clang] Improve diagnostics when 'placement new' was
called with const storage argument
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +++
clang/lib/Sema/SemaExprCXX.cpp | 10 +++++++++-
clang/test/SemaCXX/new-delete.cpp | 7 +++++++
4 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 33ee8a53b5f37..9fdc8660a981e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -629,6 +629,8 @@ Improvements to Clang's diagnostics
#GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
#GH36703, #GH32903, #GH23312, #GH69874.
+- Improve the diagnostics for placement new expression when const-qualified
+ object was passed as the storage argument.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8fe7ad6138aa0..0bc1e7deff5ab 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8285,6 +8285,9 @@ def err_need_header_before_typeid : Error<
def err_need_header_before_placement_new : Error<
"no matching %0 function for non-allocating placement new expression; "
"include <new>">;
+def err_placement_new_into_const_qualified_storage : Error<
+ "placement new expression with a const-qualified argument of type %0 "
+ "is not allowed">;
def err_ms___leave_not_in___try : Error<
"'__leave' statement not in __try block">;
def err_uuidof_without_guid : Error<
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ba52e8f8932d3..e9cd40b9061d0 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2753,10 +2753,18 @@ static bool resolveAllocationOverloadInterior(
if (Diagnose) {
// If this is an allocation of the form 'new (p) X' for some object
// pointer p (or an expression that will decay to such a pointer),
- // diagnose the missing inclusion of <new>.
+ // diagnose potential error.
if (!R.isClassLookup() && Args.size() == 2 &&
(Args[1]->getType()->isObjectPointerType() ||
Args[1]->getType()->isArrayType())) {
+ if (Args[1]->getType()->isPointerType()) {
+ if (Args[1]->getType()->getPointeeType().isConstQualified()) {
+ S.Diag(Args[1]->getExprLoc(),
+ diag::err_placement_new_into_const_qualified_storage)
+ << Args[1]->getType() << Args[1]->getSourceRange();
+ return true;
+ }
+ }
S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new)
<< R.getLookupName() << Range;
// Listing the candidates is unlikely to be useful; skip it.
diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp
index 9bbee32c58c36..fae9487cbe2c1 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -160,6 +160,13 @@ void bad_news(int *ip)
#if __cplusplus < 201103L
(void)new int[]{}; // expected-error {{array size must be specified in new expression with no initializer}}
#endif
+ struct X { int n; };
+ const X cx = {5};
+ (void)new(&cx) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *' is not allowed}}
+ const X* const cx2 = 0;
+ (void)new(cx2) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *const' is not allowed}}
+ const int arr[1] = {1};
+ (void)new(&arr[0]) int(10); // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
}
void no_matching_placement_new() {
>From 18473ca34d181b6e46452db7d050a71220a1f64c Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sun, 15 Jun 2025 22:53:04 +0300
Subject: [PATCH 2/3] improve comment wording before diagnostics
---
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e9cd40b9061d0..7367b906b70ba 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2753,7 +2753,7 @@ static bool resolveAllocationOverloadInterior(
if (Diagnose) {
// If this is an allocation of the form 'new (p) X' for some object
// pointer p (or an expression that will decay to such a pointer),
- // diagnose potential error.
+ // diagnose the reason for the error.
if (!R.isClassLookup() && Args.size() == 2 &&
(Args[1]->getType()->isObjectPointerType() ||
Args[1]->getType()->isArrayType())) {
>From 3498ad5a125838989b9c1ac54935b5c44325dd84 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sun, 22 Jun 2025 23:07:02 +0300
Subject: [PATCH 3/3] add usage of 'getBaseElementType' and enhance tests
---
clang/lib/Sema/SemaExprCXX.cpp | 16 ++++++-----
clang/test/SemaCXX/new-delete.cpp | 46 +++++++++++++++++++++++++++----
2 files changed, 49 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 7367b906b70ba..d1be312efae74 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2757,13 +2757,15 @@ static bool resolveAllocationOverloadInterior(
if (!R.isClassLookup() && Args.size() == 2 &&
(Args[1]->getType()->isObjectPointerType() ||
Args[1]->getType()->isArrayType())) {
- if (Args[1]->getType()->isPointerType()) {
- if (Args[1]->getType()->getPointeeType().isConstQualified()) {
- S.Diag(Args[1]->getExprLoc(),
- diag::err_placement_new_into_const_qualified_storage)
- << Args[1]->getType() << Args[1]->getSourceRange();
- return true;
- }
+ const QualType Arg1Type = Args[1]->getType();
+ QualType UnderlyingType = S.Context.getBaseElementType(Arg1Type);
+ if (UnderlyingType->isPointerType())
+ UnderlyingType = UnderlyingType->getPointeeType();
+ if (UnderlyingType.isConstQualified()) {
+ S.Diag(Args[1]->getExprLoc(),
+ diag::err_placement_new_into_const_qualified_storage)
+ << Arg1Type << Args[1]->getSourceRange();
+ return true;
}
S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new)
<< R.getLookupName() << Range;
diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp
index fae9487cbe2c1..f918501554f80 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -160,6 +160,19 @@ void bad_news(int *ip)
#if __cplusplus < 201103L
(void)new int[]{}; // expected-error {{array size must be specified in new expression with no initializer}}
#endif
+}
+
+void no_matching_placement_new() {
+ struct X { int n; };
+ __attribute__((aligned(__alignof(X)))) unsigned char buffer[sizeof(X)];
+ (void)new(buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
+ (void)new(+buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
+ (void)new(&buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
+}
+
+void const_placement_new() {
+ const int value = 42;
+ (void)new(&value) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
struct X { int n; };
const X cx = {5};
(void)new(&cx) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *' is not allowed}}
@@ -167,14 +180,35 @@ void bad_news(int *ip)
(void)new(cx2) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *const' is not allowed}}
const int arr[1] = {1};
(void)new(&arr[0]) int(10); // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
+ const void* ptr = 0;
+ (void)new(ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'const void *' is not allowed}}
+ const int complex_arr[5][3] = {};
+ (void)new(&complex_arr[0][0]) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
+ (void)new(complex_arr[0]) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int[3]' is not allowed}}
+ const char str[] = "test";
+ (void)new(str) int; // expected-error {{placement new expression with a const-qualified argument of type 'const char[5]' is not allowed}}
+ const int* const* ptr_to_const_ptr_to_const = 0;
+ (void)new(ptr_to_const_ptr_to_const) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *const *' is not allowed}}
+ int* const* ptr_to_const_ptr = 0;
+ (void)new(ptr_to_const_ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'int *const *' is not allowed}}
+ typedef const int* ConstIntPtr;
+ ConstIntPtr cip = 0;
+ (void)new(cip) int; // expected-error {{placement new expression with a const-qualified argument of type 'ConstIntPtr' (aka 'const int *') is not allowed}}
+ typedef const void* ConstVoidPtr;
+}
+
+void const_placement_new_param(const void* ptr) {
+ new (ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'const void *' is not allowed}}
}
-void no_matching_placement_new() {
- struct X { int n; };
- __attribute__((aligned(__alignof(X)))) unsigned char buffer[sizeof(X)];
- (void)new(buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
- (void)new(+buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
- (void)new(&buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
+template<typename T>
+void const_template_placement_new(const T* storage) {
+ (void)new(storage) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
+}
+
+void const_template_placement_new_instantiation() {
+ int x = 5;
+ const_template_placement_new(&x); // expected-note {{in instantiation of function template specialization 'const_template_placement_new<int>' requested here}}
}
void good_deletes()
More information about the cfe-commits
mailing list