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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0225c66..a3e3c11 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1840,24 +1840,32 @@
<< Type << Ex.get()->getSourceRange());
QualType Pointee = Type->getAs<PointerType>()->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<RecordType>())
+ PointeeRD = cast<CXXRecordDecl>(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 @@
DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
ArrayForm ? OO_Array_Delete : OO_Delete);
- QualType PointeeElem = Context.getBaseElementType(Pointee);
- if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(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 @@
UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
- if (!RD->hasTrivialDestructor())
- if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
+ if (!PointeeRD->hasTrivialDestructor())
+ if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
MarkDeclarationReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
@@ -1915,8 +1921,9 @@
// behavior is undefined.
//
// Note: a final class cannot be derived from, no issue there
- if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) {
- CXXDestructorDecl *dtor = RD->getDestructor();
+ if (!ArrayForm && PointeeRD->isPolymorphic() &&
+ !PointeeRD->hasAttr<FinalAttr>()) {
+ CXXDestructorDecl *dtor = PointeeRD->getDestructor();
if (!dtor || !dtor->isVirtual())
Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
}
@@ -1944,9 +1951,8 @@
MarkDeclarationReferenced(StartLoc, OperatorDelete);
// Check access and ambiguity of operator delete and destructor.
- if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(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);
}