public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Go patch committed: Use temps for calls with multiple results
@ 2011-08-01  1:45 Ian Lance Taylor
  0 siblings, 0 replies; only message in thread
From: Ian Lance Taylor @ 2011-08-01  1:45 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 580 bytes --]

This patch changes the Go frontend such that the representation of calls
with multiple results uses temporary variables rather than relying on
expanding such calls while expanding Call_multiple_result expressions.
Unfortunately I can't yet get rid of Call_multiple_result expressions as
they are needed to represent the point of the call in order to ensure
that the call is executed in the right order.  Maybe later.  In the
meantime this is a small cleanup and simplification of the IR.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 60899 bytes --]

diff -r fbc7499fcdc7 go/expressions.cc
--- a/go/expressions.cc	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/expressions.cc	Sun Jul 31 11:16:19 2011 -0700
@@ -926,7 +926,8 @@
 // if necessary.
 
 Expression*
-Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
+Var_expression::do_lower(Gogo* gogo, Named_object* function,
+			 Statement_inserter* inserter, int)
 {
   if (this->variable_->is_variable())
     {
@@ -935,8 +936,11 @@
       // reference to a variable which is local to an enclosing
       // function will be a reference to a field in a closure.
       if (var->is_global())
-	function = NULL;
-      var->lower_init_expression(gogo, function);
+	{
+	  function = NULL;
+	  inserter = NULL;
+	}
+      var->lower_init_expression(gogo, function, inserter);
     }
   return this;
 }
@@ -1061,7 +1065,9 @@
   // that here by adding a type cast.  We need to use base() to push
   // the circularity down one level.
   tree ret = var_to_tree(bvar);
-  if (POINTER_TYPE_P(TREE_TYPE(ret)) && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
+  if (!this->is_lvalue_
+      && POINTER_TYPE_P(TREE_TYPE(ret))
+      && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
     {
       Btype* type_btype = this->type()->base()->get_backend(context->gogo());
       tree type_tree = type_to_tree(type_btype);
@@ -1072,7 +1078,7 @@
 
 // Make a reference to a temporary variable.
 
-Expression*
+Temporary_reference_expression*
 Expression::make_temporary_reference(Temporary_statement* statement,
 				     source_location location)
 {
@@ -1302,7 +1308,7 @@
 // Lower a reference to an unknown name.
 
 Expression*
-Unknown_expression::do_lower(Gogo*, Named_object*, int)
+Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
 {
   source_location location = this->location();
   Named_object* no = this->named_object_;
@@ -2394,7 +2400,7 @@
   do_traverse(Traverse*);
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
   do_is_constant() const
@@ -2462,7 +2468,8 @@
 // predeclared constant iota into an integer value.
 
 Expression*
-Const_expression::do_lower(Gogo* gogo, Named_object*, int iota_value)
+Const_expression::do_lower(Gogo* gogo, Named_object*,
+			   Statement_inserter*, int iota_value)
 {
   if (this->constant_->const_value()->expr()->classification()
       == EXPRESSION_IOTA)
@@ -2931,7 +2938,7 @@
 
  protected:
   Expression*
-  do_lower(Gogo*, Named_object*, int)
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int)
   { go_unreachable(); }
 
   // There should only ever be one of these.
@@ -2988,7 +2995,7 @@
   do_traverse(Traverse* traverse);
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
   do_is_constant() const
@@ -3057,7 +3064,8 @@
 // Convert to a constant at lowering time.
 
 Expression*
-Type_conversion_expression::do_lower(Gogo*, Named_object*, int)
+Type_conversion_expression::do_lower(Gogo*, Named_object*,
+				     Statement_inserter*, int)
 {
   Type* type = this->type_;
   Expression* val = this->expr_;
@@ -3753,7 +3761,7 @@
   { return Expression::traverse(&this->expr_, traverse); }
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
   do_is_constant() const;
@@ -3808,7 +3816,7 @@
 // instead.
 
 Expression*
-Unary_expression::do_lower(Gogo*, Named_object*, int)
+Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
 {
   source_location loc = this->location();
   Operator op = this->op_;
@@ -5137,7 +5145,7 @@
 // constants.
 
 Expression*
-Binary_expression::do_lower(Gogo*, Named_object*, int)
+Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
 {
   source_location location = this->location();
   Operator op = this->op_;
@@ -6656,7 +6664,7 @@
  protected:
   // This overrides Call_expression::do_lower.
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
   do_is_constant() const;
@@ -6864,7 +6872,8 @@
 // specific expressions.  We also convert to a constant if we can.
 
 Expression*
-Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
+Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
+				  Statement_inserter* inserter, int)
 {
   if (this->classification() == EXPRESSION_ERROR)
     return this;
@@ -6974,7 +6983,7 @@
 	  this->set_is_error();
 	  return this;
 	}
-      return this->lower_varargs(gogo, function, slice_type, 2);
+      return this->lower_varargs(gogo, function, inserter, slice_type, 2);
     }
 
   return this;
@@ -8553,9 +8562,10 @@
 // Lower a call statement.
 
 Expression*
-Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
-{
-  // A type case can look like a function call.
+Call_expression::do_lower(Gogo* gogo, Named_object* function,
+			  Statement_inserter* inserter, int)
+{
+  // A type cast can look like a function call.
   if (this->fn_->is_type_expression()
       && this->args_ != NULL
       && this->args_->size() == 1)
@@ -8597,6 +8607,29 @@
 	}
     }
 
+  // If this call returns multiple results, create a temporary
+  // variable for each result.
+  size_t rc = this->result_count();
+  if (rc > 1 && this->results_ == NULL)
+    {
+      std::vector<Temporary_statement*>* temps =
+	new std::vector<Temporary_statement*>;
+      temps->reserve(rc);
+      const Typed_identifier_list* results =
+	this->fn_->type()->function_type()->results();
+      for (Typed_identifier_list::const_iterator p = results->begin();
+	   p != results->end();
+	   ++p)
+	{
+	  Temporary_statement* temp = Statement::make_temporary(p->type(),
+								NULL,
+								p->location());
+	  inserter->insert(temp);
+	  temps->push_back(temp);
+	}
+      this->results_ = temps;
+    }
+
   // Handle a call to a varargs function by packaging up the extra
   // parameters.
   if (this->fn_->type()->function_type() != NULL
@@ -8606,7 +8639,7 @@
       const Typed_identifier_list* parameters = fntype->parameters();
       go_assert(parameters != NULL && !parameters->empty());
       Type* varargs_type = parameters->back().type();
-      return this->lower_varargs(gogo, function, varargs_type,
+      return this->lower_varargs(gogo, function, inserter, varargs_type,
 				 parameters->size());
     }
 
@@ -8622,6 +8655,7 @@
 
 Expression*
 Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
+			       Statement_inserter* inserter,
 			       Type* varargs_type, size_t param_count)
 {
   if (this->varargs_are_lowered_)
@@ -8702,13 +8736,12 @@
 
   // Lower all the new subexpressions.
   Expression* ret = this;
-  gogo->lower_expression(function, &ret);
+  gogo->lower_expression(function, inserter, &ret);
   go_assert(ret == this);
   return ret;
 }
 
-// Get the function type.  Returns NULL if we don't know the type.  If
-// this returns NULL, and if_ERROR is true, issues an error.
+// Get the function type.  This can return NULL in error cases.
 
 Function_type*
 Call_expression::get_function_type() const
@@ -8729,6 +8762,16 @@
   return fntype->results()->size();
 }
 
+// Return the temporary which holds a result.
+
+Temporary_statement*
+Call_expression::result(size_t i) const
+{
+  go_assert(this->results_ != NULL
+	    && this->results_->size() > i);
+  return (*this->results_)[i];
+}
+
 // Return whether this is a call to the predeclared function recover.
 
 bool
@@ -8759,6 +8802,21 @@
   go_unreachable();
 }
 
+// We have found an error with this call expression; return true if
+// we should report it.
+
+bool
+Call_expression::issue_error()
+{
+  if (this->issued_error_)
+    return false;
+  else
+    {
+      this->issued_error_ = true;
+      return true;
+    }
+}
+
 // Get the type.
 
 Type*
@@ -8941,15 +8999,12 @@
 
 // Return whether we have to use a temporary variable to ensure that
 // we evaluate this call expression in order.  If the call returns no
-// results then it will inevitably be executed last.  If the call
-// returns more than one result then it will be used with Call_result
-// expressions.  So we only have to use a temporary variable if the
-// call returns exactly one result.
+// results then it will inevitably be executed last.
 
 bool
 Call_expression::do_must_eval_in_order() const
 {
-  return this->result_count() == 1;
+  return this->result_count() > 0;
 }
 
 // Get the function and the first argument to use when calling a bound
@@ -9193,16 +9248,56 @@
       ret = build1(NOP_EXPR, rettype, ret);
     }
 
-  // If there is more than one result, we will refer to the call
-  // multiple times.
-  if (fntype->results() != NULL && fntype->results()->size() > 1)
-    ret = save_expr(ret);
+  if (this->results_ != NULL)
+    ret = this->set_results(context, ret);
 
   this->tree_ = ret;
 
   return ret;
 }
 
+// Set the result variables if this call returns multiple results.
+
+tree
+Call_expression::set_results(Translate_context* context, tree call_tree)
+{
+  tree stmt_list = NULL_TREE;
+
+  call_tree = save_expr(call_tree);
+
+  if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
+    {
+      go_assert(saw_errors());
+      return call_tree;
+    }
+
+  source_location loc = this->location();
+  tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
+  size_t rc = this->result_count();
+  for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field))
+    {
+      go_assert(field != NULL_TREE);
+
+      Temporary_statement* temp = this->result(i);
+      Temporary_reference_expression* ref =
+	Expression::make_temporary_reference(temp, loc);
+      ref->set_is_lvalue();
+      tree temp_tree = ref->get_tree(context);
+      if (temp_tree == error_mark_node)
+	continue;
+
+      tree val_tree = build3_loc(loc, COMPONENT_REF, TREE_TYPE(field),
+				 call_tree, field, NULL_TREE);
+      tree set_tree = build2_loc(loc, MODIFY_EXPR, void_type_node, temp_tree,
+				 val_tree);
+
+      append_to_statement_list(set_tree, &stmt_list);
+    }
+  go_assert(field == NULL_TREE);
+
+  return save_expr(stmt_list);
+}
+
 // Make a call expression.
 
 Call_expression*
