summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2012-03-01 04:01:32 +0000
committerEli Friedman <eli.friedman@gmail.com>2012-03-01 04:01:32 +0000
commit23f0267e2d56c0407f12e62df3561ecf75d74e6e (patch)
treef6e536907913aaa1fa958f250092fefd74cb7d4c /lib/Sema/SemaDeclCXX.cpp
parent5e4e58b805e0e03a669aa517d1d20d4735a3192e (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151797 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp89
1 files changed, 15 insertions, 74 deletions
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();