[cfe-commits] r91548 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/CodeGen/CGCXX.cpp lib/CodeGen/CGExprAgg.cpp lib/Frontend/PCHReaderStmt.cpp lib/Frontend/PCHWriterStmt.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaInit.cpp test/CodeGenCXX/value-init.cpp test/SemaCXX/dcl_init_aggr.cpp
Douglas Gregor
dgregor at apple.com
Wed Dec 16 10:50:27 PST 2009
Author: dgregor
Date: Wed Dec 16 12:50:27 2009
New Revision: 91548
URL: http://llvm.org/viewvc/llvm-project?rev=91548&view=rev
Log:
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.
Added:
cfe/trunk/test/CodeGenCXX/value-init.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/CodeGen/CGCXX.cpp
cfe/trunk/lib/CodeGen/CGExprAgg.cpp
cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Dec 16 12:50:27 2009
@@ -490,8 +490,8 @@
CXXConstructorDecl *Constructor;
SourceLocation Loc;
- bool Elidable;
-
+ bool Elidable : 1;
+ bool ZeroInitialization : 1;
Stmt **Args;
unsigned NumArgs;
@@ -499,7 +499,8 @@
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
- Expr **args, unsigned numargs);
+ Expr **args, unsigned numargs,
+ bool ZeroInitialization = false);
~CXXConstructExpr() { }
virtual void DoDestroy(ASTContext &C);
@@ -512,7 +513,8 @@
static CXXConstructExpr *Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs);
+ Expr **Args, unsigned NumArgs,
+ bool ZeroInitialization = false);
CXXConstructorDecl* getConstructor() const { return Constructor; }
@@ -525,6 +527,13 @@
bool isElidable() const { return Elidable; }
void setElidable(bool E) { Elidable = E; }
+ /// \brief Whether this construction first requires
+ /// zero-initialization before the initializer is called.
+ bool requiresZeroInitialization() const { return ZeroInitialization; }
+ void setRequiresZeroInitialization(bool ZeroInit) {
+ ZeroInitialization = ZeroInit;
+ }
+
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Wed Dec 16 12:50:27 2009
@@ -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,
Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Wed Dec 16 12:50:27 2009
@@ -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());
}
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Wed Dec 16 12:50:27 2009
@@ -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);
}
Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Wed Dec 16 12:50:27 2009
@@ -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();
Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Wed Dec 16 12:50:27 2009
@@ -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));
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Dec 16 12:50:27 2009
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Dec 16 12:50:27 2009
@@ -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
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Dec 16 12:50:27 2009
@@ -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;
}
}
Added: cfe/trunk/test/CodeGenCXX/value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/value-init.cpp?rev=91548&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/value-init.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/value-init.cpp Wed Dec 16 12:50:27 2009
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct A {
+ virtual ~A();
+};
+
+struct B : A { };
+
+struct C {
+ int i;
+ B b;
+};
+
+// CHECK: _Z15test_value_initv
+void test_value_init() {
+ // This value initialization requires zero initialization of the 'B'
+ // subobject followed by a call to its constructor.
+ // PR5800
+
+ // CHECK: store i32 17
+ // CHECK: call void @llvm.memset.i64
+ // CHECK: call void @_ZN1BC1Ev(%struct.A* %tmp1)
+ C c = { 17 } ;
+ // CHECK: call void @_ZN1CD1Ev(%struct.C* %c)
+}
Propchange: cfe/trunk/test/CodeGenCXX/value-init.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CodeGenCXX/value-init.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CodeGenCXX/value-init.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp?rev=91548&r1=91547&r2=91548&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp (original)
+++ cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp Wed Dec 16 12:50:27 2009
@@ -40,17 +40,18 @@
struct TooFew { int a; char* b; int c; };
TooFew too_few = { 1, "asdf" }; // okay
-struct NoDefaultConstructor { // expected-note 3 {{candidate function}}
+struct NoDefaultConstructor { // expected-note 3 {{candidate function}} \
+ // expected-note{{declared here}}
NoDefaultConstructor(int); // expected-note 3 {{candidate function}}
};
-struct TooFewError {
+struct TooFewError { // expected-error{{implicit default constructor for}}
int a;
- NoDefaultConstructor nodef;
+ NoDefaultConstructor nodef; // expected-note{{member is declared here}}
};
TooFewError too_few_okay = { 1, 1 };
TooFewError too_few_error = { 1 }; // expected-error{{no matching constructor}}
-TooFewError too_few_okay2[2] = { 1, 1 };
+TooFewError too_few_okay2[2] = { 1, 1 }; // expected-note{{implicit default constructor for 'struct TooFewError' first required here}}
TooFewError too_few_error2[2] = { 1 }; // expected-error{{no matching constructor}}
NoDefaultConstructor too_few_error3[3] = { }; // expected-error {{no matching constructor}}
More information about the cfe-commits
mailing list