"expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behaviour">;
+def err_no_suitable_delete_member_function_found : Error<
+ "no suitable member %0 in %1">;
+def note_delete_member_function_declared_here : Note<
+ "%0 declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated">;
DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
ArrayForm ? OO_Array_Delete : OO_Delete);
+ LookupResult Found;
if (Pointee->isRecordType() && !UseGlobal) {
CXXRecordDecl *Record
= cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl());
// Try to find operator delete/operator delete[] in class scope.
- LookupResult Found;
LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
if (Found.isAmbiguous()) {
}
}
+ 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,
class X8 : public X6, public X7 {
};
-void f(X8* x8) {
+void f(X8 *x8) {
delete x8; // expected-error {{member 'operator delete' found in multiple base classes of different types}}
}
+class X9 {
+ static void operator delete(void*, int); // expected-note {{'operator delete' declared here}}
+ static void operator delete(void*, float); // expected-note {{'operator delete' declared here}}
+};
+
+void f(X9 *x9) {
+ delete x9; // expected-error {{no suitable member 'operator delete' in 'X9'}}
+}