compiler: Add temporaries required in cases of interface conversion.

From-SVN: r218979
This commit is contained in:
Ian Lance Taylor 2014-12-19 22:21:01 +00:00
parent e8af59bc73
commit 72db90a9fc
2 changed files with 45 additions and 16 deletions

View File

@ -8786,6 +8786,10 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*,
if (this->classification() == EXPRESSION_ERROR)
return this;
if (this->is_flattened_)
return this;
this->is_flattened_ = true;
// Add temporary variables for all arguments that require type
// conversion.
Function_type* fntype = this->get_function_type();
@ -10590,21 +10594,31 @@ Map_index_expression::do_traverse(Traverse* traverse)
// recomputation.
Expression*
Map_index_expression::do_flatten(Gogo*, Named_object*,
Map_index_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
Location loc = this->location();
Map_type* mt = this->get_map_type();
if (this->index_->type() != mt->key_type())
this->index_ = Expression::make_cast(mt->key_type(), this->index_,
this->location());
if (!Type::are_identical(mt->key_type(), this->index_->type(), false, NULL))
{
if (this->index_->type()->interface_type() != NULL
&& !this->index_->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->index_, loc);
inserter->insert(temp);
this->index_ = Expression::make_temporary_reference(temp, loc);
}
this->index_ = Expression::convert_for_assignment(gogo, mt->key_type(),
this->index_, loc);
}
if (!this->index_->is_variable())
{
Temporary_statement* temp = Statement::make_temporary(NULL, this->index_,
this->location());
loc);
inserter->insert(temp);
this->index_ = Expression::make_temporary_reference(temp,
this->location());
this->index_ = Expression::make_temporary_reference(temp, loc);
}
if (this->value_pointer_ == NULL)
@ -10612,11 +10626,9 @@ Map_index_expression::do_flatten(Gogo*, Named_object*,
if (!this->value_pointer_->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->value_pointer_,
this->location());
Statement::make_temporary(NULL, this->value_pointer_, loc);
inserter->insert(temp);
this->value_pointer_ =
Expression::make_temporary_reference(temp, this->location());
this->value_pointer_ = Expression::make_temporary_reference(temp, loc);
}
return this;
@ -12540,12 +12552,26 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*,
++pv, ++i)
{
Expression_list* key_value_pair = new Expression_list();
Expression* key =
Expression::convert_for_assignment(gogo, key_type, *pv, loc);
Expression* key = *pv;
if (key->type()->interface_type() != NULL && !key->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, key, loc);
inserter->insert(temp);
key = Expression::make_temporary_reference(temp, loc);
}
key = Expression::convert_for_assignment(gogo, key_type, key, loc);
++pv;
Expression* val =
Expression::convert_for_assignment(gogo, val_type, *pv, loc);
Expression* val = *pv;
if (val->type()->interface_type() != NULL && !val->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, val, loc);
inserter->insert(temp);
val = Expression::make_temporary_reference(temp, loc);
}
val = Expression::convert_for_assignment(gogo, val_type, val, loc);
key_value_pair->push_back(key);
key_value_pair->push_back(val);

View File

@ -1632,7 +1632,8 @@ class Call_expression : public Expression
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_multi_value_arg_(false)
is_deferred_(false), issued_error_(false), is_multi_value_arg_(false),
is_flattened_(false)
{ }
// The function to call.
@ -1817,6 +1818,8 @@ class Call_expression : public Expression
bool issued_error_;
// True if this call is used as an argument that returns multiple results.
bool is_multi_value_arg_;
// True if this expression has already been flattened.
bool is_flattened_;
};
// An expression which represents a pointer to a function.