diff options
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 421 |
1 files changed, 276 insertions, 145 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f1fbbb1..16d06d7 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -15,6 +15,7 @@ #include "RAIIObjectsForParser.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -123,13 +124,13 @@ Decl *Parser::ParseNamespace(unsigned Context, << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); - SkipUntil(tok::r_brace, false); + SkipUntil(tok::r_brace); return 0; } if (!ExtraIdent.empty()) { TentativeParsingAction TPA(*this); - SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + SkipUntil(tok::r_brace, StopBeforeMatch); Token rBraceToken = Tok; TPA.Revert(); @@ -451,20 +452,18 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Decl **OwnedType) { CXXScopeSpec SS; SourceLocation TypenameLoc; - bool IsTypeName = false; - ParsedAttributesWithRange Attrs(AttrFactory); + bool HasTypenameKeyword = false; - // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. - MaybeParseCXX11Attributes(Attrs); - ProhibitAttributes(Attrs); - Attrs.clear(); - Attrs.Range = SourceRange(); + // Check for misplaced attributes before the identifier in an + // alias-declaration. + ParsedAttributesWithRange MisplacedAttrs(AttrFactory); + MaybeParseCXX11Attributes(MisplacedAttrs); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { TypenameLoc = ConsumeToken(); - IsTypeName = true; + HasTypenameKeyword = true; } // Parse nested-name-specifier. @@ -508,13 +507,25 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseGNUAttributes(Attrs); MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. - bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; + bool IsAliasDecl = Tok.is(tok::equal); if (IsAliasDecl) { - // TODO: Can GNU attributes appear here? + // If we had any misplaced attributes from earlier, this is where they + // should have been written. + if (MisplacedAttrs.Range.isValid()) { + Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) + << FixItHint::CreateInsertionFromRange( + Tok.getLocation(), + CharSourceRange::getTokenRange(MisplacedAttrs.Range)) + << FixItHint::CreateRemoval(MisplacedAttrs.Range); + Attrs.takeAllFrom(MisplacedAttrs); + } + ConsumeToken(); Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? @@ -549,7 +560,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // No removal fixit: can't recover from this. SkipUntil(tok::semi); return 0; - } else if (IsTypeName) + } else if (HasTypenameKeyword) Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SourceRange(TypenameLoc, SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); @@ -564,6 +575,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. + ProhibitAttributes(MisplacedAttrs); ProhibitAttributes(Attrs); // Parse (optional) attributes (most likely GNU strong-using extension). @@ -593,11 +605,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // "typename" keyword is allowed for identifiers only, // because it may be a type definition. - if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) { + if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); - // Proceed parsing, but reset the IsTypeName flag. - IsTypeName = false; + // Proceed parsing, but reset the HasTypenameKeyword flag. + HasTypenameKeyword = false; } if (IsAliasDecl) { @@ -610,9 +622,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias); } - return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, - Name, Attrs.getList(), - IsTypeName, TypenameLoc); + return Actions.ActOnUsingDeclaration(getCurScope(), AS, + /* HasUsingKeyword */ true, UsingLoc, + SS, Name, Attrs.getList(), + HasTypenameKeyword, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. @@ -729,8 +742,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { Result = ParseExpression(); if (Result.isInvalid()) { DS.SetTypeSpecError(); - if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, - /*DontConsume=*/true)) { + if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { EndLoc = ConsumeParen(); } else { if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { @@ -813,7 +825,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -827,6 +839,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, DiagID, Result.release())) Diag(StartLoc, DiagID) << PrevSpec; + DS.setTypeofParensRange(T.getRange()); } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a @@ -917,8 +930,13 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, << Id; } - if (!Template) + if (!Template) { + TemplateArgList TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS, + true, LAngleLoc, TemplateArgs, RAngleLoc); return true; + } // Form the template name UnqualifiedId TemplateName; @@ -979,8 +997,8 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { Tok.is(tok::kw___virtual_inheritance)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_GNU); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); } } @@ -1140,8 +1158,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. - if (Tok.is(tok::kw___attribute)) - ParseGNUAttributes(attrs); + MaybeParseGNUAttributes(attrs); // If declspecs exist after tag, parse them. while (Tok.is(tok::kw___declspec)) @@ -1151,7 +1168,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::kw___single_inheritance) || Tok.is(tok::kw___multiple_inheritance) || Tok.is(tok::kw___virtual_inheritance)) - ParseMicrosoftInheritanceClassAttributes(attrs); + ParseMicrosoftInheritanceClassAttributes(attrs); // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different @@ -1180,15 +1197,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.is(tok::kw___is_scalar) || Tok.is(tok::kw___is_signed) || Tok.is(tok::kw___is_unsigned) || - Tok.is(tok::kw___is_void))) { + Tok.is(tok::kw___is_void))) // 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. - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } + TryKeywordIdentFallback(true); // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); @@ -1231,7 +1246,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) << (TagType == DeclSpec::TST_class? 0 : TagType == DeclSpec::TST_struct? 1 - : TagType == DeclSpec::TST_interface? 2 + : TagType == DeclSpec::TST_union? 2 : 3) << Name << SourceRange(LAngleLoc, RAngleLoc); @@ -1272,10 +1287,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Range.setBegin(SS.getBeginLoc()); Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) - << Name << static_cast<int>(TemplateId->Kind) << Range; + << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range; DS.SetTypeSpecError(); - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); return; } } @@ -1323,7 +1338,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Skip everything up to the semicolon, so that this looks like a proper // friend class (or template thereof) declaration. - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); TUK = Sema::TUK_Friend; } else { // Okay, this is a class definition. @@ -1342,12 +1357,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, while (true) { if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { ConsumeBracket(); - if (!SkipUntil(tok::r_square)) + if (!SkipUntil(tok::r_square, StopAtSemi)) break; } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) { ConsumeToken(); ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) break; } else { break; @@ -1412,7 +1427,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << DeclSpec::getSpecifierName(TagType); } - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -1465,7 +1480,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // This is an explicit specialization or a class template // partial specialization. TemplateParameterLists FakedParamLists; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // This looks like an explicit instantiation, because we have // something like @@ -1475,25 +1489,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // but it actually has a definition. Most likely, this was // meant to be an explicit specialization, but the user forgot // the '<>' after 'template'. - assert(TUK == Sema::TUK_Definition && "Expected a definition here"); - - SourceLocation LAngleLoc - = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(TemplateId->TemplateNameLoc, - diag::err_explicit_instantiation_with_definition) - << SourceRange(TemplateInfo.TemplateLoc) - << FixItHint::CreateInsertion(LAngleLoc, "<>"); - - // Create a fake template parameter list that contains only - // "template<>", so that we treat this construct as a class - // template specialization. - FakedParamLists.push_back( - Actions.ActOnTemplateParameterList(0, SourceLocation(), - TemplateInfo.TemplateLoc, - LAngleLoc, - 0, 0, - LAngleLoc)); - TemplateParams = &FakedParamLists; + // It this is friend declaration however, since it cannot have a + // template header, it is most likely that the user meant to + // remove the 'template' keyword. + assert((TUK == Sema::TUK_Definition || TUK == Sema::TUK_Friend) && + "Expected a definition here"); + + if (TUK == Sema::TUK_Friend) { + Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation); + TemplateParams = 0; + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(TemplateId->TemplateNameLoc, + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Create a fake template parameter list that contains only + // "template<>", so that we treat this construct as a class + // template specialization. + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + TemplateParams = &FakedParamLists; + } } // Build the class template specialization. @@ -1540,6 +1560,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) ProhibitAttributes(attrs); + if (TUK == Sema::TUK_Definition && + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + TemplateParams = 0; + } + bool IsDependent = false; // Don't pass down template parameter lists if this is just a tag @@ -1641,7 +1670,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { if (Result.isInvalid()) { // Skip the rest of this base specifier, up until the comma or // opening brace. - SkipUntil(tok::comma, tok::l_brace, true, true); + SkipUntil(tok::comma, tok::l_brace, StopAtSemi | StopBeforeMatch); } else { // Add this to our array of base specifiers. BaseInfo.push_back(Result.get()); @@ -1800,12 +1829,17 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } if (II == Ident_override) return VirtSpecifiers::VS_Override; + if (II == Ident_sealed) + return VirtSpecifiers::VS_Sealed; + if (II == Ident_final) return VirtSpecifiers::VS_Final; } @@ -1833,14 +1867,18 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - if (IsInterface && Specifier == VirtSpecifiers::VS_Final) { + if (IsInterface && (Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed)) { Diag(Tok.getLocation(), diag::err_override_control_interface) << VirtSpecifiers::getSpecifierName(Specifier); + } else if (Specifier == VirtSpecifiers::VS_Sealed) { + Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword); } else { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); } ConsumeToken(); } @@ -1858,10 +1896,13 @@ bool Parser::isCXX11FinalKeyword() const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } - - return Tok.getIdentifierInfo() == Ident_final; + + return Tok.getIdentifierInfo() == Ident_final || + Tok.getIdentifierInfo() == Ident_sealed; } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. @@ -1892,6 +1933,7 @@ bool Parser::isCXX11FinalKeyword() const { /// virt-specifier: /// override /// final +/// [MS] sealed /// /// pure-specifier: /// '= 0' @@ -1908,12 +1950,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Diag(Tok, diag::err_at_defs_cxx); else Diag(Tok, diag::err_at_in_class); - + ConsumeToken(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); return; } - + // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && @@ -1952,10 +1994,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; Actions.ActOnUsingDeclaration(getCurScope(), AS, - false, SourceLocation(), + /* HasUsingKeyword */ false, + SourceLocation(), SS, Name, /* AttrList */ 0, - /* IsTypeName */ false, + /* HasTypenameKeyword */ false, SourceLocation()); return; } @@ -2010,7 +2053,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); } else { SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. @@ -2032,6 +2075,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); + // If we had a free-standing type definition with a missing semicolon, we + // may get this far before the problem becomes obvious. + if (DS.hasTagDefinition() && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate && + DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class, + &CommonLateParsedAttrs)) + return; + MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); @@ -2066,7 +2117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return; @@ -2085,7 +2136,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, EqualLoc = ConsumeToken(); Init = ParseInitializer(); if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); else HasInitializer = true; } @@ -2123,7 +2174,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi*/false); + SkipUntil(tok::r_brace); // Consume the optional ';' if (Tok.is(tok::semi)) @@ -2143,11 +2194,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, VS, DefinitionKind, Init); - for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { - CommonLateParsedAttrs[i]->addDecl(FunDecl); - } - for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { - LateParsedAttrs[i]->addDecl(FunDecl); + if (FunDecl) { + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { + CommonLateParsedAttrs[i]->addDecl(FunDecl); + } + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { + LateParsedAttrs[i]->addDecl(FunDecl); + } } LateParsedAttrs.clear(); @@ -2176,7 +2229,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ConsumeToken(); BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); } // If a simple-asm-expr is present, parse it. @@ -2184,7 +2237,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); @@ -2201,7 +2254,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); } else { HasInitializer = true; if (!DeclaratorInfo.isDeclarationOfFunction() && @@ -2225,7 +2278,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector<SourceRange, 4> Ranges; DeclaratorInfo.getCXX11AttributeRanges(Ranges); if (!Ranges.empty()) { - for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(), + for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I; @@ -2241,28 +2294,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateParams, BitfieldSize.release(), VS, HasInClassInit); - if (AccessAttrs) - Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, - false, true); - } - - // Set the Decl for any late parsed attributes - for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { - CommonLateParsedAttrs[i]->addDecl(ThisDecl); - } - for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { - LateParsedAttrs[i]->addDecl(ThisDecl); + + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + + if (ThisDecl && AccessAttrs) + Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs); } - LateParsedAttrs.clear(); // Handle the initializer. if (HasInClassInit != ICIS_NoInit && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) { // The initializer was deferred; parse it and cache the tokens. - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_nonstatic_member_init : - diag::ext_nonstatic_member_init); + Diag(Tok, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_nonstatic_member_init + : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++11 [dcl.array]p3: An array bound may also be omitted when the @@ -2271,38 +2321,46 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. Diag(Tok, diag::err_incomplete_array_member_init); - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + + // Avoid later warnings about a class member of incomplete type. if (ThisDecl) - // Avoid later warnings about a class member of incomplete type. ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); } else if (HasInitializer) { // Normal initializer. if (!Init.isUsable()) - Init = ParseCXXMemberInitializer(ThisDecl, - DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); - + Init = ParseCXXMemberInitializer( + ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); + if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), DS.containsPlaceholderType()); - } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { + } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) // No initializer. Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType()); - } - + if (ThisDecl) { + if (!ThisDecl->isInvalidDecl()) { + // Set the Decl for any late parsed attributes + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) + CommonLateParsedAttrs[i]->addDecl(ThisDecl); + + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) + LateParsedAttrs[i]->addDecl(ThisDecl); + } Actions.FinalizeDeclaration(ThisDecl); DeclsInGroup.push_back(ThisDecl); + + if (DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_typedef) + HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); } - - if (ThisDecl && DeclaratorInfo.isFunctionDeclarator() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef) { - HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); - } + LateParsedAttrs.clear(); DeclaratorInfo.complete(ThisDecl); @@ -2343,14 +2401,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (ExpectSemi && ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { // Skip to end of block or statement. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); return; } - Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), - DeclsInGroup.size()); + Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or @@ -2369,7 +2426,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// assignment-expression /// braced-init-list /// -/// defaulted/deleted function-definition: +/// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// @@ -2476,20 +2533,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); SourceLocation FinalLoc; + bool IsFinalSpelledSealed = false; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { - assert(isCXX11FinalKeyword() && "not a class definition"); + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); + assert((Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed) && + "not a class definition"); FinalLoc = ConsumeToken(); + IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed; - if (TagType == DeclSpec::TST_interface) { + if (TagType == DeclSpec::TST_interface) Diag(FinalLoc, diag::err_override_control_interface) - << "final"; - } else { - Diag(FinalLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) << "final"; - } + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Final) + Diag(FinalLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Sealed) + Diag(FinalLoc, diag::ext_ms_sealed_keyword); // Parse any C++11 attributes after 'final' keyword. // These attributes are not allowed to appear here, @@ -2516,6 +2580,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, + IsFinalSpelledSealed, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private @@ -2565,6 +2630,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + // If we see a namespace here, a close brace was missing somewhere. + if (Tok.is(tok::kw_namespace)) { + DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl)); + break; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2606,15 +2677,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } - // FIXME: Make sure we don't have a template here. - // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); } T.consumeClose(); } else { - SkipUntil(tok::r_brace, false, false); + SkipUntil(tok::r_brace); } // If attributes exist after class contents, parse them. @@ -2658,6 +2727,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ClassScope.Exit(); } +void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) { + assert(Tok.is(tok::kw_namespace)); + + // FIXME: Suggest where the close brace should have gone by looking + // at indentation changes within the definition body. + Diag(D->getLocation(), + diag::err_missing_end_of_definition) << D; + Diag(Tok.getLocation(), + diag::note_missing_end_of_definition_before) << D; + + // Push '};' onto the token stream to recover. + PP.EnterToken(Tok); + + Tok.startToken(); + Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation)); + Tok.setKind(tok::semi); + PP.EnterToken(Tok); + + Tok.setKind(tok::r_brace); +} + /// ParseConstructorInitializer - Parse a C++ constructor initializer, /// which explicitly initializes the members or base classes of a /// class (C++ [class.base.init]). For example, the three initializers @@ -2691,9 +2781,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { do { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteConstructorInitializer(ConstructorDecl, - MemInitializers.data(), - MemInitializers.size()); + Actions.CodeCompleteConstructorInitializer(ConstructorDecl, + MemInitializers); return cutOffParsing(); } else { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); @@ -2716,7 +2805,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { } else { // Skip over garbage, until we get to '{'. Don't eat the '{'. Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); - SkipUntil(tok::l_brace, true, true); + SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); break; } } while (true); @@ -2797,7 +2886,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { ExprVector ArgExprs; CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } @@ -2809,9 +2898,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, DS, IdLoc, - T.getOpenLocation(), ArgExprs.data(), - ArgExprs.size(), T.getCloseLocation(), - EllipsisLoc); + T.getOpenLocation(), ArgExprs, + T.getCloseLocation(), EllipsisLoc); } Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace @@ -2894,6 +2982,16 @@ Parser::tryParseExceptionSpecification( return Result; } +static void diagnoseDynamicExceptionSpecification( + Parser &P, const SourceRange &Range, bool IsNoexcept) { + if (P.getLangOpts().CPlusPlus11) { + const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)"; + P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range; + P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated) + << Replacement << FixItHint::CreateReplacement(Range, Replacement); + } +} + /// ParseDynamicExceptionSpecification - Parse a C++ /// dynamic-exception-specification (C++ [except.spec]). /// @@ -2927,6 +3025,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); + diagnoseDynamicExceptionSpecification(*this, SpecificationRange, false); return EST_MSAny; } @@ -2958,6 +3057,8 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); + diagnoseDynamicExceptionSpecification(*this, SpecificationRange, + Exceptions.empty()); return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } @@ -3167,7 +3268,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected_ident); - SkipUntil(tok::r_square, tok::comma, true, true); + SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch); continue; } } @@ -3193,7 +3294,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, // FIXME: handle other formats of c++11 attribute arguments ConsumeParen(); - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren); } } @@ -3201,8 +3302,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, attrs.addNew(AttrName, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), - ScopeName, ScopeLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_CXX11); + ScopeName, ScopeLoc, 0, 0, AttributeList::AS_CXX11); if (Tok.is(tok::ellipsis)) { ConsumeToken(); @@ -3213,11 +3313,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square); if (endLoc) *endLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square); } /// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. @@ -3239,6 +3339,37 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, attrs.Range = SourceRange(StartLoc, *endLoc); } +void Parser::DiagnoseAndSkipCXX11Attributes() { + if (!isCXX11AttributeSpecifier()) + return; + + // Start and end location of an attribute or an attribute list. + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + + do { + if (Tok.is(tok::l_square)) { + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } else { + assert(Tok.is(tok::kw_alignas) && "not an attribute specifier"); + ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (!T.consumeOpen()) + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } + } while (isCXX11AttributeSpecifier()); + + if (EndLoc.isValid()) { + SourceRange Range(StartLoc, EndLoc); + Diag(StartLoc, diag::err_attributes_not_allowed) + << Range; + } +} + /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] /// /// [MS] ms-attribute: @@ -3254,7 +3385,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, while (Tok.is(tok::l_square)) { // FIXME: If this is actually a C++11 attribute, parse it as one. ConsumeBracket(); - SkipUntil(tok::r_square, true, true); + SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); if (endLoc) *endLoc = Tok.getLocation(); ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); } |