diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-20 22:23:05 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-20 22:23:05 +0000 |
commit | c3bf52ced9652f555aa0767bb822ec4c64546212 (patch) | |
tree | e1bc9a6ecec46f15038eb98b525de05179d8479b /lib | |
parent | 7db58e0fe92a7a64daf14f78ceea103ba7fbf03d (diff) |
C++1y: Allow aggregates to have default initializers.
Add a CXXDefaultInitExpr, analogous to CXXDefaultArgExpr, and use it both in
CXXCtorInitializers and in InitListExprs to represent a default initializer.
There's an additional complication here: because the default initializer can
refer to the initialized object via its 'this' pointer, we need to make sure
that 'this' points to the right thing within the evaluation.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179958 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 7 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 2 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 26 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 11 | ||||
-rw-r--r-- | lib/AST/ExprClassification.cpp | 4 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 38 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 4 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 6 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 41 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 59 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 26 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 9 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 7 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 |
25 files changed, 271 insertions, 24 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2c7c4d335d..ece831571c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -505,7 +505,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-declared // constructors [...]. - // C++0x [dcl.init.aggr]p1: + // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. if (getASTContext().getLangOpts().CPlusPlus11 @@ -690,7 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no // brace-or-equal-initializers for non-static data members. - data().Aggregate = false; + // + // This rule was removed in C++1y. + if (!getASTContext().getLangOpts().CPlusPlus1y) + data().Aggregate = false; // C++11 [class]p10: // A POD struct is [...] a trivial class. diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 995925350c..bcc4e3865a 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -487,7 +487,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), E = CDecl->init_end(); B != E; ++B) { - CXXCtorInitializer * BMInitializer = (*B); + CXXCtorInitializer *BMInitializer = (*B); if (BMInitializer->isInClassMemberInitializer()) continue; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 748d3084fe..1303fb0cee 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -100,11 +100,20 @@ Expr::skipRValueSubobjectAdjustments( const Expr * Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const { const Expr *E = this; + + // This might be a default initializer for a reference member. Walk over the + // wrapper node for that. + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + // Look through single-element init lists that claim to be lvalues. They're // just syntactic wrappers in this case. if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) + if (ILE->getNumInits() == 1 && ILE->isGLValue()) { E = ILE->getInit(0); + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + } } // Look through expressions for materialized temporaries (for now). @@ -2174,6 +2183,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case CXXDefaultArgExprClass: return (cast<CXXDefaultArgExpr>(this) ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); + case CXXDefaultInitExprClass: + return (cast<CXXDefaultInitExpr>(this) + ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side @@ -2851,6 +2863,12 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); + case CXXDefaultInitExprClass: + if (const Expr *E = cast<CXXDefaultInitExpr>(this)->getExpr()) + return E->HasSideEffects(Ctx); + // If we've not yet parsed the initializer, assume it has side-effects. + return true; + case CXXDynamicCastExprClass: { // A dynamic_cast expression has side-effects if it can throw. const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this); @@ -3038,8 +3056,12 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { - // See through default argument expressions + // See through default argument expressions. return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultInitExpr *DefaultInit + = dyn_cast<CXXDefaultInitExpr>(this)) { + // See through default initializer expressions. + return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 12a47fcd78..277c8c09a5 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -704,6 +704,17 @@ CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, SubExpr); } +CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, + FieldDecl *Field, QualType T) + : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C), + T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType() + ? VK_XValue + : VK_RValue, + /*FIXME*/ OK_Ordinary, false, false, false, false), + Field(Field), Loc(Loc) { + assert(Field->hasInClassInitializer()); +} + CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index c2a35f42c1..bcb6d4e809 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -298,6 +298,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXDefaultArgExprClass: return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr()); + // Same idea for default initializers. + case Expr::CXXDefaultInitExprClass: + return ClassifyInternal(Ctx, cast<CXXDefaultInitExpr>(E)->getExpr()); + // Same idea for temporary binding. case Expr::CXXBindTemporaryExprClass: return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 3675b2ff44..4e468806dc 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -301,6 +301,22 @@ namespace { ~CallStackFrame(); }; + /// Temporarily override 'this'. + class ThisOverrideRAII { + public: + ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable) + : Frame(Frame), OldThis(Frame.This) { + if (Enable) + Frame.This = NewThis; + } + ~ThisOverrideRAII() { + Frame.This = OldThis; + } + private: + CallStackFrame &Frame; + const LValue *OldThis; + }; + /// A partial diagnostic which we might know in advance that we are not going /// to emit. class OptionalDiagnostic { @@ -2397,6 +2413,8 @@ public: { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) + { return StmtVisitorTy::Visit(E->getExpr()); } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -3398,12 +3416,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // If the initializer list for a union does not contain any elements, the // first element of the union is value-initialized. + // FIXME: The element should be initialized from an initializer list. + // Is this difference ever observable for initializer lists which + // we don't build? ImplicitValueInitExpr VIE(Field->getType()); const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; LValue Subobject = This; if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) return false; + + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(InitExpr)); + return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } @@ -3433,10 +3459,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); + const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; - if (!EvaluateInPlace( - Result.getStructField(Field->getFieldIndex()), - Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) { + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(Init)); + + if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, + Subobject, Init)) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -6807,6 +6837,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::CXXDefaultArgExprClass: return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::CXXDefaultInitExprClass: + return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); case Expr::ChooseExprClass: { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index e82b017e4a..0b77933f0b 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2473,6 +2473,10 @@ recurse: mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); break; + case Expr::CXXDefaultInitExprClass: + mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Arity); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 1b2285c794..95bacb64b3 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1314,7 +1314,11 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { } void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { - // Nothing to print: we picked up the default argument + // Nothing to print: we picked up the default argument. +} + +void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) { + // Nothing to print: we picked up the default initializer. } void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index d99400c603..8ade242d56 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -789,6 +789,11 @@ void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { VisitDecl(S->getParam()); } +void StmtProfiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { + VisitExpr(S); + VisitDecl(S->getField()); +} + void StmtProfiler::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { VisitExpr(S); VisitDecl( diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 1adb8b84e4..096c7a080b 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1085,11 +1085,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc); case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDefaultInitExprClass: // FIXME: The expression inside a CXXDefaultArgExpr is owned by the // called function's declaration, not by the caller. If we simply add // this expression to the CFG, we could end up with the same Expr // appearing multiple times. // PR13385 / <rdar://problem/12156507> + // + // It's likewise possible for multiple CXXDefaultInitExprs for the same + // expression to be used in the same function (through aggregate + // initialization). return VisitStmt(S, asc); case Stmt::CXXBindTemporaryExprClass: diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 05925567b0..2b9a55b2a6 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1139,6 +1139,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, InitializeVTablePointers(ClassDecl); // And finally, initialize class members. + FieldConstructionScope FCS(*this, CXXThisValue); ConstructorMemcpyizer CM(*this, CD, Args); for (; B != E; B++) { CXXCtorInitializer *Member = (*B); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index a0725b5f9c..ea13de17ab 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -903,6 +903,10 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E)); case Expr::CXXDefaultArgExprClass: return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr()); + case Expr::CXXDefaultInitExprClass: { + CXXDefaultInitExprScope Scope(*this); + return EmitLValue(cast<CXXDefaultInitExpr>(E)->getExpr()); + } case Expr::CXXTypeidExprClass: return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E)); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 6b29b3155a..b974e1dcc6 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -170,6 +170,10 @@ public: void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { Visit(DAE->getExpr()); } + void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + Visit(DIE->getExpr()); + } void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitLambdaExpr(LambdaExpr *E); @@ -1189,7 +1193,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl(); - + + // Prepare a 'this' for CXXDefaultInitExprs. + CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddr()); + if (record->isUnion()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5fc73aa790..36f974a313 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -182,6 +182,10 @@ public: ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + ComplexPairTy VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) { CGF.enterFullExpression(E); CodeGenFunction::RunCleanupsScope Scope(CGF); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index faaf6468f1..f5c8187c26 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -757,6 +757,12 @@ public: return Visit(DAE->getExpr()); } + llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + // No need for a DefaultInitExprScope: we don't handle 'this' in a + // constant expression. + return Visit(DIE->getExpr()); + } + llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { return Visit(E->GetTemporaryExpr()); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index ea1eae8088..c1c252d12b 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -344,6 +344,10 @@ public: Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } Value *VisitCXXThisExpr(CXXThisExpr *TE) { return CGF.LoadCXXThis(); } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index cda3ce0286..a12e7dc445 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -45,6 +45,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), + CXXDefaultInitExprThis(0), CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0), OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6e2d62760f..f0c2c1e672 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1206,12 +1206,53 @@ private: /// lazily by getUnreachableBlock(). llvm::BasicBlock *UnreachableBlock; +public: + /// A scope within which we are constructing the fields of an object which + /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use + /// if we need to evaluate a CXXDefaultInitExpr within the evaluation. + class FieldConstructionScope { + public: + FieldConstructionScope(CodeGenFunction &CGF, llvm::Value *This) + : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) { + CGF.CXXDefaultInitExprThis = This; + } + ~FieldConstructionScope() { + CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis; + } + + private: + CodeGenFunction &CGF; + llvm::Value *OldCXXDefaultInitExprThis; + }; + + /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this' + /// is overridden to be the object under construction. + class CXXDefaultInitExprScope { + public: + CXXDefaultInitExprScope(CodeGenFunction &CGF) + : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue) { + CGF.CXXThisValue = CGF.CXXDefaultInitExprThis; + } + ~CXXDefaultInitExprScope() { + CGF.CXXThisValue = OldCXXThisValue; + } + + public: + CodeGenFunction &CGF; + llvm::Value *OldCXXThisValue; + }; + +private: /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXABIThisDecl; llvm::Value *CXXABIThisValue; llvm::Value *CXXThisValue; + /// The value of 'this' to use when evaluating CXXDefaultInitExprs within + /// this expression. + llvm::Value *CXXDefaultInitExprThis; + /// CXXStructorImplicitParamDecl - When generating code for a constructor or /// destructor, this will hold the implicit argument (e.g. VTT). ImplicitParamDecl *CXXStructorImplicitParamDecl; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 94a507449b..b29ce23fe9 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3054,7 +3054,7 @@ struct BaseAndFieldInfo { AllToInit.push_back(Init); // Check whether this initializer makes the field "used". - if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context)) + if (Init->getInit()->HasSideEffects(S.Context)) S.UnusedPrivateFields.remove(Init->getAnyMember()); return false; @@ -3103,16 +3103,18 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + Info.Ctor->getLocation(), Field); CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); else Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); return Info.addFieldInitializer(Init); } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4758718006..1a5f4824d0 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1011,7 +1011,6 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ConditionalOperatorClass: case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: - case Expr::CXXDefaultArgExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::DesignatedInitExprClass: case Expr::ExprWithCleanupsClass: @@ -1044,6 +1043,12 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::StmtExprClass: return CT_Can; + case Expr::CXXDefaultArgExprClass: + return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); + + case Expr::CXXDefaultInitExprClass: + return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); + case Expr::ChooseExprClass: if (E->isTypeDependent() || E->isValueDependent()) return CT_Dependent; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 5a5fd26835..0e513992ba 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -293,6 +293,21 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { + // If there's no explicit initializer but we have a default initializer, use + // that. This only happens in C++1y, since classes with default + // initializers are not aggregates in C++11. + if (Field->hasInClassInitializer()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + ILE->getRBraceLoc(), Field); + if (Init < NumInits) + ILE->setInit(Init, DIE); + else { + ILE->updateInit(SemaRef.Context, Init, DIE); + RequiresSecondPass = true; + } + return; + } + // FIXME: We probably don't need to handle references // specially here, since value-initialization of references is // handled in InitializationSequence. @@ -358,15 +373,24 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, Loc = ILE->getSyntacticForm()->getLocStart(); if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { - if (RType->getDecl()->isUnion() && - ILE->getInitializedFieldInUnion()) + const RecordDecl *RDecl = RType->getDecl(); + if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass); - else { + else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && + cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + FillInValueInitForField(0, *Field, Entity, ILE, RequiresSecondPass); + break; + } + } + } else { unsigned Init = 0; - for (RecordDecl::field_iterator - Field = RType->getDecl()->field_begin(), - FieldEnd = RType->getDecl()->field_end(); + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; @@ -381,7 +405,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, ++Init; // Only look at the first initialization of a union. - if (RType->getDecl()->isUnion()) + if (RDecl->isUnion()) break; } } @@ -1323,8 +1347,23 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - // Value-initialize the first named member of the union. RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + + // If there's a default initializer, use it. + if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { + if (VerifyOnly) + return; + for (RecordDecl::field_iterator FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + StructuredList->setInitializedFieldInUnion(*Field); + // FIXME: Actually build a CXXDefaultInitExpr? + return; + } + } + } + + // Value-initialize the first named member of the union. for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Field->getDeclName()) { @@ -1428,7 +1467,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // Find first (if any) named field and emit warning. for (RecordDecl::field_iterator it = Field, end = RD->field_end(); it != end; ++it) { - if (!it->isUnnamedBitfield()) { + if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) { SemaRef.Diag(IList->getSourceRange().getEnd(), diag::warn_missing_field_initializers) << it->getName(); break; @@ -1441,7 +1480,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, !Field->getType()->isIncompleteArrayType()) { // FIXME: Should check for holes left by designated initializers too. for (; Field != FieldEnd && !hadError; ++Field) { - if (!Field->isUnnamedBitfield()) + if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) CheckValueInitializable( InitializedEntity::InitializeMember(*Field, &Entity)); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 55f1587a85..97316f89b3 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1980,6 +1980,17 @@ public: Param)); } + /// \brief Build a new C++11 default-initialization expression. + /// + /// By default, builds a new default field initialization expression, which + /// does not require any semantic analysis. Subclasses may override this + /// routine to provide different behavior. + ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc, + FieldDecl *Field) { + return getSema().Owned(CXXDefaultInitExpr::Create(getSema().Context, Loc, + Field)); + } + /// \brief Build a new C++ zero-initialization expression. /// /// By default, performs semantic analysis to build the new expression. @@ -7262,6 +7273,21 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + FieldDecl *Field + = cast_or_null<FieldDecl>(getDerived().TransformDecl(E->getLocStart(), + E->getField())); + if (!Field) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Field == E->getField()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXScalarValueInitExpr( CXXScalarValueInitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index b18114fdcb..c7748b7f6b 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1230,6 +1230,12 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { E->Loc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + E->Field = ReadDeclAs<FieldDecl>(Record, Idx); + E->Loc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx)); @@ -2111,6 +2117,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) CXXDefaultArgExpr(Empty); break; } + case EXPR_CXX_DEFAULT_INIT: + S = new (Context) CXXDefaultInitExpr(Empty); + break; case EXPR_CXX_BIND_TEMPORARY: S = new (Context) CXXBindTemporaryExpr(Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 61ddec0fb0..5c8e213384 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1223,6 +1223,13 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { Code = serialization::EXPR_CXX_DEFAULT_ARG; } +void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getField(), Record); + Writer.AddSourceLocation(E->getExprLoc(), Record); + Code = serialization::EXPR_CXX_DEFAULT_INIT; +} + void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); Writer.AddCXXTemporary(E->getTemporary(), Record); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 92a3a952df..5b6e97d3fb 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -604,6 +604,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, switch (S->getStmtClass()) { // C++ and ARC stuff we don't support yet. case Expr::ObjCIndirectCopyRestoreExprClass: + case Stmt::CXXDefaultInitExprClass: case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTryStmtClass: |