Thanks for doing this! Looks like this won't reject the ill-formed construct [[deprecated()]]. (Both [[gnu::deprecated()]] and __attribute__((deprecated())) are OK, IIRC.)
On Mon, Mar 31, 2014 at 10:32 AM, Aaron Ballman <[email protected]>wrote: > Author: aaronballman > Date: Mon Mar 31 12:32:39 2014 > New Revision: 205226 > > URL: http://llvm.org/viewvc/llvm-project?rev=205226&view=rev > Log: > Introduced an attribute syntax-neutral method for parsing attribute > arguments that is currently being used by GNU and C++-style attributes. > This allows C++11 attributes with argument lists to be handled properly, > fixing the "deprecated", "type_visibility", and capability-related > attributes with arguments. > > Modified: > cfe/trunk/include/clang/Parse/Parser.h > cfe/trunk/lib/Parse/ParseDecl.cpp > cfe/trunk/lib/Parse/ParseDeclCXX.cpp > cfe/trunk/test/Parser/cxx0x-attributes.cpp > > Modified: cfe/trunk/include/clang/Parse/Parser.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=205226&r1=205225&r2=205226&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Parse/Parser.h (original) > +++ cfe/trunk/include/clang/Parse/Parser.h Mon Mar 31 12:32:39 2014 > @@ -1996,6 +1996,16 @@ private: > /// locations where attributes are not allowed. > void DiagnoseAndSkipCXX11Attributes(); > > + /// \brief Parses syntax-generic attribute arguments for attributes > which are > + /// known to the implementation, and adds them to the given > ParsedAttributes > + /// list with the given attribute syntax. > + void ParseAttributeArgsCommon(IdentifierInfo *AttrName, > + SourceLocation AttrNameLoc, > + ParsedAttributes &Attrs, SourceLocation > *EndLoc, > + IdentifierInfo *ScopeName, > + SourceLocation ScopeLoc, > + AttributeList::Syntax Syntax); > + > void MaybeParseGNUAttributes(Declarator &D, > LateParsedAttrList *LateAttrs = 0) { > if (Tok.is(tok::kw___attribute)) { > @@ -2053,6 +2063,13 @@ private: > SourceLocation *EndLoc = 0); > void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, > SourceLocation *EndLoc = 0); > + /// \brief Parses a C++-style attribute argument list. Returns true if > this > + /// results in adding an attribute to the ParsedAttributes list. > + bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, > + SourceLocation AttrNameLoc, > + ParsedAttributes &Attrs, SourceLocation > *EndLoc, > + IdentifierInfo *ScopeName, > + SourceLocation ScopeLoc); > > IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); > > > Modified: cfe/trunk/lib/Parse/ParseDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=205226&r1=205225&r2=205226&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 31 12:32:39 2014 > @@ -259,6 +259,65 @@ void Parser::ParseAttributeWithTypeArg(I > 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU); > } > > +void Parser::ParseAttributeArgsCommon( > + IdentifierInfo *AttrName, SourceLocation AttrNameLoc, > + ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo > *ScopeName, > + SourceLocation ScopeLoc, AttributeList::Syntax Syntax) { > + // Ignore the left paren location for now. > + ConsumeParen(); > + > + ArgsVector ArgExprs; > + if (Tok.is(tok::identifier)) { > + // If this attribute wants an 'identifier' argument, make it so. > + bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); > + AttributeList::Kind AttrKind = > + AttributeList::getKind(AttrName, ScopeName, Syntax); > + > + // If we don't know how to parse this attribute, but this is the only > + // token in this argument, assume it's meant to be an identifier. > + if (AttrKind == AttributeList::UnknownAttribute || > + AttrKind == AttributeList::IgnoredAttribute) { > + const Token &Next = NextToken(); > + IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); > + } > + > + if (IsIdentifierArg) > + ArgExprs.push_back(ParseIdentifierLoc()); > + } > + > + if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) { > + // Eat the comma. > + if (!ArgExprs.empty()) > + ConsumeToken(); > + > + // Parse the non-empty comma-separated list of expressions. > + do { > + std::unique_ptr<EnterExpressionEvaluationContext> Unevaluated; > + if (attributeParsedArgsUnevaluated(*AttrName)) > + Unevaluated.reset( > + new EnterExpressionEvaluationContext(Actions, > Sema::Unevaluated)); > + > + ExprResult ArgExpr(ParseAssignmentExpression()); > + if (ArgExpr.isInvalid()) { > + SkipUntil(tok::r_paren, StopAtSemi); > + return; > + } > + ArgExprs.push_back(ArgExpr.release()); > + // Eat the comma, move to the next argument > + } while (TryConsumeToken(tok::comma)); > + } > + > + SourceLocation RParen = Tok.getLocation(); > + if (!ExpectAndConsume(tok::r_paren)) { > + SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; > + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, > ScopeLoc, > + ArgExprs.data(), ArgExprs.size(), Syntax); > + } > + > + if (EndLoc) > + *EndLoc = RParen; > +} > + > /// Parse the arguments to a parameterized GNU attribute or > /// a C++11 attribute in "gnu" namespace. > void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, > @@ -314,58 +373,8 @@ void Parser::ParseGNUAttributeArgs(Ident > } > } > > - // Ignore the left paren location for now. > - ConsumeParen(); > - > - ArgsVector ArgExprs; > - > - if (Tok.is(tok::identifier)) { > - // If this attribute wants an 'identifier' argument, make it so. > - bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); > - > - // If we don't know how to parse this attribute, but this is the only > - // token in this argument, assume it's meant to be an identifier. > - if (AttrKind == AttributeList::UnknownAttribute || > - AttrKind == AttributeList::IgnoredAttribute) { > - const Token &Next = NextToken(); > - IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); > - } > - > - if (IsIdentifierArg) > - ArgExprs.push_back(ParseIdentifierLoc()); > - } > - > - if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) { > - // Eat the comma. > - if (!ArgExprs.empty()) > - ConsumeToken(); > - > - // Parse the non-empty comma-separated list of expressions. > - do { > - std::unique_ptr<EnterExpressionEvaluationContext> Unevaluated; > - if (attributeParsedArgsUnevaluated(*AttrName)) > - Unevaluated.reset(new EnterExpressionEvaluationContext(Actions, > - Sema::Unevaluated)); > - > - ExprResult ArgExpr(ParseAssignmentExpression()); > - if (ArgExpr.isInvalid()) { > - SkipUntil(tok::r_paren, StopAtSemi); > - return; > - } > - ArgExprs.push_back(ArgExpr.release()); > - // Eat the comma, move to the next argument > - } while (TryConsumeToken(tok::comma)); > - } > - > - SourceLocation RParen = Tok.getLocation(); > - if (!ExpectAndConsume(tok::r_paren)) { > - SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; > - Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, > ScopeLoc, > - ArgExprs.data(), ArgExprs.size(), Syntax); > - } > - > - if (EndLoc) > - *EndLoc = RParen; > + ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, > ScopeName, > + ScopeLoc, Syntax); > } > > /// \brief Parses a single argument for a declspec, including the > > Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=205226&r1=205225&r2=205226&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 31 12:32:39 2014 > @@ -15,7 +15,9 @@ > #include "RAIIObjectsForParser.h" > #include "clang/AST/ASTContext.h" > #include "clang/AST/DeclTemplate.h" > +#include "clang/Basic/Attributes.h" > #include "clang/Basic/CharInfo.h" > +#include "clang/Basic/TargetInfo.h" > #include "clang/Basic/OperatorKinds.h" > #include "clang/Parse/ParseDiagnostic.h" > #include "clang/Sema/DeclSpec.h" > @@ -3197,8 +3199,50 @@ static bool IsBuiltInOrStandardCXX11Attr > } > } > > -/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. > Currently > -/// only parses standard attributes. > +/// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause. > +/// > +/// [C++11] attribute-argument-clause: > +/// '(' balanced-token-seq ')' > +/// > +/// [C++11] balanced-token-seq: > +/// balanced-token > +/// balanced-token-seq balanced-token > +/// > +/// [C++11] balanced-token: > +/// '(' balanced-token-seq ')' > +/// '[' balanced-token-seq ']' > +/// '{' balanced-token-seq '}' > +/// any token but '(', ')', '[', ']', '{', or '}' > +bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, > + SourceLocation AttrNameLoc, > + ParsedAttributes &Attrs, > + SourceLocation *EndLoc, > + IdentifierInfo *ScopeName, > + SourceLocation ScopeLoc) { > + assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list"); > + > + // If the attribute isn't known, we will not attempt to parse any > + // arguments. > + if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName, > + getTargetInfo().getTriple(), getLangOpts())) { > + // Eat the left paren, then skip to the ending right paren. > + ConsumeParen(); > + SkipUntil(tok::r_paren); > + return false; > + } > + > + if (ScopeName && ScopeName->getName() == "gnu") > + // GNU-scoped attributes have some special cases to handle > GNU-specific > + // behaviors. > + ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, > + ScopeLoc, AttributeList::AS_CXX11, 0); > + else > + ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, > ScopeName, > + ScopeLoc, AttributeList::AS_CXX11); > + return true; > +} > + > +/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. > /// > /// [C++11] attribute-specifier: > /// '[' '[' attribute-list ']' ']' > @@ -3222,19 +3266,6 @@ static bool IsBuiltInOrStandardCXX11Attr > /// > /// [C++11] attribute-namespace: > /// identifier > -/// > -/// [C++11] attribute-argument-clause: > -/// '(' balanced-token-seq ')' > -/// > -/// [C++11] balanced-token-seq: > -/// balanced-token > -/// balanced-token-seq balanced-token > -/// > -/// [C++11] balanced-token: > -/// '(' balanced-token-seq ')' > -/// '[' balanced-token-seq ']' > -/// '{' balanced-token-seq '}' > -/// any token but '(', ')', '[', ']', '{', or '}' > void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, > SourceLocation *endLoc) { > if (Tok.is(tok::kw_alignas)) { > @@ -3279,29 +3310,22 @@ void Parser::ParseCXX11AttributeSpecifie > } > } > > - bool StandardAttr = > IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName); > + bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, > ScopeName); > bool AttrParsed = false; > > if (StandardAttr && > !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second) > Diag(AttrLoc, diag::err_cxx11_attribute_repeated) > - << AttrName << SourceRange(SeenAttrs[AttrName]); > + << AttrName << SourceRange(SeenAttrs[AttrName]); > > // Parse attribute arguments > if (Tok.is(tok::l_paren)) { > - if (ScopeName && ScopeName->getName() == "gnu") { > - ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc, > - ScopeName, ScopeLoc, > AttributeList::AS_CXX11, 0); > - AttrParsed = true; > - } else { > - if (StandardAttr) > - Diag(Tok.getLocation(), > diag::err_cxx11_attribute_forbids_arguments) > + if (StandardAttr) > + Diag(Tok.getLocation(), > diag::err_cxx11_attribute_forbids_arguments) > << AttrName->getName(); > > - // FIXME: handle other formats of c++11 attribute arguments > - ConsumeParen(); > - SkipUntil(tok::r_paren); > - } > + AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, > endLoc, > + ScopeName, ScopeLoc); > } > > if (!AttrParsed) > > Modified: cfe/trunk/test/Parser/cxx0x-attributes.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-attributes.cpp?rev=205226&r1=205225&r2=205226&view=diff > > ============================================================================== > --- cfe/trunk/test/Parser/cxx0x-attributes.cpp (original) > +++ cfe/trunk/test/Parser/cxx0x-attributes.cpp Mon Mar 31 12:32:39 2014 > @@ -48,13 +48,13 @@ int array_attr [1] [[]]; > alignas(8) int aligned_attr; > [[test::valid(for 42 [very] **** '+' symbols went on a trip and had a > "good"_time; the end.)]] int garbage_attr; // expected-warning {{unknown > attribute 'valid' ignored}} > [[,,,static, class, namespace,, inline, constexpr, mutable,, bitand, > bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr; // expected-warning > {{unknown attribute 'static' ignored}} \ > - // expected-warning {{unknown attribute 'class' ignored}} \ > - // expected-warning {{unknown attribute 'namespace' ignored}} \ > - // expected-warning {{unknown attribute 'inline' ignored}} \ > - // expected-warning {{unknown attribute 'constexpr' ignored}} \ > - // expected-warning {{unknown attribute 'mutable' ignored}} \ > - // expected-warning {{unknown attribute 'bitand' ignored}} \ > - // expected-warning {{unknown attribute 'compl' ignored}} > + // expected-warning {{unknown attribute 'class' ignored}} \ > + // expected-warning {{unknown attribute 'namespace' ignored}} \ > + // expected-warning {{unknown attribute 'inline' ignored}} \ > + // expected-warning {{unknown attribute 'constexpr' ignored}} \ > + // expected-warning {{unknown attribute 'mutable' ignored}} \ > + // expected-warning {{unknown attribute 'bitand' ignored}} \ > + // expected-warning {{unknown attribute 'compl' ignored}} > [[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected > ']'}} > void fn_attr () [[]]; > void noexcept_fn_attr () noexcept [[]]; > @@ -281,7 +281,8 @@ enum class [[]] EvenMoreSecrets {}; > > namespace arguments { > void f[[gnu::format(printf, 1, 2)]](const char*, ...); > - void g() [[unknown::foo(arguments of attributes from unknown namespace > other than 'gnu' namespace are ignored... blah...)]]; // expected-warning > {{unknown attribute 'foo' ignored}} > + void g() [[unknown::foo(ignore arguments for unknown attributes, even > with symbols!)]]; // expected-warning {{unknown attribute 'foo' ignored}} > + [[deprecated("with argument")]] int i; > } > > // Forbid attributes on decl specifiers. > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
