/// marked with the 'objc_designated_initializer' attribute.
void setHasDesignatedInitializers();
+ /// Returns true if this interface decl contains at least one initializer
+ /// marked with the 'objc_designated_initializer' attribute.
+ bool hasDesignatedInitializers() const;
+
const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "Caller did not check for forward reference!");
if (data().ExternallyCompleted)
def warn_objc_designated_init_non_designated_init_call : Warning<
"designated initializer invoked a non-designated initializer">,
InGroup<ObjCDesignatedInit>;
+def warn_objc_secondary_init_super_init_call : Warning<
+ "secondary initializer should not invoke an initializer on 'super'">,
+ InGroup<ObjCDesignatedInit>;
+def warn_objc_secondary_init_missing_init_call : Warning<
+ "secondary initializer missing a 'self' call to another initializer">,
+ InGroup<ObjCDesignatedInit>;
def err_ns_bridged_not_interface : Error<
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;
/// the super class.
bool ObjCWarnForNoDesignatedInitChain;
+ /// True when this is an initializer method not marked as a designated
+ /// initializer within a class that has at least one initializer marked as a
+ /// designated initializer.
+ bool ObjCIsSecondaryInit;
+ /// This starts true for a secondary initializer method and will be set to
+ /// false if there is an invocation of an initializer on 'self'.
+ bool ObjCWarnForNoInitDelegation;
+
/// \brief Used to determine if errors occurred in this function or block.
DiagnosticErrorTrap ErrorTrap;
ObjCShouldCallSuper(false),
ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false),
+ ObjCIsSecondaryInit(false),
+ ObjCWarnForNoInitDelegation(false),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();
data().HasDesignatedInitializers = true;
}
+bool ObjCInterfaceDecl::hasDesignatedInitializers() const {
+ assert(hasDefinition() && "Forward declarations can't contain methods");
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ return data().HasDesignatedInitializers;
+}
+
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (const ObjCInterfaceDecl *Def = getDefinition()) {
if (data().ExternallyCompleted)
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;
+ ObjCIsSecondaryInit = false;
+ ObjCWarnForNoInitDelegation = false;
SwitchStack.clear();
Returns.clear();
diag::note_objc_designated_init_marked_here);
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
}
+ if (getCurFunction()->ObjCWarnForNoInitDelegation) {
+ Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call);
+ getCurFunction()->ObjCWarnForNoInitDelegation = false;
+ }
} else {
return 0;
}
MDecl->getLocation(), 0);
}
- if (MDecl->isDesignatedInitializerForTheInterface())
- getCurFunction()->ObjCIsDesignatedInit = true;
+ if (MDecl->getMethodFamily() == OMF_init) {
+ if (MDecl->isDesignatedInitializerForTheInterface()) {
+ getCurFunction()->ObjCIsDesignatedInit = true;
+ getCurFunction()->ObjCWarnForNoDesignatedInitChain =
+ IC->getSuperClass() != 0;
+ } else if (IC->hasDesignatedInitializers()) {
+ getCurFunction()->ObjCIsSecondaryInit = true;
+ getCurFunction()->ObjCWarnForNoInitDelegation = true;
+ }
+ }
// If this is "dealloc" or "finalize", set some bit here.
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
-
- if (getCurFunction()->ObjCIsDesignatedInit)
- getCurFunction()->ObjCWarnForNoDesignatedInitChain = true;
}
}
}
}
}
+ if (Method && Method->getMethodFamily() == OMF_init &&
+ getCurFunction()->ObjCIsSecondaryInit &&
+ (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+ if (SuperLoc.isValid()) {
+ Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call);
+ } else {
+ getCurFunction()->ObjCWarnForNoInitDelegation = false;
+ }
+ }
+
// Check the message arguments.
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
-(void)meth {}
-(id)init NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
+(id)init { return 0; }
--(id)init3 { return 0; }
--(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
+-(id)init3 { return 0; } // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
+-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}} \
+ // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
@end
__attribute__((objc_root_class))
@implementation B1
-(id)initB1 { return 0; }
--(id)initB2 { return 0; }
+-(id)initB2 { return 0; } // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
-(id)initB3 { return 0; }
@end
return [super initB3];
}
-(void)meth {}
+-(id)initS1 {
+ return 0;
+}
+-(id)initS2 {
+ return [super initB1];
+}
+@end
+
+@interface S6 : B1
+-(id)initS1 NS_DESIGNATED_INITIALIZER;
+-(id)initS2;
+-(id)initS3;
+-(id)initS4;
+@end
+
+@implementation S6
+-(id)initS1 {
+ return [super initB1];
+}
+-(id)initS2 { // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
+ return [super initB1]; // expected-warning {{secondary initializer should not invoke an initializer on 'super'}}
+}
+-(id)initS3 {
+ return [self initB1];
+}
+-(id)initS4 {
+ return [self initS1];
+}
+-(id)initS5 {
+ [super initB1]; // expected-warning {{secondary initializer should not invoke an initializer on 'super'}}
+ void (^blk)(void) = ^{
+ [super initB1];
+ };
+ return [self initS1];
+}
+-(id)initS6 { // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
+ S6 *s;
+ return [s initS1];
+}
@end