Skip to content

Commit 94e652b

Browse files
committed
More fixes for P3144R2 implementation
P3144R2 made it ill-formed to delete a pointer to an incomplete class type, and asserted that incomplete class types were the only incomplete types that were possible to pass to the delete operator. This assertion was wrong, and PR 99278 already updated the check to exclude incomplete enum types, but that is still wrong: pointers to arrays of unknown length are another instance of incomplete types that are possible to delete and were not included in PR3144R2's ban. Additionally, the diagnostic still claimed that the problem was with deleting pointers to incomplete types, rather than to incomplete class types. This PR ensures that when we implement the check for incomplete class type, we only check for incomplete class type, and adjusts the diagnostics to say 'incomplete struct' or 'incomplete union' to be accurate without being overly verbose.
1 parent f295617 commit 94e652b

File tree

7 files changed

+35
-25
lines changed

7 files changed

+35
-25
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8392,17 +8392,19 @@ def ext_default_init_const : ExtWarn<
83928392
"is a Microsoft extension">,
83938393
InGroup<MicrosoftConstInit>;
83948394
def err_delete_operand : Error<"cannot delete expression of type %0">;
8395+
def err_delete_void_ptr_operand : Error<
8396+
"cannot delete expression with pointer-to-'void' type %0">;
83958397
def ext_delete_void_ptr_operand : ExtWarn<
83968398
"cannot delete expression with pointer-to-'void' type %0">,
83978399
InGroup<DeleteIncomplete>;
83988400
def err_ambiguous_delete_operand : Error<
83998401
"ambiguous conversion of delete expression of type %0 to a pointer">;
84008402
def warn_delete_incomplete : Warning<
8401-
"deleting pointer to incomplete type %0 is incompatible with C++2c"
8403+
"deleting pointer to incomplete %select{struct|union}0 %1 is incompatible with C++2c"
84028404
" and may cause undefined behavior">,
84038405
InGroup<DeleteIncomplete>;
84048406
def err_delete_incomplete : Error<
8405-
"cannot delete pointer to incomplete type %0">;
8407+
"cannot delete pointer to incomplete %select{struct|union}0 %1">;
84068408
def err_delete_incomplete_class_type : Error<
84078409
"deleting incomplete class type %0; no conversions to pointer type">;
84088410
def err_delete_explicit_conversion : Error<

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,25 +4033,24 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
40334033
// effectively bans deletion of "void*". However, most compilers support
40344034
// this, so we treat it as a warning unless we're in a SFINAE context.
40354035
// But we still prohibit this since C++26.
4036-
Diag(StartLoc, LangOpts.CPlusPlus26 ? diag::err_delete_incomplete
4036+
Diag(StartLoc, LangOpts.CPlusPlus26 ? diag::err_delete_void_ptr_operand
40374037
: diag::ext_delete_void_ptr_operand)
4038-
<< (LangOpts.CPlusPlus26 ? Pointee : Type)
4039-
<< Ex.get()->getSourceRange();
4038+
<< Type << Ex.get()->getSourceRange();
40404039
} else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
40414040
Pointee->isSizelessType()) {
40424041
return ExprError(Diag(StartLoc, diag::err_delete_operand)
4043-
<< Type << Ex.get()->getSourceRange());
4042+
<< Type << Ex.get()->getSourceRange());
40444043
} else if (!Pointee->isDependentType()) {
40454044
// FIXME: This can result in errors if the definition was imported from a
40464045
// module but is hidden.
4047-
if (Pointee->isEnumeralType() ||
4048-
!RequireCompleteType(StartLoc, Pointee,
4049-
LangOpts.CPlusPlus26
4050-
? diag::err_delete_incomplete
4051-
: diag::warn_delete_incomplete,
4052-
Ex.get())) {
4053-
if (const RecordType *RT = PointeeElem->getAs<RecordType>())
4046+
if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
4047+
if (!RequireCompleteType(StartLoc, Pointee,
4048+
LangOpts.CPlusPlus26
4049+
? diag::err_delete_incomplete
4050+
: diag::warn_delete_incomplete,
4051+
RT->isUnionType(), Ex.get())) {
40544052
PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
4053+
}
40554054
}
40564055
}
40574056

clang/test/Analysis/dtor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ namespace PseudoDtor {
499499

500500
namespace Incomplete {
501501
class Foo; // expected-note{{forward declaration}}
502-
void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
502+
void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete struct 'Foo'}}
503503
}
504504

