Honor objc_precise_lifetime in GC mode by feeding the value
in the variable to an inline asm which gets run when the variable
goes out of scope.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133840 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index b6ad130..7e126d9 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -364,6 +364,20 @@
     }
   };
 
+  struct ExtendGCLifetime : EHScopeStack::Cleanup {
+    const VarDecl &Var;
+    ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
+
+    void Emit(CodeGenFunction &CGF, bool forEH) {
+      // Compute the address of the local variable, in case it's a
+      // byref or something.
+      DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
+                      SourceLocation());
+      llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
+      CGF.EmitExtendGCLifetime(value);
+    }
+  };
+
   struct CallCleanupFunction : EHScopeStack::Cleanup {
     llvm::Constant *CleanupFn;
     const CGFunctionInfo &FnInfo;
@@ -1029,6 +1043,12 @@
     }
   }
 
+  // In GC mode, honor objc_precise_lifetime.
+  if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+      D.hasAttr<ObjCPreciseLifetimeAttr>()) {
+    EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
+  }
+
   // Handle the cleanup attribute.
   if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
     const FunctionDecl *FD = CA->getFunctionDecl();
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 9107e98..62ee03c 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -2484,4 +2484,22 @@
     DI->EmitRegionEnd(Builder);
   }
 }
+
+/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+/// make sure it survives garbage collection until this point.
+void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
+  // We just use an inline assembly.
+  const llvm::Type *paramTypes[] = { VoidPtrTy };
+  llvm::FunctionType *extenderType
+    = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false);
+  llvm::Value *extender
+    = llvm::InlineAsm::get(extenderType,
+                           /* assembly */ "",
+                           /* constraints */ "r",
+                           /* side effects */ true);
+
+  object = Builder.CreateBitCast(object, VoidPtrTy);
+  Builder.CreateCall(extender, object)->setDoesNotThrow();
+}
+
 CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index fea2e61..717f319 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -2146,6 +2146,10 @@
   void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
                                 QualType Ty);
 
+  /// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+  /// make sure it survives garbage collection until this point.
+  void EmitExtendGCLifetime(llvm::Value *object);
+
   /// EmitComplexExpr - Emit the computation of the specified expression of
   /// complex type, returning the result.
   ComplexPairTy EmitComplexExpr(const Expr *E,