aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2014-07-18 21:59:12 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-07-18 21:59:12 +0000
commit30728d3e80a2653028e5aabb0acbed52c9936f4c (patch)
treebb24d5d2976aba0f2dec4db00e327105e4b46cb4
parent6742052af4eac19acab2313a82dda5a80bd4c665 (diff)
downloadgcc-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.cc32
-rw-r--r--gcc/go/gofrontend/expressions.h15
-rw-r--r--gcc/go/gofrontend/parse.cc3
-rw-r--r--gcc/go/gofrontend/statements.cc1
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)