]> granicus.if.org Git - clang/commitdiff
When value-initializing a class with no user-defined constructors but
authorDouglas Gregor <dgregor@apple.com>
Wed, 16 Dec 2009 18:50:27 +0000 (18:50 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 16 Dec 2009 18:50:27 +0000 (18:50 +0000)
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

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 [new file with mode: 0644]
test/SemaCXX/dcl_init_aggr.cpp

index 02c7a017c00d11dd54315520a224275089517302..4b540d9c54fa0bd8ae41402060c34c7784fdba1c 100644 (file)
@@ -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;
 
index f173d795ce9a94ba06ce530a62a8e7609d914920..9c14f741fdddd4839c998ad84bf405391529cb40 100644 (file)
@@ -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, 
index 0d11be22201cf4687a23ce4076d33392194be040..e1a5004c916691c451bfbfe3dede04542de1dfff 100644 (file)
@@ -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());
   }
index 70fc2c4ccfff0f5ead10c75754d190572504922c..185d1a2d71ec2074bb50986b9d670d44d7909c53 100644 (file)
@@ -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);
 }
 
index 6c3cbca2159b3262850b82790cc755c1c14aa842..ba82d26010268e279231bd8a267ec26409b14f65 100644 (file)
@@ -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();
index bf1d06f9ced8541b165bc6c466fa379a019f2080..abf4eaa0f8aa9e793d3a5839760e5bdd4360a82b 100644 (file)
@@ -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));
index bca9ae9e5bc959cdbe89b1444e0109b769bb666c..3d03dfd8cee8b290038da9bdb4727c79531aabab 100644 (file)
@@ -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,
index 7eb1d9ed0aa5d353be9247adcbd6cc7c0f9d151c..091c0384460e941cc9b8f158db0164408f253ce3 100644 (file)
@@ -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
index 20008a7c1cd508770fb18c604ddc2a6608ce0d8d..629ab9adb319e4bfda6a279b213e7e94c9dfb7d5 100644 (file)
@@ -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/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
new file mode 100644 (file)
index 0000000..decfc18
--- /dev/null
@@ -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)
+}
index a900411b9808753f6eeb6a1819ea9d56e382aeb3..f7dc8f11c702370a8eb98846795d0404b7e7fe0e 100644 (file)
@@ -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}}