forked from OSchip/llvm-project
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. llvm-svn: 159072
This commit is contained in:
parent
d9c7d0dda4
commit
6aa9beef50
|
@ -1045,10 +1045,13 @@ private:
|
|||
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 @@ private:
|
|||
DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts,
|
||||
unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &attrs,
|
||||
ParsedAttributesWithRange &attrs,
|
||||
bool RequireSemi,
|
||||
ForRangeInit *FRI = 0);
|
||||
bool MightBeDeclarator(unsigned Context);
|
||||
|
|
|
@ -1126,10 +1126,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
|
|||
|
||||
/// 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 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
|
|||
/// 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
}
|
||||
|
||||
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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
DS.SetRangeEnd(Tok.getLocation());
|
||||
if (DiagID != diag::err_bool_redeclaration)
|
||||
ConsumeToken();
|
||||
|
||||
AttrsLastTime = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2941,6 +2964,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
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 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
|
|||
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;
|
||||
|
|
|
@ -444,6 +444,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
|||
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 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ParsedAttributes attrs(AttrFactory);
|
||||
MaybeParseCXX0XAttributes(attrs);
|
||||
|
||||
// Maybe this is an alias-declaration.
|
||||
bool IsAliasDecl = Tok.is(tok::equal);
|
||||
|
@ -533,9 +540,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
|||
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 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
|||
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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
} 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
//
|
||||
// template struct Outer<int>::Inner;
|
||||
//
|
||||
ProhibitAttributes(attrs);
|
||||
|
||||
TagOrTempResult
|
||||
= Actions.ActOnExplicitInstantiation(getCurScope(),
|
||||
TemplateInfo.ExternLoc,
|
||||
|
@ -1295,6 +1313,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
// 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 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
|
|||
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
|
||||
|
|
|
@ -1296,7 +1296,12 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
|
|||
return true;
|
||||
}
|
||||
|
||||
ParsedAttributesWithRange attrs(AttrFactory);
|
||||
MaybeParseCXX0XAttributes(attrs);
|
||||
|
||||
if (!isCXXConditionDeclaration()) {
|
||||
ProhibitAttributes(attrs);
|
||||
|
||||
// Parse the expression.
|
||||
ExprOut = ParseExpression(); // expression
|
||||
DeclOut = 0;
|
||||
|
|
|
@ -420,7 +420,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
|
|||
// 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;
|
||||
}
|
||||
|
|
|
@ -1259,6 +1259,12 @@ StmtResult Parser::ParseDoStatement() {
|
|||
// 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 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
|||
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 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
|||
Diag(Tok, diag::err_expected_semi_for);
|
||||
}
|
||||
} else {
|
||||
ProhibitAttributes(attrs);
|
||||
Value = ParseExpression();
|
||||
|
||||
ForEach = isTokIdentifier_in();
|
||||
|
|
|
@ -219,7 +219,10 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
|||
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));
|
||||
|
|
|
@ -746,8 +746,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
|
|||
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 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
|
|||
/// [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::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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 @@ void noexcept_fn_attr () noexcept [[]];
|
|||
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 @@ template <typename T> [[]] void template_attr ();
|
|||
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 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
|
|||
[[]] 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 @@ void foo () {
|
|||
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 }) {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue