Author: Baranov Victor Date: 2025-07-12T09:58:06+03:00 New Revision: f6c927e8dbe8e760c5d21c52f0c211ab3fb58735
URL: https://github.com/llvm/llvm-project/commit/f6c927e8dbe8e760c5d21c52f0c211ab3fb58735 DIFF: https://github.com/llvm/llvm-project/commit/f6c927e8dbe8e760c5d21c52f0c211ab3fb58735.diff LOG: [Clang] Improve diagnostics for 'placement new' with const storage argument (#144270) Before this patch, the following code gave misleading diagnostics about absence of `#include <new>`: ```cpp #include <new> struct X { int n; }; int foo() { const X cx = {5}; // error: no matching 'operator new' function for non-allocating placement new expression; include <new> (void)new(&cx) X{10}; }; ``` Now it gives correct diagnostics about constness of passed argument: ```cpp #include <new> struct X { int n; }; int foo() { const X cx = {5}; // error: placement new expression with a const-qualified argument of type 'const X *' is not allowed (void)new(&cx) X{10}; }; ``` Fixes https://github.com/llvm/llvm-project/issues/143708. --------- Co-authored-by: Corentin Jabot <corentinja...@gmail.com> Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaExprCXX.cpp clang/test/SemaCXX/new-delete.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e81a3d4976cf8..8f72553acfa4c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -699,6 +699,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. (#GH143708) + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f1290738d46b2..b285309e0b3ca 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..5e232fbbd590c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2752,10 +2752,20 @@ 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 the reason for the error. if (!R.isClassLookup() && Args.size() == 2 && (Args[1]->getType()->isObjectPointerType() || Args[1]->getType()->isArrayType())) { + 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; // 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..f918501554f80 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -170,6 +170,47 @@ void no_matching_placement_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}} + 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}} + 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}} +} + +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() { delete (int*)0; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits