diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 1338657ff497..68fa374913d5 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3060,6 +3060,7 @@ private: 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 @@ protected: 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 @@ public: 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, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 967dc29c4d26..7d9f83500002 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3654,7 +3654,12 @@ public: /// 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, diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index f6aa9b4b4856..1b35fa0ee4de 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -622,10 +622,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { 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 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { 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(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 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // 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()) { diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index e3b577738700..6b5a1497109b 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1795,9 +1795,7 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { return; } - InLambdaConversionToBlock = true; EmitFunctionBody(Args); - InLambdaConversionToBlock = false; } void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 5d18169695b8..47176bd8ecc3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -32,8 +32,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) 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), diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 42c9b7dc9b2d..7f39868dd91e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -601,7 +601,6 @@ public: llvm::DenseMap 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. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 73df1c9457e3..4f0e1609509e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -8825,15 +8825,6 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { - CXXRecordDecl *Lambda = Conv->getParent(); - - // Make sure that the lambda call operator is marked used. - CXXMethodDecl *CallOperator - = cast( - *Lambda->lookup( - Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); - CallOperator->setReferenced(); - CallOperator->setUsed(); Conv->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, Conv); @@ -8842,79 +8833,29 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( // 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 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(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 84afc032c0b4..1893d6dfa106 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4460,11 +4460,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { // 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(E)) { - D = Send->getMethodDecl(); - } + } else if (ObjCMessageExpr *Send = dyn_cast(E)) { + ObjCMethodDecl *D = Send->getMethodDecl(); ReturnsRetained = (D && D->hasAttr()); @@ -4474,6 +4471,13 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!ReturnsRetained && D && D->getMethodFamily() == OMF_performSelector) return Owned(E); + } else if (isa(E) && + isa(cast(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::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, 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(SubE); + if (CE && CE->getCastKind() == CK_NoOp) + SubE = CE->getSubExpr(); + SubE = SubE->IgnoreParens(); + if (CXXBindTemporaryExpr *BE = dyn_cast(SubE)) + SubE = BE->getSubExpr(); + if (isa(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()) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index b0c6a61bce9f..3611350de0eb 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -740,3 +740,81 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, 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( + *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 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; +} diff --git a/clang/test/CodeGenObjCXX/lambda-expressions.mm b/clang/test/CodeGenObjCXX/lambda-expressions.mm index c55699a2319c..36a1996ee87d 100644 --- a/clang/test/CodeGenObjCXX/lambda-expressions.mm +++ b/clang/test/CodeGenObjCXX/lambda-expressions.mm @@ -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 @@ fp f() { auto x = []{ return 3; }; return x; } // 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