diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-22 05:02:47 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-22 05:02:47 +0000 |
commit | ac1303eca6cbe3e623fb5ec6fe7ec184ef4b0dfa (patch) | |
tree | 722f199bf702a2292747f89396b3c066869c3e85 /lib/Sema | |
parent | e9ee382c32a83e9807a2fe4cfd52b5a11169a4b8 (diff) |
Generate an AST for the conversion from a lambda closure type to a
block pointer that returns a block literal which captures (by copy)
the lambda closure itself. Some aspects of the block literal are left
unspecified, namely the capture variable (which doesn't actually
exist) and the body (which will be filled in by IRgen because it can't
be written as an AST).
Because we're switching to this model, this patch also eliminates
tracking the copy-initialization expression for the block capture of
the conversion function, since that information is now embedded in the
synthesized block literal. -1 side tables FTW.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151131 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 89 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 2 |
3 files changed, 85 insertions, 14 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 9454a75155..7f42b2059d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3000,9 +3000,11 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) { Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); QualType T = SubExpr->getType(); - if (SubExpr->getType()->isPointerType() || - SubExpr->getType()->isBlockPointerType() || - SubExpr->getType()->isObjCQualifiedIdType()) + if (cast<CastExpr>(E)->getCastKind() == CK_CopyAndAutoreleaseBlockObject) + return 0; + else if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isBlockPointerType() || + SubExpr->getType()->isObjCQualifiedIdType()) return EvalAddr(SubExpr, refVars); else if (T->isArrayType()) return EvalVal(SubExpr, refVars); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a1a952b833..22fb8cb7a8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8755,9 +8755,9 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { /// \brief Mark the call operator of the given lambda closure type as "used". static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) { CXXMethodDecl *CallOperator - = cast<CXXMethodDecl>( - *Lambda->lookup( - S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); + = cast<CXXMethodDecl>( + *Lambda->lookup( + S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); CallOperator->setReferenced(); CallOperator->setUsed(); } @@ -8805,14 +8805,21 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { + CXXRecordDecl *Lambda = Conv->getParent(); + // Make sure that the lambda call operator is marked used. - markLambdaCallOperatorUsed(*this, Conv->getParent()); + CXXMethodDecl *CallOperator + = cast<CXXMethodDecl>( + *Lambda->lookup( + Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); + CallOperator->setReferenced(); + CallOperator->setUsed(); Conv->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); - // Copy-initialize the lambda object as needed to capture + // 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( @@ -8823,16 +8830,78 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.take()); - if (!Init.isInvalid()) - Conv->setLambdaToBlockPointerCopyInit(Init.take()); - else { + if (Init.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); + Conv->setInvalidDecl(); + return; } - // Introduce a bogus body, which IR generation will override anyway. - Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(), + // 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 is uses a fake (NULL) variable, since we don't + // actually want to have to name a capture variable. However, the + // initializer copy-initializes the lambda object. + BlockDecl::Capture Capture(/*Variable=*/0, /*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); + if (Return.isInvalid()) { + Diag(CurrentLocation, diag::note_lambda_to_block_conv); + Conv->setInvalidDecl(); + return; + } + + // Set the body of the conversion function. + Stmt *ReturnS = Return.take(); + Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1, + Conv->getLocation(), Conv->getLocation())); + // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 016322fe52..b0c6a61bce 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -643,7 +643,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. - if (getLangOptions().Blocks) + if (getLangOptions().Blocks && getLangOptions().ObjC1) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. |