aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-04-20 22:23:05 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-04-20 22:23:05 +0000
commitc3bf52ced9652f555aa0767bb822ec4c64546212 (patch)
treee1bc9a6ecec46f15038eb98b525de05179d8479b /lib
parent7db58e0fe92a7a64daf14f78ceea103ba7fbf03d (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.cpp7
-rw-r--r--lib/AST/DeclPrinter.cpp2
-rw-r--r--lib/AST/Expr.cpp26
-rw-r--r--lib/AST/ExprCXX.cpp11
-rw-r--r--lib/AST/ExprClassification.cpp4
-rw-r--r--lib/AST/ExprConstant.cpp38
-rw-r--r--lib/AST/ItaniumMangle.cpp4
-rw-r--r--lib/AST/StmtPrinter.cpp6
-rw-r--r--lib/AST/StmtProfile.cpp5
-rw-r--r--lib/Analysis/CFG.cpp5
-rw-r--r--lib/CodeGen/CGClass.cpp1
-rw-r--r--lib/CodeGen/CGExpr.cpp4
-rw-r--r--lib/CodeGen/CGExprAgg.cpp9
-rw-r--r--lib/CodeGen/CGExprComplex.cpp4
-rw-r--r--lib/CodeGen/CGExprConstant.cpp6
-rw-r--r--lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp1
-rw-r--r--lib/CodeGen/CodeGenFunction.h41
-rw-r--r--lib/Sema/SemaDeclCXX.cpp8
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp7
-rw-r--r--lib/Sema/SemaInit.cpp59
-rw-r--r--lib/Sema/TreeTransform.h26
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp9
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp1
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: