]> granicus.if.org Git - clang/commitdiff
When performing an @throw in ARC, retain + autorelease
authorJohn McCall <rjmccall@apple.com>
Sat, 1 Oct 2011 10:32:24 +0000 (10:32 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 1 Oct 2011 10:32:24 +0000 (10:32 +0000)
the pointer, being sure to do so before running cleanups
associated with that full-expression.  rdar://10042689

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140945 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenObjC/arc-with-atthrow.m

index d406e3a064531ec1f05d1efaccabcd16e34deae5..96ab3dcd68650e8f15e7923dee4f6b864cf8e67d 100644 (file)
@@ -2386,6 +2386,30 @@ CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
   return value;
 }
 
+llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
+  // In ARC, retain and autorelease the expression.
+  if (getLangOptions().ObjCAutoRefCount) {
+    // Do so before running any cleanups for the full-expression.
+    // tryEmitARCRetainScalarExpr does make an effort to do things
+    // inside cleanups, but there are crazy cases like
+    //   @throw A().foo;
+    // where a full retain+autorelease is required and would
+    // otherwise happen after the destructor for the temporary.
+    CodeGenFunction::RunCleanupsScope cleanups(*this);
+    if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr))
+      expr = ewc->getSubExpr();
+
+    return EmitARCRetainAutoreleaseScalarExpr(expr);
+  }
+
+  // Otherwise, use the normal scalar-expression emission.  The
+  // exception machinery doesn't do anything special with the
+  // exception like retaining it, so there's no safety associated with
+  // only running cleanups after the throw has started, and when it
+  // matters it tends to be substantially inferior code.
+  return EmitScalarExpr(expr);
+}
+
 std::pair<LValue,llvm::Value*>
 CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
                                     bool ignored) {
index c948c3270eed1ec71793eb8d4923bddb69c60c0a..6bdc519a2606b0ef30ccd2d1d4354a032a792f04 100644 (file)
@@ -2277,7 +2277,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
   llvm::Value *ExceptionAsObject;
 
   if (const Expr *ThrowExpr = S.getThrowExpr()) {
-    llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+    llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
     ExceptionAsObject = Exception;
   } else {
     assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
index d6eeba292a79c69b5b2316d6a8b9d3cabb1a3ffa..1b317c45f231f911322d5f22108414213e84acba 100644 (file)
@@ -3204,7 +3204,7 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
   llvm::Value *ExceptionAsObject;
 
   if (const Expr *ThrowExpr = S.getThrowExpr()) {
-    llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+    llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
     ExceptionAsObject =
       CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
   } else {
@@ -6002,7 +6002,7 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
 void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
                                            const ObjCAtThrowStmt &S) {
   if (const Expr *ThrowExpr = S.getThrowExpr()) {
-    llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+    llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
     Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
     CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
       .setDoesNotReturn();
index 19541a97673470aa1ac31ae35dc9d16415ecb3b3..0f120923d6129e3b59151cab494554192eed2521 100644 (file)
@@ -2141,6 +2141,8 @@ public:
   std::pair<LValue,llvm::Value*>
   EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
 
+  llvm::Value *EmitObjCThrowOperand(const Expr *expr);
+
   llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr);
   llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
   llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
index 984bf5582ed643d3e520d63f0fbdbc69c2f5af82..e25ef3e3a08b33324d4f0bb963b11c86dc1aa9b6 100644 (file)
@@ -1,15 +1,17 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-nonfragile-abi -fobjc-exceptions -o - %s | FileCheck %s
 // pr10411
+// rdar://10042689
 
-@interface NSException
-+ (id)exception;
-@end
-
-void test() 
-{ 
-  @throw [NSException exception]; 
+id make(void);
+void test() { 
+  @throw make();
 }
 
-// CHECK: objc_retainAutoreleasedReturnValue
-// CHECK:   call void @objc_release
-// CHECK:   call void @objc_exception_throw
+// TODO: We should probably emit this specific pattern without the reclaim.
+
+// CHECK:    define void @test()
+// CHECK:      [[T0:%.*]] = call i8* @make()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autorelease(i8* [[T1]])
+// CHECK-NEXT: call void @objc_exception_throw(i8* [[T2]]) noreturn
+// CHECK-NEXT: unreachable