When value-initializing a class with no user-defined constructors but
with a non-trivial default constructor, zero-initialize the storage
and then call the default constructor. Fixes PR5800.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91548 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index f173d79..9c14f74 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -380,28 +380,32 @@
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs) {
+ Expr **Args, unsigned NumArgs,
+ bool ZeroInitialization) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs);
+ Elidable, Args, NumArgs, ZeroInitialization);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
- Expr **args, unsigned numargs)
+ Expr **args, unsigned numargs,
+ bool ZeroInitialization)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
- Constructor(D), Loc(Loc), Elidable(elidable), Args(0), NumArgs(numargs) {
- if (NumArgs) {
- Args = new (C) Stmt*[NumArgs];
-
- for (unsigned i = 0; i != NumArgs; ++i) {
- assert(args[i] && "NULL argument in CXXConstructExpr");
- Args[i] = args[i];
- }
+ Constructor(D), Loc(Loc), Elidable(elidable),
+ ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs)
+{
+ if (NumArgs) {
+ Args = new (C) Stmt*[NumArgs];
+
+ for (unsigned i = 0; i != NumArgs; ++i) {
+ assert(args[i] && "NULL argument in CXXConstructExpr");
+ Args[i] = args[i];
}
+ }
}
CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C,
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 0d11be2..e1a5004 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -571,7 +571,7 @@
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
if (RD->hasTrivialConstructor())
- return;
+ return;
}
// Code gen optimization to eliminate copy constructor and return
// its first argument instead.
@@ -591,6 +591,7 @@
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(Dest, BasePtr);
+
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
E->arg_begin(), E->arg_end());
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 70fc2c4..185d1a2 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -458,6 +458,11 @@
Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
}
+ if (E->requiresZeroInitialization())
+ EmitNullInitializationToLValue(LValue::MakeAddr(Val,
+ E->getType().getQualifiers()),
+ E->getType());
+
CGF.EmitCXXConstructExpr(Val, E);
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 6c3cbca..ba82d26 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -860,6 +860,7 @@
E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setElidable(Record[Idx++]);
+ E->setRequiresZeroInitialization(Record[Idx++]);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
return E->getNumArgs();
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index bf1d06f..abf4eaa 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -787,6 +787,7 @@
Writer.AddDeclRef(E->getConstructor(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isElidable());
+ Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getNumArgs());
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Writer.WriteSubStmt(E->getArg(I));
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index bca9ae9..3d03dfd 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1816,7 +1816,8 @@
OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
QualType DeclInitType,
CXXConstructorDecl *Constructor,
- MultiExprArg Exprs);
+ MultiExprArg Exprs,
+ bool RequiresZeroInit = false);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -1824,7 +1825,8 @@
QualType DeclInitType,
CXXConstructorDecl *Constructor,
bool Elidable,
- MultiExprArg Exprs);
+ MultiExprArg Exprs,
+ bool RequiresZeroInit = false);
OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
QualType writtenTy,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7eb1d9e..091c038 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3759,7 +3759,8 @@
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
- MultiExprArg ExprArgs) {
+ MultiExprArg ExprArgs,
+ bool RequiresZeroInit) {
bool Elidable = false;
// C++ [class.copy]p15:
@@ -3785,7 +3786,7 @@
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs));
+ Elidable, move(ExprArgs), RequiresZeroInit);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3793,14 +3794,15 @@
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
- MultiExprArg ExprArgs) {
+ MultiExprArg ExprArgs,
+ bool RequiresZeroInit) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
- Constructor,
- Elidable, Exprs, NumExprs));
+ Constructor, Elidable, Exprs, NumExprs,
+ RequiresZeroInit));
}
Sema::OwningExprResult
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 20008a7..629ab9a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -444,6 +444,9 @@
if (Field->isUnnamedBitfield())
continue;
+ if (hadError)
+ return;
+
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(*Field, &Entity);
if (Init >= NumInits || !ILE->getInit(Init)) {
@@ -477,7 +480,7 @@
= InitSeq.Perform(SemaRef, MemberEntity, Kind,
Sema::MultiExprArg(SemaRef, 0, 0));
if (MemberInit.isInvalid()) {
- hadError = 0;
+ hadError = true;
return;
}
@@ -529,6 +532,9 @@
for (unsigned Init = 0; Init != NumElements; ++Init) {
+ if (hadError)
+ return;
+
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
ElementEntity.setElementIndex(Init);
@@ -546,7 +552,7 @@
= InitSeq.Perform(SemaRef, ElementEntity, Kind,
Sema::MultiExprArg(SemaRef, 0, 0));
if (ElementInit.isInvalid()) {
- hadError = 0;
+ hadError = true;
return;
}
@@ -585,7 +591,7 @@
if (!hadError) {
bool RequiresSecondPass = false;
FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
- if (RequiresSecondPass)
+ if (RequiresSecondPass && !hadError)
FillInValueInitializations(Entity, FullyStructuredList,
RequiresSecondPass);
}
@@ -2619,8 +2625,16 @@
if (ClassDecl->hasUserDeclaredConstructor())
return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
- // FIXME: non-union class type w/ non-trivial default constructor gets
- // zero-initialized, then constructor gets called.
+ // -- if T is a (possibly cv-qualified) non-union class type
+ // without a user-provided constructor, then the object is
+ // zero-initialized and, if T’s implicitly-declared default
+ // constructor is non-trivial, that constructor is called.
+ if ((ClassDecl->getTagKind() == TagDecl::TK_class ||
+ ClassDecl->getTagKind() == TagDecl::TK_struct) &&
+ !ClassDecl->hasTrivialConstructor()) {
+ Sequence.AddZeroInitializationStep(Entity.getType().getType());
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+ }
}
}
@@ -3050,6 +3064,7 @@
// Walk through the computed steps for the initialization sequence,
// performing the specified conversions along the way.
+ bool ConstructorInitRequiresZeroInit = false;
for (step_iterator Step = step_begin(), StepEnd = step_end();
Step != StepEnd; ++Step) {
if (CurInit.isInvalid())
@@ -3216,7 +3231,8 @@
// Build the an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
- move_arg(ConstructorArgs));
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit);
if (CurInit.isInvalid())
return S.ExprError();
@@ -3224,14 +3240,22 @@
}
case SK_ZeroInitialization: {
- if (Kind.getKind() == InitializationKind::IK_Value &&
- S.getLangOptions().CPlusPlus &&
- !Kind.isImplicitValueInit())
+ step_iterator NextStep = Step;
+ ++NextStep;
+ if (NextStep != StepEnd &&
+ NextStep->Kind == SK_ConstructorInitialization) {
+ // The need for zero-initialization is recorded directly into
+ // the call to the object's constructor within the next step.
+ ConstructorInitRequiresZeroInit = true;
+ } else if (Kind.getKind() == InitializationKind::IK_Value &&
+ S.getLangOptions().CPlusPlus &&
+ !Kind.isImplicitValueInit()) {
CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type,
Kind.getRange().getBegin(),
Kind.getRange().getEnd()));
- else
+ } else {
CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type));
+ }
break;
}
}