From c56298d87a9df507805a548d7d515e8b511df2c0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 10 Apr 2012 03:25:07 +0000 Subject: 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 --- lib/Parse/ParseDecl.cpp | 6 +-- lib/Parse/ParseDeclCXX.cpp | 94 ++++++++++++++++++++++++++++++++------------ lib/Parse/ParseTentative.cpp | 7 ++-- 3 files changed, 74 insertions(+), 33 deletions(-) (limited to 'lib/Parse') 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. -- cgit v1.2.3