Variation of objc_copyStruct API generation when
property (atomic/nonatomic) is of aggregate type with
gc'able member objects) (NeXT runtime).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101156 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index ffdcbdc..c40fe93 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -148,19 +148,21 @@
                                          const ObjCPropertyImplDecl *PID) {
   ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
   const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+  bool IsAtomic =
+    !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
   ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
   assert(OMD && "Invalid call to generate getter (empty method)");
   // FIXME: This is rather murky, we create this here since they will not have
   // been created by Sema for us.
   OMD->createImplicitParams(getContext(), IMP->getClassInterface());
   StartObjCMethod(OMD, IMP->getClassInterface());
-
+  
   // Determine if we should use an objc_getProperty call for
   // this. Non-atomic properties are directly evaluated.
   // atomic 'copy' and 'retain' properties are also directly
   // evaluated in gc-only mode.
   if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
-      !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
+      IsAtomic &&
       (PD->getSetterKind() == ObjCPropertyDecl::Copy ||
        PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
     llvm::Value *GetPropertyFn =
@@ -208,7 +210,8 @@
       StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
     }
     else if (hasAggregateLLVMType(Ivar->getType())) {
-      if (!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+      bool IsStrong = false;
+      if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType())))
           && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
           && CGM.getObjCRuntime().GetCopyStructFunction()) {
         llvm::Value *GetCopyStructFn =
@@ -232,12 +235,15 @@
         // FIXME. Implement when Atomic is false; But when struct has
         // gc'able data member!
         llvm::Value *isAtomic =
-          llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
+        llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 
+                               IsAtomic ? 1 : 0);
         Args.push_back(std::make_pair(RValue::get(isAtomic), 
                                       getContext().BoolTy));
-        llvm::Value *False =
-          llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
-        Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy));
+        llvm::Value *hasStrong =
+          llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 
+                                 IsStrong ? 1 : 0);
+        Args.push_back(std::make_pair(RValue::get(hasStrong), 
+                                      getContext().BoolTy));
         EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
                                        FunctionType::ExtInfo()),
                  GetCopyStructFn, ReturnValueSlot(), Args);
@@ -396,6 +402,14 @@
   return (AI.getKind() == ABIArgInfo::Indirect);
 }
 
+bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
+  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+    return false;
+  if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
+    return FDTTy->getDecl()->hasObjectMember();
+  return false;
+}
+
 llvm::Value *CodeGenFunction::LoadObjCSelf() {
   const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
   // See if we need to lazily forward self inside a block literal.