Compiling more Go code revealed a couple more cases that need a
temporary for interface conversion.  The first is passing an interface
value to panic.  The second is when a temporary itself has a type that
forces conversion, which can happen in a return statement.  This patch
adds them.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff -r bbc7cf8bad07 go/expressions.cc
--- a/go/expressions.cc Thu Dec 18 20:04:18 2014 -0800
+++ b/go/expressions.cc Fri Dec 19 07:34:33 2014 -0800
@@ -5142,6 +5142,9 @@
 Binary_expression::do_flatten(Gogo* gogo, Named_object*,
                               Statement_inserter* inserter)
 {
+  if (this->classification() == EXPRESSION_ERROR)
+    return this;
+
   Location loc = this->location();
   Temporary_statement* temp;
   if (this->left_->type()->is_string_type()
@@ -6877,30 +6880,53 @@
 Builtin_call_expression::do_flatten(Gogo*, Named_object*,
                                     Statement_inserter* inserter)
 {
-  if (this->code_ == BUILTIN_APPEND
-      || this->code_ == BUILTIN_COPY)
-    {
-      Location loc = this->location();
-      Type* at = this->args()->front()->type();
+  Location loc = this->location();
+
+  switch (this->code_)
+    {
+    default:
+      break;
+
+    case BUILTIN_APPEND:
+    case BUILTIN_COPY:
+      {
+       Type* at = this->args()->front()->type();
+       for (Expression_list::iterator pa = this->args()->begin();
+            pa != this->args()->end();
+            ++pa)
+         {
+           if ((*pa)->is_nil_expression())
+             {
+               Expression* nil = Expression::make_nil(loc);
+               Expression* zero = Expression::make_integer_ul(0, NULL, loc);
+               *pa = Expression::make_slice_value(at, nil, zero, zero, loc);
+             }
+           if (!(*pa)->is_variable())
+             {
+               Temporary_statement* temp =
+                  Statement::make_temporary(NULL, *pa, loc);
+               inserter->insert(temp);
+               *pa = Expression::make_temporary_reference(temp, loc);
+             }
+         }
+      }
+      break;
+
+    case BUILTIN_PANIC:
       for (Expression_list::iterator pa = this->args()->begin();
-           pa != this->args()->end();
-           ++pa)
-        {
-          if ((*pa)->is_nil_expression())
+          pa != this->args()->end();
+          ++pa)
+       {
+         if (!(*pa)->is_variable() && (*pa)->type()->interface_type() != NULL)
            {
-             Expression* nil = Expression::make_nil(loc);
-             Expression* zero = Expression::make_integer_ul(0, NULL, loc);
-             *pa = Expression::make_slice_value(at, nil, zero, zero, loc);
+             Temporary_statement* temp =
+               Statement::make_temporary(NULL, *pa, loc);
+             inserter->insert(temp);
+             *pa = Expression::make_temporary_reference(temp, loc);
            }
-          if (!(*pa)->is_variable())
-            {
-              Temporary_statement* temp =
-                  Statement::make_temporary(NULL, *pa, loc);
-              inserter->insert(temp);
-              *pa = Expression::make_temporary_reference(temp, loc);
-            }
-        }
-    }
+       }
+    }
+
   return this;
 }
 
diff -r bbc7cf8bad07 go/statements.cc
--- a/go/statements.cc  Thu Dec 18 20:04:18 2014 -0800
+++ b/go/statements.cc  Fri Dec 19 07:34:33 2014 -0800
@@ -421,6 +421,28 @@
     }
 }
 
+// Flatten a temporary statement: add another temporary when it might
+// be needed for interface conversion.
+
+Statement*
+Temporary_statement::do_flatten(Gogo*, Named_object*, Block*,
+                               Statement_inserter* inserter)
+{
+  if (this->type_ != NULL
+      && this->init_ != NULL
+      && !Type::are_identical(this->type_, this->init_->type(), false, NULL)
+      && this->init_->type()->interface_type() != NULL
+      && !this->init_->is_variable())
+    {
+      Temporary_statement *temp =
+       Statement::make_temporary(NULL, this->init_, this->location());
+      inserter->insert(temp);
+      this->init_ = Expression::make_temporary_reference(temp,
+                                                        this->location());
+    }
+  return this;
+}
+
 // Convert to backend representation.
 
 Bstatement*
@@ -440,9 +462,10 @@
     binit = this->init_->get_backend(context);
   else
     {
-      Expression* init = Expression::make_cast(this->type_, this->init_,
-                                              this->location());
-      context->gogo()->lower_expression(context->function(), NULL, &init);
+      Expression* init = Expression::convert_for_assignment(context->gogo(),
+                                                           this->type_,
+                                                           this->init_,
+                                                           this->location());
       binit = init->get_backend(context);
     }
 
diff -r bbc7cf8bad07 go/statements.h
--- a/go/statements.h   Thu Dec 18 20:04:18 2014 -0800
+++ b/go/statements.h   Fri Dec 19 07:34:33 2014 -0800
@@ -550,6 +550,9 @@
   void
   do_check_types(Gogo*);
 
+  Statement*
+  do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);
+
   Bstatement*
   do_get_backend(Translate_context*);
 

Reply via email to