This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]