@@ -9292,10 +9387,11 @@
       return Type::make_error_type();
     }
   const Typed_identifier_list* results = fntype->results();
-  if (results == NULL)
-    {
-      this->report_error(_("number of results does not match "
-			   "number of values"));
+  if (results == NULL || results->size() < 2)
+    {
+      if (ce->issue_error())
+	this->report_error(_("number of results does not match "
+			     "number of values"));
       return Type::make_error_type();
     }
   Typed_identifier_list::const_iterator pr = results->begin();
@@ -9307,8 +9403,9 @@
     }
   if (pr == results->end())
     {
-      this->report_error(_("number of results does not match "
-			   "number of values"));
+      if (ce->issue_error())
+	this->report_error(_("number of results does not match "
+			     "number of values"));
       return Type::make_error_type();
     }
   return pr->type();
@@ -9332,27 +9429,18 @@
   this->call_->determine_type_no_context();
 }
 
-// Return the tree.
+// Return the tree.  We just refer to the temporary set by the call
+// expression.  We don't do this at lowering time because it makes it
+// hard to evaluate the call at the right time.
 
 tree
 Call_result_expression::do_get_tree(Translate_context* context)
 {
-  tree call_tree = this->call_->get_tree(context);
-  if (call_tree == error_mark_node)
-    return error_mark_node;
-  if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
-    {
-      go_assert(saw_errors());
-      return error_mark_node;
-    }
-  tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
-  for (unsigned int i = 0; i < this->index_; ++i)
-    {
-      go_assert(field != NULL_TREE);
-      field = DECL_CHAIN(field);
-    }
-  go_assert(field != NULL_TREE);
-  return build3(COMPONENT_REF, TREE_TYPE(field), call_tree, field, NULL_TREE);
+  Call_expression* ce = this->call_->call_expression();
+  go_assert(ce != NULL);
+  Temporary_statement* ts = ce->result(this->index_);
+  Expression* ref = Expression::make_temporary_reference(ts, this->location());
+  return ref->get_tree(context);
 }
 
 // Make a reference to a single result of a call which returns
@@ -9383,7 +9471,7 @@
 // expression into an array index, a string index, or a map index.
 
 Expression*
-Index_expression::do_lower(Gogo*, Named_object*, int)
+Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
 {
   source_location location = this->location();
   Expression* left = this->left_;
@@ -10542,7 +10630,7 @@
   { return Expression::traverse(&this->left_, traverse); }
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   Expression*
   do_copy()
@@ -10565,7 +10653,8 @@
 // hand side.
 
 Expression*
-Selector_expression::do_lower(Gogo* gogo, Named_object*, int)
+Selector_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*,
+			      int)
 {
   Expression* left = this->left_;
   if (left->is_type_expression())
@@ -10734,6 +10823,8 @@
 	}
     }
 
+  gogo->start_block(location);
+
   Call_expression* call = Expression::make_call(bm, args,
 						method_type->is_varargs(),
 						location);
@@ -10756,6 +10847,13 @@
     }
   gogo->add_statement(s);
 
+  Block* b = gogo->finish_block(location);
+
+  gogo->add_block(b, location);
+
+  // Lower the call in case there are multiple results.
+  gogo->lower_block(no, b);
+
   gogo->finish_function(location);
 
   return Expression::make_func_reference(no, NULL, location);
@@ -11860,7 +11958,7 @@
   do_traverse(Traverse* traverse);
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   Expression*
   do_copy()
@@ -11884,7 +11982,7 @@
   make_array(Type*, Expression_list*);
 
   Expression*
-  lower_map(Gogo*, Named_object*, Type*);
+  lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
 
   // The type of the composite literal.
   Type* type_;
@@ -11913,7 +12011,8 @@
 // the type.
 
 Expression*
-Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
+Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
+				       Statement_inserter* inserter, int)
 {
   Type* type = this->type_;
 
@@ -11940,7 +12039,7 @@
   else if (type->array_type() != NULL)
     return this->lower_array(type);
   else if (type->map_type() != NULL)
-    return this->lower_map(gogo, function, type);
+    return this->lower_map(gogo, function, inserter, type);
   else
     {
       error_at(this->location(),
@@ -12244,6 +12343,7 @@
 
 Expression*
 Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
+					Statement_inserter* inserter,
 					Type* type)
 {
   source_location location = this->location();
@@ -12272,7 +12372,7 @@
 	  if ((*p)->unknown_expression() != NULL)
 	    {
 	      (*p)->unknown_expression()->clear_is_composite_literal_key();
-	      gogo->lower_expression(function, &*p);
+	      gogo->lower_expression(function, inserter, &*p);
 	      go_assert((*p)->is_error_expression());
 	      return Expression::make_error(location);
 	    }
diff -r fbc7499fcdc7 go/expressions.h
--- a/go/expressions.h	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/expressions.h	Sun Jul 31 11:16:19 2011 -0700
@@ -15,6 +15,7 @@
 class Gogo;
 class Translate_context;
 class Traverse;
+class Statement_inserter;
 class Type;
 struct Type_context;
 class Function_type;
@@ -128,7 +129,7 @@
   // Make a reference to a temporary variable.  Temporary variables
   // are always created by a single statement, which is what we use to
   // refer to them.
-  static Expression*
+  static Temporary_reference_expression*
   make_temporary_reference(Temporary_statement*, source_location);
 
   // Make a sink expression--a reference to the blank identifier _.
@@ -521,13 +522,18 @@
   traverse_subexpressions(Traverse*);
 
   // Lower an expression.  This is called immediately after parsing.
-  // IOTA_VALUE is the value that we should give to any iota
-  // expressions.  This function must resolve expressions which could
-  // not be fully parsed into their final form.  It returns the same
-  // Expression or a new one.
+  // FUNCTION is the function we are in; it will be NULL for an
+  // expression initializing a global variable.  INSERTER may be used
+  // to insert statements before the statement or initializer
+  // containing this expression; it is normally used to create
+  // temporary variables.  IOTA_VALUE is the value that we should give
+  // to any iota expressions.  This function must resolve expressions
+  // which could not be fully parsed into their final form.  It
+  // returns the same Expression or a new one.
   Expression*
-  lower(Gogo* gogo, Named_object* function, int iota_value)
-  { return this->do_lower(gogo, function, iota_value); }
+  lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
+	int iota_value)
+  { return this->do_lower(gogo, function, inserter, iota_value); }
 
   // Determine the real type of an expression with abstract integer,
   // floating point, or complex type.  TYPE_CONTEXT describes the
@@ -636,7 +642,7 @@
 
   // Return a lowered expression.
   virtual Expression*
-  do_lower(Gogo*, Named_object*, int)
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int)
   { return this; }
 
   // Return whether this is a constant expression.
@@ -871,7 +877,7 @@
 
  protected:
   virtual Expression*
-  do_lower(Gogo*, Named_object*, int) = 0;
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
 
   Type*
   do_type();
@@ -906,7 +912,7 @@
 
  protected:
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   Type*
   do_type();
@@ -941,9 +947,15 @@
   Temporary_reference_expression(Temporary_statement* statement,
 				 source_location location)
     : Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
-      statement_(statement)
+      statement_(statement), is_lvalue_(false)
   { }
 
+  // Indicate that this reference appears on the left hand side of an
+  // assignment statement.
+  void
+  set_is_lvalue()
+  { this->is_lvalue_ = true; }
+
  protected:
   Type*
   do_type();
@@ -969,6 +981,9 @@
  private:
   // The statement where the temporary variable is defined.
   Temporary_statement* statement_;
+  // Whether this reference appears on the left hand side of an
+  // assignment statement.
+  bool is_lvalue_;
 };
 
 // A string expression.
@@ -1099,7 +1114,7 @@
   do_traverse(Traverse* traverse);
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
   do_is_constant() const
@@ -1156,9 +1171,9 @@
   Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
 		  source_location location)
     : Expression(EXPRESSION_CALL, location),
-      fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
-      varargs_are_lowered_(false), types_are_determined_(false),
-      is_deferred_(false)
+      fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
+      is_varargs_(is_varargs), varargs_are_lowered_(false),
+      types_are_determined_(false), is_deferred_(false), issued_error_(false)
   { }
 
   // The function to call.
@@ -1183,6 +1198,12 @@
   size_t
   result_count() const;
 
+  // Return the temporary variable which holds result I.  This is only
+  // valid after the expression has been lowered, and is only valid
+  // for calls which return multiple results.
+  Temporary_statement*
+  result(size_t i) const;
+
   // Return whether this is a call to the predeclared function
   // recover.
   bool
@@ -1207,12 +1228,17 @@
   set_is_deferred()
   { this->is_deferred_ = true; }
 
+  // We have found an error with this call expression; return true if
+  // we should report it.
+  bool
+  issue_error();
+
  protected:
   int
   do_traverse(Traverse*);
 
   virtual Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   void
   do_discarding_value()
@@ -1256,8 +1282,8 @@
 
   // Let a builtin expression lower varargs.
   Expression*
-  lower_varargs(Gogo*, Named_object* function, Type* varargs_type,
-		size_t param_count);
+  lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
+		Type* varargs_type, size_t param_count);
 
   // Let a builtin expression check whether types have been
   // determined.
@@ -1276,6 +1302,9 @@
 			    Interface_field_reference_expression*,
 			    tree*);
 
+  tree
+  set_results(Translate_context*, tree);
+
   // The function to call.
   Expression* fn_;
   // The arguments to pass.  This may be NULL if there are no
@@ -1283,6 +1312,9 @@
   Expression_list* args_;
   // The type of the expression, to avoid recomputing it.
   Type* type_;
+  // The list of temporaries which will hold the results if the
+  // function returns a tuple.
+  std::vector<Temporary_statement*>* results_;
   // The tree for the call, used for a call which returns a tuple.
   tree tree_;
   // True if the last argument is a varargs argument (f(a...)).
@@ -1293,6 +1325,10 @@
   bool types_are_determined_;
   // True if the call is an argument to a defer statement.
   bool is_deferred_;
+  // True if we reported an error about a mismatch between call
+  // results and uses.  This is to avoid producing multiple errors
+  // when there are multiple Call_result_expressions.
+  bool issued_error_;
 };
 
 // An expression which represents a pointer to a function.
@@ -1390,7 +1426,7 @@
 
  protected:
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   Expression*
   do_copy()
@@ -1425,7 +1461,7 @@
   do_traverse(Traverse*);
 
   Expression*
-  do_lower(Gogo*, Named_object*, int);
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   Expression*
   do_copy()
diff -r fbc7499fcdc7 go/gogo.cc
--- a/go/gogo.cc	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/gogo.cc	Sun Jul 31 11:16:19 2011 -0700
@@ -1148,9 +1148,13 @@
 	       | traverse_functions
 	       | traverse_statements
 	       | traverse_expressions),
-      gogo_(gogo), function_(function), iota_value_(-1)
+      gogo_(gogo), function_(function), iota_value_(-1), inserter_()
   { }
 
+  void
+  set_inserter(const Statement_inserter* inserter)
+  { this->inserter_ = *inserter; }
+
   int
   variable(Named_object*);
 
@@ -1173,18 +1177,44 @@
   Named_object* function_;
   // Value to use for the predeclared constant iota.
   int iota_value_;
+  // Current statement inserter for use by expressions.
+  Statement_inserter inserter_;
 };
 
