This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gccgo] Destroy temporary variables when we leave a block
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 21 Jan 2010 16:34:36 -0800
- Subject: [gccgo] Destroy temporary variables when we leave a block
My earlier support for destroying temporary variables made little
sense and completely failed in some cases. This implementation
destroys temporary variables using a TRY_FINALLY clause, which is the
only reasonable way to do it. Actually the variables are not
destroyed in any meaningful sense; that is farther down the line of
the garbage collection work. This is an incremental forward step.
Committed to gccgo branch.
Ian
Index: gcc/go/gogo.cc
===================================================================
--- gcc/go/gogo.cc (revision 156057)
+++ gcc/go/gogo.cc (working copy)
@@ -1511,7 +1511,8 @@ Shortcuts::convert_shortcut(Block* enclo
Block* retblock = new Block(enclosing, loc);
retblock->set_end_location(loc);
- Temporary_statement* ts = Statement::make_temporary(Type::make_boolean_type(),
+ Temporary_statement* ts = Statement::make_temporary(retblock,
+ Type::make_boolean_type(),
left, loc);
retblock->add_statement(ts);
@@ -1685,24 +1686,12 @@ Order_eval::statement(Block* block, size
break;
source_location loc = (*pexpr)->location();
- Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
+ Temporary_statement* ts = Statement::make_temporary(block, NULL, *pexpr,
loc);
block->insert_statement_before(*pindex, ts);
++*pindex;
*pexpr = Expression::make_temporary_reference(ts, loc);
- Statement* sdestroy = Statement::destroy_temporary(ts);
- if (sdestroy != NULL)
- {
- // FIXME: This does the wrong thing for an expression in a
- // compound statement (if, switch, select) and also does the
- // wrong thing for a return statement. The destruction gets
- // put after the entire statement rather than after the
- // expression. The reference counting code needs to be
- // revamped anyhow.
- if (s->return_statement() == NULL)
- block->insert_statement_after(*pindex, sdestroy);
- }
}
return TRAVERSE_CONTINUE;
@@ -1737,13 +1726,10 @@ Order_eval::variable(Named_object* no)
{
Expression** pexpr = *p;
source_location loc = (*pexpr)->location();
- Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
- loc);
+ Temporary_statement* ts = Statement::make_temporary(var->preinit_block(),
+ NULL, *pexpr, loc);
var->add_preinit_statement(ts);
*pexpr = Expression::make_temporary_reference(ts, loc);
- Statement* sdestroy = Statement::destroy_temporary(ts);
- if (sdestroy != NULL)
- var->add_postinit_statement(sdestroy);
}
return TRAVERSE_SKIP_COMPONENTS;
@@ -2440,6 +2426,9 @@ Block::traverse(Traverse* traverse)
return TRAVERSE_EXIT;
}
+ // We don't traverse the final statements, which are only used for
+ // reference counting purposes.
+
return TRAVERSE_CONTINUE;
}
@@ -2480,11 +2469,10 @@ Block::may_fall_through() const
Variable::Variable(Type* type, Expression* init, bool is_global,
bool is_parameter, bool is_receiver,
source_location location)
- : type_(type), init_(init), preinit_(NULL), postinit_(NULL),
- location_(location), is_global_(is_global),
- is_parameter_(is_parameter), is_receiver_(is_receiver),
- is_varargs_parameter_(false), is_address_taken_(false),
- holds_only_args_(false), init_is_lowered_(false),
+ : type_(type), init_(init), preinit_(NULL), location_(location),
+ is_global_(is_global), is_parameter_(is_parameter),
+ is_receiver_(is_receiver), is_varargs_parameter_(false),
+ is_address_taken_(false), holds_only_args_(false), init_is_lowered_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
type_from_range_value_(false), type_from_chan_element_(false),
is_type_switch_var_(false)
@@ -2508,11 +2496,6 @@ Variable::traverse_expression(Traverse*
if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
- if (this->postinit_ != NULL)
- {
- if (this->postinit_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
return TRAVERSE_CONTINUE;
}
@@ -2529,28 +2512,25 @@ Variable::lower_init_expression(Gogo* go
}
}
-// Add a statement to be run before the initialization expression.
+// Get the preinit block.
-void
-Variable::add_preinit_statement(Statement* s)
+Block*
+Variable::preinit_block()
{
gcc_assert(this->is_global_);
if (this->preinit_ == NULL)
- this->preinit_ = new Block(NULL, s->location());
- this->preinit_->add_statement(s);
- this->preinit_->set_end_location(s->location());
+ this->preinit_ = new Block(NULL, this->location());
+ return this->preinit_;
}
-// Add a statement to be run after the initialization expression.
+// Add a statement to be run before the initialization expression.
void
-Variable::add_postinit_statement(Statement* s)
+Variable::add_preinit_statement(Statement* s)
{
- gcc_assert(this->is_global_);
- if (this->postinit_ == NULL)
- this->postinit_ = new Block(NULL, s->location());
- this->postinit_->add_statement(s);
- this->postinit_->set_end_location(s->location());
+ Block* b = this->preinit_block();
+ b->add_statement(s);
+ b->set_end_location(s->location());
}
// In an assignment which sets a variable to a tuple of EXPR, return
Index: gcc/go/gogo.h
===================================================================
--- gcc/go/gogo.h (revision 156050)
+++ gcc/go/gogo.h (working copy)
@@ -1044,21 +1044,16 @@ class Variable
init() const
{ return this->init_; }
- // Return whether there are preinit or postinit expressions.
+ // Return whether there are any preinit statements.
bool
- has_pre_or_post_init() const
- { return this->preinit_ != NULL || this->postinit_ != NULL; }
+ has_pre_init() const
+ { return this->preinit_ != NULL; }
- // Return the preinit expressions if any.
+ // Return the preinit statements if any.
Block*
preinit() const
{ return this->preinit_; }
- // Return the postinit expressions if any.
- Block*
- postinit() const
- { return this->postinit_; }
-
// Return whether this is a global variable.
bool
is_global() const
@@ -1118,16 +1113,16 @@ class Variable
set_init(Expression* init)
{ this->init_ = init; }
+ // Get the preinit block, a block of statements to be run before the
+ // initialization expression.
+ Block*
+ preinit_block();
+
// Add a statement to be run before the initialization expression.
// This is only used for global variables.
void
add_preinit_statement(Statement*);
- // Add a statement to be run after the initialization expression.
- // This is only used for global variables.
- void
- add_postinit_statement(Statement*);
-
// Lower the initialization expression after parsing is complete.
void
lower_init_expression(Gogo*);
@@ -1197,11 +1192,16 @@ class Variable
set_holds_only_args()
{ this->holds_only_args_ = true; }
- // Get the initial value of the variable as a tree. Sets *PREINIT
- // and *POSTINIT to statements to run before and after the
- // initialization.
+ // Get the initial value of the variable as a tree. This may only
+ // be called if has_pre_init() returns false.
+ tree
+ get_init_tree(Gogo*, Named_object* function);
+
+ // Return a series of statements which sets the value of the
+ // variable in DECL. This should only be called is has_pre_init()
+ // returns true. DECL may be NULL for a sink variable.
tree
- get_init_tree(Gogo*, Named_object* function, tree* preinit, tree* postinit);
+ get_init_block(Gogo*, Named_object* function, tree decl);
// Export the variable.
void
@@ -1232,8 +1232,6 @@ class Variable
Expression* init_;
// Statements to run before the init statement.
Block* preinit_;
- // Statements to run after the init statement.
- Block* postinit_;
// Location of variable definition.
source_location location_;
// Whether this is a global variable.
Index: gcc/go/statements.cc
===================================================================
--- gcc/go/statements.cc (revision 156096)
+++ gcc/go/statements.cc (working copy)
@@ -249,12 +249,9 @@ Variable_declaration_statement::do_get_t
return error_mark_node;
Variable* variable = this->var_->var_value();
- tree preinit, postinit;
- tree init = variable->get_init_tree(context->gogo(), context->function(),
- &preinit, &postinit);
+ tree init = variable->get_init_tree(context->gogo(), context->function());
if (init == error_mark_node)
return error_mark_node;
- gcc_assert(preinit == NULL_TREE && postinit == NULL_TREE);
// If this variable lives on the heap, we need to allocate it now.
if (!variable->is_in_heap())
@@ -398,13 +395,16 @@ Temporary_statement::do_get_tree(Transla
return this->build_stmt_1(DECL_EXPR, this->decl_);
}
-// Make and initialize a temporary variable.
+// Make and initialize a temporary variable in BLOCK.
Temporary_statement*
-Statement::make_temporary(Type* type, Expression* init,
+Statement::make_temporary(Block* block, Type* type, Expression* init,
source_location location)
{
- return new Temporary_statement(type, init, location);
+ Temporary_statement* ret = new Temporary_statement(type, init, location);
+ if (ret->type()->has_refcounted_component())
+ block->add_final_statement(Statement::destroy_temporary(ret));
+ return ret;
}
// Destroy a temporary variable.
@@ -421,16 +421,13 @@ class Destroy_temporary_statement : publ
protected:
int
do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
+ { gcc_unreachable(); }
bool
- do_traverse_assignments(Traverse_assignments* tassign)
- {
- // Destroying a temporary is like assigning an empty value to it.
- tassign->assignment(&this->ref_, NULL);
- return true;
- }
+ do_traverse_assignments(Traverse_assignments*)
+ { gcc_unreachable(); }
+ // FIXME.
tree
do_get_tree(Translate_context* context)
{ return this->ref_->get_tree(context); }
@@ -445,8 +442,7 @@ class Destroy_temporary_statement : publ
Statement*
Statement::destroy_temporary(Temporary_statement* statement)
{
- if (!statement->type()->has_refcounted_component())
- return NULL;
+ gcc_assert(statement->type()->has_refcounted_component());
return new Destroy_temporary_statement(statement);
}
@@ -621,7 +617,8 @@ Move_ordered_evals::expression(Expressio
if ((*pexpr)->must_eval_in_order())
{
source_location loc = (*pexpr)->location();
- Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
+ Temporary_statement* temp = Statement::make_temporary(this->block_,
+ NULL, *pexpr, loc);
this->block_->add_statement(temp);
*pexpr = Expression::make_temporary_reference(temp, loc);
}
@@ -831,7 +828,7 @@ Tuple_assignment_statement::do_lower(Gog
continue;
}
- Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
+ Temporary_statement* temp = Statement::make_temporary(b, (*plhs)->type(),
*prhs, loc);
b->add_statement(temp);
temps.push_back(temp);
@@ -943,17 +940,17 @@ Tuple_map_assignment_statement::do_lower
// var key_temp KEY_TYPE = MAP_INDEX
Temporary_statement* key_temp =
- Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
+ Statement::make_temporary(b, map_type->key_type(), map_index->index(), loc);
b->add_statement(key_temp);
// var val_temp VAL_TYPE
Temporary_statement* val_temp =
- Statement::make_temporary(map_type->val_type(), NULL, loc);
+ Statement::make_temporary(b, map_type->val_type(), NULL, loc);
b->add_statement(val_temp);
// var present_temp bool
Temporary_statement* present_temp =
- Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+ Statement::make_temporary(b, Type::lookup_bool_type(), NULL, loc);
b->add_statement(present_temp);
// func mapaccess2(hmap map[k]v, key *k, val *v) bool
@@ -1083,19 +1080,19 @@ Map_assignment_statement::do_lower(Gogo*
// Evaluate the map first to get order of evaluation right.
// map_temp := m // we are evaluating m[k] = v, p
- Temporary_statement* map_temp = Statement::make_temporary(map_type,
+ Temporary_statement* map_temp = Statement::make_temporary(b, map_type,
map_index->map(),
loc);
b->add_statement(map_temp);
// var key_temp MAP_KEY_TYPE = k
Temporary_statement* key_temp =
- Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
+ Statement::make_temporary(b, map_type->key_type(), map_index->index(), loc);
b->add_statement(key_temp);
// var val_temp MAP_VAL_TYPE = v
Temporary_statement* val_temp =
- Statement::make_temporary(map_type->val_type(), this->val_, loc);
+ Statement::make_temporary(b, map_type->val_type(), this->val_, loc);
b->add_statement(val_temp);
// func mapassign2(hmap map[k]v, key *k, val *v, p)
@@ -1215,12 +1212,12 @@ Tuple_receive_assignment_statement::do_l
// var val_temp ELEMENT_TYPE
Temporary_statement* val_temp =
- Statement::make_temporary(channel_type->element_type(), NULL, loc);
+ Statement::make_temporary(b, channel_type->element_type(), NULL, loc);
b->add_statement(val_temp);
// var success_temp bool
Temporary_statement* success_temp =
- Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+ Statement::make_temporary(b, Type::lookup_bool_type(), NULL, loc);
b->add_statement(success_temp);
// func chanrecv2(c chan T, val *T) bool
@@ -1455,8 +1452,8 @@ Tuple_type_guard_assignment_statement::l
source_location loc = this->location();
// var val_temp TYPE
- Temporary_statement* val_temp = Statement::make_temporary(this->type_, NULL,
- loc);
+ Temporary_statement* val_temp = Statement::make_temporary(b, this->type_,
+ NULL, loc);
b->add_statement(val_temp);
// func ifaceI2T2(*descriptor, *interface, *T) bool
@@ -3696,7 +3693,7 @@ Type_switch_statement::do_lower(Gogo*, B
// var descriptor_temp DESCRIPTOR_TYPE
Type* descriptor_type = Type::make_type_descriptor_ptr_type();
Temporary_statement* descriptor_temp =
- Statement::make_temporary(descriptor_type, NULL, loc);
+ Statement::make_temporary(b, descriptor_type, NULL, loc);
b->add_statement(descriptor_temp);
if (val_type->interface_type() == NULL)
@@ -3822,7 +3819,7 @@ Select_clauses::Select_clause::lower(Blo
source_location loc = this->location_;
// Evaluate the channel before the select statement.
- Temporary_statement* channel_temp = Statement::make_temporary(NULL,
+ Temporary_statement* channel_temp = Statement::make_temporary(b, NULL,
this->channel_,
loc);
b->add_statement(channel_temp);
@@ -3833,7 +3830,7 @@ Select_clauses::Select_clause::lower(Blo
Temporary_statement* val_temp = NULL;
if (this->is_send_)
{
- val_temp = Statement::make_temporary(NULL, this->val_, loc);
+ val_temp = Statement::make_temporary(b, NULL, this->val_, loc);
b->add_statement(val_temp);
}
@@ -4397,18 +4394,20 @@ For_range_statement::do_lower(Gogo* gogo
range_object = ve->named_object();
else
{
- range_temp = Statement::make_temporary(NULL, this->range_, loc);
+ range_temp = Statement::make_temporary(temp_block, NULL, this->range_,
+ loc);
temp_block->add_statement(range_temp);
}
- Temporary_statement* index_temp = Statement::make_temporary(index_type,
+ Temporary_statement* index_temp = Statement::make_temporary(temp_block,
+ index_type,
NULL, loc);
temp_block->add_statement(index_temp);
Temporary_statement* value_temp = NULL;
if (this->value_var_ != NULL)
{
- value_temp = Statement::make_temporary(value_type, NULL, loc);
+ value_temp = Statement::make_temporary(temp_block, value_type, NULL, loc);
temp_block->add_statement(value_temp);
}
@@ -4548,7 +4547,8 @@ For_range_statement::lower_range_array(G
Expression* ref = this->make_range_ref(range_object, range_temp, loc);
Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
- Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
+ Temporary_statement* len_temp = Statement::make_temporary(init,
+ index_temp->type(),
len_call, loc);
init->add_statement(len_temp);
@@ -4637,7 +4637,7 @@ For_range_statement::lower_range_string(
Block* init = new Block(enclosing, loc);
Temporary_statement* next_index_temp =
- Statement::make_temporary(index_temp->type(), NULL, loc);
+ Statement::make_temporary(init, index_temp->type(), NULL, loc);
init->add_statement(next_index_temp);
mpz_t zval;
@@ -4822,7 +4822,8 @@ For_range_statement::lower_range_map(Gog
Type* map_iteration_type = Type::make_array_type(ptr_type, iexpr);
Type* map_iteration_ptr = Type::make_pointer_type(map_iteration_type);
- Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
+ Temporary_statement* hiter = Statement::make_temporary(init,
+ map_iteration_type,
NULL, loc);
init->add_statement(hiter);
@@ -5027,8 +5028,6 @@ Statement::make_for_range_statement(Expr
return new For_range_statement(index_var, value_var, range, location);
}
-// Return the tree for looping over an array.
-
// An assignment to an entry in the reference count queue.
class Refcount_queue_assignment_statement : public Statement
Index: gcc/go/gogo-tree.cc
===================================================================
--- gcc/go/gogo-tree.cc (revision 155845)
+++ gcc/go/gogo-tree.cc (working copy)
@@ -360,16 +360,13 @@ Find_var::expression(Expression** pexpr)
// Return true if EXPR refers to VAR.
static bool
-expression_requires(Expression* expr, Block* preinit, Block* postinit,
- Named_object* var)
+expression_requires(Expression* expr, Block* preinit, Named_object* var)
{
Find_var::Seen_objects seen_objects;
Find_var find_var(var, &seen_objects);
Expression::traverse(&expr, &find_var);
if (preinit != NULL)
preinit->traverse(&find_var);
- if (postinit != NULL)
- postinit->traverse(&find_var);
return find_var.found();
}
@@ -436,7 +433,6 @@ sort_var_inits(Var_inits* var_inits)
Named_object* var = p1->var();
Expression* init = var->var_value()->init();
Block* preinit = var->var_value()->preinit();
- Block* postinit = var->var_value()->postinit();
// Start walking through the list to see which variables VAR
// needs to wait for. We can skip P1->WAITING variables--that
@@ -448,12 +444,11 @@ sort_var_inits(Var_inits* var_inits)
for (; p2 != var_inits->end(); ++p2)
{
- if (expression_requires(init, preinit, postinit, p2->var()))
+ if (expression_requires(init, preinit, p2->var()))
{
// Check for cycles.
if (expression_requires(p2->var()->var_value()->init(),
p2->var()->var_value()->preinit(),
- p2->var()->var_value()->postinit(),
var))
{
std::string n1 = Gogo::unpack_hidden_name(var->name());
@@ -485,7 +480,7 @@ sort_var_inits(Var_inits* var_inits)
// VAR does not depends upon any other initialization expressions.
// Check for a loop of VAR on itself.
- if (expression_requires(init, preinit, postinit, var))
+ if (expression_requires(init, preinit, var))
error_at(var->location(),
"initialization expression for %qs depends upon itself",
Gogo::unpack_hidden_name(var->name()).c_str());
@@ -522,10 +517,11 @@ Gogo::write_globals()
p != bindings->end_definitions();
++p, ++i)
{
- gcc_assert(!(*p)->is_type_declaration()
- && !(*p)->is_function_declaration());
+ Named_object* no = *p;
+
+ gcc_assert(!no->is_type_declaration() && !no->is_function_declaration());
// There is nothing to do for a package.
- if ((*p)->is_package())
+ if (no->is_package())
{
--i;
--count;
@@ -534,7 +530,7 @@ Gogo::write_globals()
// There is nothing to do for an object which was imported from
// a different package into the global scope.
- if ((*p)->package() != NULL)
+ if (no->package() != NULL)
{
--i;
--count;
@@ -543,11 +539,11 @@ Gogo::write_globals()
// Don't try to output anything for constants which still have
// abstract type.
- if ((*p)->is_const())
+ if (no->is_const())
{
- Type* type = (*p)->const_value()->type();
+ Type* type = no->const_value()->type();
if (type == NULL)
- type = (*p)->const_value()->expr()->type();
+ type = no->const_value()->expr()->type();
if (type->is_abstract())
{
--i;
@@ -556,7 +552,7 @@ Gogo::write_globals()
}
}
- vec[i] = (*p)->get_tree(this, NULL);
+ vec[i] = no->get_tree(this, NULL);
if (vec[i] == error_mark_node)
{
@@ -570,12 +566,32 @@ Gogo::write_globals()
// initialization in an initialization function.
if (TREE_CODE(vec[i]) == VAR_DECL)
{
- gcc_assert((*p)->is_variable());
+ gcc_assert(no->is_variable());
+
+ // Check for a sink variable, which may be used to run
+ // an initializer purely for its side effects.
+ bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
- if ((*p)->var_value()->has_pre_or_post_init())
+ tree var_init_tree = NULL_TREE;
+ if (!no->var_value()->has_pre_init())
+ {
+ tree init = no->var_value()->get_init_tree(this, NULL);
+ if (init == error_mark_node)
+ gcc_assert(errorcount || sorrycount);
+ else if (init == NULL_TREE)
+ ;
+ else if (TREE_CONSTANT(init))
+ DECL_INITIAL(vec[i]) = init;
+ else if (is_sink)
+ var_init_tree = init;
+ else
+ var_init_tree = fold_build2_loc(no->location(), MODIFY_EXPR,
+ void_type_node, vec[i], init);
+ }
+ else
{
// We are going to create temporary variables which
- // means we need an fndecl.
+ // means that we need an fndecl.
if (init_fndecl == NULL_TREE)
init_fndecl = this->initialization_function_decl();
current_function_decl = init_fndecl;
@@ -583,58 +599,22 @@ Gogo::write_globals()
push_struct_function(init_fndecl);
else
push_cfun(DECL_STRUCT_FUNCTION(init_fndecl));
- }
- tree preinit, postinit;
- tree init = (*p)->var_value()->get_init_tree(this, NULL, &preinit,
- &postinit);
- if (init == NULL_TREE)
- gcc_assert(preinit == NULL_TREE && postinit == NULL_TREE);
- else if (init == error_mark_node)
- gcc_assert(errorcount || sorrycount);
- else if ((*p)->name()[0] == '_' && (*p)->name()[1] == '.')
- {
- // This is a dummy variable created to run a global
- // initializer. We don't want to actually output the
- // variable, just the initializer.
- --i;
- --count;
- gcc_assert((*p)->var_value()->init() != NULL);
- if (!TREE_CONSTANT(init)
- || preinit != NULL_TREE
- || postinit != NULL_TREE)
- {
- if (preinit != NULL_TREE)
- init = build2(COMPOUND_EXPR, void_type_node, preinit, init);
- if (postinit != NULL_TREE)
- init = build2(COMPOUND_EXPR, void_type_node, init,
- postinit);
- var_inits.push_back(Var_init(*p, init));
- }
- }
- else if (TREE_CONSTANT(init)
- && preinit == NULL_TREE
- && postinit == NULL_TREE)
- DECL_INITIAL(vec[i]) = init;
- else
- {
- tree set = fold_build2(MODIFY_EXPR, void_type_node, vec[i], init);
- if (preinit != NULL_TREE)
- set = build2(COMPOUND_EXPR, void_type_node, preinit, set);
- if (postinit != NULL_TREE)
- set = build2(COMPOUND_EXPR, void_type_node, set, postinit);
- Expression* vinit = (*p)->var_value()->init();
- if (vinit == NULL)
- append_to_statement_list(set, &init_stmt_list);
- else
- var_inits.push_back(Var_init(*p, set));
- }
+ tree var_decl = is_sink ? NULL_TREE : vec[i];
+ var_init_tree = no->var_value()->get_init_block(this, NULL,
+ var_decl);
- if ((*p)->var_value()->has_pre_or_post_init())
- {
current_function_decl = NULL_TREE;
pop_cfun();
}
+
+ if (var_init_tree != NULL_TREE)
+ {
+ if (no->var_value()->init() == NULL)
+ append_to_statement_list(var_init_tree, &init_stmt_list);
+ else
+ var_inits.push_back(Var_init(no, var_init_tree));
+ }
}
}
@@ -969,34 +949,57 @@ Named_object::get_tree(Gogo* gogo, Named
// initial value as though it were always stored in the stack.
tree
-Variable::get_init_tree(Gogo* gogo, Named_object* function, tree* preinit,
- tree* postinit)
+Variable::get_init_tree(Gogo* gogo, Named_object* function)
{
- *preinit = NULL_TREE;
- *postinit = NULL_TREE;
+ gcc_assert(this->preinit_ == NULL);
if (this->init_ == NULL)
{
gcc_assert(!this->is_parameter_);
- gcc_assert(this->preinit_ == NULL && this->postinit_ == NULL);
return this->type_->get_init_tree(gogo, this->is_global_);
}
else
{
Translate_context context(gogo, function, NULL, NULL_TREE);
+ tree rhs_tree = this->init_->get_tree(&context);
+ return Expression::convert_for_assignment(&context, this->type(),
+ this->init_->type(),
+ rhs_tree, this->location());
+ }
+}
- if (this->preinit_ != NULL)
- append_to_statement_list(this->preinit_->get_tree(&context), preinit);
+// Get the initial value of a variable when a block is required.
+// VAR_DECL is the decl to set; it may be NULL for a sink variable.
- tree rhs_tree = this->init_->get_tree(&context);
- tree val = Expression::convert_for_assignment(&context, this->type(),
- this->init_->type(),
- rhs_tree, this->location_);
+tree
+Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
+{
+ gcc_assert(this->preinit_ != NULL);
- if (this->postinit_ != NULL)
- append_to_statement_list(this->postinit_->get_tree(&context), postinit);
+ // We want to add the variable assignment to the end of the preinit
+ // block. The preinit block may have a TRY_FINALLY_EXPR; if it
+ // does, we want to add to the end of the regular statements.
- return val;
+ Translate_context context(gogo, function, NULL, NULL_TREE);
+ tree block_tree = this->preinit_->get_tree(&context);
+ gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
+ tree statements = BIND_EXPR_BODY(block_tree);
+ if (TREE_CODE(statements) == TRY_FINALLY_EXPR)
+ statements = TREE_OPERAND(statements, 0);
+
+ tree rhs_tree = this->init_->get_tree(&context);
+ if (var_decl == NULL_TREE)
+ append_to_statement_list(rhs_tree, &statements);
+ else
+ {
+ tree val = Expression::convert_for_assignment(&context, this->type(),
+ this->init_->type(),
+ rhs_tree, this->location());
+ tree set = fold_build2_loc(this->location(), MODIFY_EXPR, void_type_node,
+ var_decl, val);
+ append_to_statement_list(set, &statements);
}
+
+ return block_tree;
}
// Get a tree for a function decl.
Index: gcc/go/statements.h
===================================================================
--- gcc/go/statements.h (revision 156082)
+++ gcc/go/statements.h (working copy)
@@ -129,12 +129,14 @@ class Statement
make_variable_declaration(Named_object*);
// Make a statement which creates a temporary variable and
- // initializes it to an expression. References to the temporary
+ // initializes it to an expression. The block is used if the
+ // temporary variable has to be explicitly destroyed; the variable
+ // must still be added to the block. References to the temporary
// variable may be constructed using make_temporary_reference.
- // Either or the type or the initialization expression may be NULL,
- // but not both.
+ // Either the type or the initialization expression may be NULL, but
+ // not both.
static Temporary_statement*
- make_temporary(Type*, Expression*, source_location);
+ make_temporary(Block*, Type*, Expression*, source_location);
// Make a statement which destroys a temporary variable. This may
// return NULL if there is nothing to do.