https://github.com/vbvictor updated 
https://github.com/llvm/llvm-project/pull/144270

>From ba7db62070dc669d5ee0e54df075abb35772faee Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Sun, 15 Jun 2025 19:56:05 +0300
Subject: [PATCH 1/4] [Clang] Improve diagnostics when 'placement new' was
 called with const storage argument

---
 clang/docs/ReleaseNotes.rst                      |  3 +++
 clang/include/clang/Basic/DiagnosticSemaKinds.td |  3 +++
 clang/lib/Sema/SemaExprCXX.cpp                   | 10 +++++++++-
 clang/test/SemaCXX/new-delete.cpp                |  7 +++++++
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9e16613826a77..8257fcd3a3826 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -690,6 +690,9 @@ Improvements to Clang's diagnostics
 - Clang now tries to avoid printing file paths that contain ``..``, instead 
preferring
   the canonical file path if it ends up being shorter.
 
+- 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 09ba796b22765..eca58bcd370c7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8308,6 +8308,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 f17a338825423..1800e569e4188 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2752,10 +2752,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 4073f01808a536587c8be2dd4395ebb78479dbd2 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Sun, 15 Jun 2025 22:53:04 +0300
Subject: [PATCH 2/4] 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 1800e569e4188..07990afedebab 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2752,7 +2752,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 c279766cc067f91059f70656ad8f340f8c79d409 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Sun, 22 Jun 2025 23:07:02 +0300
Subject: [PATCH 3/4] 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 07990afedebab..5e232fbbd590c 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2756,13 +2756,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()

>From c96b69ba60ac9e6ea0c3862974c9fa327d98aaac Mon Sep 17 00:00:00 2001
From: Baranov Victor <bar.victor.2...@gmail.com>
Date: Fri, 11 Jul 2025 15:58:09 +0300
Subject: [PATCH 4/4] Update clang/docs/ReleaseNotes.rst

Co-authored-by: Corentin Jabot <corentinja...@gmail.com>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8257fcd3a3826..5013e5a214a04 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -691,7 +691,7 @@ Improvements to Clang's diagnostics
   the canonical file path if it ends up being shorter.
 
 - Improve the diagnostics for placement new expression when const-qualified
-  object was passed as the storage argument.
+  object was passed as the storage argument. (#GH143708)
 
 Improvements to Clang's time-trace
 ----------------------------------

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to