diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index fcd3887ec7a09..0dad1bf0f5acc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -977,6 +977,7 @@ Bug Fixes to C++ Support non-empty initializer list. (#GH147949) - Fixed constant evaluation of equality comparisons of constexpr-unknown references. (#GH147663) - Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) +- Clang no longer rejects deleting a pointer of incomplete array type. (#GH149406) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index f851c9e1d5015..2371ae7376ed2 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4040,18 +4040,18 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } else if (Pointee->isFunctionType() || Pointee->isVoidType() || Pointee->isSizelessType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) - << Type << Ex.get()->getSourceRange()); + << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { // FIXME: This can result in errors if the definition was imported from a // module but is hidden. - if (Pointee->isEnumeralType() || - !RequireCompleteType(StartLoc, Pointee, - LangOpts.CPlusPlus26 - ? diag::err_delete_incomplete - : diag::warn_delete_incomplete, - Ex.get())) { - if (const RecordType *RT = PointeeElem->getAs()) + if (const RecordType *RT = PointeeElem->getAs()) { + if (!RequireCompleteType(StartLoc, Pointee, + LangOpts.CPlusPlus26 + ? diag::err_delete_incomplete + : diag::warn_delete_incomplete, + Ex.get())) { PointeeRD = cast(RT->getDecl()); + } } } diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index c17c886d97fb4..4e9f4ed8988e1 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -499,7 +499,7 @@ namespace PseudoDtor { namespace Incomplete { class Foo; // expected-note{{forward declaration}} - void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}} + void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type 'Foo'}} } namespace TypeTraitExpr { diff --git a/clang/test/CXX/expr/expr.unary/expr.delete/p5.cpp b/clang/test/CXX/expr/expr.unary/expr.delete/p5.cpp index ecb29189af60b..0c96ca3cb524a 100644 --- a/clang/test/CXX/expr/expr.unary/expr.delete/p5.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.delete/p5.cpp @@ -6,12 +6,12 @@ // The trivial case. class T0; // expected-note {{forward declaration}} -void f0(T0 *a) { delete a; } // expected-warning {{deleting pointer to incomplete type}} +void f0(T0 *a) { delete a; } // expected-warning {{deleting pointer to incomplete type 'T0'}} class T0 { ~T0(); }; // The trivial case, inside a template instantiation. template -struct T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete type}} +struct T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete type 'T1_B'}} class T1_B; // expected-note {{forward declaration}} void f0() { T1_A x; } // expected-note {{in instantiation of member function}} @@ -44,3 +44,8 @@ class T3_A { private: ~T3_A(); // expected-note{{declared private here}} }; + +// The trivial case but with a union. +union T4; // expected-note {{forward declaration}} +void f4(T4 *a) { delete a; } // expected-warning {{deleting pointer to incomplete type 'T4'}} +union T4 { ~T4(); }; diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index f918501554f80..717cf11f67370 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -227,7 +227,7 @@ void bad_deletes() // cxx98-23-warning@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}} // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}} delete (T*)0; - // cxx98-23-warning@-1 {{deleting pointer to incomplete type}} + // cxx98-23-warning@-1 {{deleting pointer to incomplete type 'T'}} // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'T'}} ::S::delete (int*)0; // expected-error {{expected unqualified-id}} } @@ -570,7 +570,7 @@ namespace DeleteIncompleteClassPointerError { struct A; // expected-note {{forward declaration}} void f(A *x) { 1+delete x; } // expected-error@-1 {{invalid operands to binary expression}} - // cxx98-23-warning@-2 {{deleting pointer to incomplete type}} + // cxx98-23-warning@-2 {{deleting pointer to incomplete type 'A'}} // since-cxx26-error@-3 {{cannot delete pointer to incomplete type 'A'}} } @@ -595,6 +595,10 @@ struct GH99278_2 { } f; }; GH99278_2 e; +void GH99278_3(int(*p)[]) { + delete p; + // expected-warning@-1 {{'delete' applied to a pointer-to-array type 'int (*)[]' treated as 'delete[]'}} +}; #endif struct PlacementArg {};