Update aosp/master Clang for rebase to r222490.
Change-Id: Ic557ac55e97fbf6ee08771c7b7c3594777b0aefd
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index cd2e397..79ae878 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -73,7 +73,15 @@
std::vector<IdentifierInfo*> ExtraIdent;
std::vector<SourceLocation> ExtraNamespaceLoc;
- Token attrTok;
+ ParsedAttributesWithRange attrs(AttrFactory);
+ SourceLocation attrLoc;
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (!getLangOpts().CPlusPlus1z)
+ Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ << 0 /*namespace*/;
+ attrLoc = Tok.getLocation();
+ ParseCXX11Attributes(attrs);
+ }
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
@@ -85,10 +93,13 @@
}
}
+ // A nested namespace definition cannot have attributes.
+ if (!ExtraNamespaceLoc.empty() && attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);
+
// Read label attributes, if present.
- ParsedAttributes attrs(AttrFactory);
if (Tok.is(tok::kw___attribute)) {
- attrTok = Tok;
+ attrLoc = Tok.getLocation();
ParseGNUAttributes(attrs);
}
@@ -99,8 +110,8 @@
SkipUntil(tok::semi);
return nullptr;
}
- if (!attrs.empty())
- Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
+ if (attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
Diag(InlineLoc, diag::err_inline_namespace_alias)
<< FixItHint::CreateRemoval(InlineLoc);
@@ -110,39 +121,36 @@
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
- if (!ExtraIdent.empty()) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
- << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
- }
-
if (Ident)
Diag(Tok, diag::err_expected) << tok::l_brace;
else
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
-
return nullptr;
}
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
- if (!ExtraIdent.empty()) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
- << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
- }
Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace);
return nullptr;
}
- if (!ExtraIdent.empty()) {
+ if (ExtraIdent.empty()) {
+ // Normal namespace definition, not a nested-namespace-definition.
+ } else if (InlineLoc.isValid()) {
+ Diag(InlineLoc, diag::err_inline_nested_namespace_definition);
+ } else if (getLangOpts().CPlusPlus1z) {
+ Diag(ExtraNamespaceLoc[0],
+ diag::warn_cxx14_compat_nested_namespace_definition);
+ } else {
TentativeParsingAction TPA(*this);
SkipUntil(tok::r_brace, StopBeforeMatch);
Token rBraceToken = Tok;
TPA.Revert();
if (!rBraceToken.is(tok::r_brace)) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
} else {
std::string NamespaceFix;
@@ -156,7 +164,7 @@
for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
RBraces += "} ";
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
ExtraIdentLoc.back()),
NamespaceFix)
@@ -195,11 +203,11 @@
}
/// ParseInnerNamespace - Parse the contents of a namespace.
-void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
- std::vector<IdentifierInfo*>& Ident,
- std::vector<SourceLocation>& NamespaceLoc,
- unsigned int index, SourceLocation& InlineLoc,
- ParsedAttributes& attrs,
+void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
+ std::vector<IdentifierInfo *> &Ident,
+ std::vector<SourceLocation> &NamespaceLoc,
+ unsigned int index, SourceLocation &InlineLoc,
+ ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -216,7 +224,9 @@
return;
}
- // Parse improperly nested namespaces.
+ // Handle a nested namespace definition.
+ // FIXME: Preserve the source information through to the AST rather than
+ // desugaring it here.
ParseScope NamespaceScope(this, Scope::DeclScope);
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
@@ -493,6 +503,12 @@
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
HasTypenameKeyword = true;
+ if (Tok.is(tok::kw___super)) {
+ Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
@@ -692,7 +708,7 @@
ExprResult AssertMessage;
if (Tok.is(tok::r_paren)) {
Diag(Tok, getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_static_assert_no_message
+ ? diag::warn_cxx14_compat_static_assert_no_message
: diag::ext_static_assert_no_message)
<< (getLangOpts().CPlusPlus1z
? FixItHint()
@@ -769,7 +785,7 @@
// because the typename-specifier in a function-style cast operation can't
// be 'auto'.
Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_decltype_auto_type_specifier
: diag::ext_decltype_auto_type_specifier);
ConsumeToken();
@@ -780,7 +796,7 @@
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
nullptr,/*IsDecltype=*/true);
- Result = ParseExpression();
+ Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Result.isInvalid()) {
DS.SetTypeSpecError();
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
@@ -903,8 +919,8 @@
/// In C++98, instead of base-type-specifier, we have:
///
/// ::[opt] nested-name-specifier[opt] class-name
-Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
- SourceLocation &EndLocation) {
+TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
+ SourceLocation &EndLocation) {
// Ignore attempts to use typename
if (Tok.is(tok::kw_typename)) {
Diag(Tok, diag::err_expected_class_name_not_template)
@@ -1066,6 +1082,11 @@
case tok::comma: // __builtin_offsetof(struct foo{...} ,
case tok::kw_operator: // struct foo operator ++() {...}
case tok::kw___declspec: // struct foo {...} __declspec(...)
+ case tok::l_square: // void f(struct f [ 3])
+ case tok::ellipsis: // void f(struct f ... [Ns])
+ // FIXME: we should emit semantic diagnostic when declaration
+ // attribute is in type attribute position.
+ case tok::kw___attribute: // struct foo __attribute__((used)) x;
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -1073,6 +1094,7 @@
case tok::kw_const: // struct foo {...} const x;
case tok::kw_volatile: // struct foo {...} volatile x;
case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw__Atomic: // struct foo {...} _Atomic x;
// Function specifiers
// Note, no 'explicit'. An explicit function must be either a conversion
// operator or a constructor. Either way, it can't have a return type.
@@ -1111,10 +1133,6 @@
if (!getLangOpts().CPlusPlus)
return true;
break;
- // C++11 attributes
- case tok::l_square: // enum E [[]] x
- // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
- return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
case tok::greater:
// template<class T = class X>
return getLangOpts().CPlusPlus;
@@ -1224,22 +1242,70 @@
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- // GNU libstdc++ and libc++ use certain intrinsic names as the
- // name of struct templates, but some are keywords in GCC >= 4.3
- // MSVC and Clang. For compatibility, convert the token to an identifier
- // and issue a warning diagnostic.
- if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) &&
- !Tok.isAnnotation()) {
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- // We rarely end up here so the following check is efficient.
- if (II && II->getName().startswith("__is_"))
- TryKeywordIdentFallback(true);
- }
+ if (TagType == DeclSpec::TST_struct &&
+ !Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() &&
+ (Tok.is(tok::kw___is_abstract) ||
+ Tok.is(tok::kw___is_arithmetic) ||
+ Tok.is(tok::kw___is_array) ||
+ Tok.is(tok::kw___is_base_of) ||
+ Tok.is(tok::kw___is_class) ||
+ Tok.is(tok::kw___is_complete_type) ||
+ Tok.is(tok::kw___is_compound) ||
+ Tok.is(tok::kw___is_const) ||
+ Tok.is(tok::kw___is_constructible) ||
+ Tok.is(tok::kw___is_convertible) ||
+ Tok.is(tok::kw___is_convertible_to) ||
+ Tok.is(tok::kw___is_destructible) ||
+ Tok.is(tok::kw___is_empty) ||
+ Tok.is(tok::kw___is_enum) ||
+ Tok.is(tok::kw___is_floating_point) ||
+ Tok.is(tok::kw___is_final) ||
+ Tok.is(tok::kw___is_function) ||
+ Tok.is(tok::kw___is_fundamental) ||
+ Tok.is(tok::kw___is_integral) ||
+ Tok.is(tok::kw___is_interface_class) ||
+ Tok.is(tok::kw___is_literal) ||
+ Tok.is(tok::kw___is_lvalue_expr) ||
+ Tok.is(tok::kw___is_lvalue_reference) ||
+ Tok.is(tok::kw___is_member_function_pointer) ||
+ Tok.is(tok::kw___is_member_object_pointer) ||
+ Tok.is(tok::kw___is_member_pointer) ||
+ Tok.is(tok::kw___is_nothrow_assignable) ||
+ Tok.is(tok::kw___is_nothrow_constructible) ||
+ Tok.is(tok::kw___is_nothrow_destructible) ||
+ Tok.is(tok::kw___is_object) ||
+ Tok.is(tok::kw___is_pod) ||
+ Tok.is(tok::kw___is_pointer) ||
+ Tok.is(tok::kw___is_polymorphic) ||
+ Tok.is(tok::kw___is_reference) ||
+ Tok.is(tok::kw___is_rvalue_expr) ||
+ Tok.is(tok::kw___is_rvalue_reference) ||
+ Tok.is(tok::kw___is_same) ||
+ Tok.is(tok::kw___is_scalar) ||
+ Tok.is(tok::kw___is_sealed) ||
+ Tok.is(tok::kw___is_signed) ||
+ Tok.is(tok::kw___is_standard_layout) ||
+ Tok.is(tok::kw___is_trivial) ||
+ Tok.is(tok::kw___is_trivially_assignable) ||
+ Tok.is(tok::kw___is_trivially_constructible) ||
+ Tok.is(tok::kw___is_trivially_copyable) ||
+ Tok.is(tok::kw___is_union) ||
+ Tok.is(tok::kw___is_unsigned) ||
+ Tok.is(tok::kw___is_void) ||
+ Tok.is(tok::kw___is_volatile)))
+ // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // and Clang. Therefore, when we see the token sequence "struct
+ // X", make X into a normal identifier rather than a keyword, to
+ // allow libstdc++ 4.2 and libc++ to work properly.
+ TryKeywordIdentFallback(true);
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLangOpts().CPlusPlus) {
- // "FOO : BAR" is not a potential typo for "FOO::BAR".
+ // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it
+ // is a base-specifier-list.
ColonProtectionRAIIObject X(*this);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1668,7 +1734,11 @@
// Also enforce C++ [temp]p3:
// In a template-declaration which defines a class, no declarator
// is permitted.
+ //
+ // After a type-specifier, we don't expect a semicolon. This only happens in
+ // C, since definitions are not permitted in this context in C++.
if (TUK == Sema::TUK_Definition &&
+ (getLangOpts().CPlusPlus || !isTypeSpecifier(DSC)) &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
if (Tok.isNot(tok::semi)) {
const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
@@ -1730,7 +1800,7 @@
/// base-type-specifier
/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
/// base-type-specifier
-Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
+BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
@@ -1805,16 +1875,34 @@
}
/// \brief If the given declarator has any parts for which parsing has to be
-/// delayed, e.g., default arguments, create a late-parsed method declaration
-/// record to handle the parsing at the end of the class definition.
+/// delayed, e.g., default arguments or an exception-specification, create a
+/// late-parsed method declaration record to handle the parsing at the end of
+/// the class definition.
void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
Decl *ThisDecl) {
// We just declared a member function. If this member function
- // has any default arguments, we'll need to parse them later.
+ // has any default arguments or an exception-specification, we'll need to
+ // parse them later.
LateParsedMethodDeclaration *LateMethod = nullptr;
DeclaratorChunk::FunctionTypeInfo &FTI
= DeclaratorInfo.getFunctionTypeInfo();
+ // If there was a late-parsed exception-specification, hold onto its tokens.
+ if (FTI.getExceptionSpecType() == EST_Unparsed) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
+ getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
+ LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
+
+ // Stash the exception-specification tokens in the late-pased mthod.
+ LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
+ FTI.ExceptionSpecTokens = 0;
+
+ // Reserve space for the parameters.
+ LateMethod->DefaultArgs.reserve(FTI.NumParams);
+ }
+
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
if (!LateMethod) {
@@ -1878,12 +1966,22 @@
/// virt-specifier
/// virt-specifier-seq virt-specifier
void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
- bool IsInterface) {
+ bool IsInterface,
+ SourceLocation FriendLoc) {
while (true) {
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
return;
+ if (FriendLoc.isValid()) {
+ Diag(Tok.getLocation(), diag::err_friend_decl_spec)
+ << VirtSpecifiers::getSpecifierName(Specifier)
+ << FixItHint::CreateRemoval(Tok.getLocation())
+ << SourceRange(FriendLoc, FriendLoc);
+ ConsumeToken();
+ continue;
+ }
+
// C++ [class.mem]p8:
// A virt-specifier-seq shall contain at most one of each virt-specifier.
const char *PrevSpec = nullptr;
@@ -1926,21 +2024,21 @@
// declarator pure-specifier[opt]
// declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
- if (Tok.isNot(tok::colon)) {
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
- // is a bitfield.
- // FIXME: This should only apply when parsing the id-expression (see
- // PR18587).
- ColonProtectionRAIIObject X(*this);
+ if (Tok.isNot(tok::colon))
ParseDeclarator(DeclaratorInfo);
- }
+ else
+ DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
+ assert(DeclaratorInfo.isPastIdentifier() &&
+ "don't know where identifier would go yet?");
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
} else
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
@@ -1958,10 +2056,21 @@
// For compatibility with code written to older Clang, also accept a
// virt-specifier *after* the GNU attributes.
- // FIXME: If we saw any attributes that are known to GCC followed by a
- // virt-specifier, issue a GCC-compat warning.
- if (BitfieldSize.isUnset() && VS.isUnset())
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ if (BitfieldSize.isUnset() && VS.isUnset()) {
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
+ if (!VS.isUnset()) {
+ // If we saw any GNU-style attributes that are known to GCC followed by a
+ // virt-specifier, issue a GCC-compat warning.
+ const AttributeList *Attr = DeclaratorInfo.getAttributes();
+ while (Attr) {
+ if (Attr->isKnownToGCC() && !Attr->isCXX11Attribute())
+ Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
+ Attr = Attr->getNext();
+ }
+ }
+ }
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -2015,10 +2124,19 @@
return;
}
+ // Turn on colon protection early, while parsing declspec, although there is
+ // nothing to protect there. It prevents from false errors if error recovery
+ // incorrectly determines where the declspec ends, as in the example:
+ // struct A { enum class B { C }; };
+ // const int C = 4;
+ // struct D { A::B : C; };
+ ColonProtectionRAIIObject X(*this);
+
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
- (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) {
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw___super))) {
if (TryAnnotateCXXScopeToken())
MalformedTypeSpec = true;
@@ -2036,6 +2154,11 @@
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
+ if (SS.isInvalid()) {
+ SkipUntil(tok::semi);
+ return;
+ }
+
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
@@ -2063,9 +2186,10 @@
}
}
- // static_assert-declaration
- if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) {
- // FIXME: Check for templates
+ // static_assert-declaration. A templated static_assert declaration is
+ // diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
+ if (!TemplateInfo.Kind &&
+ (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert))) {
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
return;
@@ -2128,13 +2252,11 @@
if (MalformedTypeSpec)
DS.SetTypeSpecError();
- {
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
- // is a bitfield.
- ColonProtectionRAIIObject X(*this);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
- &CommonLateParsedAttrs);
- }
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
+ &CommonLateParsedAttrs);
+
+ // Turn off colon protection that was set for declspec.
+ X.restore();
// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
@@ -2308,7 +2430,6 @@
E = Ranges.end(); I != E; ++I)
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
- // TODO: handle initializers, VS, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
} else {
@@ -2584,13 +2705,43 @@
if (Tok.is(tok::colon)) {
ParseBaseClause(TagDecl);
-
if (!Tok.is(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
-
- if (TagDecl)
- Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
- return;
+ bool SuggestFixIt = false;
+ SourceLocation BraceLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (Tok.isAtStartOfLine()) {
+ switch (Tok.getKind()) {
+ case tok::kw_private:
+ case tok::kw_protected:
+ case tok::kw_public:
+ SuggestFixIt = NextToken().getKind() == tok::colon;
+ break;
+ case tok::kw_static_assert:
+ case tok::r_brace:
+ case tok::kw_using:
+ // base-clause can have simple-template-id; 'template' can't be there
+ case tok::kw_template:
+ SuggestFixIt = true;
+ break;
+ case tok::identifier:
+ SuggestFixIt = isConstructorDeclarator(true);
+ break;
+ default:
+ SuggestFixIt = isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
+ break;
+ }
+ }
+ DiagnosticBuilder LBraceDiag =
+ Diag(BraceLoc, diag::err_expected_lbrace_after_base_specifiers);
+ if (SuggestFixIt) {
+ LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {");
+ // Try recovering from missing { after base-clause.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::l_brace);
+ } else {
+ if (TagDecl)
+ Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
+ return;
+ }
}
}
@@ -2724,7 +2875,7 @@
// C++11 [class.mem]p2:
// Within the class member-specification, the class is regarded as complete
- // within function bodies, default arguments, and
+ // within function bodies, default arguments, exception-specifications, and
// brace-or-equal-initializers for non-static data members (including such
// things in nested classes).
if (TagDecl && NonNestedClass) {
@@ -2853,7 +3004,7 @@
/// [C++] mem-initializer-id:
/// '::'[opt] nested-name-specifier[opt] class-name
/// identifier
-Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
+MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
@@ -2943,13 +3094,63 @@
/// 'noexcept'
/// 'noexcept' '(' constant-expression ')'
ExceptionSpecificationType
-Parser::tryParseExceptionSpecification(
+Parser::tryParseExceptionSpecification(bool Delayed,
SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr) {
+ ExprResult &NoexceptExpr,
+ CachedTokens *&ExceptionSpecTokens) {
ExceptionSpecificationType Result = EST_None;
+ ExceptionSpecTokens = 0;
+
+ // Handle delayed parsing of exception-specifications.
+ if (Delayed) {
+ if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept))
+ return EST_None;
+ // Consume and cache the starting token.
+ bool IsNoexcept = Tok.is(tok::kw_noexcept);
+ Token StartTok = Tok;
+ SpecificationRange = SourceRange(ConsumeToken());
+
+ // Check for a '('.
+ if (!Tok.is(tok::l_paren)) {
+ // If this is a bare 'noexcept', we're done.
+ if (IsNoexcept) {
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
+ NoexceptExpr = 0;
+ return EST_BasicNoexcept;
+ }
+
+ Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ return EST_DynamicNone;
+ }
+
+ // Cache the tokens for the exception-specification.
+ ExceptionSpecTokens = new CachedTokens;
+ ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
+ ExceptionSpecTokens->push_back(Tok); // '('
+ SpecificationRange.setEnd(ConsumeParen()); // '('
+
+ if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/true)) {
+ NoexceptExpr = 0;
+ delete ExceptionSpecTokens;
+ ExceptionSpecTokens = 0;
+ return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone;
+ }
+ SpecificationRange.setEnd(Tok.getLocation());
+
+ // Add the 'stop' token.
+ Token End;
+ End.startToken();
+ End.setKind(tok::cxx_exceptspec_end);
+ End.setLocation(Tok.getLocation());
+ ExceptionSpecTokens->push_back(End);
+ return EST_Unparsed;
+ }
+
// See if there's a dynamic specification.
if (Tok.is(tok::kw_throw)) {
Result = ParseDynamicExceptionSpecification(SpecificationRange,