diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-10 03:25:07 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-10 03:25:07 +0000 |
commit | c56298d87a9df507805a548d7d515e8b511df2c0 (patch) | |
tree | bd9d2feb4342dc9d8f7dc063b99b0e6be9ab29d0 | |
parent | 6ee326af4e77e6f05973486097884d7431f2108d (diff) |
Parsing of C++11 attributes:
* Alternative tokens (such as 'compl') are treated as identifiers in
attribute names.
* An attribute-list can start with a comma.
* An ellipsis may not be used with either of our currently-supported
C++11 attributes.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154381 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 8 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 11 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 94 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 7 | ||||
-rw-r--r-- | test/Parser/cxx0x-attributes.cpp | 9 | ||||
-rw-r--r-- | test/Parser/objcxx11-attributes.mm | 1 |
7 files changed, 93 insertions, 43 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 5b53223e46..c183da7a6a 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -464,10 +464,10 @@ def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, def warn_cxx98_compat_attribute : Warning< "attributes are incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def err_cxx0x_attribute_forbids_arguments : Error< - "C++11 attribute '%0' cannot have an argument list">; -def err_cxx0x_attribute_requires_arguments : Error< - "C++11 attribute '%0' must have an argument list">; +def err_cxx11_attribute_forbids_arguments : Error< + "attribute '%0' cannot have an argument list">; +def err_cxx11_attribute_forbids_ellipsis : Error< + "attribute '%0' cannot be used as an attribute pack">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 5e070e4f36..e599207c24 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1907,7 +1907,7 @@ private: if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; - ParseCXX0XAttributes(attrs, &endLoc); + ParseCXX11Attributes(attrs, &endLoc); D.takeAttributes(attrs, endLoc); } } @@ -1915,7 +1915,7 @@ private: SourceLocation *endLoc = 0) { if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); - ParseCXX0XAttributes(attrsWithRange, endLoc); + ParseCXX11Attributes(attrsWithRange, endLoc); attrs.takeAllFrom(attrsWithRange); } } @@ -1924,13 +1924,14 @@ private: bool OuterMightBeMessageSend = false) { if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) - ParseCXX0XAttributes(attrs, endLoc); + ParseCXX11Attributes(attrs, endLoc); } - void ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, + void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation *EndLoc = 0); - void ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *EndLoc = 0); + IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9bafa92d7f..969e0b21b0 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3486,11 +3486,11 @@ bool Parser::isConstructorDeclarator() { /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, - bool CXX0XAttributesAllowed) { - if (getLangOpts().CPlusPlus0x && CXX0XAttributesAllowed && + bool CXX11AttributesAllowed) { + if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); - ParseCXX0XAttributes(attrs); + ParseCXX11Attributes(attrs); DS.takeAttributesFrom(attrs); } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 10ed3b1516..b2a65ff0f3 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2736,7 +2736,49 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } -/// ParseCXX0XAttributeSpecifier - Parse a C++11 attribute-specifier. Currently +/// \brief Try to parse an 'identifier' which appears within an attribute-token. +/// +/// \return the parsed identifier on success, and 0 if the next token is not an +/// attribute-token. +/// +/// C++11 [dcl.attr.grammar]p3: +/// If a keyword or an alternative token that satisfies the syntactic +/// requirements of an identifier is contained in an attribute-token, +/// it is considered an identifier. +IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { + switch (Tok.getKind()) { + default: + // Identifiers and keywords have identifier info attached. + if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + Loc = ConsumeToken(); + return II; + } + return 0; + + case tok::ampamp: // 'and' + case tok::pipe: // 'bitor' + case tok::pipepipe: // 'or' + case tok::caret: // 'xor' + case tok::tilde: // 'compl' + case tok::amp: // 'bitand' + case tok::ampequal: // 'and_eq' + case tok::pipeequal: // 'or_eq' + case tok::caretequal: // 'xor_eq' + case tok::exclaim: // 'not' + case tok::exclaimequal: // 'not_eq' + // Alternative tokens do not have identifier info, but their spelling + // starts with an alphabetical character. + llvm::SmallString<8> SpellingBuf; + StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); + if (std::isalpha(Spelling[0])) { + Loc = ConsumeToken(); + return &PP.getIdentifierTable().get(Spelling.data()); + } + return 0; + } +} + +/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently /// only parses standard attributes. /// /// [C++11] attribute-specifier: @@ -2746,6 +2788,8 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// [C++11] attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' /// /// [C++11] attribute: /// attribute-token attribute-argument-clause[opt] @@ -2772,7 +2816,7 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' -void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, +void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation *endLoc) { if (Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); @@ -2788,40 +2832,34 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, ConsumeBracket(); ConsumeBracket(); - if (Tok.is(tok::comma)) { - Diag(Tok.getLocation(), diag::err_expected_ident); - ConsumeToken(); - } - - // C++11 [dcl.attr.grammar]p3: If a keyword or an alternative token that - // satisfies the syntactic requirements of an identifier is contained in an - // attribute-token, it is considered an identifier. - // FIXME: Support alternative tokens here. - while (Tok.getIdentifierInfo() || Tok.is(tok::comma)) { + while (Tok.isNot(tok::r_square)) { // attribute not present if (Tok.is(tok::comma)) { ConsumeToken(); continue; } - IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); - SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); + SourceLocation ScopeLoc, AttrLoc; + IdentifierInfo *ScopeName = 0, *AttrName = 0; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) + // Break out to the "expected ']'" diagnostic. + break; // scoped attribute if (Tok.is(tok::coloncolon)) { ConsumeToken(); - if (!Tok.getIdentifierInfo()) { + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected_ident); SkipUntil(tok::r_square, tok::comma, true, true); continue; } - - ScopeName = AttrName; - ScopeLoc = AttrLoc; - - AttrName = Tok.getIdentifierInfo(); - AttrLoc = ConsumeToken(); } bool AttrParsed = false; @@ -2833,7 +2871,7 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, case AttributeList::AT_carries_dependency: case AttributeList::AT_noreturn: { if (Tok.is(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) << AttrName->getName(); break; } @@ -2856,8 +2894,12 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_paren, false); } - if (Tok.is(tok::ellipsis)) + if (Tok.is(tok::ellipsis)) { + if (AttrParsed) + Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) + << AttrName->getName(); ConsumeToken(); + } } if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) @@ -2868,18 +2910,18 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_square, false); } -/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier -void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, +void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; do { - ParseCXX0XAttributeSpecifier(attrs, endLoc); + ParseCXX11AttributeSpecifier(attrs, endLoc); } while (isCXX11AttributeSpecifier()); attrs.Range = SourceRange(StartLoc, *endLoc); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 18bc0ddc5b..5ce6b2b91c 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -485,18 +485,17 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, // If a keyword or an alternative token that satisfies the syntactic // requirements of an identifier is contained in an attribute-token, // it is considered an identifier. - if (!Tok.getIdentifierInfo()) { + SourceLocation Loc; + if (!TryParseCXX11AttributeIdentifier(Loc)) { IsAttribute = false; break; } - ConsumeToken(); if (Tok.is(tok::coloncolon)) { ConsumeToken(); - if (!Tok.getIdentifierInfo()) { + if (!TryParseCXX11AttributeIdentifier(Loc)) { IsAttribute = false; break; } - ConsumeToken(); } // Parse the attribute-argument-clause, if present. diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index b20873509b..bf73e0845a 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -11,6 +11,9 @@ int array_attr [1] [[]]; alignas(8) int aligned_attr; [[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]] int garbage_attr; +[[,,,static, class, namespace,, inline, constexpr, mutable,, bi\ +tand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr; +[[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected ']'}} void fn_attr () [[]]; void noexcept_fn_attr () noexcept [[]]; struct MemberFnOrder { @@ -21,7 +24,7 @@ extern "C++" [[]] int extern_attr; template <typename T> [[]] void template_attr (); [[]] [[]] int [[]] [[]] multi_attr [[]] [[]]; -int comma_attr [[,]]; // expected-error {{expected identifier}} +int comma_attr [[,]]; int scope_attr [[foo::]]; // expected-error {{expected identifier}} int (paren_attr) [[]]; // expected-error {{an attribute list cannot appear here}} unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}} @@ -70,3 +73,7 @@ void foo () { [[]] return; } + +template<typename...Ts> void variadic() { + void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}} +} diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm index 719cdcc32f..fead1d1b46 100644 --- a/test/Parser/objcxx11-attributes.mm +++ b/test/Parser/objcxx11-attributes.mm @@ -33,6 +33,7 @@ void f(X *noreturn) { [[]]; [[int(), noreturn]]; [[class, test(foo 'x' bar),,,]]; + [[bitand, noreturn]]; } template<typename...Ts> void f(Ts ...x) { |