[Sema] Check availability of ObjC super class and protocols of a container

in the context of the container itself.

Otherwise we will emit 'unavailable' errors when referencing an unavailable super class
even though the subclass is also marked 'unavailable'.

rdar://20598702

llvm-svn: 235276
This commit is contained in:
Argyrios Kyrtzidis 2015-04-19 20:15:55 +00:00
parent 8902e530bc
commit 4ecdd2cff3
5 changed files with 68 additions and 10 deletions

View File

@ -1240,6 +1240,7 @@ private:
bool ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &P,
SmallVectorImpl<SourceLocation> &PLocs,
bool WarnOnDeclarations,
bool ForObjCContainer,
SourceLocation &LAngleLoc,
SourceLocation &EndProtoLoc);
bool ParseObjCProtocolQualifiers(DeclSpec &DS);

View File

@ -6952,7 +6952,7 @@ public:
unsigned NumElts,
AttributeList *attrList);
void FindProtocolDeclaration(bool WarnOnDeclarations,
void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer,
const IdentifierLocPair *ProtocolId,
unsigned NumProtocols,
SmallVectorImpl<Decl *> &Protocols);

View File

@ -240,7 +240,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc))
return nullptr;
@ -286,7 +286,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SmallVector<SourceLocation, 8> ProtocolLocs;
SourceLocation LAngleLoc, EndProtoLoc;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc))
return nullptr;
@ -1151,7 +1151,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVectorImpl<SourceLocation> &ProtocolLocs,
bool WarnOnDeclarations,
bool WarnOnDeclarations, bool ForObjCContainer,
SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
assert(Tok.is(tok::less) && "expected <");
@ -1186,7 +1186,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return true;
// Convert the list of protocols identifiers into a list of protocol decls.
Actions.FindProtocolDeclaration(WarnOnDeclarations,
Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
&ProtocolIdents[0], ProtocolIdents.size(),
Protocols);
return false;
@ -1201,6 +1201,7 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
SmallVector<Decl *, 8> ProtocolDecl;
SmallVector<SourceLocation, 8> ProtocolLocs;
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
false,
LAngleLoc, EndProtoLoc);
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
ProtocolLocs.data(), LAngleLoc);
@ -1416,7 +1417,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
LAngleLoc, EndProtoLoc))
return DeclGroupPtrTy();

View File

@ -448,6 +448,19 @@ class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
}
static void diagnoseUseOfProtocols(Sema &TheSema,
ObjCContainerDecl *CD,
ObjCProtocolDecl *const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs) {
assert(ProtoRefs);
// Diagnose availability in the context of the ObjC container.
Sema::ContextRAII SavedContext(TheSema, CD);
for (unsigned i = 0; i < NumProtoRefs; ++i) {
(void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]);
}
}
Decl *Sema::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
@ -535,6 +548,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceDecl *SuperClassDecl =
dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
// Diagnose availability in the context of the @interface.
ContextRAII SavedContext(*this, IDecl);
// Diagnose classes that inherit from deprecated classes.
if (SuperClassDecl)
(void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
@ -591,6 +606,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Check then save referenced protocols.
if (NumProtoRefs) {
diagnoseUseOfProtocols(*this, IDecl, (ObjCProtocolDecl*const*)ProtoRefs,
NumProtoRefs, ProtoLocs);
IDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
IDecl->setEndOfDefinitionLoc(EndProtoLoc);
@ -751,6 +768,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
diagnoseUseOfProtocols(*this, PDecl, (ObjCProtocolDecl*const*)ProtoRefs,
NumProtoRefs, ProtoLocs);
PDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
}
@ -778,7 +797,7 @@ static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
/// issues an error if they are not declared. It returns list of
/// protocol declarations in its 'Protocols' argument.
void
Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer,
const IdentifierLocPair *ProtocolId,
unsigned NumProtocols,
SmallVectorImpl<Decl *> &Protocols) {
@ -804,8 +823,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
// If this is a forward protocol declaration, get its definition.
if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition())
PDecl = PDecl->getDefinition();
(void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
// For an objc container, delay protocol reference checking until after we
// can set the objc decl as the availability context, otherwise check now.
if (!ForObjCContainer) {
(void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
}
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
@ -934,7 +957,9 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
CurContext->addDecl(CDecl);
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
diagnoseUseOfProtocols(*this, CDecl, (ObjCProtocolDecl*const*)ProtoRefs,
NumProtoRefs, ProtoLocs);
CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
// Protocols in the class extension belong to the class.
if (CDecl->IsClassExtension())

View File

@ -67,3 +67,34 @@ Foo *g_foo = 0; // expected-error {{'Foo' is unavailable}}
Foo * f_func() { // expected-error {{'Foo' is unavailable}}
return 0;
}
#define UNAVAILABLE __attribute__((unavailable("not available")))
UNAVAILABLE
@interface Base // expected-note {{unavailable here}}
@end
UNAVAILABLE
@protocol SomeProto // expected-note 4 {{unavailable here}}
@end
@interface Sub : Base<SomeProto> // expected-error 2 {{unavailable}}
@end
@interface IP<SomeProto> // expected-error {{unavailable}}
@end
@protocol SubProt<SomeProto> // expected-error {{unavailable}}
@end
@interface Sub(cat)<SomeProto> // expected-error {{unavailable}}
@end
UNAVAILABLE
@interface UnavailSub : Base<SomeProto> // no error
@end
UNAVAILABLE
@interface UnavailIP<SomeProto> // no error
@end
UNAVAILABLE
@protocol UnavailProt<SomeProto> // no error
@end
@interface UnavailSub(cat)<SomeProto> // no error
@end