[cfe-commits] r159072 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseObjc.cpp lib/Parse/ParseStmt.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp test/Parser/cxx0x-attributes.cpp
Sean Hunt
scshunt at csclub.uwaterloo.ca
Fri Jun 22 22:07:59 PDT 2012
Author: coppro
Date: Sat Jun 23 00:07:58 2012
New Revision: 159072
URL: http://llvm.org/viewvc/llvm-project?rev=159072&view=rev
Log:
Clean up a large number of C++11 attribute parse issues, including parsing
attributes in more places where we didn't and catching a lot more issues.
This implements nearly every aspect of C++11 attribute parsing, except for:
- Attributes are permitted on explicit instantiations inside the declarator
(but not preceding the decl-spec)
- Attributes are permitted on friend declarations of functions.
- Multiple instances of the same attribute in an attribute-list (e.g.
[[noreturn, noreturn]], not [[noreturn]] [[noreturn]] which is conforming)
are allowed.
The first two are marked as expected-FIXME in the test file and the latter
is probably a defect and is currently untested.
Thanks to Richard Smith for providing the lion's share of the testcases.
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Parse/ParseTemplate.cpp
cfe/trunk/lib/Parse/Parser.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=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sat Jun 23 00:07:58 2012
@@ -1045,10 +1045,13 @@
ParsingDeclSpec *DS = 0);
bool isDeclarationAfterDeclarator();
bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
- DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
- AccessSpecifier AS = AS_none);
- DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
+ DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
+ ParsedAttributesWithRange &attrs,
+ ParsingDeclSpec *DS = 0,
AccessSpecifier AS = AS_none);
+ DeclGroupPtrTy ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
+ ParsingDeclSpec &DS,
+ AccessSpecifier AS);
Decl *ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1496,7 +1499,7 @@
DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts,
unsigned Context,
SourceLocation &DeclEnd,
- ParsedAttributes &attrs,
+ ParsedAttributesWithRange &attrs,
bool RequireSemi,
ForRangeInit *FRI = 0);
bool MightBeDeclarator(unsigned Context);
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sat Jun 23 00:07:58 2012
@@ -1126,10 +1126,12 @@
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
/// declaration-specifiers init-declarator-list[opt] ';'
+/// [C++11] attribute-specifier-seq decl-specifier-seq[opt]
+/// init-declarator-list ';'
///[C90/C++]init-declarator-list ';' [TODO]
/// [OMP] threadprivate-directive [TODO]
///
-/// for-range-declaration: [C++0x 6.5p1: stmt.ranged]
+/// for-range-declaration: [C++11 6.5p1: stmt.ranged]
/// attribute-specifier-seq[opt] type-specifier-seq declarator
///
/// If RequireSemi is false, this does not check for a ';' at the end of the
@@ -1138,12 +1140,11 @@
/// If FRI is non-null, we might be parsing a for-range-declaration instead
/// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here.
-Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
- unsigned Context,
- SourceLocation &DeclEnd,
- ParsedAttributes &attrs,
- bool RequireSemi,
- ForRangeInit *FRI) {
+Parser::DeclGroupPtrTy
+Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
+ SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &attrs,
+ bool RequireSemi, ForRangeInit *FRI) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(attrs);
@@ -2026,6 +2027,8 @@
}
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
+ bool AttrsLastTime = false;
+ ParsedAttributesWithRange attrs(AttrFactory);
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -2036,14 +2039,32 @@
switch (Tok.getKind()) {
default:
DoneWithDeclSpec:
- // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt]
- MaybeParseCXX0XAttributes(DS.getAttributes());
+ if (!AttrsLastTime)
+ ProhibitAttributes(attrs);
+ else
+ DS.takeAttributesFrom(attrs);
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
DS.Finish(Diags, PP);
return;
+ case tok::l_square:
+ case tok::kw_alignas:
+ if (!isCXX11AttributeSpecifier())
+ goto DoneWithDeclSpec;
+
+ ProhibitAttributes(attrs);
+ // FIXME: It would be good to recover by accepting the attributes,
+ // but attempting to do that now would cause serious
+ // madness in terms of diagnostics.
+ attrs.clear();
+ attrs.Range = SourceRange();
+
+ ParseCXX11Attributes(attrs);
+ AttrsLastTime = true;
+ continue;
+
case tok::code_completion: {
Sema::ParserCompletionContext CCC = Sema::PCC_Namespace;
if (DS.hasTypeSpecifier()) {
@@ -2696,6 +2717,8 @@
DS.SetRangeEnd(Tok.getLocation());
if (DiagID != diag::err_bool_redeclaration)
ConsumeToken();
+
+ AttrsLastTime = false;
}
}
@@ -2941,6 +2964,15 @@
return cutOffParsing();
}
+ // If attributes exist after tag, parse them.
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseGNUAttributes(attrs);
+ MaybeParseCXX0XAttributes(attrs);
+
+ // If declspecs exist after tag, parse them.
+ while (Tok.is(tok::kw___declspec))
+ ParseMicrosoftDeclSpec(attrs);
+
SourceLocation ScopedEnumKWLoc;
bool IsScopedUsingClassTag = false;
@@ -2949,6 +2981,10 @@
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
IsScopedUsingClassTag = Tok.is(tok::kw_class);
ScopedEnumKWLoc = ConsumeToken();
+
+ ProhibitAttributes(attrs);
+ // Recovery: assume that the attributes came after the tag.
+ MaybeParseCXX0XAttributes(attrs);
}
// C++11 [temp.explicit]p12:
@@ -2962,14 +2998,6 @@
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
- // If attributes exist after tag, parse them.
- ParsedAttributes attrs(AttrFactory);
- MaybeParseGNUAttributes(attrs);
-
- // If declspecs exist after tag, parse them.
- while (Tok.is(tok::kw___declspec))
- ParseMicrosoftDeclSpec(attrs);
-
// Enum definitions should not be parsed in a trailing-return-type.
bool AllowDeclaration = DSC != DSC_trailing;
@@ -3154,6 +3182,9 @@
TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(),
TemplateInfo.TemplateParams->size());
}
+
+ if (TUK == Sema::TUK_Reference)
+ ProhibitAttributes(attrs);
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
@@ -3252,8 +3283,10 @@
SourceLocation IdentLoc = ConsumeToken();
// If attributes exist after the enumerator, parse them.
- ParsedAttributes attrs(AttrFactory);
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
+ MaybeParseCXX0XAttributes(attrs);
+ ProhibitAttributes(attrs);
SourceLocation EqualLoc;
ExprResult AssignedVal;
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sat Jun 23 00:07:58 2012
@@ -444,6 +444,13 @@
CXXScopeSpec SS;
SourceLocation TypenameLoc;
bool IsTypeName;
+ ParsedAttributesWithRange attrs(AttrFactory);
+
+ // FIXME: Simply skip the attributes and diagnose, don't bother parsing them.
+ MaybeParseCXX0XAttributes(attrs);
+ ProhibitAttributes(attrs);
+ attrs.clear();
+ attrs.Range = SourceRange();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
@@ -480,7 +487,7 @@
return 0;
}
- ParsedAttributes attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
// Maybe this is an alias-declaration.
bool IsAliasDecl = Tok.is(tok::equal);
@@ -533,9 +540,14 @@
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
Declarator::AliasDeclContext, AS, OwnedType);
- } else
+ } else {
+ // C++11 attributes are not allowed on a using-declaration, but GNU ones
+ // are.
+ ProhibitAttributes(attrs);
+
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
+ }
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -572,6 +584,7 @@
MultiTemplateParamsArg TemplateParamsArg(Actions,
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
+ // FIXME: Propagate attributes.
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, TypeAlias);
}
@@ -989,7 +1002,7 @@
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
- ParsedAttributes attrs(AttrFactory);
+ ParsedAttributesWithRange attrs(AttrFactory);
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
ParseGNUAttributes(attrs);
@@ -1202,6 +1215,8 @@
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
// This is an explicit instantiation of a class template.
+ ProhibitAttributes(attrs);
+
TagOrTempResult
= Actions.ActOnExplicitInstantiation(getCurScope(),
TemplateInfo.ExternLoc,
@@ -1223,6 +1238,7 @@
} else if (TUK == Sema::TUK_Reference ||
(TUK == Sema::TUK_Friend &&
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
+ ProhibitAttributes(attrs);
TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
TemplateId->SS,
TemplateId->TemplateKWLoc,
@@ -1287,6 +1303,8 @@
//
// template struct Outer<int>::Inner;
//
+ ProhibitAttributes(attrs);
+
TagOrTempResult
= Actions.ActOnExplicitInstantiation(getCurScope(),
TemplateInfo.ExternLoc,
@@ -1295,6 +1313,8 @@
NameLoc, attrs.getList());
} else if (TUK == Sema::TUK_Friend &&
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
+ ProhibitAttributes(attrs);
+
TagOrTempResult =
Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(),
TagType, StartLoc, SS,
@@ -1308,6 +1328,9 @@
// FIXME: Diagnose this particular error.
}
+ if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
+ ProhibitAttributes(attrs);
+
bool IsDependent = false;
// Don't pass down template parameter lists if this is just a tag
@@ -2951,7 +2974,7 @@
SkipUntil(tok::r_square, false);
}
-/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq.
+/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq.
///
/// attribute-specifier-seq:
/// attribute-specifier-seq[opt] attribute-specifier
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sat Jun 23 00:07:58 2012
@@ -1296,7 +1296,12 @@
return true;
}
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+
if (!isCXXConditionDeclaration()) {
+ ProhibitAttributes(attrs);
+
// Parse the expression.
ExprOut = ParseExpression(); // expression
DeclOut = 0;
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Sat Jun 23 00:07:58 2012
@@ -420,7 +420,7 @@
// erroneous r_brace would cause an infinite loop if not handled here.
if (Tok.is(tok::r_brace))
break;
- ParsedAttributes attrs(AttrFactory);
+ ParsedAttributesWithRange attrs(AttrFactory);
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
continue;
}
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Sat Jun 23 00:07:58 2012
@@ -1259,6 +1259,12 @@
// Parse the parenthesized condition.
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
+
+ // FIXME: Do not just parse the attribute contents and throw them away
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ ProhibitAttributes(attrs);
+
ExprResult Cond = ParseExpression();
T.consumeClose();
DoScope.Exit();
@@ -1347,8 +1353,12 @@
return StmtError();
}
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
+ ProhibitAttributes(attrs);
// no first part, eat the ';'.
ConsumeToken();
} else if (isForInitDeclaration()) { // for (int X = 4;
@@ -1393,6 +1403,7 @@
Diag(Tok, diag::err_expected_semi_for);
}
} else {
+ ProhibitAttributes(attrs);
Value = ParseExpression();
ForEach = isTokIdentifier_in();
Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Sat Jun 23 00:07:58 2012
@@ -219,7 +219,10 @@
ParsingDeclSpec DS(*this, &DiagsFromTParams);
// Move the attributes from the prefix into the DS.
- DS.takeAttributesFrom(prefixAttrs);
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ ProhibitAttributes(prefixAttrs);
+ else
+ DS.takeAttributesFrom(prefixAttrs);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
getDeclSpecContextFromDeclaratorContext(Context));
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Sat Jun 23 00:07:58 2012
@@ -746,8 +746,7 @@
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
if (DS) {
- DS->takeAttributesFrom(attrs);
- return ParseDeclarationOrFunctionDefinition(*DS);
+ return ParseDeclarationOrFunctionDefinition(attrs, DS);
} else {
return ParseDeclarationOrFunctionDefinition(attrs);
}
@@ -815,20 +814,24 @@
/// [OMP] threadprivate-directive [TODO]
///
Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
- AccessSpecifier AS) {
+Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
+ ParsingDeclSpec &DS,
+ AccessSpecifier AS) {
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
+ ProhibitAttributes(attrs);
ConsumeToken();
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
+ DS.takeAttributesFrom(attrs);
+
// ObjC2 allows prefix attributes on class interfaces and protocols.
// FIXME: This still needs better diagnostics. We should only accept
// attributes here, no types, etc.
@@ -869,16 +872,20 @@
}
Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
+Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
+ ParsingDeclSpec *DS,
AccessSpecifier AS) {
- ParsingDeclSpec DS(*this);
- DS.takeAttributesFrom(attrs);
- // Must temporarily exit the objective-c container scope for
- // parsing c constructs and re-enter objc container scope
- // afterwards.
- ObjCDeclContextSwitch ObjCDC(*this);
-
- return ParseDeclarationOrFunctionDefinition(DS, AS);
+ if (DS) {
+ return ParseDeclOrFunctionDefInternal(attrs, *DS, AS);
+ } else {
+ ParsingDeclSpec PDS(*this);
+ // Must temporarily exit the objective-c container scope for
+ // parsing c constructs and re-enter objc container scope
+ // afterwards.
+ ObjCDeclContextSwitch ObjCDC(*this);
+
+ return ParseDeclOrFunctionDefInternal(attrs, PDS, AS);
+ }
}
/// ParseFunctionDefinition - We parsed and verified that the specified
Modified: cfe/trunk/test/Parser/cxx0x-attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-attributes.cpp?rev=159072&r1=159071&r2=159072&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-attributes.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-attributes.cpp Sat Jun 23 00:07:58 2012
@@ -1,15 +1,50 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s
+// Need std::initializer_list
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+
// Declaration syntax checks
[[]] int before_attr;
int [[]] between_attr;
+const [[]] int between_attr_2 = 0; // expected-error {{an attribute list cannot appear here}}
int after_attr [[]];
int * [[]] ptr_attr;
int & [[]] ref_attr = after_attr;
int && [[]] rref_attr = 0;
int array_attr [1] [[]];
alignas(8) int aligned_attr;
-[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
+[[test::valid(for 42 [very] **** '+' symbols went on a trip and had a "good"_time; the end.)]]
int garbage_attr;
[[,,,static, class, namespace,, inline, constexpr, mutable,, bi\
tand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr;
@@ -19,7 +54,18 @@
struct MemberFnOrder {
virtual void f() const volatile && noexcept [[]] final = 0;
};
+struct [[]] struct_attr;
class [[]] class_attr {};
+union [[]] union_attr;
+[[]] struct with_init_declarators {} init_declarator;
+[[]] struct no_init_declarators; // expected-error {{an attribute list cannot appear here}}
+[[]];
+struct ctordtor {
+ [[]] ctordtor();
+ [[]] ~ctordtor();
+};
+[[]] ctordtor::ctordtor() {}
+[[]] ctordtor::~ctordtor() {}
extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr ();
[[]] [[]] int [[]] [[]] multi_attr [[]] [[]];
@@ -27,7 +73,8 @@
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}}
+unsigned [[]] int attr_in_decl_spec; // expected-error {{an attribute list cannot appear here}}
+unsigned [[]] int [[]] const double_decl_spec = 0; // expected-error 2{{an attribute list cannot appear here}}
class foo {
void const_after_attr () [[]] const; // expected-error {{expected ';'}}
};
@@ -40,6 +87,52 @@
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
[[]] using namespace ns;
+[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
+using T [[]] = int; // ok
+template<typename T> using U [[]] = T;
+using ns::i [[]]; // expected-error {{an attribute list cannot appear here}}
+using [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
+
+auto trailing() -> [[]] const int; // expected-error {{an attribute list cannot appear here}}
+auto trailing() -> const [[]] int; // expected-error {{an attribute list cannot appear here}}
+auto trailing() -> const int [[]];
+auto trailing_2() -> struct struct_attr [[]];
+
+namespace N {
+ struct S {};
+};
+template<typename> struct Template {};
+
+// FIXME: Improve this diagnostic
+struct [[]] N::S s; // expected-error {{an attribute list cannot appear here}}
+struct [[]] Template<int> t; // expected-error {{an attribute list cannot appear here}}
+struct [[]] ::template Template<int> u; // expected-error {{an attribute list cannot appear here}}
+template struct [[]] Template<char>; // expected-error {{an attribute list cannot appear here}}
+template <> struct [[]] Template<void>;
+
+enum [[]] E1 {};
+enum [[]] E2; // expected-error {{forbids forward references}}
+enum [[]] E1;
+enum [[]] E3 : int;
+enum [[]] {
+ k_123 [[]] = 123 // expected-error {{an attribute list cannot appear here}}
+};
+enum [[]] E1 e; // expected-error {{an attribute list cannot appear here}}
+enum [[]] class E4 { }; // expected-error {{an attribute list cannot appear here}}
+enum struct [[]] E5;
+
+struct S {
+ friend int f [[]] (); // expected-FIXME{{an attribute list cannot appear here}}
+ [[]] friend int g(); // expected-FIXME{{an attribute list cannot appear here}}
+ [[]] friend int h() {
+ }
+ friend class [[]] C; // expected-error{{an attribute list cannot appear here}}
+};
+template<typename T> void tmpl(T) {}
+template void tmpl [[]] (int); // expected-FIXME {{an attribute list cannot appear here}}
+template [[]] void tmpl(char); // expected-error {{an attribute list cannot appear here}}
+template void [[]] tmpl(short);
+
// Argument tests
alignas int aligned_no_params; // expected-error {{expected '('}}
alignas(i) int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}} expected-note {{read of non-const variable 'i'}}
@@ -81,3 +174,36 @@
template<typename...Ts> void variadic() {
void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
}
+
+// Expression tests
+void bar () {
+ [] () [[noreturn]] { return; } (); // expected-error {{should not return}}
+ [] () [[noreturn]] { throw; } ();
+ new int[42][[]][5][[]]{};
+}
+
+// Condition tests
+void baz () {
+ if ([[]] bool b = true) {
+ switch ([[]] int n { 42 }) {
+ default:
+ for ([[]] int n = 0; [[]] char b = n < 5; ++b) {
+ }
+ }
+ }
+ int x;
+ // An attribute can be applied to an expression-statement, such as the first
+ // statement in a for. But it can't be applied to a condition which is an
+ // expression.
+ for ([[]] x = 0; ; ) {} // expected-error {{an attribute list cannot appear here}}
+ for (; [[]] x < 5; ) {} // expected-error {{an attribute list cannot appear here}}
+ while ([[]] bool k { false }) {
+ }
+ while ([[]] true) { // expected-error {{an attribute list cannot appear here}}
+ }
+ do {
+ } while ([[]] false); // expected-error {{an attribute list cannot appear here}}
+
+ for ([[]] int n : { 1, 2, 3 }) {
+ }
+}
More information about the cfe-commits
mailing list