erik.pilkington created this revision.
erik.pilkington added reviewers: aaron.ballman, arphaman, rjmccall.
Herald added subscribers: dexonsmith, jkorous.
Herald added a project: clang.

This is useful to make availability checking work with forward declarations, 
but there also seem to be other attributes that make sense here.

rdar://43118198


Repository:
  rC Clang

https://reviews.llvm.org/D65665

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/test/CodeGenObjC/objc-asm-attribute-test.m
  clang/test/Misc/pragma-attribute-objc.m
  clang/test/Parser/attributes.mm
  clang/test/SemaObjC/attr-forward-class.m
  clang/test/SemaObjC/objc-asm-attribute-neg-test.m

Index: clang/test/SemaObjC/objc-asm-attribute-neg-test.m
===================================================================
--- clang/test/SemaObjC/objc-asm-attribute-neg-test.m
+++ clang/test/SemaObjC/objc-asm-attribute-neg-test.m
@@ -28,7 +28,7 @@
 @end
 
 __attribute__((objc_runtime_name("MySecretNamespace.ForwardClass")))
-@class ForwardClass; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}}
+@class ForwardClass;
 
 __attribute__((objc_runtime_name("MySecretNamespace.ForwardProtocol")))
 @protocol ForwardProtocol;
Index: clang/test/SemaObjC/attr-forward-class.m
===================================================================
--- /dev/null
+++ clang/test/SemaObjC/attr-forward-class.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -verify %s -triple x86_64-apple-macos10.14
+
+__attribute__((availability(macos, introduced=1000)))
+@class JustForward; // expected-note{{introduced in macOS 1000 here}}
+
+JustForward *makeIt(); // expected-warning{{'JustForward' is only available on macOS 1000 or newer}} expected-note{{annotate 'makeIt' with an availability attribute to silence this warning}}
+
+__attribute__((availability(macos, introduced=1000)))
+@class FwdDefined;
+
+// FIXME: it'd be nice to point to the declaration with the attribute if its
+// inherited.
+@interface FwdDefined // expected-note{{introduced in macOS 1000 here}}
+@end
+
+FwdDefined *makeIt2(); // expected-warning{{'FwdDefined' is only available on macOS 1000 or newer}} expected-note{{annotate 'makeIt2' with an availability attribute to silence this warning}}
+
+@class FwdDefined2;
+
+__attribute__((availability(macos, introduced=1000)))
+@interface FwdDefined2 // expected-note{{introduced in macOS 1000 here}}
+@end
+
+FwdDefined2 *makeIt3(); // expected-warning{{'FwdDefined2' is only available on macOS 1000 or newer}} expected-note {{annotate}}
+
+
+// expected-error@+1{{postfix attributes are not allowed on Objective-C directives}}
+@class __attribute__((availability(macos, introduced=1000))) InTheMiddle;
+
+#pragma clang attribute push (__attribute__((availability(macos,introduced=1000))), apply_to=objc_interface)
+
+@class PragmaAttribute; // expected-note{{'PragmaAttribute' has been marked as being introduced in macOS 1000 here, but the deployment target is macOS 10.14.0}}
+
+#pragma clang attribute pop
+
+PragmaAttribute *makeIt4();  // expected-warning{{PragmaAttribute' is only available on macOS 1000 or newer}} expected-note {{annotate}}
Index: clang/test/Parser/attributes.mm
===================================================================
--- clang/test/Parser/attributes.mm
+++ clang/test/Parser/attributes.mm
@@ -1,8 +1,6 @@
 // RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
 
-// FIXME: Why isn't this supported? Seems useful for availability attributes at
-// the very least.
-__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}}
+__attribute__((deprecated)) @class B;
 
 __attribute__((deprecated)) @interface A @end
 __attribute__((deprecated)) @protocol P0;
@@ -20,7 +18,7 @@
 EXP @implementation I2 @end
 
 @class EXP OC; // expected-error-re {{postfix attributes are not allowed on Objective-C directives{{$}}}}
