]> granicus.if.org Git - clang/commitdiff
More toward synthesizing copy assignments. SWIP.
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 12 Aug 2009 23:34:46 +0000 (23:34 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 12 Aug 2009 23:34:46 +0000 (23:34 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78861 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/CodeGen/CGCXX.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaDeclCXX.cpp

index ff498ba4a404dd226427af9f57072ea6463f8d1f..2d0edc8418f436f81fad33afdc90776f23636a82 100644 (file)
@@ -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
index e9ae7e77f04dc9d9082f75670dda10eb51bc7a56..6c4034f78723d1ebe5c42656d86c9f946e470d54 100644 (file)
@@ -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<CXXRecordDecl*>(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;
index 5edc1e049c8a636367e4f35ab3bd80d1c531d21e..b378bf83e66f2bcefa353ad99c5e9b8c324c578f 100644 (file)
@@ -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 qualification; 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<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
+      CXXRecordDecl *FieldClassDecl
+      = cast<CXXRecordDecl>(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();
 }  
 
index 4375fbccc7a9232d642078d3ed24f3c361912423..71861273b8964807e87fcf23fb468dc9cbb268f3 100644 (file)
@@ -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,
index f00b3157f9a385b73a430558c8a60f8bba9df17e..2bc70f4a52bc82c980d03d6cc574b883fab3f0cb 100644 (file)
@@ -1398,7 +1398,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
          HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) {
       const CXXRecordDecl *BaseClassDecl
         = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
         const CXXRecordDecl *FieldClassDecl
           = cast<CXXRecordDecl>(FieldClassType->getDecl());
+        const CXXMethodDecl *MD = 0;
         HasConstCopyAssignment
-          = FieldClassDecl->hasConstCopyAssignment(Context);
+          = FieldClassDecl->hasConstCopyAssignment(Context, MD);
       }
     }