diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 38 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 360 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 13 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 145 |
4 files changed, 278 insertions, 278 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 68f4a821e6..d15cfefed0 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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(); } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index a604eef49a..f3f4d42478 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -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); } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 90a3ec4a4b..74f0a488b5 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b9c7d7948f..818a2bd446 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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 |