From bbd5e8c2cfc19b796fd407727d403bd3098791f7 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 12 Aug 2009 23:34:46 +0000 Subject: [PATCH] More toward synthesizing copy assignments. SWIP. llvm-svn: 78861 --- clang/include/clang/AST/DeclCXX.h | 4 +- clang/lib/AST/DeclCXX.cpp | 5 +- clang/lib/CodeGen/CGCXX.cpp | 100 ++++++++++++++++++++++++++-- clang/lib/CodeGen/CodeGenFunction.h | 5 ++ clang/lib/Sema/SemaDeclCXX.cpp | 7 +- 5 files changed, 112 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index ff498ba4a404..2d0edc8418f4 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -493,7 +493,9 @@ public: /// hasConstCopyAssignment - Determines whether this class has a /// copy assignment operator that accepts a const-qualified argument. - bool hasConstCopyAssignment(ASTContext &Context) const; + /// It returns its decl in MD if found. + bool hasConstCopyAssignment(ASTContext &Context, + const CXXMethodDecl *&MD) const; /// addedConstructor - Notify the class that another constructor has /// been added. This routine helps maintain information about the diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index e9ae7e77f04d..6c4034f78723 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -168,7 +168,8 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, return 0; } -bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { +bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, + const CXXMethodDecl *& MD) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -200,7 +201,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { } if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) continue; - + MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 5edc1e049c8a..b378bf83e66f 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -822,6 +822,46 @@ void CodeGenFunction::EmitClassMemberwiseCopy( } } +/// EmitClassCopyAssignment - This routine generates code to copy assign a class +/// object from SrcValue to DestValue. Assignment can be either a bitwise +/// assignment of via an assignment operator call. +void CodeGenFunction::EmitClassCopyAssignment( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + if (ClassDecl) { + Dest = AddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl); + Src = AddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl) ; + } + if (BaseClassDecl->hasTrivialCopyAssignment()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + const CXXMethodDecl *MD = 0; + if (BaseClassDecl->hasConstCopyAssignment(getContext(), MD)) { + const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = + MD->getType()->getAsFunctionType()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); + } +} + /// SynthesizeDefaultConstructor - synthesize a default constructor void CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *CD, @@ -916,19 +956,71 @@ void CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *CD, /// the base-specifier-list, and then the immediate nonstatic data members of X /// are assigned, in the order in which they were declared in the class /// definition.Each subobject is assigned in the manner appropriate to its type: -/// — if the subobject is of class type, the copy assignment operator for the -/// class is used (as if by explicit qual- ification; that is, ignoring any +/// if the subobject is of class type, the copy assignment operator for the +/// class is used (as if by explicit qualification; that is, ignoring any /// possible virtual overriding functions in more derived classes); -/// — if the subobject is an array, each element is assigned, in the manner +/// +/// if the subobject is an array, each element is assigned, in the manner /// appropriate to the element type; -/// — if the subobject is of scalar type, the built-in assignment operator is +/// +/// if the subobject is of scalar type, the built-in assignment operator is /// used. void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, const FunctionDecl *FD, llvm::Function *Fn, const FunctionArgList &Args) { + + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); StartFunction(FD, FD->getResultType(), Fn, Args, SourceLocation()); + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + + // FIXME. How about copy assignment of arrays! + assert(!getContext().getAsArrayType(FieldType) && + "FIXME. Copy assignment of arrays NYI"); + + if (const RecordType *FieldClassType = FieldType->getAs()) { + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + + EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); + EmitStoreThroughLValue(RVRHS, LHS, FieldType); + } + FinishFunction(); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 4375fbccc7a9..71861273b896 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -575,6 +575,11 @@ public: const CXXRecordDecl *BaseClassDecl, QualType Ty); + void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f00b3157f9a3..2bc70f4a52bc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1398,7 +1398,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) { const CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); - HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context); + const CXXMethodDecl *MD = 0; + HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context, + MD); } // -- for all the nonstatic data members of X that are of a class @@ -1414,8 +1416,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { if (const RecordType *FieldClassType = FieldType->getAs()) { const CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); + const CXXMethodDecl *MD = 0; HasConstCopyAssignment - = FieldClassDecl->hasConstCopyAssignment(Context); + = FieldClassDecl->hasConstCopyAssignment(Context, MD); } }