diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e7b061647cc0..add2ac365c34 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -96,6 +96,7 @@ def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; def : DiagGroup<"overflow">; def OverlengthStrings : DiagGroup<"overlength-strings">; def OverloadedVirtual : DiagGroup<"overloaded-virtual">; +def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; def Packed : DiagGroup<"packed">; def Padded : DiagGroup<"padded">; def PointerArith : DiagGroup<"pointer-arith">; @@ -273,6 +274,7 @@ def Most : DiagGroup<"most", [ UnknownPragmas, Unused, VolatileRegisterVar, + ObjCMissingSuperCalls, OverloadedVirtual ]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c76dca0f7baf..89ffebbbab9a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -570,6 +570,9 @@ def error_property_implemented : Error<"property %0 is already implemented">; def warn_objc_property_attr_mutually_exclusive : Warning< "property attributes '%0' and '%1' are mutually exclusive">, InGroup, DefaultIgnore; +def warn_objc_missing_super_dealloc : Warning< + "method possibly missing a [super dealloc] call">, + InGroup; def warn_undeclared_selector : Warning< "undeclared selector %0">, InGroup, DefaultIgnore; def warn_implicit_atomic_property : Warning< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4bb014b88aac..07bbd18bee8e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -489,6 +489,11 @@ public: /// have been declared. bool GlobalNewDeleteDeclared; + + /// A flag that is set when parsing a -dealloc method and no [super dealloc] + /// call was found yet. + bool ObjCShouldCallSuperDealloc; + /// \brief The set of declarations that have been referenced within /// a potentially evaluated expression. typedef SmallVector, 10> diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 657f2d92e378..f9da82dbb3b9 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -84,6 +84,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), + ObjCShouldCallSuperDealloc(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), SuppressAccessChecking(false), AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 26af6ef97d12..e45e7dafc628 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6690,10 +6690,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), MD->getResultType(), MD); } + if (ObjCShouldCallSuperDealloc) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); + ObjCShouldCallSuperDealloc = false; + } } else { return 0; } + assert(!ObjCShouldCallSuperDealloc && "This should only be set for " + "ObjC methods, which should have been handled in the block above."); + // Verify and clean out per-function state. if (Body) { // C++ constructors that have function-try-blocks can't have return diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index d255a3686ff2..35e32d4ad9d3 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -278,14 +278,22 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { } } - // Warn on implementating deprecated methods under - // -Wdeprecated-implementations flag. - if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) + // Warn on deprecated methods under -Wdeprecated-implementations, + // and prepare for warning on missing super calls. + if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) { if (ObjCMethodDecl *IMD = IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod())) DiagnoseObjCImplementedDeprecations(*this, dyn_cast(IMD), MDecl->getLocation(), 0); + + // If this is "dealloc", set some bit here. + // Then in ActOnSuperMessage() (SemaExprObjC), set it back to false. + // Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set. + // Only do this if the current class actually has a superclass. + if (IC->getSuperClass()) + ObjCShouldCallSuperDealloc = MDecl->getMethodFamily() == OMF_dealloc; + } } Decl *Sema:: diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index e88726b6d2a2..f3893ce2a587 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -975,6 +975,9 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // We are in a method whose class has a superclass, so 'super' // is acting as a keyword. if (Method->isInstanceMethod()) { + if (Sel.getMethodFamily() == OMF_dealloc) + ObjCShouldCallSuperDealloc = false; + // Since we are in an instance method, this is an instance // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); diff --git a/clang/test/SemaObjC/warn-missing-super.m b/clang/test/SemaObjC/warn-missing-super.m new file mode 100644 index 000000000000..8d04bf28667d --- /dev/null +++ b/clang/test/SemaObjC/warn-missing-super.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@protocol NSCopying @end + +@interface NSObject +- (void)dealloc; +@end + +@implementation NSObject +- (void)dealloc { + // Root class, shouldn't warn +} +@end + +@interface Subclass1 : NSObject +- (void)dealloc; +@end + +@implementation Subclass1 +- (void)dealloc { +} // expected-warning{{method possibly missing a [super dealloc] call}} +@end + +@interface Subclass2 : NSObject +- (void)dealloc; +@end + +@implementation Subclass2 +- (void)dealloc { + [super dealloc]; // Shouldn't warn +} +@end