Skip to content

Commit f6c927e

Browse files
vbvictorcor3ntin
andauthored
[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 #143708. --------- Co-authored-by: Corentin Jabot <corentinjabot@gmail.com>
1 parent 2f4a804 commit f6c927e

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,9 @@ Improvements to Clang's diagnostics
699699
- Clang now tries to avoid printing file paths that contain ``..``, instead preferring
700700
the canonical file path if it ends up being shorter.
701701

702+
- Improve the diagnostics for placement new expression when const-qualified
703+
object was passed as the storage argument. (#GH143708)
704+
702705
Improvements to Clang's time-trace
703706
----------------------------------
704707

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8308,6 +8308,9 @@ def err_need_header_before_typeid : Error<
83088308
def err_need_header_before_placement_new : Error<
83098309
"no matching %0 function for non-allocating placement new expression; "
83108310
"include <new>">;
8311+
def err_placement_new_into_const_qualified_storage : Error<
8312+
"placement new expression with a const-qualified argument of type %0 "
8313+
"is not allowed">;
83118314
def err_ms___leave_not_in___try : Error<
83128315
"'__leave' statement not in __try block">;
83138316
def err_uuidof_without_guid : Error<

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2752,10 +2752,20 @@ static bool resolveAllocationOverloadInterior(
27522752
if (Diagnose) {
27532753
// If this is an allocation of the form 'new (p) X' for some object
27542754
// pointer p (or an expression that will decay to such a pointer),
2755-
// diagnose the missing inclusion of <new>.
2755+
// diagnose the reason for the error.
27562756
if (!R.isClassLookup() && Args.size() == 2 &&
27572757
(Args[1]->getType()->isObjectPointerType() ||
27582758
Args[1]->getType()->isArrayType())) {
2759+
const QualType Arg1Type = Args[1]->getType();
2760+
QualType UnderlyingType = S.Context.getBaseElementType(Arg1Type);
2761+
if (UnderlyingType->isPointerType())
2762+
UnderlyingType = UnderlyingType->getPointeeType();
2763+
if (UnderlyingType.isConstQualified()) {
2764+
S.Diag(Args[1]->getExprLoc(),
2765+
diag::err_placement_new_into_const_qualified_storage)
2766+
<< Arg1Type << Args[1]->getSourceRange();
2767+
return true;
2768+
}
27592769
S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new)
27602770
<< R.getLookupName() << Range;
27612771
// Listing the candidates is unlikely to be useful; skip it.

clang/test/SemaCXX/new-delete.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,47 @@ void no_matching_placement_new() {
170170
(void)new(&buffer) X; // expected-error {{no matching 'operator new' function for non-allocating placement new expression; include <new>}}
171171
}
172172

173+
void const_placement_new() {
174+
const int value = 42;
175+
(void)new(&value) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
176+
struct X { int n; };
177+
const X cx = {5};
178+
(void)new(&cx) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *' is not allowed}}
179+
const X* const cx2 = 0;
180+
(void)new(cx2) X{10}; // expected-error {{placement new expression with a const-qualified argument of type 'const X *const' is not allowed}}
181+
const int arr[1] = {1};
182+
(void)new(&arr[0]) int(10); // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
183+
const void* ptr = 0;
184+
(void)new(ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'const void *' is not allowed}}
185+
const int complex_arr[5][3] = {};
186+
(void)new(&complex_arr[0][0]) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
187+
(void)new(complex_arr[0]) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int[3]' is not allowed}}
188+
const char str[] = "test";
189+
(void)new(str) int; // expected-error {{placement new expression with a const-qualified argument of type 'const char[5]' is not allowed}}
190+
const int* const* ptr_to_const_ptr_to_const = 0;
191+
(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}}
192+
int* const* ptr_to_const_ptr = 0;
193+
(void)new(ptr_to_const_ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'int *const *' is not allowed}}
194+
typedef const int* ConstIntPtr;
195+
ConstIntPtr cip = 0;
196+
(void)new(cip) int; // expected-error {{placement new expression with a const-qualified argument of type 'ConstIntPtr' (aka 'const int *') is not allowed}}
197+
typedef const void* ConstVoidPtr;
198+
}
199+
200+
void const_placement_new_param(const void* ptr) {
201+
new (ptr) int; // expected-error {{placement new expression with a const-qualified argument of type 'const void *' is not allowed}}
202+
}
203+
204+
template<typename T>
205+
void const_template_placement_new(const T* storage) {
206+
(void)new(storage) int; // expected-error {{placement new expression with a const-qualified argument of type 'const int *' is not allowed}}
207+
}
208+
209+
void const_template_placement_new_instantiation() {
210+
int x = 5;
211+
const_template_placement_new(&x); // expected-note {{in instantiation of function template specialization 'const_template_placement_new<int>' requested here}}
212+
}
213+
173214
void good_deletes()
174215
{
175216
delete (int*)0;

0 commit comments

Comments
 (0)