-EXP @class OC2; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}}
+EXP @class OC2;
 
 @protocol EXP P @end // expected-error {{postfix attributes are not allowed on Objective-C directives, place them in front of '@protocol'}}
 EXP @protocol P2 @end
Index: clang/test/Misc/pragma-attribute-objc.m
===================================================================
--- clang/test/Misc/pragma-attribute-objc.m
+++ clang/test/Misc/pragma-attribute-objc.m
@@ -135,13 +135,13 @@
 
 @end
 
-// @class/@compatibility_alias declarations can't receive explicit attributes,
-// so don't add pragma attributes to them.
 @class testClass;
 // CHECK-LABEL: ObjCInterfaceDecl{{.*}}testClass
-// CHECK-NOT: AnnotateAttr
-// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NEXT: AnnotateAttr
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr
 
+// @compatibility_alias declarations can't receive explicit attributes, so don't
+// add pragma attributes to them.
 @compatibility_alias testCompat testInterface1;
 // CHECK-LABEL: ObjCCompatibleAliasDecl{{.*}}testCompat
 // CHECK-NOT: AnnotateAttr
Index: clang/test/CodeGenObjC/objc-asm-attribute-test.m
===================================================================
--- clang/test/CodeGenObjC/objc-asm-attribute-test.m
+++ clang/test/CodeGenObjC/objc-asm-attribute-test.m
@@ -55,14 +55,24 @@
     return [SLREarth alloc];
 }
 
+__attribute__((objc_runtime_name("MySecretNamespace.ForwardClass")))
+@class ForwardClass;
+
+void testForwardClass() {
+  [ForwardClass alloc];
+}
+
 // CHECK: @"OBJC_IVAR_$_MySecretNamespace.Message.MyIVAR" = global i64 0
 // CHECK: @"OBJC_CLASS_$_MySecretNamespace.Message" = global %struct._class_t
 // CHECK: @"OBJC_METACLASS_$_MySecretNamespace.Message" = global %struct._class_t
-
 // CHECK: private unnamed_addr constant [42 x i8] c"T@\22MySecretNamespace.Message\22,&,V_msgProp\00"
 // CHECK: private unnamed_addr constant [76 x i8] c"T@\22MySecretNamespace.Message<MySecretNamespace.Protocol3>\22,&,V_msgProtoProp\00"
 // CHECK: private unnamed_addr constant [50 x i8] c"T@\22<MySecretNamespace.Protocol3>\22,&,V_idProtoProp\00"
 
 // CHECK: @"OBJC_CLASS_$_foo" = external global %struct._class_t
+
+// CHECK: @"OBJC_CLASS_$_MySecretNamespace.ForwardClass" = external global %struct._class_t
+
 // CHECK: define internal i8* @"\01-[Message MyMethod]"
 // CHECK: [[IVAR:%.*]] = load i64, i64* @"OBJC_IVAR_$_MySecretNamespace.Message.MyIVAR"
+
Index: clang/lib/Sema/SemaDeclObjC.cpp
===================================================================
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -1067,6 +1067,9 @@
 
   ProcessDeclAttributeList(TUScope, IDecl, AttrList);
   AddPragmaAttributes(TUScope, IDecl);
+  if (PrevIDecl)
+    mergeDeclAttributes(IDecl, PrevIDecl);
+
   PushOnScopeChains(IDecl, TUScope);
 
   // Start the definition of this class. If we're in a redefinition case, there
@@ -3028,12 +3031,10 @@
     llvm_unreachable("invalid ObjCContainerDecl type.");
 }
 