-// Lower variables.  We handle variables specially to break loops in
-// which a variable initialization expression refers to itself.  The
-// loop breaking is in lower_init_expression.
+// Lower variables.
 
 int
 Lower_parse_tree::variable(Named_object* no)
 {
-  if (no->is_variable())
-    no->var_value()->lower_init_expression(this->gogo_, this->function_);
-  return TRAVERSE_CONTINUE;
+  if (!no->is_variable())
+    return TRAVERSE_CONTINUE;
+
+  if (no->is_variable() && no->var_value()->is_global())
+    {
+      // Global variables can have loops in their initialization
+      // expressions.  This is handled in lower_init_expression.
+      no->var_value()->lower_init_expression(this->gogo_, this->function_,
+					     &this->inserter_);
+      return TRAVERSE_CONTINUE;
+    }
+
+  // This is a local variable.  We are going to return
+  // TRAVERSE_SKIP_COMPONENTS here because we want to traverse the
+  // initialization expression when we reach the variable declaration
+  // statement.  However, that means that we need to traverse the type
+  // ourselves.
+  if (no->var_value()->has_type())
+    {
+      Type* type = no->var_value()->type();
+      if (type != NULL)
+	{
+	  if (Type::traverse(type, this) == TRAVERSE_EXIT)
+	    return TRAVERSE_EXIT;
+	}
+    }
+  go_assert(!no->var_value()->has_pre_init());
+
+  return TRAVERSE_SKIP_COMPONENTS;
 }
 
 // Lower constants.  We handle constants specially so that we can set
@@ -1238,27 +1268,38 @@
 int
 Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
 {
+  Statement_inserter hold_inserter(this->inserter_);
+  this->inserter_ = Statement_inserter(block, pindex);
+
   // Lower the expressions first.
   int t = sorig->traverse_contents(this);
   if (t == TRAVERSE_EXIT)
-    return t;
+    {
+      this->inserter_ = hold_inserter;
+      return t;
+    }
 
   // Keep lowering until nothing changes.
   Statement* s = sorig;
   while (true)
     {
-      Statement* snew = s->lower(this->gogo_, this->function_, block);
+      Statement* snew = s->lower(this->gogo_, this->function_, block,
+				 &this->inserter_);
       if (snew == s)
 	break;
       s = snew;
       t = s->traverse_contents(this);
       if (t == TRAVERSE_EXIT)
-	return t;
+	{
+	  this->inserter_ = hold_inserter;
+	  return t;
+	}
     }
 
   if (s != sorig)
     block->replace_statement(*pindex, s);
 
+  this->inserter_ = hold_inserter;
   return TRAVERSE_SKIP_COMPONENTS;
 }
 
@@ -1277,7 +1318,7 @@
     {
       Expression* e = *pexpr;
       Expression* enew = e->lower(this->gogo_, this->function_,
-				  this->iota_value_);
+				  &this->inserter_, this->iota_value_);
       if (enew == e)
 	break;
       *pexpr = enew;
@@ -1304,12 +1345,16 @@
   block->traverse(&lower_parse_tree);
 }
 
-// Lower an expression.
+// Lower an expression.  INSERTER may be NULL, in which case the
+// expression had better not need to create any temporaries.
 
 void
-Gogo::lower_expression(Named_object* function, Expression** pexpr)
+Gogo::lower_expression(Named_object* function, Statement_inserter* inserter,
+		       Expression** pexpr)
 {
   Lower_parse_tree lower_parse_tree(this, function);
+  if (inserter != NULL)
+    lower_parse_tree.set_inserter(inserter);
   lower_parse_tree.expression(pexpr);
 }
 
@@ -1951,11 +1996,26 @@
 	break;
 
       source_location loc = (*pexpr)->location();
-      Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
-      block->insert_statement_before(*pindex, ts);
+      Statement* s;
+      if ((*pexpr)->call_expression() == NULL
+	  || (*pexpr)->call_expression()->result_count() < 2)
+	{
+	  Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
+							      loc);
+	  s = ts;
+	  *pexpr = Expression::make_temporary_reference(ts, loc);
+	}
+      else
+	{
+	  // A call expression which returns multiple results needs to
+	  // be handled specially.  We can't create a temporary
+	  // because there is no type to give it.  Any actual uses of
+	  // the values will be done via Call_result_expressions.
+	  s = Statement::make_statement(*pexpr);
+	}
+
+      block->insert_statement_before(*pindex, s);
       ++*pindex;
-
-      *pexpr = Expression::make_temporary_reference(ts, loc);
     }
 
   if (init != orig_init)
@@ -1978,7 +2038,7 @@
     return TRAVERSE_CONTINUE;
 
   Find_eval_ordering find_eval_ordering;
-  init->traverse_subexpressions(&find_eval_ordering);
+  Expression::traverse(&init, &find_eval_ordering);
 
   if (find_eval_ordering.size() <= 1)
     {
@@ -1993,9 +2053,22 @@
     {
       Expression** pexpr = *p;
       source_location loc = (*pexpr)->location();
-      Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
-      var->add_preinit_statement(this->gogo_, ts);
-      *pexpr = Expression::make_temporary_reference(ts, loc);
+      Statement* s;
+      if ((*pexpr)->call_expression() == NULL
+	  || (*pexpr)->call_expression()->result_count() < 2)
+	{
+	  Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
+							      loc);
+	  s = ts;
+	  *pexpr = Expression::make_temporary_reference(ts, loc);
+	}
+      else
+	{
+	  // A call expression which returns multiple results needs to
+	  // be handled specially.
+	  s = Statement::make_statement(*pexpr);
+	}
+      var->add_preinit_statement(this->gogo_, s);
     }
 
   return TRAVERSE_SKIP_COMPONENTS;
@@ -2181,6 +2254,8 @@
     }
   args->push_back(this->can_recover_arg(location));
 
+  gogo->start_block(location);
+
   Call_expression* call = Expression::make_call(fn, args, false, location);
 
   Statement* s;
@@ -2202,6 +2277,13 @@
   s->determine_types();
   gogo->add_statement(s);
 
+  Block* b = gogo->finish_block(location);
+
+  gogo->add_block(b, location);
+
+  // Lower the call in case it returns multiple results.
+  gogo->lower_block(new_no, b);
+
   gogo->finish_function(location);
 
   // Swap the function bodies and types.
