[cfe-commits] r134605 - in /cfe/trunk: include/clang/AST/ lib/ARCMigrate/ lib/AST/ lib/CodeGen/ lib/Sema/ lib/StaticAnalyzer/Core/ test/CodeGenObjC/ test/CodeGenObjCXX/

John McCall rjmccall at apple.com
Wed Jul 6 23:58:02 PDT 2011


Author: rjmccall
Date: Thu Jul  7 01:58:02 2011
New Revision: 134605

URL: http://llvm.org/viewvc/llvm-project?rev=134605&view=rev
Log:
In ARC, reclaim all return values of retainable type, not just those
where we have an immediate need of a retained value.

As an exception, don't do this when the call is made as the immediate
operand of a __bridge retain.  This is more in the way of a workaround
than an actual guarantee, so it's acceptable to be brittle here.

rdar://problem/9504800


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/OperationKinds.h
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
    cfe/trunk/lib/ARCMigrate/TransformActions.cpp
    cfe/trunk/lib/ARCMigrate/Transforms.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprComplex.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/CodeGenObjC/arc.m
    cfe/trunk/test/CodeGenObjCXX/arc.mm

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Jul  7 01:58:02 2011
@@ -538,6 +538,10 @@
   ///        the rules of C++ [expr.unary.noexcept].
   CanThrowResult CanThrow(ASTContext &C) const;
 
+  /// IgnoreImplicit - Skip past any implicit AST nodes which might
+  /// surround this expression.
+  Expr *IgnoreImplicit() { return cast<Expr>(Stmt::IgnoreImplicit()); }
+
   /// IgnoreParens - Ignore parentheses.  If this Expr is a ParenExpr, return
   ///  its subexpression.  If that subexpression is also a ParenExpr,
   ///  then this method recursively returns its subexpression, and so forth.
@@ -2330,6 +2334,7 @@
     case CK_IntegralComplexToFloatingComplex:
     case CK_ObjCProduceObject:
     case CK_ObjCConsumeObject:
+    case CK_ObjCReclaimReturnedObject:
       assert(!getType()->isBooleanType() && "unheralded conversion to bool");
       // fallthrough to check for null base path
 

Modified: cfe/trunk/include/clang/AST/OperationKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OperationKinds.h?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OperationKinds.h (original)
+++ cfe/trunk/include/clang/AST/OperationKinds.h Thu Jul  7 01:58:02 2011
@@ -247,15 +247,20 @@
   ///   _Complex unsigned -> _Complex float
   CK_IntegralComplexToFloatingComplex,
 
-  /// \brief Produces an Objective-C object so that it may be
+  /// \brief Produces a retainable object pointer so that it may be
   /// consumed, e.g. by being passed to a consuming parameter.  Calls
   /// objc_retain.
   CK_ObjCProduceObject,
 
-  /// \brief Consumes an Objective-C object that has just been
+  /// \brief Consumes a retainable object pointer that has just been
   /// produced, e.g. as the return value of a retaining call.  Enters
   /// a cleanup to call objc_release at some indefinite time.
-  CK_ObjCConsumeObject
+  CK_ObjCConsumeObject,
+
+  /// \brief Reclaim a retainable object pointer object that may have
+  /// been produced and autoreleased as part of a function return
+  /// sequence.
+  CK_ObjCReclaimReturnedObject
 };
 
 #define CK_Invalid ((CastKind) -1)

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Thu Jul  7 01:58:02 2011
@@ -293,6 +293,10 @@
   ///   works on systems with GraphViz (Mac OS X) or dot+gv installed.
   void viewAST() const;
 
+  /// Skip past any implicit AST nodes which might surround this
+  /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
+  Stmt *IgnoreImplicit();
+
   // Implement isa<T> support.
   static bool classof(const Stmt *) { return true; }
 

Modified: cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp Thu Jul  7 01:58:02 2011
@@ -116,11 +116,16 @@
       return true;
     }
 
-    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E)))
+    Stmt *parent = StmtMap->getParent(E);
+
+    if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
+      return tryRemoving(castE);
+
+    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
       return tryRemoving(parenE);
 
     if (BinaryOperator *
-          bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) {
+          bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
           isRemovable(bopE)) {
         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());

Modified: cfe/trunk/lib/ARCMigrate/TransformActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransformActions.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransformActions.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransformActions.cpp Thu Jul  7 01:58:02 2011
@@ -313,7 +313,7 @@
   assert(IsInTransaction && "Actions only allowed during a transaction");
   ActionData data;
   data.Kind = Act_RemoveStmt;
-  data.S = S;
+  data.S = S->IgnoreImplicit(); // important for uniquing
   CachedActions.push_back(data);
 }
 

Modified: cfe/trunk/lib/ARCMigrate/Transforms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Transforms.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Transforms.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/Transforms.cpp Thu Jul  7 01:58:02 2011
@@ -180,12 +180,9 @@
   void mark(Stmt *S) {
     if (!S) return;
     
-    if (LabelStmt *Label = dyn_cast<LabelStmt>(S))
-      return mark(Label->getSubStmt());
-    if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S))
-      return mark(CE->getSubExpr());
-    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
-      return mark(EWC->getSubExpr());
+    while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
+      S = Label->getSubStmt();
+    S = S->IgnoreImplicit();
     if (Expr *E = dyn_cast<Expr>(S))
       Removables.insert(E);
   }

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Thu Jul  7 01:58:02 2011
@@ -1102,6 +1102,8 @@
     return "ObjCConsumeObject";
   case CK_ObjCProduceObject:
     return "ObjCProduceObject";
+  case CK_ObjCReclaimReturnedObject:
+    return "ObjCReclaimReturnedObject";
   }
 
   llvm_unreachable("Unhandled cast kind!");

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jul  7 01:58:02 2011
@@ -1819,6 +1819,7 @@
   case CK_UserDefinedConversion:
   case CK_ObjCProduceObject:
   case CK_ObjCConsumeObject:
+  case CK_ObjCReclaimReturnedObject:
     return false;
 
   case CK_LValueToRValue:
@@ -2325,6 +2326,7 @@
   case CK_IntegralComplexToBoolean:
   case CK_ObjCProduceObject:
   case CK_ObjCConsumeObject:
+  case CK_ObjCReclaimReturnedObject:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Thu Jul  7 01:58:02 2011
@@ -85,6 +85,18 @@
   return StatSwitch;
 }
 
+Stmt *Stmt::IgnoreImplicit() {
+  Stmt *s = this;
+
+  if (ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(s))
+    s = ewc->getSubExpr();
+
+  while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(s))
+    s = ice->getSubExpr();
+
+  return s;
+}
+
 namespace {
   struct good {};
   struct bad {};

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Jul  7 01:58:02 2011
@@ -2011,7 +2011,8 @@
   case CK_MemberPointerToBoolean:
   case CK_AnyPointerToBlockPointerCast:
   case CK_ObjCProduceObject:
-  case CK_ObjCConsumeObject: {
+  case CK_ObjCConsumeObject:
+  case CK_ObjCReclaimReturnedObject: {
     // These casts only produce lvalues when we're binding a reference to a 
     // temporary realized from a (converted) pure rvalue. Emit the expression
     // as a value, copy it into a temporary, and return an lvalue referring to

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Thu Jul  7 01:58:02 2011
@@ -360,6 +360,7 @@
   case CK_IntegralComplexToFloatingComplex:
   case CK_ObjCProduceObject:
   case CK_ObjCConsumeObject:
+  case CK_ObjCReclaimReturnedObject:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }

Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Thu Jul  7 01:58:02 2011
@@ -407,6 +407,7 @@
   case CK_IntegralComplexToBoolean:
   case CK_ObjCProduceObject:
   case CK_ObjCConsumeObject:
+  case CK_ObjCReclaimReturnedObject:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Jul  7 01:58:02 2011
@@ -582,6 +582,7 @@
     case CK_Dynamic:
     case CK_ObjCProduceObject:
     case CK_ObjCConsumeObject:
+    case CK_ObjCReclaimReturnedObject:
       return 0;
 
     // These might need to be supported for constexpr.

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Thu Jul  7 01:58:02 2011
@@ -1109,6 +1109,11 @@
     return CGF.EmitARCRetainScalarExpr(E);
   case CK_ObjCConsumeObject:
     return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
+  case CK_ObjCReclaimReturnedObject: {
+    llvm::Value *value = Visit(E);
+    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+    return CGF.EmitObjCConsumeObject(E->getType(), value);
+  }
 
   case CK_FloatingRealToComplex:
   case CK_FloatingComplexCast:

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Thu Jul  7 01:58:02 2011
@@ -2333,6 +2333,14 @@
         return TryEmitResult(result, true);
       }
 
+      // For reclaims, emit the subexpression as a retained call and
+      // skip the consumption.
+      case CK_ObjCReclaimReturnedObject: {
+        llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
+        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+        return TryEmitResult(result, true);
+      }
+
       case CK_GetObjCProperty: {
         llvm::Value *result = emitARCRetainCall(CGF, ce);
         if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jul  7 01:58:02 2011
@@ -3543,6 +3543,7 @@
       case CK_BitCast:
       case CK_LValueBitCast:
       case CK_LValueToRValue:
+      case CK_ObjCReclaimReturnedObject:
         e = cast->getSubExpr();
         continue;
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jul  7 01:58:02 2011
@@ -4039,13 +4039,12 @@
       ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
     }
 
-    if (ReturnsRetained) {
-      ExprNeedsCleanups = true;
-      E = ImplicitCastExpr::Create(Context, E->getType(),
-                                   CK_ObjCConsumeObject, E, 0,
-                                   VK_RValue);
-    }
-    return Owned(E);
+    ExprNeedsCleanups = true;
+
+    CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject
+                                   : CK_ObjCReclaimReturnedObject);
+    return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
+                                          VK_RValue));
   }
 
   if (!getLangOptions().CPlusPlus)

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Thu Jul  7 01:58:02 2011
@@ -1771,6 +1771,20 @@
     << castRange << castExpr->getSourceRange();
 }
 
+/// Look for an ObjCReclaimReturnedObject cast and destroy it.
+static Expr *maybeUndoReclaimObject(Expr *e) {
+  // For now, we just undo operands that are *immediately* reclaim
+  // expressions, which prevents the vast majority of potential
+  // problems here.  To catch them all, we'd need to rebuild arbitrary
+  // value-propagating subexpressions --- we can't reliably rebuild
+  // in-place because of expression sharing.
+  if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+    if (ice->getCastKind() == CK_ObjCReclaimReturnedObject)
+      return ice->getSubExpr();
+
+  return e;
+}
+
 ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
                                       ObjCBridgeCastKind Kind,
                                       SourceLocation BridgeKeywordLoc,
@@ -1815,6 +1829,9 @@
     // Okay: id -> CF
     switch (Kind) {
     case OBC_Bridge:
+      // Reclaiming a value that's going to be __bridge-casted to CF
+      // is very dangerous, so we don't do it.
+      SubExpr = maybeUndoReclaimObject(SubExpr);
       break;
       
     case OBC_BridgeRetained:        

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Jul  7 01:58:02 2011
@@ -2194,7 +2194,8 @@
       // The analyzer doesn't do anything special with these casts,
       // since it understands retain/release semantics already.
       case CK_ObjCProduceObject:
-      case CK_ObjCConsumeObject: // Fall-through.
+      case CK_ObjCConsumeObject:
+      case CK_ObjCReclaimReturnedObject: // Fall-through.
       // True no-ops.
       case CK_NoOp:
       case CK_FunctionToPointerDecay: {

Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Thu Jul  7 01:58:02 2011
@@ -283,7 +283,10 @@
   // CHECK-NEXT: load [[TEST10]]** [[X]], align
   // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
   // CHECK-NEXT: bitcast
-  // CHECK-NEXT: call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[V:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
   // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
   // CHECK-NEXT: bitcast
   // CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
@@ -292,6 +295,8 @@
   // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
   // CHECK-NEXT: [[T4:%.*]] = bitcast [[TEST10]]* [[T3]] to i8*
   // CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST10]]* [[V]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
   // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
   // CHECK-NEXT: call void @objc_release(i8* [[T0]])
   // CHECK-NEXT: [[T0:%.*]] = load [[TEST10]]** [[X]]
@@ -323,11 +328,15 @@
 
   __weak id x = test12_helper();
   // CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
-  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T0]])
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T1]])
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
 
   x = test12_helper();
-  // CHECK-NEXT: [[T1:%.*]] = call i8* @test12_helper()
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
   // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[X]], i8* [[T1]])
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
 
   id y = x;
   // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
@@ -1214,7 +1223,9 @@
   // CHECK:      [[VAR:%.*]] = alloca i8*
   // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
   // CHECK-NEXT: [[T0:%.*]] = call i8* @test39_source()
-  // CHECK-NEXT: store i8* [[T0]], i8** [[VAR]],
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   // 0x40000000 - has signature but no copy/dispose
   // CHECK:      store i32 1073741824, i32*
   // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
@@ -1239,7 +1250,9 @@
   // CHECK-NEXT: store i32 33554432, i32* [[T0]]
   // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
   // CHECK-NEXT: [[T0:%.*]] = call i8* @test40_source()
-  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
   // 0x42000000 - has signature, copy/dispose helpers
   // CHECK:      store i32 1107296256,
@@ -1287,7 +1300,9 @@
   // CHECK:      [[VAR:%.*]] = alloca i8*,
   // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
   // CHECK:      [[T0:%.*]] = call i8* @test41_source()
-  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T0]])
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   // 0x42000000 - has signature, copy/dispose helpers
   // CHECK:      store i32 1107296256,
   // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
@@ -1389,17 +1404,21 @@
   // TODO: this is sub-optimal, we should retain at the actual call site.
 
   // CHECK:      [[T0:%.*]] = call i8* @test46_helper()
-  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
-  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+  // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+  // CHECK-NEXT: store i8* [[T4]], i8**
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   id x = *wp = test46_helper();
 
   // CHECK:      [[T0:%.*]] = call i8* @test46_helper()
-  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
-  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+  // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+  // CHECK-NEXT: store i8* [[T4]], i8**
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   id y = *wvp = test46_helper();
 }
 
@@ -1432,8 +1451,10 @@
   // CHECK:      [[X:%.*]] = alloca i8*
   // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_initWeak(i8** [[X]], i8* null)
   // CHECK-NEXT: [[T1:%.*]] = call i8* @test48_helper()
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T1]])
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
   // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T2]])
+  // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T3]])
+  // CHECK-NEXT: call void @objc_release(i8* [[T2]])
   // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
   // CHECK-NEXT: ret void
 }

Modified: cfe/trunk/test/CodeGenObjCXX/arc.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc.mm?rev=134605&r1=134604&r2=134605&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/arc.mm Thu Jul  7 01:58:02 2011
@@ -9,17 +9,21 @@
   // TODO: in the non-volatile case, we do not need to be reloading.
 
   // CHECK:      [[T0:%.*]] = call i8* @_Z12test0_helperv()
-  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
-  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+  // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]])
+  // CHECK-NEXT: store i8* [[T4]], i8**
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   id x = *wp = test0_helper();
 
   // CHECK:      [[T0:%.*]] = call i8* @_Z12test0_helperv()
-  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
-  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T1]])
-  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+  // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T2]])
+  // CHECK-NEXT: store i8* [[T4]], i8**
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
   id y = *wvp = test0_helper();
 }
 





More information about the cfe-commits mailing list