From: Ian Lance Taylor Date: Mon, 15 Jan 2018 19:13:47 +0000 (+0000) Subject: compiler: make sure variables captured by defer closure live X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7c3bc15e4a2aba3eb43d59624d646bbdbff60a83;p=gcc.git compiler: make sure variables captured by defer closure live Local variables captured by the deferred closure need to be live until the function finishes, especially when the deferred function runs. In Function::build, for function that has a defer, we wrap the function body in a try block. So the backend sees the local variables only live in the try block, without knowing that they are needed also in the finally block where we invoke the deferred function. Fix this by creating top-level declarations for non-escaping address-taken locals when there is a defer. An example of miscompilation without this CL: func F(fn func()) { didPanic := true defer func() { println(didPanic) }() fn() didPanic = false } With escape analysis turned on, at optimization level -O1 or -O2, the store "didPanic = false" is elided by the backend's optimizer, presumably because it thinks "didPanic" is not live after the store, so the store is useless. Reviewed-on: https://go-review.googlesource.com/86241 From-SVN: r256706 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 7d87aa8ab53..8f5e4ba6866 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -4aa531c1765bba52848c6d71b9f57b593063d3ba +afac7d7bed07ebe3add1784aaa9547c4d660d0ed The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 579b8a3ee5e..e8bc7aea9bf 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -5568,6 +5568,7 @@ Function::build(Gogo* gogo, Named_object* named_function) // initial values. std::vector vars; std::vector var_inits; + std::vector var_decls_stmts; for (Bindings::const_definitions_iterator p = this->block_->bindings()->begin_definitions(); p != this->block_->bindings()->end_definitions(); @@ -5642,6 +5643,24 @@ Function::build(Gogo* gogo, Named_object* named_function) vars.push_back(bvar); var_inits.push_back(init); } + else if (this->defer_stack_ != NULL + && (*p)->is_variable() + && (*p)->var_value()->is_non_escaping_address_taken() + && !(*p)->var_value()->is_in_heap()) + { + // Local variable captured by deferred closure needs to be live + // until the end of the function. We create a top-level + // declaration for it. + // TODO: we don't need to do this if the variable is not captured + // by the defer closure. There is no easy way to check it here, + // so we do this for all address-taken variables for now. + Variable* var = (*p)->var_value(); + Temporary_statement* ts = + Statement::make_temporary(var->type(), NULL, var->location()); + ts->set_is_address_taken(); + var->set_toplevel_decl(ts); + var_decls_stmts.push_back(ts); + } } if (!gogo->backend()->function_set_parameters(this->fndecl_, param_vars)) { @@ -5661,7 +5680,7 @@ Function::build(Gogo* gogo, Named_object* named_function) { // Declare variables if necessary. Bblock* var_decls = NULL; - + std::vector var_decls_bstmt_list; Bstatement* defer_init = NULL; if (!vars.empty() || this->defer_stack_ != NULL) { @@ -5675,6 +5694,14 @@ Function::build(Gogo* gogo, Named_object* named_function) Translate_context dcontext(gogo, named_function, this->block_, var_decls); defer_init = this->defer_stack_->get_backend(&dcontext); + var_decls_bstmt_list.push_back(defer_init); + for (std::vector::iterator p = var_decls_stmts.begin(); + p != var_decls_stmts.end(); + ++p) + { + Bstatement* bstmt = (*p)->get_backend(&dcontext); + var_decls_bstmt_list.push_back(bstmt); + } } } @@ -5693,8 +5720,6 @@ Function::build(Gogo* gogo, Named_object* named_function) var_inits[i]); init.push_back(init_stmt); } - if (defer_init != NULL) - init.push_back(defer_init); Bstatement* var_init = gogo->backend()->statement_list(init); // Initialize all variables before executing this code block. @@ -5722,8 +5747,8 @@ Function::build(Gogo* gogo, Named_object* named_function) // we built one. if (var_decls != NULL) { - std::vector code_stmt_list(1, code_stmt); - gogo->backend()->block_add_statements(var_decls, code_stmt_list); + var_decls_bstmt_list.push_back(code_stmt); + gogo->backend()->block_add_statements(var_decls, var_decls_bstmt_list); code_stmt = gogo->backend()->block_statement(var_decls); }