diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 24 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 89 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 78 |
7 files changed, 149 insertions, 90 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index f6aa9b4b48..1b35fa0ee4 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/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<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 @@ 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/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index e3b5777387..6b5a149710 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/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/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 5d18169695..47176bd8ec 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/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/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 42c9b7dc9b..7f39868dd9 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -601,7 +601,6 @@ public: 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. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 73df1c9457..4f0e160950 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/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<CXXMethodDecl>( - *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<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(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 84afc032c0..1893d6dfa1 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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<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 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { 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::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<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()) diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index b0c6a61bce..3611350de0 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/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<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; +} |