[cfe-commits] r103079 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CodeGenFunction.h lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/implicit-copy-constructor.cpp

Douglas Gregor dgregor at apple.com
Tue May 4 22:51:00 PDT 2010


Author: dgregor
Date: Wed May  5 00:51:00 2010
New Revision: 103079

URL: http://llvm.org/viewvc/llvm-project?rev=103079&view=rev
Log:
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.

The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.

However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:

  struct A { A(const A&); };
  
  struct B {
    A array[2][3];
  };

then we generate an implicit copy assignment operator for B that looks
something like this:

  B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }

CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.

Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.

Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.


Added:
    cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=103079&r1=103078&r2=103079&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed May  5 00:51:00 2010
@@ -1061,10 +1061,6 @@
   /// In above example, BaseOrMember holds the field decl. for anonymous union
   /// and AnonUnionMember holds field decl for au_i1.
   FieldDecl *AnonUnionMember;
-
-  /// IsVirtual - If the initializer is a base initializer, this keeps track
-  /// of whether the base is virtual or not.
-  bool IsVirtual;
   
   /// LParenLoc - Location of the left paren of the ctor-initializer.
   SourceLocation LParenLoc;
@@ -1072,6 +1068,22 @@
   /// RParenLoc - Location of the right paren of the ctor-initializer.
   SourceLocation RParenLoc;
 
+  /// \brief The number of array index variables stored after this object
+  /// in memory.
+  unsigned NumArrayIndices;
+  
+  /// IsVirtual - If the initializer is a base initializer, this keeps track
+  /// of whether the base is virtual or not.
+  bool IsVirtual;
+  
+  CXXBaseOrMemberInitializer(ASTContext &Context,
+                             FieldDecl *Member, SourceLocation MemberLoc,
+                             SourceLocation L,
+                             Expr *Init,
+                             SourceLocation R,
+                             VarDecl **Indices,
+                             unsigned NumIndices);
+  
 public:
   /// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
   explicit
@@ -1089,6 +1101,17 @@
                              Expr *Init,
                              SourceLocation R);
 
+  /// \brief Creates a new member initializer that optionally contains 
+  /// array indices used to describe an elementwise initialization.
+  static CXXBaseOrMemberInitializer *Create(ASTContext &Context,
+                                            FieldDecl *Member, 
+                                            SourceLocation MemberLoc,
+                                            SourceLocation L,
+                                            Expr *Init,
+                                            SourceLocation R,
+                                            VarDecl **Indices,
+                                            unsigned NumIndices);
+  
   /// \brief Destroy the base or member initializer.
   void Destroy(ASTContext &Context);
 
@@ -1154,9 +1177,29 @@
     AnonUnionMember = anonMember;
   }
 
+  
   SourceLocation getLParenLoc() const { return LParenLoc; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
 
+  /// \brief Determine the number of implicit array indices used while
+  /// described an array member initialization.
+  unsigned getNumArrayIndices() const { return NumArrayIndices; }
+
+  /// \brief Retrieve a particular array index variable used to 
+  /// describe an array member initialization.
+  VarDecl *getArrayIndex(unsigned I) {
+    assert(I < NumArrayIndices && "Out of bounds member array index");
+    return reinterpret_cast<VarDecl **>(this + 1)[I];
+  }
+  const VarDecl *getArrayIndex(unsigned I) const {
+    assert(I < NumArrayIndices && "Out of bounds member array index");
+    return reinterpret_cast<const VarDecl * const *>(this + 1)[I];
+  }
+  void setArrayIndex(unsigned I, VarDecl *Index) {
+    assert(I < NumArrayIndices && "Out of bounds member array index");
+    reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
+  }
+  
   Expr *getInit() { return static_cast<Expr *>(Init); }
 };
 

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=103079&r1=103078&r2=103079&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed May  5 00:51:00 2010
@@ -700,8 +700,8 @@
 CXXBaseOrMemberInitializer(ASTContext &Context,
                            TypeSourceInfo *TInfo, bool IsVirtual,
                            SourceLocation L, Expr *Init, SourceLocation R)
-  : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual),
-    LParenLoc(L), RParenLoc(R) 
+  : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), 
+    LParenLoc(L), RParenLoc(R), NumArrayIndices(0), IsVirtual(IsVirtual)
 {
 }
 
@@ -710,13 +710,45 @@
                            FieldDecl *Member, SourceLocation MemberLoc,
                            SourceLocation L, Expr *Init, SourceLocation R)
   : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), 
-    AnonUnionMember(0), LParenLoc(L), RParenLoc(R) 
+    AnonUnionMember(0), LParenLoc(L), RParenLoc(R) , NumArrayIndices(0),
+    IsVirtual(false)
 {
 }
 
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(ASTContext &Context,
+                           FieldDecl *Member, SourceLocation MemberLoc,
+                           SourceLocation L, Expr *Init, SourceLocation R,
+                           VarDecl **Indices,
+                           unsigned NumIndices)
+  : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), 
+    AnonUnionMember(0), LParenLoc(L), RParenLoc(R) , 
+    NumArrayIndices(NumIndices), IsVirtual(false)
+{
+  VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
+  memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
+}
+
+CXXBaseOrMemberInitializer *
+CXXBaseOrMemberInitializer::Create(ASTContext &Context,
+                                   FieldDecl *Member, 
+                                   SourceLocation MemberLoc,
+                                   SourceLocation L,
+                                   Expr *Init,
+                                   SourceLocation R,
+                                   VarDecl **Indices,
+                                   unsigned NumIndices) {
+  void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) +
+                               sizeof(VarDecl *) * NumIndices,
+                               llvm::alignof<CXXBaseOrMemberInitializer>());
+  return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc,
+                                              L, Init, R, Indices, NumIndices);
+}
+
 void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
   if (Init)
     Init->Destroy(Context);
+  // FIXME: Destroy indices
   this->~CXXBaseOrMemberInitializer();
 }
 

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=103079&r1=103078&r2=103079&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed May  5 00:51:00 2010
@@ -262,102 +262,7 @@
   
   return Value;
 }
-
-/// EmitCopyCtorCall - Emit a call to a copy constructor.
-static void
-EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor,
-                 llvm::Value *ThisPtr, llvm::Value *Src) {
-  llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete);
-
-  CallArgList CallArgs;
-
-  // Push the this ptr.
-  CallArgs.push_back(std::make_pair(RValue::get(ThisPtr),
-                                    CopyCtor->getThisType(CGF.getContext())));
-   
-  // Push the Src ptr.
-  CallArgs.push_back(std::make_pair(RValue::get(Src),
-                                    CopyCtor->getParamDecl(0)->getType()));
-
-
-  {
-    CodeGenFunction::CXXTemporariesCleanupScope Scope(CGF);
-
-    // If the copy constructor has default arguments, emit them.
-    for (unsigned I = 1, E = CopyCtor->getNumParams(); I < E; ++I) {
-      const ParmVarDecl *Param = CopyCtor->getParamDecl(I);
-      const Expr *DefaultArgExpr = Param->getDefaultArg();
-
-      assert(DefaultArgExpr && "Ctor parameter must have default arg!");
-
-      QualType ArgType = Param->getType();
-      CallArgs.push_back(std::make_pair(CGF.EmitCallArg(DefaultArgExpr, 
-                                                        ArgType),
-                                        ArgType));
-    }
-
-    const FunctionProtoType *FPT =
-      CopyCtor->getType()->getAs<FunctionProtoType>();
-    CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
-                 Callee, ReturnValueSlot(), CallArgs, CopyCtor);
-  }
-}
                              
-/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
-/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
-/// copy or via a copy constructor call.
-//  FIXME. Consolidate this with EmitCXXAggrConstructorCall.
-void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
-                                            llvm::Value *Src,
-                                            const ConstantArrayType *Array,
-                                            const CXXRecordDecl *ClassDecl) {
-  // Create a temporary for the loop index and initialize it with 0.
-  llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
-                                           "loop.index");
-  llvm::Value* zeroConstant =
-    llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
-  Builder.CreateStore(zeroConstant, IndexPtr);
-  // Start the loop with a block that tests the condition.
-  llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
-  llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
-  EmitBlock(CondBlock);
-
-  llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-  // Generate: if (loop-index < number-of-elements fall to the loop body,
-  // otherwise, go to the block after the for-loop.
-  uint64_t NumElements = getContext().getConstantArrayElementCount(Array);
-  llvm::Value * NumElementsPtr =
-    llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
-  llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
-  llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
-                                              "isless");
-  // If the condition is true, execute the body.
-  Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
-  EmitBlock(ForBody);
-  llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
-  // Inside the loop body, emit the constructor call on the array element.
-  Counter = Builder.CreateLoad(IndexPtr);
-  Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
-  Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
-  EmitClassMemberwiseCopy(Dest, Src, ClassDecl);
-  
-  EmitBlock(ContinueBlock);
-
-  // Emit the increment of the loop counter.
-  llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
-  Counter = Builder.CreateLoad(IndexPtr);
-  NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
-  Builder.CreateStore(NextVal, IndexPtr);
-
-  // Finally, branch back up to the condition for the next iteration.
-  EmitBranch(CondBlock);
-
-  // Emit the fall-through block.
-  EmitBlock(AfterFor, true);
-}
-
 /// GetVTTParameter - Return the VTT parameter that should be passed to a
 /// base constructor/destructor with virtual bases.
 static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
@@ -405,111 +310,6 @@
   return VTT;
 }
 
-                                    
-/// EmitClassMemberwiseCopy - This routine generates code to copy a class
-/// object from SrcValue to DestValue. Copying can be either a bitwise copy
-/// or via a copy constructor call.
-void CodeGenFunction::EmitClassMemberwiseCopy(
-                        llvm::Value *Dest, llvm::Value *Src,
-                        const CXXRecordDecl *ClassDecl) {
-  if (ClassDecl->hasTrivialCopyConstructor()) {
-    EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl));
-    return;
-  }
-
-  CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0);
-  assert(CopyCtor && "Did not have copy ctor!");
-
-  EmitCopyCtorCall(*this, CopyCtor, Dest, Src);
-}
-
-/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
-/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03
-/// The implicitly-defined copy constructor for class X performs a memberwise
-/// copy of its subobjects. The order of copying is the same as the order of
-/// initialization of bases and members in a user-defined constructor
-/// Each subobject is copied in the manner appropriate to its type:
-///  if the subobject is of class type, the copy constructor for the class is
-///  used;
-///  if the subobject is an array, each element is copied, in the manner
-///  appropriate to the element type;
-///  if the subobject is of scalar type, the built-in assignment operator is
-///  used.
-/// Virtual base class subobjects shall be copied only once by the
-/// implicitly-defined copy constructor
-
-void 
-CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
-  const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
-  CXXCtorType CtorType = CurGD.getCtorType();
-  (void) CtorType;
-
-  const CXXRecordDecl *ClassDecl = Ctor->getParent();
-  assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
-      "SynthesizeCXXCopyConstructor - copy constructor has definition already");
-  assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
-
-  llvm::Value *ThisPtr = LoadCXXThis();
-
-  // Find the source pointer.
-  unsigned SrcArgIndex = Args.size() - 1;
-  assert(CtorType == Ctor_Base || SrcArgIndex == 1);
-  assert(CtorType != Ctor_Base ||
-         (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) ||
-         SrcArgIndex == 1);
-
-  llvm::Value *SrcPtr =
-    Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first));
-
-  for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
-       E = ClassDecl->field_end(); I != E; ++I) {
-    const FieldDecl *Field = *I;
-    
-    QualType FieldType = getContext().getCanonicalType(Field->getType());
-    const ConstantArrayType *Array =
-      getContext().getAsConstantArrayType(FieldType);
-    if (Array)
-      FieldType = getContext().getBaseElementType(FieldType);
-
-    if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
-      CXXRecordDecl *FieldClassDecl
-        = cast<CXXRecordDecl>(FieldClassType->getDecl());
-      LValue LHS = EmitLValueForField(ThisPtr, Field, 0);
-      LValue RHS = EmitLValueForField(SrcPtr, Field, 0);
-      if (Array) {
-        const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo();
-        llvm::Value *DestBaseAddrPtr =
-          Builder.CreateBitCast(LHS.getAddress(), BasePtr);
-        llvm::Value *SrcBaseAddrPtr =
-          Builder.CreateBitCast(RHS.getAddress(), BasePtr);
-        EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
-                                    FieldClassDecl);
-      }
-      else
-        EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
-                                FieldClassDecl);
-      continue;
-    }
-    
-    // Do a built-in assignment of scalar data members.
-    LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0);
-    LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0);
-
-    if (!hasAggregateLLVMType(Field->getType())) {
-      RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
-      EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
-    } else if (Field->getType()->isAnyComplexType()) {
-      ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
-                                               RHS.isVolatileQualified());
-      StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
-    } else {
-      EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
-    }
-  }
-
-  InitializeVTablePointers(ClassDecl);
-}
-
 static void EmitBaseInitializer(CodeGenFunction &CGF, 
                                 const CXXRecordDecl *ClassDecl,
                                 CXXBaseOrMemberInitializer *BaseInit,
@@ -547,9 +347,98 @@
   }
 }
 
+static void EmitAggMemberInitializer(CodeGenFunction &CGF,
+                                     LValue LHS,
+                                     llvm::Value *ArrayIndexVar,
+                                     CXXBaseOrMemberInitializer *MemberInit,
+                                     QualType T,
+                                     unsigned Index) {
+  if (Index == MemberInit->getNumArrayIndices()) {
+    CodeGenFunction::CleanupScope Cleanups(CGF);
+    
+    llvm::Value *Dest = LHS.getAddress();
+    if (ArrayIndexVar) {
+      // If we have an array index variable, load it and use it as an offset.
+      // Then, increment the value.
+      llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
+      Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
+      llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
+      Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
+      CGF.Builder.CreateStore(Next, ArrayIndexVar);      
+    }
+    
+    CGF.EmitAggExpr(MemberInit->getInit(), Dest, 
+                    LHS.isVolatileQualified(),
+                    /*IgnoreResult*/ false,
+                    /*IsInitializer*/ true);
+    
+    return;
+  }
+  
+  const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
+  assert(Array && "Array initialization without the array type?");
+  llvm::Value *IndexVar
+    = CGF.GetAddrOfLocalVar(MemberInit->getArrayIndex(Index));
+  assert(IndexVar && "Array index variable not loaded");
+  
+  // Initialize this index variable to zero.
+  llvm::Value* Zero
+    = llvm::Constant::getNullValue(
+                              CGF.ConvertType(CGF.getContext().getSizeType()));
+  CGF.Builder.CreateStore(Zero, IndexVar);
+                                   
+  // Start the loop with a block that tests the condition.
+  llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
+  llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
+  
+  CGF.EmitBlock(CondBlock);
+
+  llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
+  // Generate: if (loop-index < number-of-elements) fall to the loop body,
+  // otherwise, go to the block after the for-loop.
+  uint64_t NumElements = Array->getSize().getZExtValue();
+  llvm::Value * NumElementsPtr =
+    llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGF.getLLVMContext()),
+                                                  NumElements);
+  llvm::Value *Counter = CGF.Builder.CreateLoad(IndexVar);
+  llvm::Value *IsLess = CGF.Builder.CreateICmpULT(Counter, NumElementsPtr,
+                                                  "isless");
+                                   
+  // If the condition is true, execute the body.
+  CGF.Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+  CGF.EmitBlock(ForBody);
+  llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
+  
+  {
+    CodeGenFunction::CleanupScope Cleanups(CGF);
+    
+    // Inside the loop body recurse to emit the inner loop or, eventually, the
+    // constructor call.
+    EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, 
+                             Array->getElementType(), Index + 1);
+  }
+  
+  CGF.EmitBlock(ContinueBlock);
+
+  // Emit the increment of the loop counter.
+  llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+  Counter = CGF.Builder.CreateLoad(IndexVar);
+  NextVal = CGF.Builder.CreateAdd(Counter, NextVal, "inc");
+  CGF.Builder.CreateStore(NextVal, IndexVar);
+
+  // Finally, branch back up to the condition for the next iteration.
+  CGF.EmitBranch(CondBlock);
+
+  // Emit the fall-through block.
+  CGF.EmitBlock(AfterFor, true);
+}
+  
 static void EmitMemberInitializer(CodeGenFunction &CGF,
                                   const CXXRecordDecl *ClassDecl,
-                                  CXXBaseOrMemberInitializer *MemberInit) {
+                                  CXXBaseOrMemberInitializer *MemberInit,
+                                  const CXXConstructorDecl *Constructor,
+                                  FunctionArgList &Args) {
   assert(MemberInit->isMemberInitializer() &&
          "Must have member initializer!");
   
@@ -583,14 +472,61 @@
     CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
                                 LHS.isVolatileQualified());
   } else {
-    CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), 
-                    LHS.isVolatileQualified(),
-                    /*IgnoreResult*/ false,
-                    /*IsInitializer*/ true);
+    llvm::Value *ArrayIndexVar = 0;
+    const ConstantArrayType *Array
+      = CGF.getContext().getAsConstantArrayType(FieldType);
+    if (Array && Constructor->isImplicit() && 
+        Constructor->isCopyConstructor()) {
+      const llvm::Type *SizeTy
+        = CGF.ConvertType(CGF.getContext().getSizeType());
+      
+      // The LHS is a pointer to the first object we'll be constructing, as
+      // a flat array.
+      QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
+      const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
+      BasePtr = llvm::PointerType::getUnqual(BasePtr);
+      llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), 
+                                                           BasePtr);
+      LHS = LValue::MakeAddr(BaseAddrPtr, CGF.MakeQualifiers(BaseElementTy));
+      
+      // Create an array index that will be used to walk over all of the
+      // objects we're constructing.
+      ArrayIndexVar = CGF.CreateTempAlloca(SizeTy, "object.index");
+      llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
+      CGF.Builder.CreateStore(Zero, ArrayIndexVar);
+      
+      // If we are copying an array of scalars or classes with trivial copy 
+      // constructors, perform a single aggregate copy.
+      const RecordType *Record = BaseElementTy->getAs<RecordType>();
+      if (!Record || 
+          cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) {
+        // Find the source pointer. We knows it's the last argument because
+        // we know we're in a copy constructor.
+        unsigned SrcArgIndex = Args.size() - 1;
+        llvm::Value *SrcPtr
+          = CGF.Builder.CreateLoad(
+                               CGF.GetAddrOfLocalVar(Args[SrcArgIndex].first));
+        LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
+        
+        // Copy the aggregate.
+        CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
+                              LHS.isVolatileQualified());
+        return;
+      }
+      
+      // Emit the block variables for the array indices, if any.
+      for (unsigned I = 0, N = MemberInit->getNumArrayIndices(); I != N; ++I)
+        CGF.EmitLocalBlockVarDecl(*MemberInit->getArrayIndex(I));
+    }
+    
+    EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0);
     
     if (!CGF.Exceptions)
       return;
 
+    // FIXME: If we have an array of classes w/ non-trivial destructors, 
+    // we need to destroy in reverse order of construction along the exception
+    // path.
     const RecordType *RT = FieldType->getAs<RecordType>();
     if (!RT)
       return;
@@ -680,20 +616,13 @@
 
   // Emit the constructor prologue, i.e. the base and member
   // initializers.
-  EmitCtorPrologue(Ctor, CtorType);
+  EmitCtorPrologue(Ctor, CtorType, Args);
 
   // Emit the body of the statement.
   if (IsTryBody)
     EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
   else if (Body)
     EmitStmt(Body);
-  else {
-    assert(Ctor->isImplicit() && "bodyless ctor not implicit");
-    if (!Ctor->isDefaultConstructor()) {
-      assert(Ctor->isCopyConstructor());
-      SynthesizeCXXCopyConstructor(Args);
-    }
-  }
 
   // Emit any cleanup blocks associated with the member or base
   // initializers, which includes (along the exceptional path) the
@@ -708,7 +637,8 @@
 /// EmitCtorPrologue - This routine generates necessary code to initialize
 /// base classes and non-static data members belonging to this constructor.
 void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
-                                       CXXCtorType CtorType) {
+                                       CXXCtorType CtorType,
+                                       FunctionArgList &Args) {
   const CXXRecordDecl *ClassDecl = CD->getParent();
 
   llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
@@ -733,7 +663,7 @@
     assert(LiveTemporaries.empty() &&
            "Should not have any live temporaries at initializer start!");
     
-    EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]);
+    EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
   }
 }
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=103079&r1=103078&r2=103079&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed May  5 00:51:00 2010
@@ -531,7 +531,8 @@
   /// GenerateThunk - Generate a thunk for the given method.
   void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk);
   
-  void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
+  void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
+                        FunctionArgList &Args);
 
   /// InitializeVTablePointer - Initialize the vtable pointer of the given
   /// subobject.
@@ -554,8 +555,6 @@
   void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
 
 
-  void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
-
   /// EmitDtorEpilogue - Emit all code that comes at the end of class's
   /// destructor. This is to call destructors on members and base classes in
   /// reverse order of their construction.
@@ -802,14 +801,6 @@
                                          const CXXRecordDecl *ClassDecl,
                                          const CXXRecordDecl *BaseClassDecl);
     
-  void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
-                                   llvm::Value *SrcValue,
-                                   const ConstantArrayType *Array,
-                                   const CXXRecordDecl *ClassDecl);
-
-  void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue,
-                               const CXXRecordDecl *ClassDecl);
-
   void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
                                       CXXCtorType CtorType,
                                       const FunctionArgList &Args);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=103079&r1=103078&r2=103079&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed May  5 00:51:00 2010
@@ -1551,41 +1551,103 @@
                                FieldDecl *Field,
                                CXXBaseOrMemberInitializer *&CXXMemberInit) {
   if (ImplicitInitKind == IIK_Copy) {
-    // FIXME: We should not return early here, but will do so until 
-    // we know how to handle copy initialization of arrays.
-    CXXMemberInit = 0;
-    return false;
-    
+    SourceLocation Loc = Constructor->getLocation();
     ParmVarDecl *Param = Constructor->getParamDecl(0);
     QualType ParamType = Param->getType().getNonReferenceType();
     
     Expr *MemberExprBase = 
       DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, 
-                          SourceLocation(), ParamType, 0);
+                          Loc, ParamType, 0);
+
+    // Build a reference to this field within the parameter.
+    CXXScopeSpec SS;
+    LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc,
+                              Sema::LookupMemberName);
+    MemberLookup.addDecl(Field, AS_public);
+    MemberLookup.resolveKind();
+    Sema::OwningExprResult CopyCtorArg 
+      = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase),
+                                         ParamType, Loc,
+                                         /*IsArrow=*/false,
+                                         SS,
+                                         /*FirstQualifierInScope=*/0,
+                                         MemberLookup,
+                                         /*TemplateArgs=*/0);    
+    if (CopyCtorArg.isInvalid())
+      return true;
     
+    // When the field we are copying is an array, create index variables for 
+    // each dimension of the array. We use these index variables to subscript
+    // the source array, and other clients (e.g., CodeGen) will perform the
+    // necessary iteration with these index variables.
+    llvm::SmallVector<VarDecl *, 4> IndexVariables;
+    QualType BaseType = Field->getType();
+    QualType SizeType = SemaRef.Context.getSizeType();
+    while (const ConstantArrayType *Array
+                          = SemaRef.Context.getAsConstantArrayType(BaseType)) {
+      // Create the iteration variable for this array index.
+      IdentifierInfo *IterationVarName = 0;
+      {
+        llvm::SmallString<8> Str;
+        llvm::raw_svector_ostream OS(Str);
+        OS << "__i" << IndexVariables.size();
+        IterationVarName = &SemaRef.Context.Idents.get(OS.str());
+      }
+      VarDecl *IterationVar
+        = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc,
+                          IterationVarName, SizeType,
+                        SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+                          VarDecl::None, VarDecl::None);
+      IndexVariables.push_back(IterationVar);
+      
+      // Create a reference to the iteration variable.
+      Sema::OwningExprResult IterationVarRef
+        = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc);
+      assert(!IterationVarRef.isInvalid() &&
+             "Reference to invented variable cannot fail!");
+      
+      // Subscript the array with this iteration variable.
+      CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg),
+                                                            Loc,
+                                                          move(IterationVarRef),
+                                                            Loc);
+      if (CopyCtorArg.isInvalid())
+        return true;
+      
+      BaseType = Array->getElementType();
+    }
     
-    Expr *CopyCtorArg = 
-      MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, 
-                         0, SourceRange(), Field, 
-                         DeclAccessPair::make(Field, Field->getAccess()),
-                         SourceLocation(), 0, 
-                         Field->getType().getNonReferenceType());
+    // Construct the entity that we will be initializing. For an array, this
+    // will be first element in the array, which may require several levels
+    // of array-subscript entities. 
+    llvm::SmallVector<InitializedEntity, 4> Entities;
+    Entities.reserve(1 + IndexVariables.size());
+    Entities.push_back(InitializedEntity::InitializeMember(Field));
+    for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+      Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context,
+                                                              0,
+                                                              Entities.back()));
     
