From: Eli Friedman Date: Tue, 26 Jul 2011 22:25:31 +0000 (+0000) Subject: A couple minor issues with Sema for delete: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e52c91478a144f913019591ee1839e1846345f71;p=clang A couple minor issues with Sema for delete: 1. Attempting to delete an expression of incomplete class type should be an error, not a warning. 2. If someone tries to delete a pointer to an incomplete class type, make sure we actually emit the delete expression after we warn. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136161 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8b21362532..20332dc286 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3364,7 +3364,7 @@ def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " "expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behaviour">; -def err_delete_incomplete_class_type : Warning< +def err_delete_incomplete_class_type : Error< "deleting incomplete class type %0; no conversions to pointer type">; def warn_delete_array_type : Warning< "'delete' applied to a pointer-to-array type %0 treated as delete[]">; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0225c6629e..a3e3c11c6a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1840,24 +1840,32 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex.get()->getSourceRange()); QualType Pointee = Type->getAs()->getPointeeType(); + QualType PointeeElem = Context.getBaseElementType(Pointee); + + if (unsigned AddressSpace = Pointee.getAddressSpace()) + return Diag(Ex.get()->getLocStart(), + diag::err_address_space_qualified_delete) + << Pointee.getUnqualifiedType() << AddressSpace; + + CXXRecordDecl *PointeeRD = 0; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); - } else if (Pointee->isFunctionType() || Pointee->isVoidType()) + } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); - else if (!Pointee->isDependentType() && - RequireCompleteType(StartLoc, Pointee, - PDiag(diag::warn_delete_incomplete) - << Ex.get()->getSourceRange())) - return ExprError(); - else if (unsigned AddressSpace = Pointee.getAddressSpace()) - return Diag(Ex.get()->getLocStart(), - diag::err_address_space_qualified_delete) - << Pointee.getUnqualifiedType() << AddressSpace; + } else if (!Pointee->isDependentType()) { + if (!RequireCompleteType(StartLoc, Pointee, + PDiag(diag::warn_delete_incomplete) + << Ex.get()->getSourceRange())) { + if (const RecordType *RT = PointeeElem->getAs()) + PointeeRD = cast(RT->getDecl()); + } + } + // C++ [expr.delete]p2: // [Note: a pointer to a const type can be the operand of a // delete-expression; it is not necessary to cast away the constness @@ -1877,12 +1885,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); - QualType PointeeElem = Context.getBaseElementType(Pointee); - if (const RecordType *RT = PointeeElem->getAs()) { - CXXRecordDecl *RD = cast(RT->getDecl()); - + if (PointeeRD) { if (!UseGlobal && - FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) + FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, + OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the @@ -1900,8 +1906,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); } - if (!RD->hasTrivialDestructor()) - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (!PointeeRD->hasTrivialDestructor()) + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkDeclarationReferenced(StartLoc, const_cast(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); @@ -1915,8 +1921,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // behavior is undefined. // // Note: a final class cannot be derived from, no issue there - if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr()) { - CXXDestructorDecl *dtor = RD->getDestructor(); + if (!ArrayForm && PointeeRD->isPolymorphic() && + !PointeeRD->hasAttr()) { + CXXDestructorDecl *dtor = PointeeRD->getDestructor(); if (!dtor || !dtor->isVirtual()) Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; } @@ -1944,9 +1951,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, MarkDeclarationReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. - if (const RecordType *RT = PointeeElem->getAs()) { - CXXRecordDecl *RD = cast(RT->getDecl()); - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (PointeeRD) { + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index efdfa0f066..850229c320 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -397,3 +397,15 @@ namespace ArrayNewNeedsDtor { return new B[5]; // expected-note {{implicit default destructor for 'ArrayNewNeedsDtor::B' first required here}} } } + +namespace DeleteIncompleteClass { + struct A; // expected-note {{forward declaration}} + extern A x; + void f() { delete x; } // expected-error {{deleting incomplete class type}} +} + +namespace DeleteIncompleteClassPointerError { + struct A; // expected-note {{forward declaration}} + void f(A *x) { 1+delete x; } // expected-warning {{deleting pointer to incomplete type}} \ + // expected-error {{invalid operands to binary expression}} +}