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; 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 Decls); - DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, - IdentifierInfo **IdentList, - SourceLocation *IdentLocs, - ArrayRef TypeParamLists, - unsigned NumElts); + DeclGroupPtrTy ActOnForwardClassDeclaration( + SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, + ArrayRef TypeParamLists, unsigned NumElts, + const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, 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 ClassNames; SmallVector 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/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/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 TypeParamLists, - unsigned NumElts) { +Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration( + SourceLocation AtClassLoc, IdentifierInfo **IdentList, + SourceLocation *IdentLocs, ArrayRef TypeParamLists, + unsigned NumElts, const ParsedAttributesView &AttrList) { SmallVector 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/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\22,&,V_msgProtoProp\00" // CHECK: private unnamed_addr constant [50 x i8] c"T@\22\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/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/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/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/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;