505505
namespace TypeTraitExpr {

clang/test/CXX/drs/cwg5xx.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ namespace cwg573 { // cwg573: no
907907
// cxx98-error@-1 {{cast between pointer-to-function and pointer-to-object is an extension}}
908908
void f() { delete a; }
909909
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
910-
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
910+
// since-cxx26-error@-2 {{cannot delete expression with pointer-to-'void' type 'void *'}}
911911
int n = d - a;
912912
// expected-error@-1 {{arithmetic on pointers to void}}
913913
// FIXME: This is ill-formed.
@@ -1298,12 +1298,12 @@ namespace cwg599 { // cwg599: partial
12981298
void f(void *p, void (*q)(), S s, T t, U u, V v) {
12991299
delete p;
13001300
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
1301-
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
1301+
// since-cxx26-error@-2 {{cannot delete expression with pointer-to-'void' type 'void *'}}
13021302
delete q;
13031303
// expected-error@-1 {{cannot delete expression of type 'void (*)()'}}
13041304
delete s;
13051305
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
1306-
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
1306+
// since-cxx26-error@-2 {{cannot delete expression with pointer-to-'void' type 'void *'}}
13071307
delete t;
13081308
// expected-error@-1 {{cannot delete expression of type 'T'}}
13091309
// FIXME: This is valid, but is rejected due to a non-conforming GNU

clang/test/CXX/expr/expr.unary/expr.delete/p5.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
// The trivial case.
88
class T0; // expected-note {{forward declaration}}
9-
void f0(T0 *a) { delete a; } // expected-warning {{deleting pointer to incomplete type}}
9+
void f0(T0 *a) { delete a; } // expected-warning {{deleting pointer to incomplete struct 'T0'}}
1010
class T0 { ~T0(); };
1111

1212
// The trivial case, inside a template instantiation.
1313
template<typename T>
14-
struct T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete type}}
14+
struct T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete struct 'T1_B'}}
1515
class T1_B; // expected-note {{forward declaration}}
1616
void f0() { T1_A<T1_B> x; } // expected-note {{in instantiation of member function}}
1717

@@ -44,3 +44,8 @@ class T3_A {
4444
private:
4545
~T3_A(); // expected-note{{declared private here}}
4646
};
47+
48+
// The trivial case but with a union.
49+
union T4; // expected-note {{forward declaration}}
50+
void f4(T4 *a) { delete a; } // expected-warning {{deleting pointer to incomplete union 'T4'}}
51+
union T4 { ~T4(); };

clang/test/OpenMP/deferred-diags.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace TestDeleteIncompleteClassDefinition {
4141
struct a;
4242
struct b {
4343
b() {
44-
delete c; // expected-warning {{deleting pointer to incomplete type 'a' is incompatible with C++2c and may cause undefined behavior}}
44+
delete c; // expected-warning {{deleting pointer to incomplete struct 'a' is incompatible with C++2c and may cause undefined behavior}}
4545
}
4646
a *c;
4747
};

clang/test/SemaCXX/new-delete.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ void bad_deletes()
225225
delete [0] (int*)0; // expected-error {{expected variable name or 'this' in lambda capture list}}
226226
delete (void*)0;
227227
// cxx98-23-warning@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
228-
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
228+
// since-cxx26-error@-2 {{cannot delete expression with pointer-to-'void' type 'void *'}}
229229
delete (T*)0;
230-
// cxx98-23-warning@-1 {{deleting pointer to incomplete type}}
231-
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'T'}}
230+
// cxx98-23-warning@-1 {{deleting pointer to incomplete struct 'T'}}
231+
// since-cxx26-error@-2 {{cannot delete pointer to incomplete struct 'T'}}
232232
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
233233
}
234234

@@ -570,8 +570,8 @@ namespace DeleteIncompleteClassPointerError {
570570
struct A; // expected-note {{forward declaration}}
571571
void f(A *x) { 1+delete x; }
572572
// expected-error@-1 {{invalid operands to binary expression}}
573-
// cxx98-23-warning@-2 {{deleting pointer to incomplete type}}
574-
// since-cxx26-error@-3 {{cannot delete pointer to incomplete type 'A'}}
573+
// cxx98-23-warning@-2 {{deleting pointer to incomplete struct 'A'}}
574+
// since-cxx26-error@-3 {{cannot delete pointer to incomplete struct 'A'}}
575575
}
576576

577577
namespace PR10504 {
@@ -595,6 +595,10 @@ struct GH99278_2 {
595595
} f;
596596
};
597597
GH99278_2<void> e;
598+
void GH99278_3(int(*p)[]) {
599+
delete p;
600+
// expected-warning@-1 {{'delete' applied to a pointer-to-array type 'int (*)[]' treated as 'delete[]'}}
601+
};
598602
#endif
599603

600604
struct PlacementArg {};

0 commit comments

Comments
 (0)