Commit 30728d3e by Ian Lance Taylor

compiler: fix test for mismatch between function results and uses

Test is http://codereview.appspot.com/111360045 .

From-SVN: r212830
parent 6742052a
...@@ -9065,6 +9065,15 @@ Call_expression::result(size_t i) const ...@@ -9065,6 +9065,15 @@ Call_expression::result(size_t i) const
return (*this->results_)[i]; return (*this->results_)[i];
} }
// Set the number of results expected from a call expression.
void
Call_expression::set_expected_result_count(size_t count)
{
go_assert(this->expected_result_count_ == 0);
this->expected_result_count_ = count;
}
// Return whether this is a call to the predeclared function recover. // Return whether this is a call to the predeclared function recover.
bool bool
...@@ -9252,6 +9261,15 @@ Call_expression::do_check_types(Gogo*) ...@@ -9252,6 +9261,15 @@ Call_expression::do_check_types(Gogo*)
return; return;
} }
if (this->expected_result_count_ != 0
&& this->expected_result_count_ != this->result_count())
{
if (this->issue_error())
this->report_error(_("function result count mismatch"));
this->set_is_error();
return;
}
bool is_method = fntype->is_method(); bool is_method = fntype->is_method();
if (is_method) if (is_method)
{ {
...@@ -9302,6 +9320,20 @@ Call_expression::do_check_types(Gogo*) ...@@ -9302,6 +9320,20 @@ Call_expression::do_check_types(Gogo*)
if (!is_method || this->args_->size() > 1) if (!is_method || this->args_->size() > 1)
this->report_error(_("too many arguments")); this->report_error(_("too many arguments"));
} }
else if (this->args_->size() == 1
&& this->args_->front()->call_expression() != NULL
&& this->args_->front()->call_expression()->result_count() > 1)
{
// This is F(G()) when G returns more than one result. If the
// results can be matched to parameters, it would have been
// lowered in do_lower. If we get here we know there is a
// mismatch.
if (this->args_->front()->call_expression()->result_count()
< parameters->size())
this->report_error(_("not enough arguments"));
else
this->report_error(_("too many arguments"));
}
else else
{ {
int i = 0; int i = 0;
......
...@@ -1606,9 +1606,9 @@ class Call_expression : public Expression ...@@ -1606,9 +1606,9 @@ class Call_expression : public Expression
Location location) Location location)
: Expression(EXPRESSION_CALL, location), : Expression(EXPRESSION_CALL, location),
fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL), fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
call_temp_(NULL), is_varargs_(is_varargs), are_hidden_fields_ok_(false), call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
varargs_are_lowered_(false), types_are_determined_(false), are_hidden_fields_ok_(false), varargs_are_lowered_(false),
is_deferred_(false), issued_error_(false) types_are_determined_(false), is_deferred_(false), issued_error_(false)
{ } { }
// The function to call. // The function to call.
...@@ -1639,6 +1639,12 @@ class Call_expression : public Expression ...@@ -1639,6 +1639,12 @@ class Call_expression : public Expression
Temporary_statement* Temporary_statement*
result(size_t i) const; result(size_t i) const;
// Set the number of results expected from this call. This is used
// when the call appears in a context that expects multiple results,
// such as a, b = f().
void
set_expected_result_count(size_t);
// Return whether this is a call to the predeclared function // Return whether this is a call to the predeclared function
// recover. // recover.
bool bool
...@@ -1767,6 +1773,9 @@ class Call_expression : public Expression ...@@ -1767,6 +1773,9 @@ class Call_expression : public Expression
Bexpression* call_; Bexpression* call_;
// A temporary variable to store this call if the function returns a tuple. // A temporary variable to store this call if the function returns a tuple.
Temporary_statement* call_temp_; Temporary_statement* call_temp_;
// If not 0, the number of results expected from this call, when
// used in a context that expects multiple values.
size_t expected_result_count_;
// True if the last argument is a varargs argument (f(a...)). // True if the last argument is a varargs argument (f(a...)).
bool is_varargs_; bool is_varargs_;
// True if this statement may pass hidden fields in the arguments. // True if this statement may pass hidden fields in the arguments.
......
...@@ -1694,6 +1694,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type, ...@@ -1694,6 +1694,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
// the right number of values, but it might. Declare the variables, // the right number of values, but it might. Declare the variables,
// and then assign the results of the call to them. // and then assign the results of the call to them.
call->set_expected_result_count(vars->size());
Named_object* first_var = NULL; Named_object* first_var = NULL;
unsigned int index = 0; unsigned int index = 0;
bool any_new = false; bool any_new = false;
...@@ -4101,6 +4103,7 @@ Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit, ...@@ -4101,6 +4103,7 @@ Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit,
{ {
if (op != OPERATOR_EQ) if (op != OPERATOR_EQ)
error_at(location, "multiple results only permitted with %<=%>"); error_at(location, "multiple results only permitted with %<=%>");
call->set_expected_result_count(lhs->size());
delete vals; delete vals;
vals = new Expression_list; vals = new Expression_list;
for (unsigned int i = 0; i < lhs->size(); ++i) for (unsigned int i = 0; i < lhs->size(); ++i)
......
...@@ -2664,6 +2664,7 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, ...@@ -2664,6 +2664,7 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
&& vals->front()->call_expression() != NULL) && vals->front()->call_expression() != NULL)
{ {
Call_expression* call = vals->front()->call_expression(); Call_expression* call = vals->front()->call_expression();
call->set_expected_result_count(results_count);
delete vals; delete vals;
vals = new Expression_list; vals = new Expression_list;
for (size_t i = 0; i < results_count; ++i) for (size_t i = 0; i < results_count; ++i)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment