]> granicus.if.org Git - clang/commitdiff
Reimplement code generation for copying fields in the
authorDouglas Gregor <dgregor@apple.com>
Wed, 5 May 2010 05:51:00 +0000 (05:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 5 May 2010 05:51:00 +0000 (05:51 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103079 91177308-0d34-0410-b5e6-96231b3b80d8

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 [new file with mode: 0644]

index aa649c811115a074f6dbf0f84d5c5f2c2feb50ce..20ee5ab1e01fbd4c6724ac01e9ced162a0dee263 100644 (file)
@@ -1061,10 +1061,6 @@ class CXXBaseOrMemberInitializer {
   /// 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 @@ class CXXBaseOrMemberInitializer {
   /// 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 @@ public:
                              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 @@ public:
     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); }
 };
 
index 68f4a821e689ae8341a4881c496b637a4be74336..d15cfefed0483c4feeaa24722e1ea6429900b7fe 100644 (file)
@@ -700,8 +700,8 @@ CXXBaseOrMemberInitializer::
 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 @@ CXXBaseOrMemberInitializer(ASTContext &Context,
                            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();
 }
 
index a604eef49a13dadad2539d3b9e81836e625f3960..f3f4d424789b58da2dd9a81d961c193838726e05 100644 (file)
@@ -262,102 +262,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
   
   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 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
   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 EmitBaseInitializer(CodeGenFunction &CGF,
   }
 }
 
+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 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
     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 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
 
   // 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 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
 /// 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 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
     assert(LiveTemporaries.empty() &&
            "Should not have any live temporaries at initializer start!");
     
-    EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]);
+    EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
   }
 }
 
index 90a3ec4a4b109d5f489e247b3738c804e89c5a16..74f0a488b56831843837dc37b15df24a40c6b6e8 100644 (file)
@@ -531,7 +531,8 @@ public:
   /// 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 @@ public:
   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 @@ public:
                                          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);
index b9c7d7948f2c82560854d509eb345a38db8f1770..818a2bd446265cf230694228f1f6dd893976dadb 100644 (file)
@@ -1551,41 +1551,103 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
                                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());
+      InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
     
-    InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
-                                   &CopyCtorArg, 1);
+    Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+    InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
+                                   &CopyCtorArgE, 1);
     
-    Sema::OwningExprResult MemberInit =
-      InitSeq.Perform(SemaRef, InitEntity, InitKind, 
-                      Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+    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 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
           }
         }
       }
-      continue;
+      
+      if (ImplicitInitKind == IIK_Default)        
+        continue;
     }
     if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
       AllToInit.push_back(Value);
@@ -4575,34 +4639,17 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
 
   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
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
new file mode 100644 (file)
index 0000000..a343dd1
--- /dev/null
@@ -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));
+}