More test cases, more cases where the Go frontend needs to create a temporary in the case of interface conversion. This is for map index expressions and map composite literals. Also only flatten call expressions once; they tend to appear in the tree multiple times. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r 9753943fcd89 go/expressions.cc --- a/go/expressions.cc Fri Dec 19 07:36:12 2014 -0800 +++ b/go/expressions.cc Fri Dec 19 14:17:00 2014 -0800 @@ -8786,6 +8786,10 @@ 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 @@ // 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 @@ 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 @@ ++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); diff -r 9753943fcd89 go/expressions.h --- a/go/expressions.h Fri Dec 19 07:36:12 2014 -0800 +++ b/go/expressions.h Fri Dec 19 14:17:00 2014 -0800 @@ -1632,7 +1632,8 @@ 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 @@ 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.