diff mbox

Go patch committed: Don't lower multi-valued arguments into temporaries

Message ID CAOyqgcVAapMWf31oSM-Wc7QtM-hJDGO+V=oSw+=7q8A79Gb18Q@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Dec. 10, 2014, 8:38 p.m. UTC
This patch from Chris Manghane fixes a compiler crash when lowering a
multi-valued temporary (as in f(g()) when g returns multiple values).
This is GCC PR 61316.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r fc51bd51a948 go/expressions.cc
--- a/go/expressions.cc	Tue Dec 09 16:54:11 2014 -0800
+++ b/go/expressions.cc	Wed Dec 10 11:40:53 2014 -0800
@@ -8525,6 +8525,7 @@ 
               || fntype->is_builtin()))
 	{
 	  Call_expression* call = this->args_->front()->call_expression();
+	  call->set_is_multi_value_arg();
 	  Expression_list* args = new Expression_list;
 	  for (size_t i = 0; i < rc; ++i)
 	    args->push_back(Expression::make_call_result(call, i));
diff -r fc51bd51a948 go/expressions.h
--- a/go/expressions.h	Tue Dec 09 16:54:11 2014 -0800
+++ b/go/expressions.h	Wed Dec 10 11:40:53 2014 -0800
@@ -1632,7 +1632,7 @@ 
       fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
       call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
       varargs_are_lowered_(false), types_are_determined_(false),
-      is_deferred_(false), issued_error_(false)
+      is_deferred_(false), issued_error_(false), is_multi_value_arg_(false)
   { }
 
   // The function to call.
@@ -1703,6 +1703,17 @@ 
   bool
   issue_error();
 
+  // Whether this call returns multiple results that are used as an
+  // multi-valued argument.
+  bool
+  is_multi_value_arg() const
+  { return this->is_multi_value_arg_; }
+
+  // Note this call is used as a multi-valued argument.
+  void
+  set_is_multi_value_arg()
+  { this->is_multi_value_arg_ = true; }
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1806,6 +1817,8 @@ 
   // results and uses.  This is to avoid producing multiple errors
   // when there are multiple Call_result_expressions.
   bool issued_error_;
+  // True if this call is used as an argument that returns multiple results.
+  bool is_multi_value_arg_;
 };
 
 // An expression which represents a pointer to a function.
diff -r fc51bd51a948 go/statements.cc
--- a/go/statements.cc	Tue Dec 09 16:54:11 2014 -0800
+++ b/go/statements.cc	Wed Dec 10 11:40:53 2014 -0800
@@ -726,6 +726,17 @@ 
 
   if ((*pexpr)->must_eval_in_order())
     {
+      Call_expression* call = (*pexpr)->call_expression();
+      if (call != NULL && call->is_multi_value_arg())
+	{
+	  // A call expression which returns multiple results as an argument
+	  // to another call must be handled specially.  We can't create a
+	  // temporary because there is no type to give it.  Instead, group
+	  // the caller and this multi-valued call argument and use a temporary
+	  // variable to hold them.
+	  return TRAVERSE_SKIP_COMPONENTS;
+	}
+
       Location loc = (*pexpr)->location();
       Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
       this->block_->add_statement(temp);