[cfe-commits] r151797 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Sema/Sema.h lib/CodeGen/CGBlocks.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaLambda.cpp test/CodeGenObjCXX/lambda-expressions.mm

Eli Friedman eli.friedman at gmail.com
Wed Feb 29 20:01:33 PST 2012


Author: efriedma
Date: Wed Feb 29 22:01:32 2012
New Revision: 151797

URL: http://llvm.org/viewvc/llvm-project?rev=151797&view=rev
Log:
Implement "optimization" for lambda-to-block conversion which inlines the generated block literal for lambdas which are immediately converted to block pointer type.  This simplifies the AST, avoids an unnecessary copy of the lambda and makes it much easier to avoid copying the result onto the heap.

Note that this transformation has a substantial semantic effect outside of ARC: it gives the converted lambda lifetime semantics similar to a block literal.  With ARC, the effect is much less obvious because the lifetime of blocks is already managed.


Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Feb 29 22:01:32 2012
@@ -3060,6 +3060,7 @@
   bool IsVariadic : 1;
   bool CapturesCXXThis : 1;
   bool BlockMissingReturnType : 1;
+  bool IsConversionFromLambda : 1;
   /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
   /// parameters of this function.  This is null if a prototype or if there are
   /// no formals.
@@ -3076,7 +3077,7 @@
   BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
     : Decl(Block, DC, CaretLoc), DeclContext(Block),
       IsVariadic(false), CapturesCXXThis(false),
-      BlockMissingReturnType(true),
+      BlockMissingReturnType(true), IsConversionFromLambda(false),
       ParamInfo(0), NumParams(0), Body(0),
       SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
 
@@ -3138,6 +3139,9 @@
   bool blockMissingReturnType() const { return BlockMissingReturnType; }
   void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; }
 
+  bool isConversionFromLambda() const { return IsConversionFromLambda; }
+  void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; }
+
   bool capturesVariable(const VarDecl *var) const;
 
   void setCaptures(ASTContext &Context,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Feb 29 22:01:32 2012
@@ -3654,7 +3654,12 @@
   /// block pointer conversion.
   void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc,
                                                     CXXConversionDecl *Conv);
-  
+
+  ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
+                                           SourceLocation ConvLocation,
+                                           CXXConversionDecl *Conv,
+                                           Expr *Src);
+
   // ParseObjCStringLiteral - Parse Objective-C string literals.
   ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
                                     Expr **Strings,

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Wed Feb 29 22:01:32 2012
@@ -622,10 +622,11 @@
 
 llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
   // Using the computed layout, generate the actual block function.
+  bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
   llvm::Constant *blockFn
     = CodeGenFunction(CGM).GenerateBlockFunction(CurGD, blockInfo,
                                                  CurFuncDecl, LocalDeclMap,
-                                                 InLambdaConversionToBlock);
+                                                 isLambdaConv);
   blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
 
   // If there is nothing to capture, we can emit this as a global block.
@@ -700,11 +701,10 @@
       src = Builder.CreateStructGEP(LoadBlockStruct(),
                                     enclosingCapture.getIndex(),
                                     "block.capture.addr");
-    } else if (InLambdaConversionToBlock) {
+    } else if (blockDecl->isConversionFromLambda()) {
       // The lambda capture in a lambda's conversion-to-block-pointer is
-      // special; we know its argument is an lvalue we can simply emit.
-      CXXConstructExpr *CE = cast<CXXConstructExpr>(ci->getCopyExpr());
-      src = EmitLValue(CE->getArg(0)).getAddress();
+      // special; we'll simply emit it directly.
+      src = 0;
     } else {
       // This is a [[type]]*.
       src = LocalDeclMap[variable];
@@ -726,7 +726,19 @@
 
     // If we have a copy constructor, evaluate that into the block field.
     } else if (const Expr *copyExpr = ci->getCopyExpr()) {
-      EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
+      if (blockDecl->isConversionFromLambda()) {
+        // If we have a lambda conversion, emit the expression
+        // directly into the block instead.
+        CharUnits Align = getContext().getTypeAlignInChars(type);
+        AggValueSlot Slot =
+            AggValueSlot::forAddr(blockField, Align, Qualifiers(),
+                                  AggValueSlot::IsDestructed,
+                                  AggValueSlot::DoesNotNeedGCBarriers,
+                                  AggValueSlot::IsNotAliased);
+        EmitAggExpr(copyExpr, Slot);
+      } else {
+        EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
+      }
 
     // If it's a reference variable, copy the reference into the block field.
     } else if (type->isReferenceType()) {

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Feb 29 22:01:32 2012
@@ -1795,9 +1795,7 @@
     return;
   }
 
