Factor finding a deallocation function for a record type out into a separate function.

llvm-svn: 88857
This commit is contained in:
Anders Carlsson 2009-11-15 18:45:20 +00:00
parent a46efbb857
commit e1d34ba0e4
2 changed files with 65 additions and 40 deletions

View File

@ -2112,6 +2112,9 @@ public:
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
QualType Argument); QualType Argument);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression /// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
bool UseGlobal, bool ArrayForm, bool UseGlobal, bool ArrayForm,

View File

@ -753,6 +753,59 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
((DeclContext *)TUScope->getEntity())->addDecl(Alloc); ((DeclContext *)TUScope->getEntity())->addDecl(Alloc);
} }
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
FunctionDecl* &Operator) {
LookupResult Found;
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD, Name, LookupOrdinaryName);
if (Found.isAmbiguous()) {
DiagnoseAmbiguousLookup(Found, Name, StartLoc);
return true;
}
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
if (Delete->isUsualDeallocationFunction()) {
Operator = Delete;
return false;
}
}
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
if (!Found.empty()) {
Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
<< Name << RD;
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
Diag((*F)->getLocation(),
diag::note_delete_member_function_declared_here)
<< Name;
}
return true;
}
// Look for a global declaration.
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation());
Expr* DeallocArgs[1];
DeallocArgs[0] = &Null;
if (FindAllocationOverload(StartLoc, SourceRange(), Name,
DeallocArgs, 1, TUDecl, /*AllowMissing=*/false,
Operator))
return true;
assert(Operator && "Did not find a deallocation function!");
return false;
}
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
/// @code ::delete ptr; @endcode /// @code ::delete ptr; @endcode
/// or /// or
@ -844,52 +897,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
ArrayForm ? OO_Array_Delete : OO_Delete); ArrayForm ? OO_Array_Delete : OO_Delete);
LookupResult Found; if (const RecordType *RT = Pointee->getAs<RecordType>()) {
if (Pointee->isRecordType() && !UseGlobal) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
CXXRecordDecl *Record
= cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl()); if (!UseGlobal &&
FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete))
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
if (Found.isAmbiguous()) {
DiagnoseAmbiguousLookup(Found, DeleteName, StartLoc);
return ExprError(); return ExprError();
}
// FIXME: Diagnose ambiguity properly if (!RD->hasTrivialDestructor())
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); if (const CXXDestructorDecl *Dtor = RD->getDestructor(Context))
F != FEnd; ++F) {
if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
if (Delete->isUsualDeallocationFunction()) {
OperatorDelete = Delete;
break;
}
}
if (!OperatorDelete && !Found.empty()) {
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
<< DeleteName << Record;
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
Diag((*F)->getLocation(),
diag::note_delete_member_function_declared_here)
<< DeleteName;
}
return ExprError();
}
if (!Record->hasTrivialDestructor())
if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
MarkDeclarationReferenced(StartLoc, MarkDeclarationReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor)); const_cast<CXXDestructorDecl*>(Dtor));
} }
if (!OperatorDelete) { if (!OperatorDelete) {
// Didn't find a member overload. Look for a global one. // Look for a global declaration.
DeclareGlobalNewDelete(); DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl(); DeclContext *TUDecl = Context.getTranslationUnitDecl();
if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName, if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,