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
This commit is contained in:
Eli Friedman 2011-07-26 22:25:31 +00:00
Родитель 54562ec947
Коммит e52c91478a
3 изменённых файлов: 41 добавлений и 23 удалений

Просмотреть файл

@ -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[]">;

Просмотреть файл

@ -1840,24 +1840,32 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< 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 @@ 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<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 @@ 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<CXXDestructorDecl*>(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<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 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
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);
}

Просмотреть файл

@ -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}}
}