aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h6
-rw-r--r--include/clang/Sema/Sema.h7
-rw-r--r--lib/CodeGen/CGBlocks.cpp24
-rw-r--r--lib/CodeGen/CGClass.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp3
-rw-r--r--lib/CodeGen/CodeGenFunction.h1
-rw-r--r--lib/Sema/SemaDeclCXX.cpp89
-rw-r--r--lib/Sema/SemaExprCXX.cpp42
-rw-r--r--lib/Sema/SemaLambda.cpp78
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm19
10 files changed, 179 insertions, 92 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 1338657ff4..68fa374913 100644
--- a/include/clang/AST/Decl.h
+++ b/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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 967dc29c4d..7d9f835000 100644
--- a/include/clang/Sema/Sema.h
+++ b/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/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;
+}
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index c55699a231..36a1996ee8 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/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