From 17c9cf3c17651950bd4bfefcbe15440fa2155810 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 2 Dec 2020 18:11:00 -0800 Subject: [PATCH] compiler: cast comparison function result to expected bool type Otherwise cases like type mybool bool var b mybool = [10]string{} == [10]string{} get an incorrect type checking error. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/274446 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 42 +++++++++++++++++++++++++++++--- gcc/go/gofrontend/expressions.h | 11 +++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f55daf7562c..cd1a3961a06 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5364d15082de77d2759a01f254208d4cb4f579e3 +b3a0b068f7fa2d65ba781271b2c0479d103b7d7b The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 50574c2bc58..ebe1b36eb53 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6287,8 +6287,21 @@ Binary_expression::lower_array_comparison(Gogo* gogo, args->push_back(this->operand_address(inserter, this->left_)); args->push_back(this->operand_address(inserter, this->right_)); - Expression* ret = Expression::make_call(func, args, false, loc); - + Call_expression* ce = Expression::make_call(func, args, false, loc); + + // Record that this is a call to a generated equality function. We + // need to do this because a comparison returns an abstract boolean + // type, but the function necessarily returns "bool". The + // difference shows up in code like + // type mybool bool + // var b mybool = [10]string{} == [10]string{} + // The comparison function returns "bool", but since a comparison + // has an abstract boolean type we need an implicit conversion to + // "mybool". The implicit conversion is inserted in + // Call_expression::do_flatten. + ce->set_is_equal_function(); + + Expression* ret = ce; if (this->op_ == OPERATOR_NOTEQ) ret = Expression::make_unary(OPERATOR_NOT, ret, loc); @@ -11163,6 +11176,13 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, return ret; } + // Add an implicit conversion to a boolean type, if needed. See the + // comment in Binary_expression::lower_array_comparison. + if (this->is_equal_function_ + && this->type_ != NULL + && this->type_ != Type::lookup_bool_type()) + return Expression::make_cast(this->type_, this, this->location()); + return this; } @@ -11938,7 +11958,7 @@ Call_expression::do_type() // parameter types to set the types of the arguments. void -Call_expression::do_determine_type(const Type_context*) +Call_expression::do_determine_type(const Type_context* context) { if (!this->determining_types()) return; @@ -11985,6 +12005,22 @@ Call_expression::do_determine_type(const Type_context*) (*pa)->determine_type_no_context(); } } + + // If this is a call to a generated equality function, we determine + // the type based on the context. See the comment in + // Binary_expression::lower_array_comparison. + if (this->is_equal_function_ + && !context->may_be_abstract + && context->type != NULL + && context->type->is_boolean_type() + && context->type != Type::lookup_bool_type()) + { + go_assert(this->type_ == NULL + || this->type_ == Type::lookup_bool_type() + || this->type_ == context->type + || this->type_->is_error()); + this->type_ = context->type; + } } // Called when determining types for a Call_expression. Return true diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index d2975238572..259eeb6027e 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -2326,8 +2326,8 @@ class Call_expression : public Expression fn_(fn), args_(args), type_(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), is_concurrent_(false), issued_error_(false), - is_multi_value_arg_(false), is_flattened_(false) + is_deferred_(false), is_concurrent_(false), is_equal_function_(false), + issued_error_(false), is_multi_value_arg_(false), is_flattened_(false) { } // The function to call. @@ -2408,6 +2408,11 @@ class Call_expression : public Expression set_is_concurrent() { this->is_concurrent_ = true; } + // Note that this is a call to a generated equality function. + void + set_is_equal_function() + { this->is_equal_function_ = true; } + // We have found an error with this call expression; return true if // we should report it. bool @@ -2545,6 +2550,8 @@ class Call_expression : public Expression bool is_deferred_; // True if the call is an argument to a go statement. bool is_concurrent_; + // True if this is a call to a generated equality function. + bool is_equal_function_; // True if we reported an error about a mismatch between call // results and uses. This is to avoid producing multiple errors // when there are multiple Call_result_expressions. -- 2.30.2