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.
Aaron Ballman
aaron at aaronballman.com
Mon Mar 31 10:32:39 PDT 2014
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.
More information about the cfe-commits
mailing list