diff options
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; @@ -1845,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. @@ -1860,7 +1857,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - VS, Init.release(), false); + VS, Init.release(), + HasDeferredInitializer, + /*IsDefinition*/ false); } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1873,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)) @@ -1906,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: @@ -2057,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; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f209723dc0..f19472ccdc 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -351,7 +351,23 @@ void Parser::ExitScope() { ScopeCache[NumCachedScopes++] = OldScope; } +/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false, +/// this object does nothing. +Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags, + bool ManageFlags) + : CurScope(ManageFlags ? Self->getCurScope() : 0) { + if (CurScope) { + OldFlags = CurScope->getFlags(); + CurScope->setFlags(ScopeFlags); + } +} +/// Restore the flags for the current scope to what they were before this +/// object overrode them. +Parser::ParseScopeFlags::~ParseScopeFlags() { + if (CurScope) + CurScope->setFlags(OldFlags); +} //===----------------------------------------------------------------------===// diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index d6e34ef8fa..8cdb55a0c1 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -2695,7 +2695,8 @@ QualType RewriteObjC::getSuperStructType() { SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, - /*Mutable=*/false)); + /*Mutable=*/false, + /*HasInit=*/false)); } SuperStructDecl->completeDefinition(); @@ -2727,7 +2728,8 @@ QualType RewriteObjC::getConstantStringStructType() { SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, - /*Mutable=*/true)); + /*Mutable=*/true, + /*HasInit=*/false)); } ConstantStringDecl->completeDefinition(); @@ -4709,7 +4711,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { SourceLocation(), &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -4763,7 +4766,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { SourceLocation(), &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -4773,7 +4777,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c2fee32aea..9446c0e8c0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2610,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setAccess(AS); if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); @@ -2700,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setImplicit(); // Add the anonymous struct object to the current context. @@ -7512,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, return false; } -/// ActOnField - Each field of a struct/union/class is passed into this in order +/// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. -Decl *Sema::ActOnField(Scope *S, Decl *TagD, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { +Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD), DeclStart, D, static_cast<Expr*>(BitfieldWidth), - AS_public); + /*HasInit=*/false, AS_public); return Res; } @@ -7527,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, - Declarator &D, Expr *BitWidth, + Declarator &D, Expr *BitWidth, bool HasInit, AccessSpecifier AS) { IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; @@ -7576,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getSourceRange().getBegin(); FieldDecl *NewFD - = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, - AS, PrevDecl, &D); + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit, + TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); @@ -7606,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitWidth, + bool Mutable, Expr *BitWidth, bool HasInit, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { @@ -7686,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, - BitWidth, Mutable); + BitWidth, Mutable, HasInit); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -8289,16 +8290,17 @@ void Sema::ActOnFields(Scope* S, // Now that the record is complete, do any delayed exception spec checks // we were missing. - if (!DelayedDestructorExceptionSpecChecks.empty()) { + while (!DelayedDestructorExceptionSpecChecks.empty()) { const CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecChecks.back().first; - if (Dtor->getParent() == Record) { - assert(!Dtor->getParent()->isDependentType() && - "Should not ever add destructors of templates into the list."); - CheckOverridingFunctionExceptionSpec(Dtor, - DelayedDestructorExceptionSpecChecks.back().second); - DelayedDestructorExceptionSpecChecks.pop_back(); - } + if (Dtor->getParent() != Record) + break; + + assert(!Dtor->getParent()->isDependentType() && + "Should not ever add destructors of templates into the list."); + CheckOverridingFunctionExceptionSpec(Dtor, + DelayedDestructorExceptionSpecChecks.back().second); + DelayedDestructorExceptionSpecChecks.pop_back(); } } else { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a4ba5fafea..ce99efbd0b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -113,8 +113,8 @@ namespace { void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { assert(Context && "ImplicitExceptionSpecification without an ASTContext"); - // If we have an MSAny spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny) + // If we have an MSAny or unknown spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) return; const FunctionProtoType *Proto @@ -123,12 +123,15 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { ExceptionSpecificationType EST = Proto->getExceptionSpecType(); // If this function can throw any exceptions, make a note of that. - if (EST == EST_MSAny || EST == EST_None) { + if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { ClearExceptions(); ComputedEST = EST; return; } + // FIXME: If the call to this decl is using any of its default arguments, we + // need to search them for potentially-throwing calls. + // If this function has a basic noexcept, it doesn't affect the outcome. if (EST == EST_BasicNoexcept) return; @@ -175,6 +178,35 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { Exceptions.push_back(*E); } +void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { + if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + return; + + // FIXME: + // + // C++0x [except.spec]p14: + // [An] implicit exception-specification specifies the type-id T if and + // only if T is allowed by the exception-specification of a function directly + // invoked by f’s implicit definition; f shall allow all exceptions if any + // function it directly invokes allows all exceptions, and f shall allow no + // exceptions if every function it directly invokes allows no exceptions. + // + // Note in particular that if an implicit exception-specification is generated + // for a function containing a throw-expression, that specification can still + // be noexcept(true). + // + // Note also that 'directly invoked' is not defined in the standard, and there + // is no indication that we should only consider potentially-evaluated calls. + // + // Ultimately we should implement the intent of the standard: the exception + // specification should be the set of exceptions which can be thrown by the + // implicit definition. For now, we assume that any non-nothrow expression can + // throw any exception. + + if (E->CanThrow(*Context)) + ComputedEST = EST_None; +} + bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { @@ -1029,13 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the -/// bitfield width if there is one and 'InitExpr' specifies the initializer if -/// any. +/// bitfield width if there is one, 'InitExpr' specifies the initializer if +/// one has been parsed, and 'HasDeferredInit' is true if an initializer is +/// present but parsing it has been deferred. Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, const VirtSpecifiers &VS, - ExprTy *InitExpr, bool IsDefinition) { + ExprTy *InitExpr, bool HasDeferredInit, + bool IsDefinition) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1050,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(isa<CXXRecordDecl>(CurContext)); assert(!DS.isFriendSpecified()); + assert(!Init || !HasDeferredInit); bool isFunc = false; if (D.isFunctionDeclarator()) @@ -1121,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // FIXME: Check for template parameters! // FIXME: Check that the name is an identifier! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - AS); + HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { + assert(!HasDeferredInit); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); if (!Member) { return 0; @@ -1194,6 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (Init) AddInitializerToDecl(Member, Init, false, DS.getTypeSpecType() == DeclSpec::TST_auto); + else if (DS.getTypeSpecType() == DeclSpec::TST_auto && + DS.getStorageClassSpec() == DeclSpec::SCS_static) { + // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static + // data member if a brace-or-equal-initializer is provided. + Diag(Loc, diag::err_auto_var_requires_init) + << Name << cast<ValueDecl>(Member)->getType(); + Member->setInvalidDecl(); + } FinalizeDeclaration(Member); @@ -1202,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return Member; } +/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an +/// in-class initializer for a non-static C++ class member. Such parsing +/// is deferred until the class is complete. +void +Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, + Expr *InitExpr) { + FieldDecl *FD = cast<FieldDecl>(D); + + if (!InitExpr) { + FD->setInvalidDecl(); + FD->removeInClassInitializer(); + return; + } + + ExprResult Init = InitExpr; + if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { + // FIXME: if there is no EqualLoc, this is list-initialization. + Init = PerformCopyInitialization( + InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + CheckImplicitConversions(Init.get(), EqualLoc); + } + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + Init = MaybeCreateExprWithCleanups(Init); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + InitExpr = Init.release(); + + FD->setInClassInitializer(InitExpr); +} + /// \brief Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. @@ -2073,7 +2159,7 @@ struct BaseAndFieldInfo { }; } -static bool CollectFieldInitializer(BaseAndFieldInfo &Info, +static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, FieldDecl *Top, FieldDecl *Field) { // Overwhelmingly common case: we have a direct initializer for this field. @@ -2082,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, return false; } + // C++0x [class.base.init]p8: if the entity is a non-static data member that + // has a brace-or-equal-initializer, the entity is initialized as specified + // in [dcl.init]. + if (Field->hasInClassInitializer()) { + Info.AllToInit.push_back( + new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + SourceLocation(), + SourceLocation(), 0, + SourceLocation())); + return false; + } + if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); assert(FieldClassType && "anonymous struct/union without record type"); @@ -2104,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // field in the class is also initialized, so exit immediately. return false; } else if ((*FA)->isAnonymousStructOrUnion()) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2119,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // necessary. for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2128,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be // missing some that the user actually wrote). - if (Info.AnyErrorsInInits) + if (Info.AnyErrorsInInits || Field->isInvalidDecl()) return false; CXXCtorInitializer *Init = 0; @@ -2260,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, "Incomplete array type is not valid"); continue; } - if (CollectFieldInitializer(Info, *Field, *Field)) + if (CollectFieldInitializer(*this, Info, *Field, *Field)) HadError = true; } @@ -2939,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { + if (F->hasInClassInitializer()) + continue; + if (F->getType()->isReferenceType() || (F->getType().isConstQualified() && F->getType()->isScalarType())) { if (!Complained) { @@ -3066,6 +3167,11 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent()); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + if (EPI.ExceptionSpecType == EST_Delayed) { + // Exception specification depends on some deferred part of the class. We'll + // try again when the class's definition has been fully processed. + return; + } const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); @@ -3383,12 +3489,15 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isInvalidDecl()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); - + // -- any non-static data member with no brace-or-equal-initializer is of // reference type - if (FieldType->isReferenceType()) + if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) return true; // -- X is a union and all its variant members are of const-qualified type @@ -3413,6 +3522,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { // array thereof) with no brace-or-equal-initializer does not have a // user-provided default constructor if (FieldType.isConstQualified() && + !FI->hasInClassInitializer() && !FieldRecord->hasUserProvidedDefaultConstructor()) return true; @@ -3445,18 +3555,21 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { continue; } - // -- any non-static data member ... has class type M (or array thereof) - // and either M has no default constructor or overload resolution as - // applied to M's default constructor results in an ambiguity or in a - // function that is deleted or inaccessible from the defaulted default - // constructor. - CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); - if (!FieldDefault || FieldDefault->isDeleted()) - return true; - if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), - PDiag()) != AR_accessible) - return true; - } else if (!Union && FieldType.isConstQualified()) { + // -- any non-static data member with no brace-or-equal-initializer has + // class type M (or array thereof) and either M has no default + // constructor or overload resolution as applied to M's default + // constructor results in an ambiguity or in a function that is deleted + // or inaccessible from the defaulted default constructor. + if (!FI->hasInClassInitializer()) { + CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); + if (!FieldDefault || FieldDefault->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } else if (!Union && FieldType.isConstQualified() && + !FI->hasInClassInitializer()) { // -- any non-variant non-static data member of const-qualified type (or // array thereof) with no brace-or-equal-initializer does not have a // user-provided default constructor @@ -5905,7 +6018,12 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (const RecordType *RecordTy + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + ExceptSpec.SetDelayed(); + } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); @@ -6001,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } +/// Get any existing defaulted default constructor for the given class. Do not +/// implicitly define one if it does not exist. +static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, + CXXRecordDecl *D) { + ASTContext &Context = Self.Context; + QualType ClassType = Context.getTypeDeclType(D); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // A function template cannot be defaulted. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor->isDefaulted() ? Constructor : 0; + } + return 0; +} + +void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { + if (!D) return; + AdjustDeclIfTemplate(D); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); + CXXConstructorDecl *CtorDecl + = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); + + if (!CtorDecl) return; + + // Compute the exception specification for the default constructor. + const FunctionProtoType *CtorTy = + CtorDecl->getType()->castAs<FunctionProtoType>(); + if (CtorTy->getExceptionSpecType() == EST_Delayed) { + ImplicitExceptionSpecification Spec = + ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + assert(EPI.ExceptionSpecType != EST_Delayed); + + CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + // If the default constructor is explicitly defaulted, checking the exception + // specification is deferred until now. + if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && + !ClassDecl->isDependentType()) + CheckExplicitlyDefaultedDefaultConstructor(CtorDecl); +} + void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further @@ -6094,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // Build up a function type for this particular constructor. // FIXME: The working paper does not consider that the exception spec // for the inheriting constructor might be larger than that of the - // source. This code doesn't yet, either. + // source. This code doesn't yet, either. When it does, this code will + // need to be delayed until after exception specifications and in-class + // member initializers are attached. const Type *NewCtorType; if (params == maxParams) NewCtorType = BaseCtorType; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 0f6108c8bc..7bcec315dd 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // - both are non-throwing, regardless of their form, // - both have the form noexcept(constant-expression) and the constant- // expressions are equivalent, - // - one exception-specification is a noexcept-specification allowing all - // exceptions and the other is of the form throw(type-id-list), or // - both are dynamic-exception-specifications that have the same set of // adjusted types. // @@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // of the form throw(), noexcept, or noexcept(constant-expression) where the // constant-expression yields true. // - // CWG 1073 Proposed resolution: Strike the third bullet above. - // // C++0x [except.spec]p4: If any declaration of a function has an exception- // specifier that is not a noexcept-specification allowing all exceptions, // all declarations [...] of that function shall have a compatible @@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); ExceptionSpecificationType NewEST = New->getExceptionSpecType(); + assert(OldEST != EST_Delayed && NewEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // Shortcut the case where both have no spec. if (OldEST == EST_None && NewEST == EST_None) return false; @@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); + assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // It does not. If the subset contains everything, we've failed. if (SubEST == EST_None || SubEST == EST_MSAny) { Diag(SubLoc, DiagID); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index dafd56bf34..0549e94995 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1333,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) { + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) { Diag(loc, diag::err_invalid_member_use_in_static_method) << indirectField->getDeclName(); return ExprError(); @@ -1342,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // Our base object expression is "this". baseObjectExpr = - new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/ true); + new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); baseObjectIsPointer = true; - baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers()); + baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); } // Build the implicit member references to the field of the @@ -1492,14 +1491,23 @@ enum IMAKind { /// conservatively answer "yes", in which case some errors will simply /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + Scope *CurScope, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); + bool isStaticContext = (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic()); + // C++0x [expr.prim]p4: + // Otherwise, if a member-declarator declares a non-static data member + // of a class X, the expression this is a prvalue of type "pointer to X" + // within the optional brace-or-equal-initializer. + if (CurScope->getFlags() & Scope::ThisScope) + isStaticContext = false; + if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -1547,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, return IMA_Error_StaticContext; } - CXXRecordDecl * - contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl(); + CXXRecordDecl *contextClass; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + contextClass = MD->getParent()->getCanonicalDecl(); + else + contextClass = cast<CXXRecordDecl>(DC); // [class.mfct.non-static]p3: // ...is used in the body of a non-static member function of class X, @@ -2026,7 +2037,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, R)) { + switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); @@ -2469,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build an // implicit 'this' expression now. // 'this' expression now. - CXXMethodDecl *method = tryCaptureCXXThis(); - assert(method && "didn't correctly pre-flight capture of 'this'"); + QualType ThisTy = getAndCaptureCurrentThisType(); + assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); - QualType thisType = method->getThisType(Context); Expr *baseExpr = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); - baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true); + baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(baseExpr, thisType, + return BuildMemberReferenceExpr(baseExpr, ThisTy, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 50462abd3a..2f5a890e51 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -575,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { return Owned(E); } -CXXMethodDecl *Sema::tryCaptureCXXThis() { +QualType Sema::getAndCaptureCurrentThisType() { // Ignore block scopes: we can capture through them. // Ignore nested enum scopes: we'll diagnose non-constant expressions // where they're invalid, and other uses are legitimate. // Don't ignore nested class scopes: you can't use 'this' in a local class. DeclContext *DC = CurContext; + unsigned NumBlocks = 0; while (true) { - if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); - else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + if (isa<BlockDecl>(DC)) { + DC = cast<BlockDecl>(DC)->getDeclContext(); + ++NumBlocks; + } else if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); else break; } - // If we're not in an instance method, error out. - CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); - if (!method || !method->isInstance()) - return 0; + QualType ThisTy; + if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { + if (method && method->isInstance()) + ThisTy = method->getThisType(Context); + } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { + // C++0x [expr.prim]p4: + // Otherwise, if a member-declarator declares a non-static data member + // of a class X, the expression this is a prvalue of type "pointer to X" + // within the optional brace-or-equal-initializer. + Scope *S = getScopeForContext(DC); + if (!S || S->getFlags() & Scope::ThisScope) + ThisTy = Context.getPointerType(Context.getRecordType(RD)); + } - // Mark that we're closing on 'this' in all the block scopes, if applicable. - for (unsigned idx = FunctionScopes.size() - 1; - isa<BlockScopeInfo>(FunctionScopes[idx]); - --idx) - cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; + // Mark that we're closing on 'this' in all the block scopes we ignored. + if (!ThisTy.isNull()) + for (unsigned idx = FunctionScopes.size() - 1; + NumBlocks; --idx, --NumBlocks) + cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; - return method; + return ThisTy; } -ExprResult Sema::ActOnCXXThis(SourceLocation loc) { +ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) return Diag(loc, diag::err_invalid_this_use); + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); - return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/false)); + return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } ExprResult @@ -2663,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundAssign = false; - bool AllNoThrow = true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), Sema::LookupOrdinaryName); @@ -2675,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); - if (!CPT->isNothrow(Self.Context)) { - AllNoThrow = false; - break; - } + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; + if (!CPT->isNothrow(Self.Context)) + return false; } } } - return FoundAssign && AllNoThrow; + return FoundAssign; } return false; case UTT_HasNothrowCopy: @@ -2700,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundConstructor = false; - bool AllNoThrow = true; unsigned FoundTQs; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); @@ -2715,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) { - AllNoThrow = false; - break; - } + if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) + return false; } } - return FoundConstructor && AllNoThrow; + return FoundConstructor; } return false; case UTT_HasNothrowConstructor: @@ -2750,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (Constructor->isDefaultConstructor()) { const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 444fb9a2f2..3c1964175b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -1744,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); llvm::SmallVector<Decl*, 4> Fields; + llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> + FieldsWithMemberInitializers; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { @@ -1766,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Decl *NewMember = Instantiator.Visit(*Member); if (NewMember) { - if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) { Fields.push_back(Field); - else if (NewMember->isInvalidDecl()) + FieldDecl *OldField = cast<FieldDecl>(*Member); + if (OldField->getInClassInitializer()) + FieldsWithMemberInitializers.push_back(std::make_pair(OldField, + Field)); + } else if (NewMember->isInvalidDecl()) Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the @@ -1782,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Instantiation); + + // Attach any in-class member initializers now the class is complete. + for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { + FieldDecl *OldField = FieldsWithMemberInitializers[I].first; + FieldDecl *NewField = FieldsWithMemberInitializers[I].second; + Expr *OldInit = OldField->getInClassInitializer(); + ExprResult NewInit = SubstExpr(OldInit, TemplateArgs); + + // If the initialization is no longer dependent, check it now. + if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent()) + && !NewField->getType()->isDependentType() + && !NewInit.get()->isTypeDependent()) { + // FIXME: handle list-initialization + SourceLocation EqualLoc = NewField->getLocation(); + NewInit = PerformCopyInitialization( + InitializedEntity::InitializeMember(NewField), EqualLoc, + NewInit.release()); + + if (!NewInit.isInvalid()) { + CheckImplicitConversions(NewInit.get(), EqualLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + NewInit = MaybeCreateExprWithCleanups(NewInit); + } + } + + if (NewInit.isInvalid()) + NewField->setInvalidDecl(); + else + NewField->setInClassInitializer(NewInit.release()); + } + + if (!FieldsWithMemberInitializers.empty()) + ActOnFinishDelayedMemberInitializers(Instantiation); + if (Instantiation->isInvalidDecl()) Invalid = true; else { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 22db4c8f61..e78aa2991e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -477,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { D->getLocation(), D->isMutable(), BitWidth, + D->hasInClassInitializer(), D->getTypeSpecStartLoc(), D->getAccess(), 0); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e7f9885698..5fd8afa6ac 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1593,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 0; // Function prototype break; case Declarator::MemberContext: + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) + break; switch (cast<TagDecl>(CurContext)->getTagKind()) { case TTK_Enum: assert(0 && "unhandled tag kind"); break; case TTK_Struct: Error = 1; /* Struct member */ break; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 245499e8a1..ff2e46a902 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6697,8 +6697,12 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { DeclContext *DC = getSema().getFunctionLevelDeclContext(); - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC); - QualType T = MD->getThisType(getSema().Context); + QualType T; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + T = MD->getThisType(getSema().Context); + else + T = getSema().Context.getPointerType( + getSema().Context.getRecordType(cast<CXXRecordDecl>(DC))); if (!getDerived().AlwaysRebuild() && T == E->getType()) return SemaRef.Owned(E); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 6e9d4d4820..fab2069bc5 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -677,8 +677,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->setMutable(Record[Idx++]); - if (Record[Idx++]) + int BitWidthOrInitializer = Record[Idx++]; + if (BitWidthOrInitializer == 1) FD->setBitWidth(Reader.ReadExpr(F)); + else if (BitWidthOrInitializer == 2) + FD->setInClassInitializer(Reader.ReadExpr(F)); if (!FD->getDeclName()) { FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); if (Tmpl) @@ -1649,7 +1652,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { break; case DECL_FIELD: D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, 0, false); + QualType(), 0, 0, false, false); break; case DECL_INDIRECTFIELD: D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index c6b159c50b..7c24088c65 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -599,9 +599,11 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - Record.push_back(D->getBitWidth()? 1 : 0); + Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0); if (D->getBitWidth()) Writer.AddStmt(D->getBitWidth()); + else if (D->hasInClassInitializer()) + Writer.AddStmt(D->getInClassInitializer()); if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); @@ -612,6 +614,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { !D->isReferenced() && D->getPCHLevel() == 0 && !D->getBitWidth() && + !D->hasInClassInitializer() && !D->hasExtInfo() && !ObjCIvarDecl::classofKind(D->getKind()) && !ObjCAtDefsFieldDecl::classofKind(D->getKind()) && |