]> granicus.if.org Git - clang/commitdiff
[Sema] Check availability of ObjC super class and protocols of a container
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sun, 19 Apr 2015 20:15:55 +0000 (20:15 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sun, 19 Apr 2015 20:15:55 +0000 (20:15 +0000)
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
include/clang/Sema/Sema.h
lib/Parse/ParseObjc.cpp
lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/class-unavail-warning.m

index b0c116cfceb571e61b43da3d51101a65ab2a0e81..5bca4625409e279a9a7c63bee3e342e7bd0d4fea 100644 (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);
index 84302fa669869af8dcd08ee0dd4d8a1994089a05..c7dc1f6d7c6b580f35049c1709a7e57272a4acd0 100644 (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);
index a597a1658cf6b87f35a519a11f4645edad3a5336..691f53f05a8fd0df505ab74d2d0218b505ad68d4 100644 (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();
 
index dc47ce966f71a1426a906c6a5c91a89d85d07a4e..37ef9baf1120cf7a6663ed5bd61d5c4dd07641bd 100644 (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())
index 3ebf3e7815f3a7613f63130aeaa0671dd2618168..6a683dd349c2140aa287d20030046559d2b00fdb 100644 (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