compiler: More cases that need a temporary for interface conversion.

From-SVN: r218952
This commit is contained in:
Ian Lance Taylor 2014-12-19 16:14:01 +00:00
parent 6b0e0695a5
commit 16f72d88dd
3 changed files with 76 additions and 24 deletions

View File

@ -5142,6 +5142,9 @@ Expression*
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 @@ Expression*
Builtin_call_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
if (this->code_ == BUILTIN_APPEND
|| this->code_ == BUILTIN_COPY)
Location loc = this->location();
switch (this->code_)
{
Location loc = this->location();
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 =
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);
}
}
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_variable() && (*pa)->type()->interface_type() != NULL)
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
inserter->insert(temp);
*pa = Expression::make_temporary_reference(temp, loc);
}
}
}
return this;
}

View File

@ -421,6 +421,28 @@ Temporary_statement::do_check_types(Gogo*)
}
}
// 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 @@ Temporary_statement::do_get_backend(Translate_context* context)
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);
}

View File

@ -550,6 +550,9 @@ class Temporary_statement : public Statement
void
do_check_types(Gogo*);
Statement*
do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*);