-  InLambdaConversionToBlock = true;
   EmitFunctionBody(Args);
-  InLambdaConversionToBlock = false;
 }
 
 void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Feb 29 22:01:32 2012
@@ -32,8 +32,7 @@
     Target(CGM.getContext().getTargetInfo()),
     Builder(cgm.getModule().getContext()),
     AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
-    LambdaThisCaptureField(0), InLambdaConversionToBlock(false),
-    NormalCleanupDest(0), NextCleanupDestIndex(1),
+    LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
     FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
     DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
     IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Feb 29 22:01:32 2012
@@ -601,7 +601,6 @@
 
   llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
   FieldDecl *LambdaThisCaptureField;
-  bool InLambdaConversionToBlock;
 
   /// \brief A mapping from NRVO variables to the flags used to indicate
   /// when the NRVO has been applied to this variable.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Feb 29 22:01:32 2012
@@ -8825,15 +8825,6 @@
        SourceLocation CurrentLocation,
        CXXConversionDecl *Conv) 
 {
-  CXXRecordDecl *Lambda = Conv->getParent();
-  
-  // Make sure that the lambda call operator is marked used.
-  CXXMethodDecl *CallOperator 
-    = cast<CXXMethodDecl>(
-        *Lambda->lookup(
-          Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
-  CallOperator->setReferenced();
-  CallOperator->setUsed();
   Conv->setUsed();
   
   ImplicitlyDefinedFunctionScope Scope(*this, Conv);
@@ -8842,79 +8833,29 @@
   // Copy-initialize the lambda object as needed to capture it.
   Expr *This = ActOnCXXThis(CurrentLocation).take();
   Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
-  ExprResult Init = PerformCopyInitialization(
-                      InitializedEntity::InitializeBlock(CurrentLocation, 
-                                                         DerefThis->getType(), 
-                                                         /*NRVO=*/false),
-                      CurrentLocation, DerefThis);
-  if (!Init.isInvalid())
-    Init = ActOnFinishFullExpr(Init.take());
   
-  if (Init.isInvalid()) {
+  ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation,
+                                                        Conv->getLocation(),
+                                                        Conv, DerefThis);
+
+  // If we're not under ARC, make sure we still get the _Block_copy/autorelease
+  // behavior.  Note that only the general conversion function does this
+  // (since it's unusable otherwise); in the case where we inline the
+  // block literal, it has block literal lifetime semantics.
+  if (!BuildBlock.isInvalid() && !getLangOptions().ObjCAutoRefCount)
+    BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(),
+                                          CK_CopyAndAutoreleaseBlockObject,
+                                          BuildBlock.get(), 0, VK_RValue);
+
+  if (BuildBlock.isInvalid()) {
     Diag(CurrentLocation, diag::note_lambda_to_block_conv);
     Conv->setInvalidDecl();
     return;
   }
-  
-  // Create the new block to be returned.
-  BlockDecl *Block = BlockDecl::Create(Context, Conv, Conv->getLocation());
-  
-  // Set the type information.
-  Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
-  Block->setIsVariadic(CallOperator->isVariadic());
-  Block->setBlockMissingReturnType(false);
-  
-  // Add parameters.
-  SmallVector<ParmVarDecl *, 4> BlockParams;
-  for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
-    ParmVarDecl *From = CallOperator->getParamDecl(I);
-    BlockParams.push_back(ParmVarDecl::Create(Context, Block,
-                                              From->getLocStart(),
-                                              From->getLocation(),
-                                              From->getIdentifier(),
-                                              From->getType(),
-                                              From->getTypeSourceInfo(),
-                                              From->getStorageClass(),
-                                            From->getStorageClassAsWritten(),
-                                              /*DefaultArg=*/0));
-  }
-  Block->setParams(BlockParams);
-  
-  // Add capture. The capture uses a fake variable, which doesn't correspond
-  // to any actual memory location. However, the initializer copy-initializes
-  // the lambda object.
-  TypeSourceInfo *CapVarTSI =
-      Context.getTrivialTypeSourceInfo(DerefThis->getType());
-  VarDecl *CapVar = VarDecl::Create(Context, Block, Conv->getLocation(),
-                                    Conv->getLocation(), 0,
-                                    DerefThis->getType(), CapVarTSI,
-                                    SC_None, SC_None);
-  BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
-                             /*Nested=*/false, /*Copy=*/Init.take());
-  Block->setCaptures(Context, &Capture, &Capture + 1, 
-                     /*CapturesCXXThis=*/false);
-  
-  // Add a fake function body to the block. IR generation is responsible
-  // for filling in the actual body, which cannot be expressed as an AST.
-  Block->setBody(new (Context) CompoundStmt(Context, 0, 0, 
-                                            Conv->getLocation(),
-                                            Conv->getLocation()));
-
-  // Create the block literal expression.
-  Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
-  ExprCleanupObjects.push_back(Block);
-  ExprNeedsCleanups = true;
 
-  // If we're not under ARC, make sure we still get the _Block_copy/autorelease
-  // behavior.
-  if (!getLangOptions().ObjCAutoRefCount)
-    BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock->getType(),
-                                          CK_CopyAndAutoreleaseBlockObject,
-                                          BuildBlock, 0, VK_RValue);
-  
   // Create the return statement that returns the block from the conversion
   // function.
-  StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock);
+  StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock.get());
   if (Return.isInvalid()) {
     Diag(CurrentLocation, diag::note_lambda_to_block_conv);
     Conv->setInvalidDecl();

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 29 22:01:32 2012
@@ -4460,11 +4460,8 @@
     // For message sends and property references, we try to find an
     // actual method.  FIXME: we should infer retention by selector in
     // cases where we don't have an actual method.
-    } else {
-      ObjCMethodDecl *D = 0;
-      if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
-        D = Send->getMethodDecl();
-      }
+    } else if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
+      ObjCMethodDecl *D = Send->getMethodDecl();
 
       ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
 
@@ -4474,6 +4471,13 @@
       if (!ReturnsRetained &&
           D && D->getMethodFamily() == OMF_performSelector)
         return Owned(E);
+    } else if (isa<CastExpr>(E) &&
+               isa<BlockExpr>(cast<CastExpr>(E)->getSubExpr())) {
+      // We hit this case with the lambda conversion-to-block optimization;
+      // we don't want any extra casts here.
+      return Owned(E);
+    } else {
+      ReturnsRetained = false;
     }
 
     // Don't reclaim an object of Class type.
@@ -5089,6 +5093,34 @@
 ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
                                         CXXConversionDecl *Method,
                                         bool HadMultipleCandidates) {
+  if (Method->getParent()->isLambda() &&
+      Method->getConversionType()->isBlockPointerType()) {
+    // This is a lambda coversion to block pointer; check if the argument
+    // is a LambdaExpr.
+    Expr *SubE = E;
+    CastExpr *CE = dyn_cast<CastExpr>(SubE);
+    if (CE && CE->getCastKind() == CK_NoOp)
+      SubE = CE->getSubExpr();
+    SubE = SubE->IgnoreParens();
+    if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubE))
+      SubE = BE->getSubExpr();
+    if (isa<LambdaExpr>(SubE)) {
+      // For the conversion to block pointer on a lambda expression, we
+      // construct a special BlockLiteral instead; this doesn't really make
+      // a difference in ARC, but outside of ARC the resulting block literal
+      // follows the normal lifetime rules for block literals instead of being
+      // autoreleased.
+      DiagnosticErrorTrap Trap(Diags);
+      ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(),
+                                                     E->getExprLoc(),
+                                                     Method, E);
+      if (Exp.isInvalid())
+        Diag(E->getExprLoc(), diag::note_lambda_to_block_conv);
+      return Exp;
+    }
+  }
+      
+
   ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0,
                                           FoundDecl, Method);
   if (Exp.isInvalid())

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Feb 29 22:01:32 2012
@@ -740,3 +740,81 @@
   
   return MaybeBindToTemporary(Lambda);
 }
+
+ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
+                                               SourceLocation ConvLocation,
+                                               CXXConversionDecl *Conv,
+                                               Expr *Src) {
+  // Make sure that the lambda call operator is marked used.
+  CXXRecordDecl *Lambda = Conv->getParent();
+  CXXMethodDecl *CallOperator 
+    = cast<CXXMethodDecl>(
+        *Lambda->lookup(
+          Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+  CallOperator->setReferenced();
+  CallOperator->setUsed();
+
+  ExprResult Init = PerformCopyInitialization(
+                      InitializedEntity::InitializeBlock(ConvLocation, 
+                                                         Src->getType(), 
+                                                         /*NRVO=*/false),
+                      CurrentLocation, Src);
+  if (!Init.isInvalid())
+    Init = ActOnFinishFullExpr(Init.take());
+  
+  if (Init.isInvalid())
+    return ExprError();
+  
+  // Create the new block to be returned.
+  BlockDecl *Block = BlockDecl::Create(Context, CurContext, ConvLocation);
+
+  // Set the type information.
+  Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
+  Block->setIsVariadic(CallOperator->isVariadic());
+  Block->setBlockMissingReturnType(false);
+
+  // Add parameters.
+  SmallVector<ParmVarDecl *, 4> BlockParams;
+  for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+    ParmVarDecl *From = CallOperator->getParamDecl(I);
+    BlockParams.push_back(ParmVarDecl::Create(Context, Block,
+                                              From->getLocStart(),
+                                              From->getLocation(),
+                                              From->getIdentifier(),
+                                              From->getType(),
+                                              From->getTypeSourceInfo(),
+                                              From->getStorageClass(),
+                                            From->getStorageClassAsWritten(),
+                                              /*DefaultArg=*/0));
+  }
+  Block->setParams(BlockParams);
+
+  Block->setIsConversionFromLambda(true);
+
+  // Add capture. The capture uses a fake variable, which doesn't correspond
+  // to any actual memory location. However, the initializer copy-initializes
+  // the lambda object.
+  TypeSourceInfo *CapVarTSI =
+      Context.getTrivialTypeSourceInfo(Src->getType());
+  VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
+                                    ConvLocation, 0,
+                                    Src->getType(), CapVarTSI,
+                                    SC_None, SC_None);
+  BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
+                             /*Nested=*/false, /*Copy=*/Init.take());
+  Block->setCaptures(Context, &Capture, &Capture + 1, 
+                     /*CapturesCXXThis=*/false);
+
+  // Add a fake function body to the block. IR generation is responsible
+  // for filling in the actual body, which cannot be expressed as an AST.
+  Block->setBody(new (Context) CompoundStmt(Context, 0, 0, 
+                                            ConvLocation,
+                                            ConvLocation));
+
+  // Create the block literal expression.
+  Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
+  ExprCleanupObjects.push_back(Block);
+  ExprNeedsCleanups = true;
+
+  return BuildBlock;
+}

Modified: cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm?rev=151797&r1=151796&r2=151797&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm Wed Feb 29 22:01:32 2012
@@ -4,6 +4,7 @@
 typedef int (^fp)();
 fp f() { auto x = []{ return 3; }; return x; }
 
+// MRC: define i32 ()* @_Z1fv(
 // MRC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
 // MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
 // MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
@@ -11,8 +12,26 @@
 // MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
 // MRC: ret i32 ()*
 
+// ARC: define i32 ()* @_Z1fv(
 // ARC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
 // ARC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
 // ARC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
 // ARC: call i8* @objc_retainBlock
 // ARC: call i8* @objc_autoreleaseReturnValue
+
+typedef int (^fp)();
+fp global;
+void f2() { global = []{ return 3; }; }
+
+// MRC: define void @_Z2f2v() nounwind {
+// MRC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
+// MRC-NOT: call
+// MRC: ret void
+// ("global" contains a dangling pointer after this function runs.)
+
+// ARC: define void @_Z2f2v() nounwind {
+// ARC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
+// ARC: call i8* @objc_retainBlock
+// ARC: call void @objc_release
+// ARC: define internal i32 @__f2_block_invoke_0
+// ARC: call i32 @"_ZZ2f2vENK3$_1clEv





More information about the cfe-commits mailing list