forked from OSchip/llvm-project
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. llvm-svn: 91548
This commit is contained in:
parent
22a8a4bfb9
commit
4f4b186215
|
@ -490,8 +490,8 @@ class CXXConstructExpr : public Expr {
|
|||
CXXConstructorDecl *Constructor;
|
||||
|
||||
SourceLocation Loc;
|
||||
bool Elidable;
|
||||
|
||||
bool Elidable : 1;
|
||||
bool ZeroInitialization : 1;
|
||||
Stmt **Args;
|
||||
unsigned NumArgs;
|
||||
|
||||
|
@ -499,7 +499,8 @@ protected:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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;
|
||||
|
||||
|
|
|
@ -380,28 +380,32 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
|
|||
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,
|
||||
|
|
|
@ -571,7 +571,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
|
|||
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 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
|
|||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(Dest, BasePtr);
|
||||
|
||||
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
|
||||
E->arg_begin(), E->arg_end());
|
||||
}
|
||||
|
|
|
@ -458,6 +458,11 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
|||
Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
|
||||
}
|
||||
|
||||
if (E->requiresZeroInitialization())
|
||||
EmitNullInitializationToLValue(LValue::MakeAddr(Val,
|
||||
E->getType().getQualifiers()),
|
||||
E->getType());
|
||||
|
||||
CGF.EmitCXXConstructExpr(Val, E);
|
||||
}
|
||||
|
||||
|
|
|
@ -860,6 +860,7 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
|
|||
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();
|
||||
|
|
|
@ -787,6 +787,7 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
|
|||
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));
|
||||
|
|
|
@ -1816,7 +1816,8 @@ public:
|
|||
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 @@ public:
|
|||
QualType DeclInitType,
|
||||
CXXConstructorDecl *Constructor,
|
||||
bool Elidable,
|
||||
MultiExprArg Exprs);
|
||||
MultiExprArg Exprs,
|
||||
bool RequiresZeroInit = false);
|
||||
|
||||
OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
|
||||
QualType writtenTy,
|
||||
|
|
|
@ -3759,7 +3759,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
|||
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 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
|
|||
}
|
||||
|
||||
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::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
|
|||
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
|
||||
|
|
|
@ -444,6 +444,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
if (Field->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
if (hadError)
|
||||
return;
|
||||
|
||||
InitializedEntity MemberEntity
|
||||
= InitializedEntity::InitializeMember(*Field, &Entity);
|
||||
if (Init >= NumInits || !ILE->getInit(Init)) {
|
||||
|
@ -477,7 +480,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
= InitSeq.Perform(SemaRef, MemberEntity, Kind,
|
||||
Sema::MultiExprArg(SemaRef, 0, 0));
|
||||
if (MemberInit.isInvalid()) {
|
||||
hadError = 0;
|
||||
hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -529,6 +532,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
|
||||
|
||||
for (unsigned Init = 0; Init != NumElements; ++Init) {
|
||||
if (hadError)
|
||||
return;
|
||||
|
||||
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
|
||||
ElementEntity.setElementIndex(Init);
|
||||
|
||||
|
@ -546,7 +552,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
= InitSeq.Perform(SemaRef, ElementEntity, Kind,
|
||||
Sema::MultiExprArg(SemaRef, 0, 0));
|
||||
if (ElementInit.isInvalid()) {
|
||||
hadError = 0;
|
||||
hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -585,7 +591,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
|
|||
if (!hadError) {
|
||||
bool RequiresSecondPass = false;
|
||||
FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
|
||||
if (RequiresSecondPass)
|
||||
if (RequiresSecondPass && !hadError)
|
||||
FillInValueInitializations(Entity, FullyStructuredList,
|
||||
RequiresSecondPass);
|
||||
}
|
||||
|
@ -2619,8 +2625,16 @@ static void TryValueInitialization(Sema &S,
|
|||
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 @@ InitializationSequence::Perform(Sema &S,
|
|||
|
||||
// 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 @@ InitializationSequence::Perform(Sema &S,
|
|||
|
||||
// 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 @@ InitializationSequence::Perform(Sema &S,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -40,17 +40,18 @@ char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-error{{excess elements in ar
|
|||
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}}
|
||||
|
|
Loading…
Reference in New Issue