diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-18 21:59:12 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-18 21:59:12 +0000 |
commit | 30728d3e80a2653028e5aabb0acbed52c9936f4c (patch) | |
tree | bb24d5d2976aba0f2dec4db00e327105e4b46cb4 | |
parent | 6742052af4eac19acab2313a82dda5a80bd4c665 (diff) | |
download | gcc-30728d3e80a2653028e5aabb0acbed52c9936f4c.zip gcc-30728d3e80a2653028e5aabb0acbed52c9936f4c.tar.gz gcc-30728d3e80a2653028e5aabb0acbed52c9936f4c.tar.bz2 |
compiler: fix test for mismatch between function results and uses
Test is http://codereview.appspot.com/111360045 .
From-SVN: r212830
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 32 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 1 |
4 files changed, 48 insertions, 3 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 53c0068..f054d0a 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -9065,6 +9065,15 @@ Call_expression::result(size_t i) const 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. bool @@ -9252,6 +9261,15 @@ Call_expression::do_check_types(Gogo*) 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(); if (is_method) { @@ -9302,6 +9320,20 @@ Call_expression::do_check_types(Gogo*) if (!is_method || this->args_->size() > 1) 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 { int i = 0; diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 8337d10..0ce6f22 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1606,9 +1606,9 @@ class Call_expression : public Expression Location location) : Expression(EXPRESSION_CALL, location), fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL), - call_temp_(NULL), is_varargs_(is_varargs), are_hidden_fields_ok_(false), - varargs_are_lowered_(false), types_are_determined_(false), - is_deferred_(false), issued_error_(false) + call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs), + are_hidden_fields_ok_(false), varargs_are_lowered_(false), + types_are_determined_(false), is_deferred_(false), issued_error_(false) { } // The function to call. @@ -1639,6 +1639,12 @@ class Call_expression : public Expression Temporary_statement* 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 // recover. bool @@ -1767,6 +1773,9 @@ class Call_expression : public Expression Bexpression* call_; // A temporary variable to store this call if the function returns a tuple. 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...)). bool is_varargs_; // True if this statement may pass hidden fields in the arguments. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 3d60171..d7d3a07 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -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, // and then assign the results of the call to them. + call->set_expected_result_count(vars->size()); + Named_object* first_var = NULL; unsigned int index = 0; bool any_new = false; @@ -4101,6 +4103,7 @@ Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit, { if (op != OPERATOR_EQ) error_at(location, "multiple results only permitted with %<=%>"); + call->set_expected_result_count(lhs->size()); delete vals; vals = new Expression_list; for (unsigned int i = 0; i < lhs->size(); ++i) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index a4a44e7..c407591 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -2664,6 +2664,7 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, && vals->front()->call_expression() != NULL) { Call_expression* call = vals->front()->call_expression(); + call->set_expected_result_count(results_count); delete vals; vals = new Expression_list; for (size_t i = 0; i < results_count; ++i) |