@@ -3152,78 +3234,64 @@
 	  | Traverse::traverse_expressions
 	  | Traverse::traverse_types)) != 0)
     {
+      const unsigned int e_or_t = (Traverse::traverse_expressions
+				   | Traverse::traverse_types);
+      const unsigned int e_or_t_or_s = (e_or_t
+					| Traverse::traverse_statements);
       for (Bindings::const_definitions_iterator pb =
 	     this->bindings_->begin_definitions();
 	   pb != this->bindings_->end_definitions();
 	   ++pb)
 	{
+	  int t = TRAVERSE_CONTINUE;
 	  switch ((*pb)->classification())
 	    {
 	    case Named_object::NAMED_OBJECT_CONST:
 	      if ((traverse_mask & Traverse::traverse_constants) != 0)
+		t = traverse->constant(*pb, false);
+	      if (t == TRAVERSE_CONTINUE
+		  && (traverse_mask & e_or_t) != 0)
 		{
-		  if (traverse->constant(*pb, false) == TRAVERSE_EXIT)
+		  Type* tc = (*pb)->const_value()->type();
+		  if (tc != NULL
+		      && Type::traverse(tc, traverse) == TRAVERSE_EXIT)
 		    return TRAVERSE_EXIT;
-		}
-	      if ((traverse_mask & Traverse::traverse_types) != 0
-		  || (traverse_mask & Traverse::traverse_expressions) != 0)
-		{
-		  Type* t = (*pb)->const_value()->type();
-		  if (t != NULL
-		      && Type::traverse(t, traverse) == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
-		}
-	      if ((traverse_mask & Traverse::traverse_expressions) != 0
-		  || (traverse_mask & Traverse::traverse_types) != 0)
-		{
-		  if ((*pb)->const_value()->traverse_expression(traverse)
-		      == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
+		  t = (*pb)->const_value()->traverse_expression(traverse);
 		}
 	      break;
 
 	    case Named_object::NAMED_OBJECT_VAR:
 	    case Named_object::NAMED_OBJECT_RESULT_VAR:
 	      if ((traverse_mask & Traverse::traverse_variables) != 0)
+		t = traverse->variable(*pb);
+	      if (t == TRAVERSE_CONTINUE
+		  && (traverse_mask & e_or_t) != 0)
 		{
-		  if (traverse->variable(*pb) == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
+		  if ((*pb)->is_result_variable()
+		      || (*pb)->var_value()->has_type())
+		    {
+		      Type* tv = ((*pb)->is_variable()
+				  ? (*pb)->var_value()->type()
+				  : (*pb)->result_var_value()->type());
+		      if (tv != NULL
+			  && Type::traverse(tv, traverse) == TRAVERSE_EXIT)
+			return TRAVERSE_EXIT;
+		    }
 		}
-	      if (((traverse_mask & Traverse::traverse_types) != 0
-		   || (traverse_mask & Traverse::traverse_expressions) != 0)
-		  && ((*pb)->is_result_variable()
-		      || (*pb)->var_value()->has_type()))
-		{
-		  Type* t = ((*pb)->is_variable()
-			     ? (*pb)->var_value()->type()
-			     : (*pb)->result_var_value()->type());
-		  if (t != NULL
-		      && Type::traverse(t, traverse) == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
-		}
-	      if ((*pb)->is_variable()
-		  && ((traverse_mask & Traverse::traverse_expressions) != 0
-		      || (traverse_mask & Traverse::traverse_types) != 0))
-		{
-		  if ((*pb)->var_value()->traverse_expression(traverse)
-		      == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
-		}
+	      if (t == TRAVERSE_CONTINUE
+		  && (traverse_mask & e_or_t_or_s) != 0
+		  && (*pb)->is_variable())
+		t = (*pb)->var_value()->traverse_expression(traverse,
+							    traverse_mask);
 	      break;
 
 	    case Named_object::NAMED_OBJECT_FUNC:
 	    case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
-	      // FIXME: Where will nested functions be found?
 	      go_unreachable();
 
 	    case Named_object::NAMED_OBJECT_TYPE:
-	      if ((traverse_mask & Traverse::traverse_types) != 0
-		  || (traverse_mask & Traverse::traverse_expressions) != 0)
-		{
-		  if (Type::traverse((*pb)->type_value(), traverse)
-		      == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
-		}
+	      if ((traverse_mask & e_or_t) != 0)
+		t = Type::traverse((*pb)->type_value(), traverse);
 	      break;
 
 	    case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
@@ -3237,6 +3305,9 @@
 	    default:
 	      go_unreachable();
 	    }
+
+	  if (t == TRAVERSE_EXIT)
+	    return TRAVERSE_EXIT;
 	}
     }
 
@@ -3351,14 +3422,17 @@
 // Traverse the initializer expression.
 
 int
-Variable::traverse_expression(Traverse* traverse)
+Variable::traverse_expression(Traverse* traverse, unsigned int traverse_mask)
 {
   if (this->preinit_ != NULL)
     {
       if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT)
 	return TRAVERSE_EXIT;
     }
-  if (this->init_ != NULL)
+  if (this->init_ != NULL
+      && ((traverse_mask
+	   & (Traverse::traverse_expressions | Traverse::traverse_types))
+	  != 0))
     {
       if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
 	return TRAVERSE_EXIT;
@@ -3369,7 +3443,8 @@
 // Lower the initialization expression after parsing is complete.
 
 void
-Variable::lower_init_expression(Gogo* gogo, Named_object* function)
+Variable::lower_init_expression(Gogo* gogo, Named_object* function,
+				Statement_inserter* inserter)
 {
   if (this->init_ != NULL && !this->init_is_lowered_)
     {
@@ -3381,7 +3456,14 @@
 	}
       this->seen_ = true;
 
-      gogo->lower_expression(function, &this->init_);
+      Statement_inserter global_inserter;
+      if (this->is_global_)
+	{
+	  global_inserter = Statement_inserter(gogo, this);
+	  inserter = &global_inserter;
+	}
+
+      gogo->lower_expression(function, inserter, &this->init_);
 
       this->seen_ = false;
 
@@ -4508,77 +4590,67 @@
 
   // We don't use an iterator because we permit the traversal to add
   // new global objects.
+  const unsigned int e_or_t = (Traverse::traverse_expressions
+			       | Traverse::traverse_types);
+  const unsigned int e_or_t_or_s = (e_or_t
+				    | Traverse::traverse_statements);
   for (size_t i = 0; i < this->named_objects_.size(); ++i)
     {
       Named_object* p = this->named_objects_[i];
+      int t = TRAVERSE_CONTINUE;
       switch (p->classification())
 	{
 	case Named_object::NAMED_OBJECT_CONST:
 	  if ((traverse_mask & Traverse::traverse_constants) != 0)
+	    t = traverse->constant(p, is_global);
+	  if (t == TRAVERSE_CONTINUE
+	      && (traverse_mask & e_or_t) != 0)
 	    {
-	      if (traverse->constant(p, is_global) == TRAVERSE_EXIT)
+	      Type* tc = p->const_value()->type();
+	      if (tc != NULL
+		  && Type::traverse(tc, traverse) == TRAVERSE_EXIT)
 		return TRAVERSE_EXIT;
-	    }
-	  if ((traverse_mask & Traverse::traverse_types) != 0
-	      || (traverse_mask & Traverse::traverse_expressions) != 0)
-	    {
-	      Type* t = p->const_value()->type();
-	      if (t != NULL
-		  && Type::traverse(t, traverse) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	      if (p->const_value()->traverse_expression(traverse)
-		  == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
+	      t = p->const_value()->traverse_expression(traverse);
 	    }
 	  break;
 
 	case Named_object::NAMED_OBJECT_VAR:
 	case Named_object::NAMED_OBJECT_RESULT_VAR:
 	  if ((traverse_mask & Traverse::traverse_variables) != 0)
+	    t = traverse->variable(p);
+	  if (t == TRAVERSE_CONTINUE
+	      && (traverse_mask & e_or_t) != 0)
 	    {
-	      if (traverse->variable(p) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
+	      if (p->is_result_variable()
+		  || p->var_value()->has_type())
+		{
+		  Type* tv = (p->is_variable()
+			      ? p->var_value()->type()
+			      : p->result_var_value()->type());
+		  if (tv != NULL
+		      && Type::traverse(tv, traverse) == TRAVERSE_EXIT)
+		    return TRAVERSE_EXIT;
+		}
 	    }
-	  if (((traverse_mask & Traverse::traverse_types) != 0
-	       || (traverse_mask & Traverse::traverse_expressions) != 0)
-	      && (p->is_result_variable()
-		  || p->var_value()->has_type()))
-	    {
-	      Type* t = (p->is_variable()
-			 ? p->var_value()->type()
-			 : p->result_var_value()->type());
-	      if (t != NULL
-		  && Type::traverse(t, traverse) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	    }
-	  if (p->is_variable()
-	      && ((traverse_mask & Traverse::traverse_types) != 0
-		  || (traverse_mask & Traverse::traverse_expressions) != 0))
-	    {
-	      if (p->var_value()->traverse_expression(traverse)
-		  == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	    }
+	  if (t == TRAVERSE_CONTINUE
+	      && (traverse_mask & e_or_t_or_s) != 0
+	      && p->is_variable())
+	    t = p->var_value()->traverse_expression(traverse, traverse_mask);
 	  break;
 
 	case Named_object::NAMED_OBJECT_FUNC:
 	  if ((traverse_mask & Traverse::traverse_functions) != 0)
-	    {
-	      int t = traverse->function(p);
-	      if (t == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	      else if (t == TRAVERSE_SKIP_COMPONENTS)
-		break;
-	    }
-
-	  if ((traverse_mask
-	       & (Traverse::traverse_variables
-		  | Traverse::traverse_constants
-		  | Traverse::traverse_functions
-		  | Traverse::traverse_blocks
-		  | Traverse::traverse_statements
-		  | Traverse::traverse_expressions
-		  | Traverse::traverse_types)) != 0)
+	    t = traverse->function(p);
+
+	  if (t == TRAVERSE_CONTINUE
+	      && (traverse_mask
+		  & (Traverse::traverse_variables
+		     | Traverse::traverse_constants
+		     | Traverse::traverse_functions
+		     | Traverse::traverse_blocks
+		     | Traverse::traverse_statements
+		     | Traverse::traverse_expressions
+		     | Traverse::traverse_types)) != 0)
 	    {
 	      if (p->func_value()->traverse(traverse) == TRAVERSE_EXIT)
 		return TRAVERSE_EXIT;
@@ -4591,12 +4663,8 @@
 	  break;
 
 	case Named_object::NAMED_OBJECT_TYPE:
-	  if ((traverse_mask & Traverse::traverse_types) != 0
-	      || (traverse_mask & Traverse::traverse_expressions) != 0)
-	    {
-	      if (Type::traverse(p->type_value(), traverse) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	    }
+	  if ((traverse_mask & e_or_t) != 0)
+	    t = Type::traverse(p->type_value(), traverse);
 	  break;
 
 	case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
@@ -4608,6 +4676,9 @@
 	default:
 	  go_unreachable();
 	}
+
+      if (t == TRAVERSE_EXIT)
+	return TRAVERSE_EXIT;
     }
 
   return TRAVERSE_CONTINUE;
@@ -4805,3 +4876,20 @@
 {
   go_unreachable();
 }
+
+// Class Statement_inserter.
+
+void
+Statement_inserter::insert(Statement* s)
+{
+  if (this->block_ != NULL)
+    {
+      go_assert(this->pindex_ != NULL);
+      this->block_->insert_statement_before(*this->pindex_, s);
+      ++*this->pindex_;
+    }
+  else if (this->var_ != NULL)
+    this->var_->add_preinit_statement(this->gogo_, s);
+  else
+    go_unreachable();
+}
diff -r fbc7499fcdc7 go/gogo.h
--- a/go/gogo.h	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/gogo.h	Sun Jul 31 11:16:19 2011 -0700
@@ -8,6 +8,7 @@
 #define GO_GOGO_H
 
 class Traverse;
+class Statement_inserter;
 class Type;
 class Type_hash_identical;
 class Type_equal;
@@ -366,7 +367,7 @@
 
   // Lower an expression.
   void
-  lower_expression(Named_object* function, Expression**);
+  lower_expression(Named_object* function, Statement_inserter*, Expression**);
 
   // Lower a constant.
   void
@@ -1157,7 +1158,7 @@
 
   // Lower the initialization expression after parsing is complete.
   void
-  lower_init_expression(Gogo*, Named_object*);
+  lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
 
   // A special case: the init value is used only to determine the
   // type.  This is used if the variable is defined using := with the
@@ -1208,7 +1209,7 @@
 
   // Traverse the initializer expression.
   int
-  traverse_expression(Traverse*);
+  traverse_expression(Traverse*, unsigned int traverse_mask);
 
   // Determine the type of the variable if necessary.
   void
@@ -2463,6 +2464,46 @@
   Expressions_seen* expressions_seen_;
 };
 
+// A class which makes it easier to insert new statements before the
+// current statement during a traversal.
+
+class Statement_inserter
+{
+ public:
+  // Empty constructor.
+  Statement_inserter()
+    : block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL)
+  { }
+
+  // Constructor for a statement in a block.
+  Statement_inserter(Block* block, size_t *pindex)
+    : block_(block), pindex_(pindex), gogo_(NULL), var_(NULL)
+  { }
+
+  // Constructor for a global variable.
+  Statement_inserter(Gogo* gogo, Variable* var)
+    : block_(NULL), pindex_(NULL), gogo_(gogo), var_(var)
+  { go_assert(var->is_global()); }
+
+  // We use the default copy constructor and assignment operator.
+
+  // Insert S before the statement we are traversing, or before the
+  // initialization expression of a global variable.
+  void
+  insert(Statement* s);
+
+ private:
+  // The block that the statement is in.
+  Block* block_;
+  // The index of the statement that we are traversing.
+  size_t* pindex_;
+  // The IR, needed when looking at an initializer expression for a
+  // global variable.
+  Gogo* gogo_;
+  // The global variable, when looking at an initializer expression.
+  Variable* var_;
+};
+
 // When translating the gogo IR into the backend data structure, this
 // is the context we pass down the blocks and statements.
 
diff -r fbc7499fcdc7 go/statements.cc
--- a/go/statements.cc	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/statements.cc	Sun Jul 31 11:16:19 2011 -0700
@@ -217,6 +217,16 @@
   return true;
 }
 
+// Lower the variable's initialization expression.
+
+Statement*
+Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
+					 Block*, Statement_inserter* inserter)
+{
+  this->var_->var_value()->lower_init_expression(gogo, function, inserter);
+  return this;
+}
+
 // Convert a variable declaration to the backend representation.
 
 Bstatement*
@@ -244,7 +254,7 @@
   Expression_list* params = new Expression_list();
   params->push_back(Expression::make_type(var->type(), loc));
   Expression* call = Expression::make_call(func, params, false, loc);
-  context->gogo()->lower_expression(context->function(), &call);
+  context->gogo()->lower_expression(context->function(), NULL, &call);
   Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
   Bstatement* btemp = temp->get_backend(context);
 
@@ -386,7 +396,7 @@
     {
       Expression* init = Expression::make_cast(this->type_, this->init_,
 					       this->location());
-      context->gogo()->lower_expression(context->function(), &init);
+      context->gogo()->lower_expression(context->function(), NULL, &init);
       binit = tree_to_expr(init->get_tree(context));
     }
 
@@ -598,7 +608,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -628,7 +638,7 @@
 
 Statement*
 Assignment_operation_statement::do_lower(Gogo*, Named_object*,
-					 Block* enclosing)
+					 Block* enclosing, Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -725,7 +735,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -752,7 +762,8 @@
 // up into a set of single assignments.
 
 Statement*
-Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+				     Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -852,7 +863,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -882,7 +893,7 @@
 
 Statement*
 Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
-					 Block* enclosing)
+					 Block* enclosing, Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -923,7 +934,8 @@
   b->add_statement(present_temp);
 
   // present_temp = mapaccess2(MAP, &key_temp, &val_temp)
-  Expression* ref = Expression::make_temporary_reference(key_temp, loc);
+  Temporary_reference_expression* ref =
+    Expression::make_temporary_reference(key_temp, loc);
   Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc);
   ref = Expression::make_temporary_reference(val_temp, loc);
   Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc);
@@ -931,6 +943,7 @@
 					map_index->map(), a1, a2);
 
   ref = Expression::make_temporary_reference(present_temp, loc);
+  ref->set_is_lvalue();
   Statement* s = Statement::make_assignment(ref, call, loc);
   b->add_statement(s);
 
@@ -979,7 +992,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1008,7 +1021,8 @@
 // Lower a map assignment to a function call.
 
 Statement*
-Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+				   Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -1093,7 +1107,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1125,7 +1139,8 @@
 
 Statement*
 Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
-					     Block* enclosing)
+					     Block* enclosing,
+					     Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -1160,13 +1175,15 @@
   b->add_statement(closed_temp);
 
   // closed_temp = chanrecv[23](channel, &val_temp)
-  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+  Temporary_reference_expression* ref =
+    Expression::make_temporary_reference(val_temp, loc);
   Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
   Expression* call = Runtime::make_call((this->for_select_
 					 ? Runtime::CHANRECV3
 					 : Runtime::CHANRECV2),
 					loc, 2, this->channel_, p2);
   ref = Expression::make_temporary_reference(closed_temp, loc);
+  ref->set_is_lvalue();
   Statement* s = Statement::make_assignment(ref, call, loc);
   b->add_statement(s);
 
@@ -1217,7 +1234,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1256,7 +1273,8 @@
 
 Statement*
 Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
-						Block* enclosing)
+						Block* enclosing,
+						Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -1378,6 +1396,10 @@
       expr_(expr)
   { }
 
+  Expression*
+  expr()
+  { return this->expr_; }
+
  protected:
   int
   do_traverse(Traverse* traverse)
@@ -1513,7 +1535,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1529,7 +1551,7 @@
 // Lower to += or -=.
 
 Statement*
-Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*)
+Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -2017,6 +2039,8 @@
   Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
 						location);
 
+  gogo->start_block(location);
+
   // For a defer statement, start with a call to
   // __go_set_defer_retaddr.  */
   Label* retaddr_label = NULL; 
@@ -2122,26 +2146,10 @@
       call_params = NULL;
     }
 
-  Expression* call = Expression::make_call(func_to_call, call_params, false,
-					   location);
-  // We need to lower in case this is a builtin function.
-  call = call->lower(gogo, function, -1);
-  Call_expression* call_ce = call->call_expression();
-  if (call_ce != NULL && may_call_recover)
-    call_ce->set_is_deferred();
-
+  Call_expression* call = Expression::make_call(func_to_call, call_params,
+						false, location);
   Statement* call_statement = Statement::make_statement(call);
 
-  // We already ran the determine_types pass, so we need to run it
-  // just for this statement now.
-  call_statement->determine_types();
-
-  // Sanity check.
-  call->check_types(gogo);
-
-  if (call_ce != NULL && recover_arg != NULL)
-    call_ce->set_recover_arg(recover_arg);
-
   gogo->add_statement(call_statement);
 
   // If this is a defer statement, the label comes immediately after
@@ -2155,6 +2163,31 @@
       gogo->add_statement(Statement::make_return_statement(vals, location));
     }
 
+  Block* b = gogo->finish_block(location);
+
+  gogo->add_block(b, location);
+
+  gogo->lower_block(function, b);
+
+  // We already ran the determine_types pass, so we need to run it
+  // just for the call statement now.  The other types are known.
+  call_statement->determine_types();
+
+  if (may_call_recover || recover_arg != NULL)
+    {
+      // Dig up the call expression, which may have been changed
+      // during lowering.
+      go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
+      Expression_statement* es =
+	static_cast<Expression_statement*>(call_statement);
+      Call_expression* ce = es->expr()->call_expression();
+      go_assert(ce != NULL);
+      if (may_call_recover)
+	ce->set_is_deferred();
+      if (recover_arg != NULL)
+	ce->set_recover_arg(recover_arg);
+    }
+
   // That is all the thunk has to do.
   gogo->finish_function(location);
 }
@@ -2265,7 +2298,8 @@
 // panic/recover work correctly.
 
 Statement*
-Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing)
+Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
+			   Statement_inserter*)
 {
   if (this->is_lowered_)
     return this;
@@ -3305,7 +3339,8 @@
 // of if statements.
 
 Statement*
-Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+			   Statement_inserter*)
 {
   source_location loc = this->location();
 
@@ -3578,7 +3613,8 @@
 // equality testing.
 
 Statement*
-Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+				Statement_inserter*)
 {
   const source_location loc = this->location();
 
@@ -3629,8 +3665,9 @@
 					     ? Runtime::EFACETYPE
 					     : Runtime::IFACETYPE),
 					    loc, 1, ref);