-    InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+    // Direct-initialize to use the copy constructor.
     InitializationKind InitKind =
-      InitializationKind::CreateDirect(Constructor->getLocation(), 
-                                       SourceLocation(), SourceLocation());
-    
-    InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
-                                   &CopyCtorArg, 1);
+      InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
     
-    Sema::OwningExprResult MemberInit =
-      InitSeq.Perform(SemaRef, InitEntity, InitKind, 
-                      Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+    Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+    InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
+                                   &CopyCtorArgE, 1);
+    
+    Sema::OwningExprResult MemberInit
+      = InitSeq.Perform(SemaRef, Entities.back(), InitKind, 
+                        Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1));
+    MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
     if (MemberInit.isInvalid())
       return true;
-    
-    CXXMemberInit = 0;
+
+    CXXMemberInit
+      = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc,
+                                           MemberInit.takeAs<Expr>(), Loc,
+                                           IndexVariables.data(),
+                                           IndexVariables.size());
     return false;
   }
 
@@ -1758,7 +1820,9 @@
           }
         }
       }
-      continue;
+      
+      if (ImplicitInitKind == IIK_Default)        
+        continue;
     }
     if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
       AllToInit.push_back(Value);
@@ -4575,34 +4639,17 @@
 
   if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
     Diag(CurrentLocation, diag::note_member_synthesized_at) 
-    << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+      << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
     CopyConstructor->setInvalidDecl();
-  } else {
-    CopyConstructor->setUsed();
-  }
-
-  // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
-  // fields, this code below should be removed.
-  for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
-                                  FieldEnd = ClassDecl->field_end();
-       Field != FieldEnd; ++Field) {
-    QualType FieldType = Context.getCanonicalType((*Field)->getType());
-    if (const ArrayType *Array = Context.getAsArrayType(FieldType))
-      FieldType = Array->getElementType();
-    if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
-      CXXRecordDecl *FieldClassDecl
-        = cast<CXXRecordDecl>(FieldClassType->getDecl());
-      if (CXXConstructorDecl *FieldCopyCtor =
-          FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
-        CheckDirectMemberAccess(Field->getLocation(),
-                                FieldCopyCtor,
-                                PDiag(diag::err_access_copy_field)
-                                  << Field->getDeclName() << Field->getType());
-
-        MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
-      }
-    }
+  }  else {
+    CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
+                                               CopyConstructor->getLocation(),
+                                               MultiStmtArg(*this, 0, 0), 
+                                               /*isStmtExpr=*/false)
+                                                              .takeAs<Stmt>());
   }
+  
+  CopyConstructor->setUsed();
 }
 
 Sema::OwningExprResult

Added: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp?rev=103079&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp Wed May  5 00:51:00 2010
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+struct A { 
+  A();
+  A(const A&);
+  A(A&);
+  ~A();
+};
+
+struct B {
+  B();
+  B(B&);
+};
+
+struct C {
+  C() {}
+  C(C& other, A a = A());
+  int i, j;
+};
+
+struct POD {
+  int array[3][4];
+};
+
+struct D : A, B, virtual C { 
+  D();
+  int scalar;
+  int scalar_array[2][3];
+  B class_member;
+  C class_member_array[2][3];
+  POD pod_array[2][3];
+
+  union {
+    int x;
+    float f[3];
+  };
+};
+
+void f(D d) {
+  D d2(d);
+}
+
+// CHECK: define linkonce_odr void @_ZN1DC1ERS_
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC2ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: call void @_ZN1AC2ERS_
+// CHECK: call void @_ZN1BC2ERS_
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: call void @_ZN1BC1ERS_
+// CHECK: br
+// CHECK: {{icmp ult.*, 2}}
+// CHECK: {{icmp ult.*, 3}}
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC1ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: ret void
+
+
+template<class T> struct X0 { void f0(T * ) { } };
+template <class > struct X1 { X1( X1& , int = 0 ) { } };
+struct X2 { X1<int> result; };
+void test_X2()
+{
+  typedef X2 impl;
+  typedef X0<impl> pimpl;
+  impl* i;
+  pimpl pdata;
+  pdata.f0( new impl(*i));
+}

Propchange: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list