r205226 - 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.
Richard Smith
richard at metafoo.co.uk
Fri Apr 11 14:38:35 PDT 2014
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 <aaron at aaronballman.com>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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140411/e66dc948/attachment.html>
More information about the cfe-commits
mailing list