[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