diff options
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 362 |
1 files changed, 285 insertions, 77 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6200363..87d9909 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -17,8 +17,8 @@ #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/Basic/TargetInfo.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -73,7 +73,15 @@ Decl *Parser::ParseNamespace(unsigned Context, 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 @@ Decl *Parser::ParseNamespace(unsigned Context, } } + // 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 @@ Decl *Parser::ParseNamespace(unsigned Context, 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 @@ Decl *Parser::ParseNamespace(unsigned Context, 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 @@ Decl *Parser::ParseNamespace(unsigned Context, 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 @@ Decl *Parser::ParseNamespace(unsigned Context, } /// 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 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, 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 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, 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 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ 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 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // 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 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // 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 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { /// 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 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { 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,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { 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; + case tok::kw___unaligned: // struct foo {...} __unaligned *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 +1134,6 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { 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,17 +1243,65 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // 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.isNot(tok::identifier) && + !Tok.isAnnotation() && + 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(); @@ -1669,7 +1736,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // 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(); @@ -1731,7 +1802,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { /// 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(); @@ -1806,16 +1877,34 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { } /// \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) { @@ -1879,12 +1968,22 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { /// 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; @@ -1929,13 +2028,19 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // identifier[opt] ':' constant-expression 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)) { @@ -1953,10 +2058,21 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // 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. @@ -2021,7 +2137,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // 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; @@ -2039,6 +2156,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + if (SS.isInvalid()) { + SkipUntil(tok::semi); + return; + } + // Try to parse an unqualified-id. SourceLocation TemplateKWLoc; UnqualifiedId Name; @@ -2066,9 +2188,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } } - // 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; @@ -2309,7 +2432,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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 { @@ -2487,7 +2609,10 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, Diag(ConsumeToken(), diag::err_default_special_members); return ExprError(); } - + } + if (const auto *PD = dyn_cast_or_null<MSPropertyDecl>(D)) { + Diag(Tok, diag::err_ms_property_initializer) << PD; + return ExprError(); } return ParseInitializer(); } @@ -2581,17 +2706,60 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // and the only possible place for them to appertain // to the class would be between class-key and class-name. CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + + // ParseClassSpecifier() does only a superficial check for attributes before + // deciding to call this method. For example, for + // `class C final alignas ([l) {` it will decide that this looks like a + // misplaced attribute since it sees `alignas '(' ')'`. But the actual + // attribute parsing code will try to parse the '[' as a constexpr lambda + // and consume enough tokens that the alignas parsing code will eat the + // opening '{'. So bail out if the next token isn't one we expect. + if (!Tok.is(tok::colon) && !Tok.is(tok::l_brace)) { + if (TagDecl) + Actions.ActOnTagDefinitionError(getCurScope(), TagDecl); + return; + } } 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; + } } } @@ -2725,7 +2893,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // 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) { @@ -2854,7 +3022,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { /// [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); @@ -2944,13 +3112,51 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// '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()); // '(' + + ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/true); + SpecificationRange.setEnd(Tok.getLocation()); + return EST_Unparsed; + } + // See if there's a dynamic specification. if (Tok.is(tok::kw_throw)) { Result = ParseDynamicExceptionSpecification(SpecificationRange, @@ -3168,9 +3374,11 @@ 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; + if (!Tok.isAnnotation()) { + if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + Loc = ConsumeToken(); + return II; + } } return nullptr; @@ -3265,7 +3473,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, if (Attr->getMaxArgs() && !NumArgs) { // The attribute was allowed to have arguments, but none were provided // even though the attribute parsed successfully. This is an error. - // FIXME: This is a good place for a fixit which removes the parens. Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; return false; } else if (!Attr->getMaxArgs()) { @@ -3273,7 +3480,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, // arguments. It doesn't matter whether any were provided -- the // presence of the argument list (even if empty) is diagnosed. Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments) - << AttrName; + << AttrName + << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); return false; } } |