diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 02c7a017c00d11dd54315520a224275089517302..4b540d9c54fa0bd8ae41402060c34c7784fdba1c 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -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; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index f173d795ce9a94ba06ce530a62a8e7609d914920..9c14f741fdddd4839c998ad84bf405391529cb40 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -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, diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 0d11be22201cf4687a23ce4076d33392194be040..e1a5004c916691c451bfbfe3dede04542de1dfff 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -571,7 +571,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXRecordDecl *RD = cast(InitType->getAs()->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()); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 70fc2c4ccfff0f5ead10c75754d190572504922c..185d1a2d71ec2074bb50986b9d670d44d7909c53 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -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); } diff --git a/clang/lib/Frontend/PCHReaderStmt.cpp b/clang/lib/Frontend/PCHReaderStmt.cpp index 6c3cbca2159b3262850b82790cc755c1c14aa842..ba82d26010268e279231bd8a267ec26409b14f65 100644 --- a/clang/lib/Frontend/PCHReaderStmt.cpp +++ b/clang/lib/Frontend/PCHReaderStmt.cpp @@ -860,6 +860,7 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { E->setConstructor(cast(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(StmtStack[StmtStack.size() - N + I])); return E->getNumArgs(); diff --git a/clang/lib/Frontend/PCHWriterStmt.cpp b/clang/lib/Frontend/PCHWriterStmt.cpp index bf1d06f9ced8541b165bc6c466fa379a019f2080..abf4eaa0f8aa9e793d3a5839760e5bdd4360a82b 100644 --- a/clang/lib/Frontend/PCHWriterStmt.cpp +++ b/clang/lib/Frontend/PCHWriterStmt.cpp @@ -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)); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index bca9ae9e5bc959cdbe89b1444e0109b769bb666c..3d03dfd8cee8b290038da9bdb4727c79531aabab 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7eb1d9ed0aa5d353be9247adcbd6cc7c0f9d151c..091c0384460e941cc9b8f158db0164408f253ce3 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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 diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 20008a7c1cd508770fb18c604ddc2a6608ce0d8d..629ab9adb319e4bfda6a279b213e7e94c9dfb7d5 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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; } } diff --git a/clang/test/CodeGenCXX/value-init.cpp b/clang/test/CodeGenCXX/value-init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..decfc18e59452bd563ee7a5745b520ba6380be44 --- /dev/null +++ b/clang/test/CodeGenCXX/value-init.cpp @@ -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) +} diff --git a/clang/test/SemaCXX/dcl_init_aggr.cpp b/clang/test/SemaCXX/dcl_init_aggr.cpp index a900411b9808753f6eeb6a1819ea9d56e382aeb3..f7dc8f11c702370a8eb98846795d0404b7e7fe0e 100644 --- a/clang/test/SemaCXX/dcl_init_aggr.cpp +++ b/clang/test/SemaCXX/dcl_init_aggr.cpp @@ -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}}