Add support for attributes on @implementations in Objective-C
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. Differential revision: https://reviews.llvm.org/D60542 llvm-svn: 358200
This commit is contained in:
parent
7822b46188
commit
c5a0583400
|
@ -419,6 +419,10 @@ def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
|
|||
[ObjCCategory]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCImplementation :
|
||||
AttrSubjectMatcherRule<"objc_implementation", [ObjCImpl]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
|
||||
[ObjCMethod], [
|
||||
AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
|
||||
|
|
|
@ -433,7 +433,7 @@ def err_objc_expected_property_attr : Error<"unknown property attribute %0">;
|
|||
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 <
|
||||
|
|
|
@ -1573,7 +1573,8 @@ private:
|
|||
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);
|
||||
|
|
|
@ -8105,17 +8105,19 @@ public:
|
|||
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);
|
||||
|
|
|
@ -64,7 +64,7 @@ Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
|
|||
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 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
|
|||
/// 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 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
|
|||
/*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 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
|
|||
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);
|
||||
|
|
|
@ -980,9 +980,10 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
|
|||
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 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
|
|||
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()));
|
||||
}
|
||||
|
|
|
@ -1892,7 +1892,8 @@ Decl *Sema::ActOnStartCategoryInterface(
|
|||
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 @@ Decl *Sema::ActOnStartCategoryImplementation(
|
|||
CDecl->setInvalidDecl();
|
||||
}
|
||||
|
||||
ProcessDeclAttributeList(TUScope, CDecl, Attrs);
|
||||
AddPragmaAttributes(TUScope, CDecl);
|
||||
|
||||
// FIXME: PushOnScopeChains?
|
||||
CurContext->addDecl(CDecl);
|
||||
|
||||
|
@ -1955,7 +1959,8 @@ Decl *Sema::ActOnStartClassImplementation(
|
|||
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 @@ Decl *Sema::ActOnStartClassImplementation(
|
|||
ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl,
|
||||
ClassLoc, AtClassImplLoc, SuperClassLoc);
|
||||
|
||||
ProcessDeclAttributeList(TUScope, IMPDecl, Attrs);
|
||||
AddPragmaAttributes(TUScope, IMPDecl);
|
||||
|
||||
if (CheckObjCDeclScope(IMPDecl))
|
||||
return ActOnObjCContainerStartDefinition(IMPDecl);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 class C2 {}; // expected-warning {{attribute 'visibility' is ignored, place
|
|||
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
|
||||
|
|
53
clang/test/Parser/objc-implementation-attrs.m
Normal file
53
clang/test/Parser/objc-implementation-attrs.m
Normal file
|
@ -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
|
|
@ -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'}}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -29,6 +29,7 @@ void foo();
|
|||
|
||||
@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
|
||||
|
|
|
@ -19,7 +19,7 @@ __attribute__((objc_runtime_name("MySecretNamespace.Message"))) // expected-erro
|
|||
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 @@ __attribute__((objc_runtime_name("MySecretNamespace.Message")))
|
|||
@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 @@ __attribute__((objc_runtime_name("MySecretNamespace.ForwardProtocol")))
|
|||
|
||||
@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
|
||||
|
|
Loading…
Reference in a new issue