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*);