diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-06-11 17:19:42 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-06-11 17:19:42 +0000 |
commit | 7a614d8380297fcd2bc23986241905d97222948c (patch) | |
tree | bcbfe125e7a2dccada57451970279902a4cfe486 /lib | |
parent | 27f45236005d9dd2bbbfeb1682eb349cb8b6998b (diff) |
Implement support for C++11 in-class initialization of non-static data members.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132878 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 18 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 5 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 14 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 26 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 115 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 28 | ||||
-rw-r--r-- | lib/AST/Mangle.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 113 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 162 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 16 | ||||
-rw-r--r-- | lib/Rewrite/RewriteObjC.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 229 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 73 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 8 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 5 |
25 files changed, 769 insertions, 224 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 17b7c9d34b..9094abad2e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3536,7 +3536,8 @@ QualType ASTContext::getCFConstantStringType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -3577,7 +3578,8 @@ QualType ASTContext::getNSConstantStringType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); NSConstantStringTypeDecl->addDecl(Field); } @@ -3616,7 +3618,8 @@ QualType ASTContext::getObjCFastEnumerationStateType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } @@ -3653,7 +3656,8 @@ QualType ASTContext::getBlockDescriptorType() const { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3701,7 +3705,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3786,7 +3791,8 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index fcca95cefd..100e604d1c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2512,9 +2512,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), - T, TInfo, BitWidth, D->isMutable()); + T, TInfo, BitWidth, D->isMutable(), + D->hasInClassInitializer()); ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); + if (ToField->hasInClassInitializer()) + ToField->setInClassInitializer(D->getInClassInitializer()); Importer.Imported(D, ToField); LexicalDC->addDecl(ToField); return ToField; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1cad64e055..12357c07a7 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2077,9 +2077,10 @@ SourceRange FunctionDecl::getSourceRange() const { FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool HasInit) { return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, - BW, Mutable); + BW, Mutable, HasInit); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -2124,10 +2125,17 @@ unsigned FieldDecl::getFieldIndex() const { SourceRange FieldDecl::getSourceRange() const { if (isBitField()) - return SourceRange(getInnerLocStart(), BitWidth->getLocEnd()); + return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd()); return DeclaratorDecl::getSourceRange(); } +void FieldDecl::setInClassInitializer(Expr *Init) { + assert(!InitializerOrBitWidth.getPointer() && + "bit width or initializer already set"); + InitializerOrBitWidth.setPointer(Init); + InitializerOrBitWidth.setInt(0); +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9e82a1a84c..08ac2a5be4 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -715,6 +715,22 @@ NotASpecialMember:; if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) data().HasNonLiteralTypeFieldsOrBases = true; + if (Field->hasInClassInitializer()) { + // C++0x [class]p5: + // A default constructor is trivial if [...] no non-static data member + // of its class has a brace-or-equal-initializer. + data().HasTrivialDefaultConstructor = false; + + // C++0x [dcl.init.aggr]p1: + // An aggregate is a [...] class with [...] no + // brace-or-equal-initializers for non-static data members. + data().Aggregate = false; + + // C++0x [class]p10: + // A POD struct is [...] a trivial class. + data().PlainOldData = false; + } + if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { @@ -1345,11 +1361,21 @@ const Type *CXXCtorInitializer::getBaseClass() const { SourceLocation CXXCtorInitializer::getSourceLocation() const { if (isAnyMemberInitializer() || isDelegatingInitializer()) return getMemberLocation(); + + if (isInClassMemberInitializer()) + return getAnyMember()->getLocation(); return getBaseClassLoc().getLocalSourceRange().getBegin(); } SourceRange CXXCtorInitializer::getSourceRange() const { + if (isInClassMemberInitializer()) { + FieldDecl *D = getAnyMember(); + if (Expr *I = D->getInClassInitializer()) + return I->getSourceRange(); + return SourceRange(); + } + return SourceRange(getSourceLocation(), getRParenLoc()); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 49f27234c0..de1b6108ba 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -450,62 +450,67 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->hasAttr<NoReturnAttr>()) Proto += " __attribute((noreturn))"; if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { - if (CDecl->getNumCtorInitializers() > 0) { - Proto += " : "; - Out << Proto; - Proto.clear(); - for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), - E = CDecl->init_end(); - B != E; ++B) { - CXXCtorInitializer * BMInitializer = (*B); - if (B != CDecl->init_begin()) - Out << ", "; - if (BMInitializer->isAnyMemberInitializer()) { - FieldDecl *FD = BMInitializer->getAnyMember(); - Out << FD; - } else { - Out << QualType(BMInitializer->getBaseClass(), - 0).getAsString(Policy); - } + bool HasInitializerList = false; + for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), + E = CDecl->init_end(); + B != E; ++B) { + CXXCtorInitializer * BMInitializer = (*B); + if (BMInitializer->isInClassMemberInitializer()) + continue; + + if (!HasInitializerList) { + Proto += " : "; + Out << Proto; + Proto.clear(); + HasInitializerList = true; + } else + Out << ", "; + + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); + Out << FD; + } else { + Out << QualType(BMInitializer->getBaseClass(), + 0).getAsString(Policy); + } + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); - Out << "("; - if (!BMInitializer->getInit()) { - // Nothing to print - } else { - Expr *Init = BMInitializer->getInit(); - if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) - Init = Tmp->getSubExpr(); - - Init = Init->IgnoreParens(); - - Expr *SimpleInit = 0; - Expr **Args = 0; - unsigned NumArgs = 0; - if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); - } else if (CXXConstructExpr *Construct - = dyn_cast<CXXConstructExpr>(Init)) { - Args = Construct->getArgs(); - NumArgs = Construct->getNumArgs(); - } else - SimpleInit = Init; - - if (SimpleInit) - SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); - else { - for (unsigned I = 0; I != NumArgs; ++I) { - if (isa<CXXDefaultArgExpr>(Args[I])) - break; - - if (I) - Out << ", "; - Args[I]->printPretty(Out, Context, 0, Policy, Indentation); - } + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); } } - Out << ")"; } + Out << ")"; } } else @@ -553,6 +558,12 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { Out << " : "; D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation); } + + Expr *Init = D->getInClassInitializer(); + if (!Policy.SuppressInitializers && Init) { + Out << " = "; + Init->printPretty(Out, Context, 0, Policy, Indentation); + } } void DeclPrinter::VisitLabelDecl(LabelDecl *D) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 012701d08a..987213907e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -1653,7 +1654,8 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { return R; } -static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D, +static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E, + const Decl *D, bool NullThrows = true) { if (!D) return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; @@ -1683,6 +1685,15 @@ static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D, if (!FT) return Expr::CT_Can; + if (FT->getExceptionSpecType() == EST_Delayed) { + assert(isa<CXXConstructorDecl>(D) && + "only constructor exception specs can be unknown"); + Ctx.getDiagnostics().Report(E->getLocStart(), + diag::err_exception_spec_unknown) + << E->getSourceRange(); + return Expr::CT_Can; + } + return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can; } @@ -1757,7 +1768,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) CT = CT_Cannot; else - CT = CanCalleeThrow(C, CE->getCalleeDecl()); + CT = CanCalleeThrow(C, this, CE->getCalleeDecl()); if (CT == CT_Can) return CT; return MergeCanThrow(CT, CanSubExprsThrow(C, this)); @@ -1765,7 +1776,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { - CanThrowResult CT = CanCalleeThrow(C, + CanThrowResult CT = CanCalleeThrow(C, this, cast<CXXConstructExpr>(this)->getConstructor()); if (CT == CT_Can) return CT; @@ -1778,8 +1789,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { CT = CT_Dependent; else CT = MergeCanThrow( - CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()), - CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(), + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()), + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(), /*NullThrows*/false)); if (CT == CT_Can) return CT; @@ -1792,10 +1803,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { if (DTy.isNull() || DTy->isDependentType()) { CT = CT_Dependent; } else { - CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete()); + CT = CanCalleeThrow(C, this, + cast<CXXDeleteExpr>(this)->getOperatorDelete()); if (const RecordType *RT = DTy->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - CT = MergeCanThrow(CT, CanCalleeThrow(C, RD->getDestructor())); + CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor())); } if (CT == CT_Can) return CT; @@ -1805,7 +1817,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXBindTemporaryExprClass: { // The bound temporary has to be destroyed again, which might throw. - CanThrowResult CT = CanCalleeThrow(C, + CanThrowResult CT = CanCalleeThrow(C, this, cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor()); if (CT == CT_Can) return CT; diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index 3a0b909430..c3f3b11cac 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -48,6 +48,11 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) { const DeclContext *ExpectedDC = BD->getDeclContext(); while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC)) ExpectedDC = ExpectedDC->getParent(); + // In-class initializers for non-static data members are lexically defined + // within the class, but are mangled as if they were specified as constructor + // member initializers. + if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC) + DC = DC->getParent(); assert(DC == ExpectedDC && "Given decl context did not match expected!"); #endif } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index f11d528e13..e5da703a61 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -304,7 +304,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { const DeclContext *DC = block->getDeclContext(); for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext()) ; - QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C); + QualType thisType; + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) + thisType = C.getPointerType(C.getRecordType(RD)); + else + thisType = cast<CXXMethodDecl>(DC)->getThisType(C); const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); std::pair<CharUnits,CharUnits> tinfo diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 0d2500894e..5725d80b7d 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -520,6 +520,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, FunctionArgList &Args) { assert(MemberInit->isAnyMemberInitializer() && "Must have member initializer!"); + assert(MemberInit->getInit() && "Must have initializer!"); // non-static data member initializers. FieldDecl *Field = MemberInit->getAnyMember(); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 520d94e1bb..8c3e9a36e3 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -4098,9 +4098,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) SourceLocation(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCIdType(), 0, 0, false)); + Ctx.getObjCIdType(), 0, 0, false, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCClassType(), 0, 0, false)); + Ctx.getObjCClassType(), 0, 0, false, false)); RD->completeDefinition(); SuperCTy = Ctx.getTagDeclType(RD); @@ -4559,9 +4559,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul SourceLocation(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.VoidPtrTy, 0, 0, false)); + Ctx.VoidPtrTy, 0, 0, false, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCSelType(), 0, 0, false)); + Ctx.getObjCSelType(), 0, 0, false, false)); RD->completeDefinition(); MessageRefCTy = Ctx.getTagDeclType(RD); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index dee00275e7..f5c69981ca 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -42,6 +42,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, VS, Init.release(), + /*HasInit=*/false, /*IsDefinition*/true); } @@ -166,8 +167,50 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, return FnD; } +/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the +/// specified Declarator is a well formed C++ non-static data member +/// declaration. Now lex its initializer and store its tokens for parsing +/// after the class is complete. +void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { + assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) && + "Current token not a '{' or '='!"); + + LateParsedMemberInitializer *MI = + new LateParsedMemberInitializer(this, VarD); + getCurrentClass().LateParsedDeclarations.push_back(MI); + CachedTokens &Toks = MI->Toks; + + tok::TokenKind kind = Tok.getKind(); + if (kind == tok::equal) { + Toks.push_back(Tok); + ConsumeAnyToken(); + } + + if (kind == tok::l_brace) { + // Begin by storing the '{' token. + Toks.push_back(Tok); + ConsumeBrace(); + + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true); + } else { + // Consume everything up to (but excluding) the comma or semicolon. + ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + } + + // Store an artificial EOF token to ensure that we don't run off the end of + // the initializer when we come to parse it. + Token Eof; + Eof.startToken(); + Eof.setKind(tok::eof); + Eof.setLocation(Tok.getLocation()); + Toks.push_back(Eof); +} + Parser::LateParsedDeclaration::~LateParsedDeclaration() {} void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} +void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) @@ -181,6 +224,10 @@ void Parser::LateParsedClass::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclarations(*Class); } +void Parser::LateParsedClass::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializers(*Class); +} + void Parser::LateParsedClass::ParseLexedMethodDefs() { Self->ParseLexedMethodDefs(*Class); } @@ -193,6 +240,10 @@ void Parser::LexedMethod::ParseLexedMethodDefs() { Self->ParseLexedMethodDef(*this); } +void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializer(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was @@ -364,8 +415,70 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { origLoc)) while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); + } +} + +/// ParseLexedMemberInitializers - We finished parsing the member specification +/// of a top (non-nested) C++ class. Now go over the stack of lexed data member +/// initializers that were collected during its parsing and parse them all. +void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + // Set or update the scope flags to include Scope::ThisScope. + bool AlreadyHasClassScope = Class.TopLevelClass; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; + ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); + ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + if (!AlreadyHasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); } + + if (!AlreadyHasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate); +} + +void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { + if (MI.Field->isInvalidDecl()) + return; + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + MI.Toks.push_back(Tok); + PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + + SourceLocation EqualLoc; + ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc); + + Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release()); + + // The next token should be our artificial terminating EOF token. + if (Tok.isNot(tok::eof)) { + SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); + if (!EndLoc.isValid()) + EndLoc = Tok.getLocation(); + // No fixit; we can't recover as if there were a semicolon here. + Diag(EndLoc, diag::err_expected_semi_decl_list); + + // Consume tokens until we hit the artificial EOF. + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index dca7f903d2..51aa01091e 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1553,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: @@ -1731,10 +1732,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, bool IsDefinition = false; // function-definition: - if (Tok.is(tok::l_brace)) { + // + // 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::colon) || Tok.is(tok::kw_try)) { + 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(); @@ -1790,7 +1795,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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(); @@ -1799,38 +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 (DeclaratorInfo.isFunctionDeclarator()) - Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) - << 1 /* delete */; - else - Diag(ConsumeToken(), diag::err_deleted_non_function); - } else if (Tok.is(tok::kw_default)) { - if (DeclaratorInfo.isFunctionDeclarator()) - Diag(Tok, diag::err_default_delete_in_multiple_declaration) - << 1 /* delete */; - else - Diag(ConsumeToken(), diag::err_default_special_members); - } 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; |