diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 92e56ba80a07..5d4d8931745d 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -421,6 +421,8 @@ DIAG(err_objc_expected_equal, ERROR, "setter/getter expects '=' followed by name") DIAG(err_objc_expected_property_attr, ERROR, "unknown property attribute detected") +DIAG(err_objc_unexpected_attr, ERROR, + "prefix attribute must be followed by an interface or protocol") DIAG(err_objc_property_attr_mutually_exclusive, ERROR, "property attributes '%0' and '%1' are mutually exclusive") DIAG(warn_objc_property_no_assignment_attribute, WARNING, diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index a66d97dcb0d5..705d99ceedba 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -694,7 +694,8 @@ public: SourceLocation ProtocolLoc, DeclTy * const *ProtoRefs, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { + SourceLocation EndProtoLoc, + AttributeList *AttrList) { return 0; } // ActOnStartCategoryInterface - this action is called immdiately after diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 195398c70546..eb508d723441 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -331,7 +331,8 @@ private: SourceLocation &EndProtoLoc); void ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, tok::ObjCKeywordKind contextKey); - DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc); + DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc, + AttributeList *prefixAttrs = 0); DeclTy *ObjCImpDecl; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 8917eeb0ffa3..17488d523e4d 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -920,7 +920,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, /// "@protocol identifier ;" should be resolved as "@protocol /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. -Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { +Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, + AttributeList *attrList) { assert(Tok.isObjCAtKeyword(tok::objc_protocol) && "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier @@ -978,7 +979,7 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { DeclTy *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, &ProtocolRefs[0], ProtocolRefs.size(), - EndProtoLoc); + EndProtoLoc, attrList); ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); // The @ sign was already consumed by ParseObjCInterfaceDeclList(). diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7598ff79969b..797de9284ecc 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -393,17 +393,22 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); } - // ObjC2 allows prefix attributes on class interfaces. + // ObjC2 allows prefix attributes on class interfaces and protocols. + // FIXME: This still needs better diagnostics. We should only accept + // attributes here, no types, etc. if (getLang().ObjC2 && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" - if (!Tok.isObjCAtKeyword(tok::objc_interface)) { - Diag(Tok, diag::err_objc_expected_property_attr);//FIXME:better diagnostic + if (!Tok.isObjCAtKeyword(tok::objc_interface) && + !Tok.isObjCAtKeyword(tok::objc_protocol)) { + Diag(Tok, diag::err_objc_unexpected_attr); SkipUntil(tok::semi); // FIXME: better skip? return 0; } const char *PrevSpec = 0; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec)) Diag(AtLoc, diag::err_invalid_decl_spec_combination, PrevSpec); + if (Tok.isObjCAtKeyword(tok::objc_protocol)) + return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index ef5954b6294c..f553629a6c93 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -686,7 +686,8 @@ public: SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, DeclTy * const *ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc); + SourceLocation EndProtoLoc, + AttributeList *AttrList); virtual DeclTy *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 1b166c4094ef..a09daa0814b5 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -173,7 +173,9 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, SourceLocation ProtocolLoc, DeclTy * const *ProtoRefs, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { + SourceLocation EndProtoLoc, + AttributeList *AttrList) { + // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolName]; if (PDecl) { diff --git a/clang/test/Parser/objc-quirks.m b/clang/test/Parser/objc-quirks.m index af4f92610cac..b726d9a8274f 100644 --- a/clang/test/Parser/objc-quirks.m +++ b/clang/test/Parser/objc-quirks.m @@ -1,3 +1,4 @@ // RUN: clang -fsyntax-only -verify %s -int @"s" = 5; // expected-error {{unknown}} +// FIXME: This is a horrible error message here. Fix. +int @"s" = 5; // expected-error {{prefix attribute must be}} diff --git a/clang/test/Parser/prefix-attributes.m b/clang/test/Parser/prefix-attributes.m new file mode 100644 index 000000000000..46eb90cd2b30 --- /dev/null +++ b/clang/test/Parser/prefix-attributes.m @@ -0,0 +1,8 @@ +// RUN: clang -verify -fsyntax-only %s + +__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}} + +__attribute__((deprecated)) @interface A @end +__attribute__((deprecated)) @protocol P0; +__attribute__((deprecated)) @protocol P1 +@end