-      Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
-							     loc);
+      Temporary_reference_expression* lhs =
+	Expression::make_temporary_reference(descriptor_temp, loc);
+      lhs->set_is_lvalue();
       Statement* s = Statement::make_assignment(lhs, call, loc);
       b->add_statement(s);
     }
@@ -3815,7 +3852,7 @@
   call = Runtime::make_call(code, loc, 3, this->channel_, val,
 			    Expression::make_boolean(this->for_select_, loc));
 
-  context->gogo()->lower_expression(context->function(), &call);
+  context->gogo()->lower_expression(context->function(), NULL, &call);
   Bexpression* bcall = tree_to_expr(call->get_tree(context));
   Bstatement* s = context->backend()->expression_statement(bcall);
 
@@ -4154,7 +4191,7 @@
 	  Expression* nil2 = nil1->copy();
 	  Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
 						zero, default_arg, nil1, nil2);
-	  context->gogo()->lower_expression(context->function(), &call);
+	  context->gogo()->lower_expression(context->function(), NULL, &call);
 	  Bexpression* bcall = tree_to_expr(call->get_tree(context));
 	  s = context->backend()->expression_statement(bcall);
 	}
@@ -4175,7 +4212,7 @@
   Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
 							 false, chan_init,
 							 location);
-  context->gogo()->lower_expression(context->function(), &chans);
+  context->gogo()->lower_expression(context->function(), NULL, &chans);
   Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
 							     chans,
 							     location);
