erik.pilkington created this revision. erik.pilkington added reviewers: aaron.ballman, rjmccall. Herald added subscribers: dexonsmith, jkorous. Herald added a project: clang.
We want to make `objc_nonlazy_class` apply to implementations, but ran into this. There doesn't seem to be any reason that this isn't supported. Thanks for taking a look! Erik Repository: rC Clang https://reviews.llvm.org/D60542 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/DiagnosticParseKinds.td 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/FixIt/fixit-pragma-attribute.cpp clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/Parser/attributes.mm clang/test/Parser/objc-implementation-attrs.m clang/test/Parser/placeholder-recovery.m clang/test/Sema/pragma-attribute-strict-subjects.c clang/test/SemaObjC/attr-objc-non-lazy.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 @@ -19,7 +19,7 @@ id MyIVAR; } __attribute__((objc_runtime_name("MySecretNamespace.Message"))) -@property int MyProperty; // expected-error {{prefix attribute must be followed by an interface or protocol}}}} +@property int MyProperty; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}}}} - (int) getMyProperty __attribute__((objc_runtime_name("MySecretNamespace.Message"))); // expected-error {{'objc_runtime_name' attribute only applies to}} @@ -28,7 +28,7 @@ @end __attribute__((objc_runtime_name("MySecretNamespace.ForwardClass"))) -@class ForwardClass; // expected-error {{prefix attribute must be followed by an interface or protocol}} +@class ForwardClass; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}} __attribute__((objc_runtime_name("MySecretNamespace.ForwardProtocol"))) @protocol ForwardProtocol; @@ -45,6 +45,6 @@ @interface NoImpl @end +// expected-error@+1 {{'objc_runtime_name' attribute only applies to Objective-C interfaces and Objective-C protocols}} __attribute__((objc_runtime_name("MySecretNamespace.Message"))) -// expected-error@+1 {{prefix attribute must be followed by an interface or protocol}} @implementation NoImpl @end Index: clang/test/SemaObjC/attr-objc-non-lazy.m =================================================================== --- clang/test/SemaObjC/attr-objc-non-lazy.m +++ clang/test/SemaObjC/attr-objc-non-lazy.m @@ -29,6 +29,7 @@ @interface E @end +// expected-error@+1 {{'objc_nonlazy_class' attribute only applies to Objective-C interfaces}} __attribute__((objc_nonlazy_class)) -@implementation E // expected-error {{prefix attribute must be followed by an interface or protocol}} +@implementation E @end Index: clang/test/Sema/pragma-attribute-strict-subjects.c =================================================================== --- clang/test/Sema/pragma-attribute-strict-subjects.c +++ clang/test/Sema/pragma-attribute-strict-subjects.c @@ -56,7 +56,8 @@ #pragma clang attribute pop #pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(enum_constant, function, record(unless(is_union)), variable, variable(is_parameter))) -// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'variable(is_parameter)', and 'enum_constant'}} +// FIXME: comma in this diagnostic is wrong. +// expected-error@-2 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'variable(is_parameter)'}} #pragma clang attribute pop #pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), enum)) Index: clang/test/Parser/placeholder-recovery.m =================================================================== --- clang/test/Parser/placeholder-recovery.m +++ clang/test/Parser/placeholder-recovery.m @@ -11,4 +11,4 @@ // bogus 'archaic' warnings with bad location info. <#methods#> // expected-error {{editor placeholder in source file}} -@end // expected-error {{prefix attribute must be followed by an interface or protocol}} expected-error {{missing '@end'}} +@end // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}} expected-error {{missing '@end'}} Index: clang/test/Parser/objc-implementation-attrs.m =================================================================== --- /dev/null +++ clang/test/Parser/objc-implementation-attrs.m @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -fsyntax-only -Wno-objc-root-class -verify %s + +@interface I1 @end + +// expected-warning@+1 {{'always_inline' attribute only applies to functions}} +__attribute__((always_inline)) +@implementation I1 @end + +// expected-warning@+1 {{'always_inline' attribute only applies to functions}} +__attribute__((always_inline)) +@implementation I1 (MyCat) @end + +// expected-warning@+1 {{'always_inline' attribute only applies to functions}} +__attribute__((always_inline)) +// expected-warning@+1 {{cannot find interface declaration for 'I2'}} +@implementation I2 @end + +// expected-error@+1 {{only applies to Objective-C interfaces}} +__attribute__((objc_root_class)) +// expected-warning@+1 {{cannot find interface declaration for 'I3'}} +@implementation I3 @end + +#define AVAIL_ATTR __attribute__((availability(macos, introduced=1000))) + +typedef int AVAIL_ATTR unavail_int; // expected-note {{marked as being introduced}} + +@interface I4 @end // expected-note {{annotate}} +@implementation I4 { + unavail_int x; // expected-warning {{'unavail_int' is only available on macOS 1000 or newer}} +} +@end + +@interface I5 @end + +#pragma clang attribute push (AVAIL_ATTR, apply_to=objc_implementation) +@implementation I5 { + unavail_int x; +} +@end +#pragma clang attribute pop + +I5 *i5; + +// expected-error@+1 2 {{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate)), apply_to=objc_implementation) +@interface I6 @end +@interface I6 (MyCat) @end +@interface I6 () @end + +@implementation I6 @end // expected-note {{when applied to this declaration}} +@implementation I6 (MyCat) @end // expected-note {{when applied to this declaration}} + +#pragma clang attribute pop Index: clang/test/Parser/attributes.mm =================================================================== --- clang/test/Parser/attributes.mm +++ clang/test/Parser/attributes.mm @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s -__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}} +// 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)) @interface A @end __attribute__((deprecated)) @protocol P0; @@ -15,11 +17,10 @@ EXP @interface I2 @end @implementation EXP I @end // expected-error-re {{postfix attributes are not allowed on Objective-C directives{{$}}}} -// FIXME: Prefix attribute recovery skips until ';' -EXP @implementation I2 @end; // expected-error {{prefix attribute must be followed by an interface or protocol}} +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 or protocol}} +EXP @class OC2; // expected-error {{prefix attribute must be followed by an interface, protocol, or implementation}} @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-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -18,7 +18,7 @@ // CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: ArcWeakrefUnavailable (SubjectMatchRule_objc_interface) // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function) -// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) +// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function) // CHECK-NEXT: CFConsumed (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: CFUnknownTransfer (SubjectMatchRule_function) @@ -49,7 +49,7 @@ // CHECK-NEXT: EnableIf (SubjectMatchRule_function) // CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum) // CHECK-NEXT: ExcludeFromExplicitInstantiation (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record) -// CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) +// CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: FlagEnum (SubjectMatchRule_enum) // CHECK-NEXT: Flatten (SubjectMatchRule_function) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) Index: clang/test/FixIt/fixit-pragma-attribute.cpp =================================================================== --- clang/test/FixIt/fixit-pragma-attribute.cpp +++ clang/test/FixIt/fixit-pragma-attribute.cpp @@ -16,8 +16,8 @@ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:133-[[@LINE-2]]:153}:"" #pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global))) -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:108-[[@LINE-1]]:132}:"" -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:153-[[@LINE-2]]:172}:"" +// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:153-[[@LINE-1]]:172}:"" +// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:108-[[@LINE-2]]:132}:"" #pragma clang attribute pop Index: clang/lib/Sema/SemaDeclObjC.cpp =================================================================== --- clang/lib/Sema/SemaDeclObjC.cpp +++ clang/lib/Sema/SemaDeclObjC.cpp @@ -1892,7 +1892,8 @@ Decl *Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CatName, SourceLocation CatLoc) { + IdentifierInfo *CatName, SourceLocation CatLoc, + const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = nullptr; if (IDecl && IDecl->hasDefinition()) { @@ -1920,6 +1921,9 @@ CDecl->setInvalidDecl(); } + ProcessDeclAttributeList(TUScope, CDecl, Attrs); + AddPragmaAttributes(TUScope, CDecl); + // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -1955,7 +1959,8 @@ SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc) { + SourceLocation SuperClassLoc, + const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = nullptr; // Check for another declaration kind with the same name. NamedDecl *PrevDecl @@ -2049,6 +2054,9 @@ ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, ClassLoc, AtClassImplLoc, SuperClassLoc); + ProcessDeclAttributeList(TUScope, IMPDecl, Attrs); + AddPragmaAttributes(TUScope, IMPDecl); + if (CheckObjCDeclScope(IMPDecl)) return ActOnObjCContainerStartDefinition(IMPDecl); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -980,9 +980,10 @@ if (getLangOpts().ObjC && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" if (!Tok.isObjCAtKeyword(tok::objc_interface) && - !Tok.isObjCAtKeyword(tok::objc_protocol)) { + !Tok.isObjCAtKeyword(tok::objc_protocol) && + !Tok.isObjCAtKeyword(tok::objc_implementation)) { Diag(Tok, diag::err_objc_unexpected_attr); - SkipUntil(tok::semi); // FIXME: better skip? + SkipUntil(tok::semi); return nullptr; } @@ -997,6 +998,9 @@ if (Tok.isObjCAtKeyword(tok::objc_protocol)) return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); + if (Tok.isObjCAtKeyword(tok::objc_implementation)) + return ParseObjCAtImplementationDeclaration(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 @@ -64,7 +64,7 @@ case tok::objc_protocol: return ParseObjCAtProtocolDeclaration(AtLoc, Attrs); case tok::objc_implementation: - return ParseObjCAtImplementationDeclaration(AtLoc); + return ParseObjCAtImplementationDeclaration(AtLoc, Attrs); case tok::objc_end: return ParseObjCAtEndDeclaration(AtLoc); case tok::objc_compatibility_alias: @@ -2097,7 +2097,8 @@ /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) Parser::DeclGroupPtrTy -Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { +Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, + ParsedAttributes &Attrs) { assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); CheckNestedObjCContexts(AtLoc); @@ -2174,8 +2175,7 @@ /*consumeLastToken=*/true); } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( - AtLoc, nameId, nameLoc, categoryId, - categoryLoc); + AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs); } else { // We have a class implementation @@ -2189,8 +2189,7 @@ superClassLoc = ConsumeToken(); // Consume super class name } ObjCImpDecl = Actions.ActOnStartClassImplementation( - AtLoc, nameId, nameLoc, - superClassId, superClassLoc); + AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs); if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -8105,17 +8105,19 @@ const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); - Decl *ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc); + Decl *ActOnStartClassImplementation(SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc, + const ParsedAttributesView &AttrList); Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, - SourceLocation CatLoc); + SourceLocation CatLoc, + const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef<Decl *> Decls); Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -1573,7 +1573,8 @@ ObjCImplParsingDataRAII *CurParsedObjCImpl; void StashAwayMethodOrFunctionBodyTokens(Decl *MDecl); - DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc); + DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, + ParsedAttributes &Attrs); DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd); Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc); Decl *ParseObjCPropertySynthesize(SourceLocation atLoc); Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -433,7 +433,7 @@ def err_objc_properties_require_objc2 : Error< "properties are an Objective-C 2 feature">; def err_objc_unexpected_attr : Error< - "prefix attribute must be followed by an interface or protocol">; + "prefix attribute must be followed by an interface, protocol, or implementation">; def err_objc_postfix_attribute : Error < "postfix attributes are not allowed on Objective-C directives">; def err_objc_postfix_attribute_hint : Error < Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -419,6 +419,10 @@ [ObjCCategory]> { let LangOpts = [ObjC]; } +def SubjectMatcherForObjCImplementation : + AttrSubjectMatcherRule<"objc_implementation", [ObjCImpl]> { + let LangOpts = [ObjC]; +} def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method", [ObjCMethod], [ AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits