diff options
author | grehan <grehan@FreeBSD.org> | 2011-06-28 06:26:03 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2011-06-28 06:26:03 +0000 |
commit | 2c6741be0f59191f2283eb268e4f7690399d578a (patch) | |
tree | b139c8c6dcca4fa284815daade405b75886ee360 /contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp | |
parent | 3c35264f695e0a1f8a04dbcca1c93bb5159b2274 (diff) | |
parent | 19ae02bba572390c7299166228d31e54003e094a (diff) | |
download | FreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.zip FreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.tar.gz |
IFC @ r222830
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp | 487 |
1 files changed, 404 insertions, 83 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 8c0aa1b..51aa010 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context, SourceLocation IdentLoc; IdentifierInfo *Ident = 0; + std::vector<SourceLocation> ExtraIdentLoc; + std::vector<IdentifierInfo*> ExtraIdent; + std::vector<SourceLocation> ExtraNamespaceLoc; Token attrTok; if (Tok.is(tok::identifier)) { Ident = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); // eat the identifier. + while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) { + ExtraNamespaceLoc.push_back(ConsumeToken()); + ExtraIdent.push_back(Tok.getIdentifierInfo()); + ExtraIdentLoc.push_back(ConsumeToken()); + } } // Read label attributes, if present. @@ -85,7 +93,12 @@ Decl *Parser::ParseNamespace(unsigned Context, return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } + if (Tok.isNot(tok::l_brace)) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } Diag(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); return 0; @@ -96,11 +109,44 @@ Decl *Parser::ParseNamespace(unsigned Context, 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(LBrace, diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); return 0; } + if (!ExtraIdent.empty()) { + TentativeParsingAction TPA(*this); + SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + Token rBraceToken = Tok; + TPA.Revert(); + + if (!rBraceToken.is(tok::r_brace)) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } else { + std::string NamespaceFix; + for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(), + E = ExtraIdent.end(); I != E; ++I) { + NamespaceFix += " { namespace "; + NamespaceFix += (*I)->getName(); + } + + std::string RBraces; + for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i) + RBraces += "} "; + + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(), + ExtraIdentLoc.back()), + NamespaceFix) + << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces); + } + } + // If we're still good, complain about inline namespaces in non-C++0x now. if (!getLang().CPlusPlus0x && InlineLoc.isValid()) Diag(InlineLoc, diag::ext_inline_namespace); @@ -115,23 +161,56 @@ Decl *Parser::ParseNamespace(unsigned Context, PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); - MaybeParseMicrosoftAttributes(attrs); - ParseExternalDeclaration(attrs); - } + SourceLocation RBraceLoc; + // Parse the contents of the namespace. This includes parsing recovery on + // any improperly nested namespaces. + ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, + InlineLoc, LBrace, attrs, RBraceLoc); // Leave the namespace scope. NamespaceScope.Exit(); - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); DeclEnd = RBraceLoc; return NamespcDecl; } +/// 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, + SourceLocation& LBrace, + ParsedAttributes& attrs, + SourceLocation& RBraceLoc) { + if (index == Ident.size()) { + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + } + RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); + + return; + } + + // Parse improperly nested namespaces. + ParseScope NamespaceScope(this, Scope::DeclScope); + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), + NamespaceLoc[index], IdentLoc[index], + Ident[index], LBrace, attrs.getList()); + + ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, + LBrace, attrs, RBraceLoc); + + NamespaceScope.Exit(); + + Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); +} + /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// @@ -387,13 +466,35 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { - // TODO: Do we want to support attributes somewhere in an alias declaration? - // Can't follow GCC since it doesn't support them yet! + // TODO: Attribute support. C++0x attributes may appear before the equals. + // Where can GNU attributes appear? ConsumeToken(); if (!getLang().CPlusPlus0x) Diag(Tok.getLocation(), diag::ext_alias_declaration); + // Type alias templates cannot be specialized. + int SpecKind = -1; + if (TemplateInfo.Kind == ParsedTemplateInfo::Template && + Name.getKind() == UnqualifiedId::IK_TemplateId) + SpecKind = 0; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) + SpecKind = 1; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + SpecKind = 2; + if (SpecKind != -1) { + SourceRange Range; + if (SpecKind == 0) + Range = SourceRange(Name.TemplateId->LAngleLoc, + Name.TemplateId->RAngleLoc); + else + Range = TemplateInfo.getSourceRange(); + Diag(Range.getBegin(), diag::err_alias_declaration_specialization) + << SpecKind << Range; + SkipUntil(tok::semi); + return 0; + } + // Name must be an identifier. if (Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); @@ -408,7 +509,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SS.getRange()); - TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext); + TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? + Declarator::AliasTemplateContext : + Declarator::AliasDeclContext); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); @@ -421,9 +524,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, tok::semi); // Diagnose an attempt to declare a templated using-declaration. - // TODO: in C++0x, alias-declarations can be templates: + // In C++0x, alias-declarations can be templates: // template <...> using id = type; - if (TemplateInfo.Kind) { + if (TemplateInfo.Kind && !IsAliasDecl) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) << R << FixItHint::CreateRemoval(R); @@ -434,9 +537,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - if (IsAliasDecl) - return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name, - TypeAlias); + if (IsAliasDecl) { + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + MultiTemplateParamsArg TemplateParamsArg(Actions, + TemplateParams ? TemplateParams->data() : 0, + TemplateParams ? TemplateParams->size() : 0); + return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, + UsingLoc, Name, TypeAlias); + } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), @@ -543,6 +651,42 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } +void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw___underlying_type) && + "Not an underlying type specifier"); + + SourceLocation StartLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "__underlying_type")) { + SkipUntil(tok::r_paren); + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (RParenLoc.isInvalid()) + return; + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + /// ParseClassName - Parse a C++ class-name, which names a class. Note /// that we only check that the result names a type; semantic analysis /// will need to verify that the type names a class. The result is @@ -1409,6 +1553,7 @@ bool Parser::isCXX0XFinalKeyword() const { /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] /// declarator constant-initializer[opt] +/// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression /// /// virt-specifier-seq: @@ -1515,8 +1660,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { - // FIXME: Check for template aliases - ProhibitAttributes(attrs); // Eat 'using'. @@ -1527,7 +1670,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::semi, true, true); } else { SourceLocation DeclEnd; - // Otherwise, it must be using-declaration. + // Otherwise, it must be a using-declaration or an alias-declaration. ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS); } @@ -1547,13 +1690,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); Decl *TheDecl = - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); return; } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); VirtSpecifiers VS; + ExprResult Init; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -1575,10 +1719,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo); + // MSVC permits pure specifier on inline functions declared at class scope. + // Hence check for =0 before checking for function definition. + if (getLang().Microsoft && Tok.is(tok::equal) && + DeclaratorInfo.isFunctionDeclarator() && + NextToken().is(tok::numeric_constant)) { + ConsumeToken(); + Init = ParseInitializer(); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + } + + bool IsDefinition = false; // function-definition: - if (Tok.is(tok::l_brace) - || (DeclaratorInfo.isFunctionDeclarator() && - (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) { + // + // In C++11, a non-function declarator followed by an open brace is a + // braced-init-list for an in-class member initialization, not an + // erroneous function definition. + if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) { + IsDefinition = true; + } else if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { + IsDefinition = true; + } else if (Tok.is(tok::equal)) { + const Token &KW = NextToken(); + if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) + IsDefinition = true; + } + } + + if (IsDefinition) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(Tok, diag::err_func_def_no_params); ConsumeBrace(); @@ -1604,10 +1774,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS); - // Consume the optional ';' - if (Tok.is(tok::semi)) + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init); + + // Consume the ';' - it's optional unless we have a delete or default + if (Tok.is(tok::semi)) { ConsumeToken(); + } return; } @@ -1619,13 +1791,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, llvm::SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; - ExprResult Init; - bool Deleted = false; while (1) { // member-declarator: // declarator pure-specifier[opt] - // declarator constant-initializer[opt] + // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression if (Tok.is(tok::colon)) { ConsumeToken(); @@ -1634,31 +1804,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); } - ParseOptionalCXX0XVirtSpecifierSeq(VS); - - // pure-specifier: - // '= 0' - // - // constant-initializer: - // '=' constant-expression - // - // defaulted/deleted function-definition: - // '=' 'default' [TODO] - // '=' 'delete' - if (Tok.is(tok::equal)) { - ConsumeToken(); - if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); - ConsumeToken(); - Deleted = true; - } else { - Init = ParseInitializer(); - if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); - } - } - // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; @@ -1673,6 +1818,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, parse them. MaybeParseGNUAttributes(DeclaratorInfo); + // FIXME: When g++ adds support for this, we'll need to check whether it + // goes before or after the GNU attributes and __asm__. + ParseOptionalCXX0XVirtSpecifierSeq(VS); + + bool HasDeferredInitializer = false; + if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) { + if (BitfieldSize.get()) { + Diag(Tok, diag::err_bitfield_member_init); + SkipUntil(tok::comma, true, true); + } else { + HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static; + + if (!HasDeferredInitializer) { + SourceLocation EqualLoc; + Init = ParseCXXMemberInitializer( + DeclaratorInfo.isFunctionDeclarator(), EqualLoc); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + } + } + } + // NOTE: If Sema is the Action module and declarator is an instance field, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. @@ -1689,8 +1858,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, move(TemplateParams), BitfieldSize.release(), VS, Init.release(), - /*IsDefinition*/Deleted, - Deleted); + HasDeferredInitializer, + /*IsDefinition*/ false); } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1703,6 +1872,24 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo.complete(ThisDecl); + if (HasDeferredInitializer) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension); + + if (DeclaratorInfo.isArrayOfUnknownBound()) { + // C++0x [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. + // + // A brace-or-equal-initializer for a member-declarator is not an + // initializer in the gramamr, so this is ill-formed. + Diag(Tok, diag::err_incomplete_array_member_init); + SkipUntil(tok::comma, true, true); + // Avoid later warnings about a class member of incomplete type. + ThisDecl->setInvalidDecl(); + } else + ParseCXXNonStaticMemberInitializer(ThisDecl); + } + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) @@ -1716,7 +1903,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, VS.clear(); BitfieldSize = 0; Init = 0; - Deleted = false; // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); @@ -1737,6 +1923,66 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclsInGroup.size()); } +/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or +/// pure-specifier. Also detect and reject any attempted defaulted/deleted +/// function definition. The location of the '=', if any, will be placed in +/// EqualLoc. +/// +/// pure-specifier: +/// '= 0' +/// +/// brace-or-equal-initializer: +/// '=' initializer-expression +/// braced-init-list [TODO] +/// +/// initializer-clause: +/// assignment-expression +/// braced-init-list [TODO] +/// +/// defaulted/deleted function-definition: +/// '=' 'default' +/// '=' 'delete' +/// +/// Prior to C++0x, the assignment-expression in an initializer-clause must +/// be a constant-expression. +ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction, + SourceLocation &EqualLoc) { + assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) + && "Data member initializer not starting with '=' or '{'"); + + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + if (Tok.is(tok::kw_delete)) { + // In principle, an initializer of '= delete p;' is legal, but it will + // never type-check. It's better to diagnose it as an ill-formed expression + // than as an ill-formed deleted non-function member. + // An initializer of '= delete p, foo' will never be parsed, because + // a top-level comma always ends the initializer expression. + const Token &Next = NextToken(); + if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || + Next.is(tok::eof)) { + if (IsFunction) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + return ExprResult(); + } + } else if (Tok.is(tok::kw_default)) { + Diag(ConsumeToken(), diag::err_default_special_members); + if (IsFunction) + Diag(Tok, diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; + else + Diag(ConsumeToken(), diag::err_default_special_members); + return ExprResult(); + } + + return ParseInitializer(); + } else + return ExprError(Diag(Tok, diag::err_generalized_initializer_lists)); +} + /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: @@ -1839,6 +2085,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one member-declaration. + if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) @@ -1882,19 +2134,20 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, LBraceLoc, RBraceLoc, attrs.getList()); - // C++ 9.2p2: Within the class member-specification, the class is regarded as - // complete within function bodies, default arguments, - // exception-specifications, and constructor ctor-initializers (including - // such things in nested classes). + // C++0x [class.mem]p2: Within the class member-specification, the class is + // regarded as complete within function bodies, default arguments, exception- + // specifications, and brace-or-equal-initializers for non-static data + // members (including such things in nested classes). // - // FIXME: Only function bodies and constructor ctor-initializers are - // parsed correctly, fix the rest. + // FIXME: Only function bodies and brace-or-equal-initializers are currently + // handled. Fix the others! if (TagDecl && NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. SourceLocation SavedPrevTokLocation = PrevTokLocation; ParseLexedMethodDeclarations(getCurrentClass()); + ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); PrevTokLocation = SavedPrevTokLocation; } @@ -1982,6 +2235,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { /// /// [C++] mem-initializer: /// mem-initializer-id '(' expression-list[opt] ')' +/// [C++0x] mem-initializer-id braced-init-list /// /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name @@ -2012,31 +2266,37 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { SourceLocation IdLoc = ConsumeToken(); // Parse the '('. - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen); + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + // FIXME: Do something with the braced-init-list. + ParseBraceInitializer(); return true; - } - SourceLocation LParenLoc = ConsumeParen(); + } else if(Tok.is(tok::l_paren)) { + SourceLocation LParenLoc = ConsumeParen(); - // Parse the optional expression-list. - ExprVector ArgExprs(Actions); - CommaLocsTy CommaLocs; - if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { - SkipUntil(tok::r_paren); - return true; - } + // Parse the optional expression-list. + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return true; + } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - SourceLocation EllipsisLoc; - if (Tok.is(tok::ellipsis)) - EllipsisLoc = ConsumeToken(); - - return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, - LParenLoc, ArgExprs.take(), - ArgExprs.size(), RParenLoc, - EllipsisLoc); + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, + TemplateTypeTy, IdLoc, + LParenLoc, ArgExprs.take(), + ArgExprs.size(), RParenLoc, + EllipsisLoc); + } + + Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace + : diag::err_expected_lparen); + return true; } /// \brief Parse a C++ exception-specification if present (C++0x [except.spec]). @@ -2438,3 +2698,64 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); } } + +void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, + AccessSpecifier& CurAS) { + bool Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + ConsumeBrace(); + + // Condition is false skip all inside the {}. + if (!Result) { + SkipUntil(tok::r_brace, false); + return; + } + + // Condition is true, parse the declaration. + while (Tok.isNot(tok::r_brace)) { + + // __if_exists, __if_not_exists can nest. + if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi) + << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + AccessSpecifier AS = getAccessSpecifierIfPresent(); + if (AS != AS_none) { + // Current token is a C++ access specifier. + CurAS = AS; + SourceLocation ASLoc = Tok.getLocation(); + ConsumeToken(); + if (Tok.is(tok::colon)) + Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); + else + Diag(Tok, diag::err_expected_colon); + ConsumeToken(); + continue; + } + + // Parse all the comma separated declarators. + ParseCXXClassMemberDeclaration(CurAS); + } + + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return; + } + ConsumeBrace(); +} |