@@ -4187,7 +4224,7 @@
 							    0, false,
 							    is_send_init,
 							    location);
-  context->gogo()->lower_expression(context->function(), &is_sends);
+  context->gogo()->lower_expression(context->function(), NULL, &is_sends);
   Temporary_statement* is_send_temp =
     Statement::make_temporary(is_send_array_type, is_sends, location);
   statements.push_back(is_send_temp->get_backend(context));
@@ -4213,7 +4250,7 @@
   Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
 					ecount->copy(), default_arg,
 					chan_arg, is_send_arg);
-  context->gogo()->lower_expression(context->function(), &call);
+  context->gogo()->lower_expression(context->function(), NULL, &call);
   Bexpression* bcall = tree_to_expr(call->get_tree(context));
 
   std::vector<std::vector<Bexpression*> > cases;
@@ -4309,7 +4346,7 @@
 
 Statement*
 Select_statement::do_lower(Gogo* gogo, Named_object* function,
-			   Block* enclosing)
+			   Block* enclosing, Statement_inserter*)
 {
   if (this->is_lowered_)
     return this;
@@ -4366,7 +4403,8 @@
 // complex statements make it easier to handle garbage collection.
 
 Statement*
-For_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+			Statement_inserter*)
 {
   Statement* s;
   source_location loc = this->location();
@@ -4497,7 +4535,8 @@
 // statements.
 
 Statement*
-For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing)
+For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
+			      Statement_inserter*)
 {
   Type* range_type = this->range_->type();
   if (range_type->points_to() != NULL
@@ -4711,8 +4750,10 @@
   Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
   mpz_clear(zval);
 
-  ref = Expression::make_temporary_reference(index_temp, loc);
-  Statement* s = Statement::make_assignment(ref, zexpr, loc);
+  Temporary_reference_expression* tref =
+    Expression::make_temporary_reference(index_temp, loc);
+  tref->set_is_lvalue();
+  Statement* s = Statement::make_assignment(tref, zexpr, loc);
   init->add_statement(s);
 
   *pinit = init;
@@ -4738,8 +4779,9 @@
       Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
       Expression* index = Expression::make_index(ref, ref2, NULL, loc);
 
-      ref = Expression::make_temporary_reference(value_temp, loc);
-      s = Statement::make_assignment(ref, index, loc);
+      tref = Expression::make_temporary_reference(value_temp, loc);
+      tref->set_is_lvalue();
+      s = Statement::make_assignment(tref, index, loc);
 
       iter_init->add_statement(s);
     }
@@ -4749,8 +4791,9 @@
   //   index_temp++
 
   Block* post = new Block(enclosing, loc);
-  ref = Expression::make_temporary_reference(index_temp, loc);
-  s = Statement::make_inc_statement(ref);
+  tref = Expression::make_temporary_reference(index_temp, loc);
+  tref->set_is_lvalue();
+  s = Statement::make_inc_statement(tref);
   post->add_statement(s);
   *ppost = post;
 }
