Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -26,6 +26,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -1244,53 +1245,65 @@ return emission; } -/// Determines whether the given __block variable is potentially -/// captured by the given expression. -static bool isCapturedBy(const VarDecl &var, const Expr *e) { - // Skip the most common kinds of expressions that make - // hierarchy-walking expensive. - e = e->IgnoreParenCasts(); +static bool isCapturedBy(const VarDecl &, const Expr *); - if (const BlockExpr *be = dyn_cast(e)) { - const BlockDecl *block = be->getBlockDecl(); - for (const auto &I : block->captures()) { - if (I.getVariable() == &var) - return true; - } +class IsCapturedBy : public RecursiveASTVisitor { + bool IsCaptured = false; + const VarDecl &Var; + bool setCaptured() { + IsCaptured = true; + // End visitation early, we know it's captured. + return false; + } +public: + IsCapturedBy(const VarDecl &Var) : Var(Var) {} + bool isCaptured() const { return IsCaptured; } + + bool TraverseBlockExpr(BlockExpr *BE) { + const BlockDecl *Block = BE->getBlockDecl(); + for (const auto &I : Block->captures()) + if (I.getVariable() == &Var) + return setCaptured(); // No need to walk into the subexpressions. return false; } - if (const StmtExpr *SE = dyn_cast(e)) { + bool TraverseStmtExpr(StmtExpr *SE) { const CompoundStmt *CS = SE->getSubStmt(); for (const auto *BI : CS->body()) if (const auto *E = dyn_cast(BI)) { - if (isCapturedBy(var, E)) - return true; - } - else if (const auto *DS = dyn_cast(BI)) { - // special case declarations - for (const auto *I : DS->decls()) { - if (const auto *VD = dyn_cast((I))) { - const Expr *Init = VD->getInit(); - if (Init && isCapturedBy(var, Init)) - return true; - } + if (isCapturedBy(Var, E)) + return setCaptured(); + } else if (const auto *DS = dyn_cast(BI)) { + // special case declarations + for (const auto *I : DS->decls()) { + if (const auto *VD = dyn_cast((I))) { + const Expr *Init = VD->getInit(); + if (Init && isCapturedBy(Var, Init)) + return setCaptured(); } + } } else - // FIXME. Make safe assumption assuming arbitrary statements cause capturing. - // Later, provide code to poke into statements for capture analysis. - return true; - return false; + // FIXME. Make safe assumption assuming arbitrary statements cause + // capturing. Later, provide code to poke into statements for capture + // analysis. + return setCaptured(); + return true; } +}; - for (const Stmt *SubStmt : e->children()) - if (isCapturedBy(var, cast(SubStmt))) - return true; +/// Determines whether the given __block variable is potentially +/// captured by the given expression. +static bool isCapturedBy(const VarDecl &Var, const Expr *E) { + // Skip the most common kinds of expressions that make + // hierarchy-walking expensive. + E = E->IgnoreParenCasts(); - return false; + IsCapturedBy Visitor(Var); + Visitor.TraverseStmt(const_cast(E)); + return Visitor.isCaptured(); } /// Determine whether the given initializer is trivial in the sense Index: test/CodeGen/block-capture.cpp =================================================================== --- /dev/null +++ test/CodeGen/block-capture.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -x c++ -std=c++11 -fblocks -emit-llvm %s -o - | FileCheck %s + +// CHECK: %struct.__block_byref_baz = type { i8*, %struct.__block_byref_baz*, i32, i32, i32 } +// CHECK: [[baz:%[0-9a-z_]*]] = alloca %struct.__block_byref_baz +// CHECK: [[bazref:%[0-9a-z_\.]*]] = getelementptr inbounds %struct.__block_byref_baz, %struct.__block_byref_baz* [[baz]], i32 0, i32 1 +// CHECK: store %struct.__block_byref_baz* [[baz]], %struct.__block_byref_baz** [[bazref]] +// CHECK: [[disposable:%[0-9a-z_]*]] = bitcast %struct.__block_byref_baz* [[baz]] to i8* +// CHECK: call void @_Block_object_dispose(i8* [[disposable]] + +int main() { + __block int baz = [&]() { return 0; }(); + return 0; +}