summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-04-10 03:25:07 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-04-10 03:25:07 +0000
commitc56298d87a9df507805a548d7d515e8b511df2c0 (patch)
treebd9d2feb4342dc9d8f7dc063b99b0e6be9ab29d0
parent6ee326af4e77e6f05973486097884d7431f2108d (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td8
-rw-r--r--include/clang/Parse/Parser.h11
-rw-r--r--lib/Parse/ParseDecl.cpp6
-rw-r--r--lib/Parse/ParseDeclCXX.cpp94
-rw-r--r--lib/Parse/ParseTentative.cpp7
-rw-r--r--test/Parser/cxx0x-attributes.cpp9
-rw-r--r--test/Parser/objcxx11-attributes.mm1
7 files changed, 93 insertions, 43 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 5b53223e46..c183da7a6a 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -464,10 +464,10 @@ def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
def warn_cxx98_compat_attribute : Warning<
"attributes are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-def err_cxx0x_attribute_forbids_arguments : Error<
- "C++11 attribute '%0' cannot have an argument list">;
-def err_cxx0x_attribute_requires_arguments : Error<
- "C++11 attribute '%0' must have an argument list">;
+def err_cxx11_attribute_forbids_arguments : Error<
+ "attribute '%0' cannot have an argument list">;
+def err_cxx11_attribute_forbids_ellipsis : Error<
+ "attribute '%0' cannot be used as an attribute pack">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
def err_l_square_l_square_not_attribute : Error<
"C++11 only allows consecutive left square brackets when "
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 5e070e4f36..e599207c24 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1907,7 +1907,7 @@ private:
if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
- ParseCXX0XAttributes(attrs, &endLoc);
+ ParseCXX11Attributes(attrs, &endLoc);
D.takeAttributes(attrs, endLoc);
}
}
@@ -1915,7 +1915,7 @@ private:
SourceLocation *endLoc = 0) {
if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
- ParseCXX0XAttributes(attrsWithRange, endLoc);
+ ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
}
}
@@ -1924,13 +1924,14 @@ private:
bool OuterMightBeMessageSend = false) {
if (getLangOpts().CPlusPlus0x &&
isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
- ParseCXX0XAttributes(attrs, endLoc);
+ ParseCXX11Attributes(attrs, endLoc);
}
- void ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
+ void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
SourceLocation *EndLoc = 0);
- void ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
+ void ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = 0);
+ IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc);
void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
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.
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index b20873509b..bf73e0845a 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -11,6 +11,9 @@ int array_attr [1] [[]];
alignas(8) int aligned_attr;
[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
int garbage_attr;
+[[,,,static, class, namespace,, inline, constexpr, mutable,, bi\
+tand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr;
+[[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected ']'}}
void fn_attr () [[]];
void noexcept_fn_attr () noexcept [[]];
struct MemberFnOrder {
@@ -21,7 +24,7 @@ extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr ();
[[]] [[]] int [[]] [[]] multi_attr [[]] [[]];
-int comma_attr [[,]]; // expected-error {{expected identifier}}
+int comma_attr [[,]];
int scope_attr [[foo::]]; // expected-error {{expected identifier}}
int (paren_attr) [[]]; // expected-error {{an attribute list cannot appear here}}
unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
@@ -70,3 +73,7 @@ void foo () {
[[]] return;
}
+
+template<typename...Ts> void variadic() {
+ void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
+}
diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm
index 719cdcc32f..fead1d1b46 100644
--- a/test/Parser/objcxx11-attributes.mm
+++ b/test/Parser/objcxx11-attributes.mm
@@ -33,6 +33,7 @@ void f(X *noreturn) {
[[]];
[[int(), noreturn]];
[[class, test(foo 'x' bar),,,]];
+ [[bitand, noreturn]];
}
template<typename...Ts> void f(Ts ...x) {