@@ -4798,7 +4841,9 @@
   mpz_init_set_ui(zval, 0UL);
   Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
 
-  Expression* ref = Expression::make_temporary_reference(index_temp, loc);
+  Temporary_reference_expression* ref =
+    Expression::make_temporary_reference(index_temp, loc);
+  ref->set_is_lvalue();
   Statement* s = Statement::make_assignment(ref, zexpr, loc);
 
   init->add_statement(s);
@@ -4829,14 +4874,20 @@
   if (value_temp == NULL)
     {
       ref = Expression::make_temporary_reference(next_index_temp, loc);
+      ref->set_is_lvalue();
       s = Statement::make_assignment(ref, call, loc);
     }
   else
     {
       Expression_list* lhs = new Expression_list();
-      lhs->push_back(Expression::make_temporary_reference(next_index_temp,
-							  loc));
-      lhs->push_back(Expression::make_temporary_reference(value_temp, loc));
+
+      ref = Expression::make_temporary_reference(next_index_temp, loc);
+      ref->set_is_lvalue();
+      lhs->push_back(ref);
+
+      ref = Expression::make_temporary_reference(value_temp, loc);
+      ref->set_is_lvalue();
+      lhs->push_back(ref);
 
       Expression_list* rhs = new Expression_list();
       rhs->push_back(Expression::make_call_result(call, 0));
@@ -4865,7 +4916,9 @@
 
   Block* post = new Block(enclosing, loc);
 
-  Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
+  Temporary_reference_expression* lhs =
+    Expression::make_temporary_reference(index_temp, loc);
+  lhs->set_is_lvalue();
   Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
   s = Statement::make_assignment(lhs, rhs, loc);
 
@@ -5024,8 +5077,12 @@
   iter_init->add_statement(ok_temp);
 
   Expression* cref = this->make_range_ref(range_object, range_temp, loc);
-  Expression* iref = Expression::make_temporary_reference(index_temp, loc);
-  Expression* oref = Expression::make_temporary_reference(ok_temp, loc);
+  Temporary_reference_expression* iref =
+    Expression::make_temporary_reference(index_temp, loc);
+  iref->set_is_lvalue();
+  Temporary_reference_expression* oref =
+    Expression::make_temporary_reference(ok_temp, loc);
+  oref->set_is_lvalue();
   Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
 							  false, loc);
   iter_init->add_statement(s);
diff -r fbc7499fcdc7 go/statements.h
--- a/go/statements.h	Tue Jul 12 18:02:18 2011 -0700
+++ b/go/statements.h	Sun Jul 31 11:16:19 2011 -0700
@@ -11,6 +11,7 @@
 
 class Gogo;
 class Traverse;
+class Statement_inserter;
 class Block;
 class Function;
 class Unnamed_label;
@@ -290,9 +291,11 @@
   // simplify statements for further processing.  It returns the same
   // Statement or a new one.  FUNCTION is the function containing this
   // statement.  BLOCK is the block containing this statement.
+  // INSERTER can be used to insert new statements before this one.
   Statement*
-  lower(Gogo* gogo, Named_object* function, Block* block)
-  { return this->do_lower(gogo, function, block); }
+  lower(Gogo* gogo, Named_object* function, Block* block,
+	Statement_inserter* inserter)
+  { return this->do_lower(gogo, function, block, inserter); }
 
   // Set type information for unnamed constants.
   void
@@ -385,7 +388,7 @@
   // Implemented by the child class: lower this statement to a simpler
   // one.
   virtual Statement*
-  do_lower(Gogo*, Named_object*, Block*)
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
   { return this; }
 
   // Implemented by child class: set type information for unnamed
@@ -535,6 +538,9 @@
   bool
   do_traverse_assignments(Traverse_assignments*);
 
+  Statement*
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
+
   Bstatement*
   do_get_backend(Translate_context*);
 
@@ -566,7 +572,7 @@
   do_traverse_assignments(Traverse_assignments*);
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   bool
   do_may_fall_through() const
@@ -806,7 +812,7 @@
   { return this->clauses_->traverse(traverse); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   void
   do_determine_types()
@@ -993,7 +999,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1051,7 +1057,7 @@
   { go_unreachable(); }
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1280,7 +1286,7 @@
   do_traverse(Traverse*);
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)
@@ -1426,7 +1432,7 @@
   do_traverse(Traverse*);
 
   Statement*
-  do_lower(Gogo*, Named_object*, Block*);
+  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
 
   Bstatement*
   do_get_backend(Translate_context*)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-08-01  1:45 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-01  1:45 Go patch committed: Use temps for calls with multiple results Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).