-Sema::DeclGroupPtrTy
-Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
-                                   IdentifierInfo **IdentList,
-                                   SourceLocation *IdentLocs,
-                                   ArrayRef<ObjCTypeParamList *> TypeParamLists,
-                                   unsigned NumElts) {
+Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(
+    SourceLocation AtClassLoc, IdentifierInfo **IdentList,
+    SourceLocation *IdentLocs, ArrayRef<ObjCTypeParamList *> TypeParamLists,
+    unsigned NumElts, const ParsedAttributesView &AttrList) {
   SmallVector<Decl *, 8> DeclsInGroup;
   for (unsigned i = 0; i != NumElts; ++i) {
     // Check for another declaration kind with the same name.
@@ -3116,6 +3117,11 @@
                                   IdentLocs[i]);
     IDecl->setAtEndRange(IdentLocs[i]);
 
+    ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+    AddPragmaAttributes(TUScope, IDecl);
+    if (PrevIDecl)
+      mergeDeclAttributes(IDecl, PrevIDecl);
+
     PushOnScopeChains(IDecl, TUScope);
     CheckObjCDeclScope(IDecl);
     DeclsInGroup.push_back(IDecl);
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -1058,7 +1058,8 @@
     SourceLocation AtLoc = ConsumeToken(); // the "@"
     if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
         !Tok.isObjCAtKeyword(tok::objc_protocol) &&
-        !Tok.isObjCAtKeyword(tok::objc_implementation)) {
+        !Tok.isObjCAtKeyword(tok::objc_implementation) &&
+        !Tok.isObjCAtKeyword(tok::objc_class)) {
       Diag(Tok, diag::err_objc_unexpected_attr);
       SkipUntil(tok::semi);
       return nullptr;
@@ -1078,6 +1079,9 @@
     if (Tok.isObjCAtKeyword(tok::objc_implementation))
       return ParseObjCAtImplementationDeclaration(AtLoc, DS.getAttributes());
 
+    if (Tok.isObjCAtKeyword(tok::objc_class))
+      return ParseObjCAtClassDeclaration(AtLoc, DS.getAttributes());
+
     return Actions.ConvertDeclToDeclGroup(
             ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()));
   }
Index: clang/lib/Parse/ParseObjc.cpp
===================================================================
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -57,7 +57,7 @@
   Decl *SingleDecl = nullptr;
   switch (Tok.getObjCKeywordID()) {
   case tok::objc_class:
-    return ParseObjCAtClassDeclaration(AtLoc);
+    return ParseObjCAtClassDeclaration(AtLoc, Attrs);
   case tok::objc_interface:
     SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, Attrs);
     break;
@@ -127,7 +127,8 @@
 ///   identifier objc-type-parameter-list[opt]
 ///
 Parser::DeclGroupPtrTy
-Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc,
+                                    ParsedAttributes &Attrs) {
   ConsumeToken(); // the identifier "class"
   SmallVector<IdentifierInfo *, 8> ClassNames;
   SmallVector<SourceLocation, 8> ClassLocs;
@@ -159,7 +160,8 @@
   return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
                                               ClassLocs.data(),
                                               ClassTypeParams,
-                                              ClassNames.size());
+                                              ClassNames.size(),
+                                              Attrs);
 }
 
 void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8305,11 +8305,10 @@
   DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl,
                                                ArrayRef<Decl *> Decls);
 
-  DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
-                   IdentifierInfo **IdentList,
-                   SourceLocation *IdentLocs,
-                   ArrayRef<ObjCTypeParamList *> TypeParamLists,
-                   unsigned NumElts);
+  DeclGroupPtrTy ActOnForwardClassDeclaration(
+      SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs,
+      ArrayRef<ObjCTypeParamList *> TypeParamLists, unsigned NumElts,
+      const ParsedAttributesView &AttrList);
 
   DeclGroupPtrTy
   ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -1492,7 +1492,8 @@
   // Objective-C External Declarations
   void MaybeSkipAttributes(tok::ObjCKeywordKind Kind);
   DeclGroupPtrTy ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs);
-  DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
+  DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc,
+                                             ParsedAttributes &Attrs);
   Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
                                         ParsedAttributes &prefixAttrs);
   class ObjCTypeParamListScope;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to