From f434397c65aa7cdbcf46ec06c0c1479eca820b3f Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Sun, 19 Apr 2015 20:15:55 +0000 Subject: [PATCH] [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235276 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 1 + include/clang/Sema/Sema.h | 2 +- lib/Parse/ParseObjc.cpp | 11 +++++---- lib/Sema/SemaDeclObjC.cpp | 33 +++++++++++++++++++++++---- test/SemaObjC/class-unavail-warning.m | 31 +++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index b0c116cfce..5bca462540 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1240,6 +1240,7 @@ private: bool ParseObjCProtocolReferences(SmallVectorImpl &P, SmallVectorImpl &PLocs, bool WarnOnDeclarations, + bool ForObjCContainer, SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); bool ParseObjCProtocolQualifiers(DeclSpec &DS); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 84302fa669..c7dc1f6d7c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 &Protocols); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index a597a1658c..691f53f05a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -240,7 +240,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, SmallVector ProtocolRefs; SmallVector 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 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 &Protocols, SmallVectorImpl &ProtocolLocs, - bool WarnOnDeclarations, + bool WarnOnDeclarations, bool ForObjCContainer, SourceLocation &LAngleLoc, SourceLocation &EndLoc) { assert(Tok.is(tok::less) && "expected <"); @@ -1186,7 +1186,7 @@ ParseObjCProtocolReferences(SmallVectorImpl &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 ProtocolDecl; SmallVector 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 ProtocolRefs; SmallVector ProtocolLocs; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true, LAngleLoc, EndProtoLoc)) return DeclGroupPtrTy(); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index dc47ce966f..37ef9baf11 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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(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 &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()) diff --git a/test/SemaObjC/class-unavail-warning.m b/test/SemaObjC/class-unavail-warning.m index 3ebf3e7815..6a683dd349 100644 --- a/test/SemaObjC/class-unavail-warning.m +++ b/test/SemaObjC/class-unavail-warning.m @@ -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 // expected-error 2 {{unavailable}} +@end +@interface IP // expected-error {{unavailable}} +@end +@protocol SubProt // expected-error {{unavailable}} +@end +@interface Sub(cat) // expected-error {{unavailable}} +@end + +UNAVAILABLE +@interface UnavailSub : Base // no error +@end +UNAVAILABLE +@interface UnavailIP // no error +@end +UNAVAILABLE +@protocol UnavailProt // no error +@end +@interface UnavailSub(cat) // no error +@end -- 2.40.0