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