diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ec51ffddce1af..a91ca5a0751ea 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -134,7 +134,9 @@ Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ - Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) - Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293) -- Fix a crash when deleting a pointer to an incomplete array (#GH150359). +- Clang no longer rejects deleting a pointer to an incomplete array, regardless + of C++ standard version. (#GH149406) +- Fix a crash when deleting a pointer to an incomplete array. (#GH150359) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0edfd6015cbd9..5eee673ea6a7d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4039,18 +4039,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, PointeeElem, + 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 c05130bb30729..b64d304a88580 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -28,7 +28,7 @@ struct S // expected-note {{candidate}} S(double, int); // expected-note 2 {{candidate}} S(float, int); // expected-note 2 {{candidate}} }; -struct T; // expected-note{{forward declaration of 'T'}} +struct T; // expected-note 3{{forward declaration of 'T'}} struct U { // A special new, to verify that the global version isn't used. @@ -216,6 +216,8 @@ void good_deletes() delete (int*)0; delete [](int*)0; delete (S*)0; + delete [](S(*)[2])0; + delete [](S(*)[])0; ::delete (int*)0; } @@ -227,7 +229,13 @@ 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'}} + delete [](T(*)[2])0; + // cxx98-23-warning@-1 {{deleting pointer to incomplete type 'T'}} + // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'T'}} + delete [](T(*)[])0; + // 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 +578,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 +603,9 @@ struct GH99278_2 { } f; }; GH99278_2 e; +void GH99278_3(int(*p)[]) { + delete[] p; +}; #endif struct PlacementArg {};