Author: jfb Date: Fri May 18 21:21:26 2018 New Revision: 332801 URL: http://llvm.org/viewvc/llvm-project?rev=332801&view=rev Log: CodeGen: block capture shouldn't ICE
When a lambda capture captures a __block in the same statement, the compiler asserts out because isCapturedBy assumes that an Expr can only be a BlockExpr, StmtExpr, or if it's a Stmt then all the statement's children are expressions. That's wrong, we need to visit all sub-statements even if they're not expressions to see if they also capture. Fix this issue by pulling out the isCapturedBy logic to use RecursiveASTVisitor. <rdar://problem/39926584> Added: cfe/trunk/test/CodeGenCXX/block-capture.cpp Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=332801&r1=332800&r2=332801&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri May 18 21:21:26 2018 @@ -1244,17 +1244,30 @@ CodeGenFunction::EmitAutoVarAlloca(const return emission; } +static bool isCapturedBy(const VarDecl &, const Expr *); + +/// Determines whether the given __block variable is potentially +/// captured by the given statement. +static bool isCapturedBy(const VarDecl &Var, const Stmt *S) { + if (const Expr *E = dyn_cast<Expr>(S)) + return isCapturedBy(Var, E); + for (const Stmt *SubStmt : S->children()) + if (isCapturedBy(Var, SubStmt)) + return true; + return false; +} + /// Determines whether the given __block variable is potentially /// captured by the given expression. -static bool isCapturedBy(const VarDecl &var, const Expr *e) { +static bool isCapturedBy(const VarDecl &Var, const Expr *E) { // Skip the most common kinds of expressions that make // hierarchy-walking expensive. - e = e->IgnoreParenCasts(); + E = E->IgnoreParenCasts(); - if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) { - const BlockDecl *block = be->getBlockDecl(); - for (const auto &I : block->captures()) { - if (I.getVariable() == &var) + if (const BlockExpr *BE = dyn_cast<BlockExpr>(E)) { + const BlockDecl *Block = BE->getBlockDecl(); + for (const auto &I : Block->captures()) { + if (I.getVariable() == &Var) return true; } @@ -1262,19 +1275,19 @@ static bool isCapturedBy(const VarDecl & return false; } - if (const StmtExpr *SE = dyn_cast<StmtExpr>(e)) { + if (const StmtExpr *SE = dyn_cast<StmtExpr>(E)) { const CompoundStmt *CS = SE->getSubStmt(); for (const auto *BI : CS->body()) - if (const auto *E = dyn_cast<Expr>(BI)) { - if (isCapturedBy(var, E)) - return true; + if (const auto *BIE = dyn_cast<Expr>(BI)) { + if (isCapturedBy(Var, BIE)) + return true; } else if (const auto *DS = dyn_cast<DeclStmt>(BI)) { // special case declarations for (const auto *I : DS->decls()) { if (const auto *VD = dyn_cast<VarDecl>((I))) { const Expr *Init = VD->getInit(); - if (Init && isCapturedBy(var, Init)) + if (Init && isCapturedBy(Var, Init)) return true; } } @@ -1286,8 +1299,8 @@ static bool isCapturedBy(const VarDecl & return false; } - for (const Stmt *SubStmt : e->children()) - if (isCapturedBy(var, cast<Expr>(SubStmt))) + for (const Stmt *SubStmt : E->children()) + if (isCapturedBy(Var, SubStmt)) return true; return false; Added: cfe/trunk/test/CodeGenCXX/block-capture.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/block-capture.cpp?rev=332801&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/block-capture.cpp (added) +++ cfe/trunk/test/CodeGenCXX/block-capture.cpp Fri May 18 21:21:26 2018 @@ -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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits