diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index fa708bceae7..a2cf0af0634 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0494dc5737f0c89ad6f45e04e8313e4161678861 +84531ef21230307773daa438a50bf095edcdbf93 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/escape.cc b/gcc/go/gofrontend/escape.cc index d9dcc8993f4..eb23c2dc4a0 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -2077,7 +2077,8 @@ Escape_analysis_assign::call(Call_expression* call) else { if (!Type::are_identical(fntype->receiver()->type(), - (*p)->expr()->type(), true, NULL)) + (*p)->expr()->type(), Type::COMPARE_TAGS, + NULL)) { // This will be converted later, preemptively track it instead // of its conversion expression which will show up in a later pass. @@ -2096,7 +2097,7 @@ Escape_analysis_assign::call(Call_expression* call) ++pn, ++p) { if (!Type::are_identical(pn->type(), (*p)->expr()->type(), - true, NULL)) + Type::COMPARE_TAGS, NULL)) { // This will be converted later, preemptively track it instead // of its conversion expression which will show up in a later pass. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 91cc30e30b5..0a6910ac879 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -178,7 +178,10 @@ Expression::convert_for_assignment(Gogo*, Type* lhs_type, || rhs->is_error_expression()) return Expression::make_error(location); - bool are_identical = Type::are_identical(lhs_type, rhs_type, false, NULL); + bool are_identical = Type::are_identical(lhs_type, rhs_type, + (Type::COMPARE_ERRORS + | Type::COMPARE_TAGS), + NULL); if (!are_identical && lhs_type->interface_type() != NULL) { if (rhs_type->interface_type() == NULL) @@ -341,7 +344,9 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, bool for_type_guard, Location location) { - if (Type::are_identical(lhs_type, rhs->type(), false, NULL)) + if (Type::are_identical(lhs_type, rhs->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) return rhs; Interface_type* lhs_interface_type = lhs_type->interface_type(); @@ -3389,7 +3394,9 @@ Type_conversion_expression::do_is_static_initializer() const if (!this->expr_->is_static_initializer()) return false; - if (Type::are_identical(type, expr_type, false, NULL)) + if (Type::are_identical(type, expr_type, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) return true; if (type->is_string_type() && expr_type->is_string_type()) @@ -3503,7 +3510,9 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Btype* btype = type->get_backend(gogo); Location loc = this->location(); - if (Type::are_identical(type, expr_type, false, NULL)) + if (Type::are_identical(type, expr_type, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) { Bexpression* bexpr = this->expr_->get_backend(context); return gogo->backend()->convert_expression(btype, bexpr, loc); @@ -5433,7 +5442,10 @@ Binary_expression::lower_struct_comparison(Gogo* gogo, Struct_type* st2 = this->right_->type()->struct_type(); if (st2 == NULL) return this; - if (st != st2 && !Type::are_identical(st, st2, false, NULL)) + if (st != st2 + && !Type::are_identical(st, st2, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) return this; if (!Type::are_compatible_for_comparison(true, this->left_->type(), this->right_->type(), NULL)) @@ -5512,7 +5524,10 @@ Binary_expression::lower_array_comparison(Gogo* gogo, Array_type* at2 = this->right_->type()->array_type(); if (at2 == NULL) return this; - if (at != at2 && !Type::are_identical(at, at2, false, NULL)) + if (at != at2 + && !Type::are_identical(at, at2, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) return this; if (!Type::are_compatible_for_comparison(true, this->left_->type(), this->right_->type(), NULL)) @@ -6902,7 +6917,7 @@ Bound_method_expression::do_check_types(Gogo*) ? this->expr_type_ : this->expr_->type()); etype = etype->deref(); - if (!Type::are_identical(rtype, etype, true, NULL)) + if (!Type::are_identical(rtype, etype, Type::COMPARE_TAGS, NULL)) this->report_error(_("method type does not match object type")); } @@ -8404,7 +8419,9 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const && !rnc.type()->is_abstract() && inc.type() != NULL && !inc.type()->is_abstract() - && !Type::are_identical(rnc.type(), inc.type(), false, NULL)) + && !Type::are_identical(rnc.type(), inc.type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) return false; mpfr_t r; @@ -8885,7 +8902,7 @@ Builtin_call_expression::do_check_types(Gogo*) if (arg2_type->is_slice_type()) { Type* e2 = arg2_type->array_type()->element_type(); - if (!Type::are_identical(e1, e2, true, NULL)) + if (!Type::are_identical(e1, e2, Type::COMPARE_TAGS, NULL)) this->report_error(_("element types must be the same")); } else if (arg2_type->is_string_type()) @@ -9023,7 +9040,8 @@ Builtin_call_expression::do_check_types(Gogo*) || args->back()->type()->is_error()) this->set_is_error(); else if (!Type::are_identical(args->front()->type(), - args->back()->type(), true, NULL)) + args->back()->type(), + Type::COMPARE_TAGS, NULL)) this->report_error(_("complex arguments must have identical types")); else if (args->front()->type()->float_type() == NULL) this->report_error(_("complex arguments must have " @@ -9935,7 +9953,8 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, for (; pa != this->args_->end(); ++pa, ++pp) { go_assert(pp != fntype->parameters()->end()); - if (Type::are_identical(pp->type(), (*pa)->type(), true, NULL)) + if (Type::are_identical(pp->type(), (*pa)->type(), + Type::COMPARE_TAGS, NULL)) args->push_back(*pa); else { @@ -11630,7 +11649,9 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, return Expression::make_error(loc); } - if (!Type::are_identical(mt->key_type(), this->index_->type(), false, NULL)) + if (!Type::are_identical(mt->key_type(), this->index_->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL)) { if (this->index_->type()->interface_type() != NULL && !this->index_->is_variable()) @@ -15948,7 +15969,8 @@ Type* Conditional_expression::do_type() { Type* result_type = Type::make_void_type(); - if (Type::are_identical(this->then_->type(), this->else_->type(), false, + if (Type::are_identical(this->then_->type(), this->else_->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL)) result_type = this->then_->type(); else if (this->then_->is_nil_expression() diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index d07068d49ac..bfbf682fc11 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -6492,7 +6492,8 @@ Variable::flatten_init_expression(Gogo* gogo, Named_object* function, // If an interface conversion is needed, we need a temporary // variable. if (this->type_ != NULL - && !Type::are_identical(this->type_, this->init_->type(), false, + && !Type::are_identical(this->type_, this->init_->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->init_->type()->interface_type() != NULL && !this->init_->is_variable()) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 1df676f53c2..c35002df13c 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -472,7 +472,9 @@ Temporary_statement::do_flatten(Gogo*, Named_object*, Block*, if (this->type_ != NULL && this->init_ != NULL - && !Type::are_identical(this->type_, this->init_->type(), false, NULL) + && !Type::are_identical(this->type_, this->init_->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL) && this->init_->type()->interface_type() != NULL && !this->init_->is_variable()) { @@ -841,7 +843,8 @@ Assignment_statement::do_flatten(Gogo*, Named_object*, Block*, if (!this->lhs_->is_sink_expression() && !Type::are_identical(this->lhs_->type(), this->rhs_->type(), - false, NULL) + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL) && this->rhs_->type()->interface_type() != NULL && !this->rhs_->is_variable()) { @@ -4384,7 +4387,9 @@ Send_statement::do_flatten(Gogo*, Named_object*, Block*, } Type* element_type = this->channel_->type()->channel_type()->element_type(); - if (!Type::are_identical(element_type, this->val_->type(), false, NULL) + if (!Type::are_identical(element_type, this->val_->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL) && this->val_->type()->interface_type() != NULL && !this->val_->is_variable()) { diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 573011a2565..bb90e92716a 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -336,29 +336,17 @@ Type::do_traverse(Traverse*) return TRAVERSE_CONTINUE; } -// Return whether two types are identical. If ERRORS_ARE_IDENTICAL, -// then return true for all erroneous types; this is used to avoid -// cascading errors. If REASON is not NULL, optionally set *REASON to -// the reason the types are not identical. +// Return whether two types are identical. If REASON is not NULL, +// optionally set *REASON to the reason the types are not identical. bool -Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, +Type::are_identical(const Type* t1, const Type* t2, int flags, std::string* reason) -{ - return Type::are_identical_cmp_tags(t1, t2, COMPARE_TAGS, - errors_are_identical, reason); -} - -// Like are_identical, but with a CMP_TAGS parameter. - -bool -Type::are_identical_cmp_tags(const Type* t1, const Type* t2, Cmp_tags cmp_tags, - bool errors_are_identical, std::string* reason) { if (t1 == NULL || t2 == NULL) { // Something is wrong. - return errors_are_identical ? true : t1 == t2; + return (flags & COMPARE_ERRORS) == 0 ? true : t1 == t2; } // Skip defined forward declarations. Ignore aliases. @@ -371,12 +359,12 @@ Type::are_identical_cmp_tags(const Type* t1, const Type* t2, Cmp_tags cmp_tags, // An undefined forward declaration is an error. if (t1->forward_declaration_type() != NULL || t2->forward_declaration_type() != NULL) - return errors_are_identical; + return (flags & COMPARE_ERRORS) == 0; // Avoid cascading errors with error types. if (t1->is_error_type() || t2->is_error_type()) { - if (errors_are_identical) + if ((flags & COMPARE_ERRORS) == 0) return true; return t1->is_error_type() && t2->is_error_type(); } @@ -418,35 +406,26 @@ Type::are_identical_cmp_tags(const Type* t1, const Type* t2, Cmp_tags cmp_tags, case TYPE_FUNCTION: return t1->function_type()->is_identical(t2->function_type(), - false, - cmp_tags, - errors_are_identical, - reason); + false, flags, reason); case TYPE_POINTER: - return Type::are_identical_cmp_tags(t1->points_to(), t2->points_to(), - cmp_tags, errors_are_identical, - reason); + return Type::are_identical(t1->points_to(), t2->points_to(), flags, + reason); case TYPE_STRUCT: - return t1->struct_type()->is_identical(t2->struct_type(), cmp_tags, - errors_are_identical); + return t1->struct_type()->is_identical(t2->struct_type(), flags); case TYPE_ARRAY: - return t1->array_type()->is_identical(t2->array_type(), cmp_tags, - errors_are_identical); + return t1->array_type()->is_identical(t2->array_type(), flags); case TYPE_MAP: - return t1->map_type()->is_identical(t2->map_type(), cmp_tags, - errors_are_identical); + return t1->map_type()->is_identical(t2->map_type(), flags); case TYPE_CHANNEL: - return t1->channel_type()->is_identical(t2->channel_type(), cmp_tags, - errors_are_identical); + return t1->channel_type()->is_identical(t2->channel_type(), flags); case TYPE_INTERFACE: - return t1->interface_type()->is_identical(t2->interface_type(), cmp_tags, - errors_are_identical); + return t1->interface_type()->is_identical(t2->interface_type(), flags); case TYPE_CALL_MULTIPLE_RESULT: if (reason != NULL) @@ -464,7 +443,7 @@ Type::are_identical_cmp_tags(const Type* t1, const Type* t2, Cmp_tags cmp_tags, bool Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) { - if (Type::are_identical(lhs, rhs, true, NULL)) + if (Type::are_identical(lhs, rhs, Type::COMPARE_TAGS, NULL)) return true; // A constant of abstract bool type may be mixed with any bool type. @@ -675,7 +654,7 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) return true; // Identical types are assignable. - if (Type::are_identical(lhs, rhs, true, reason)) + if (Type::are_identical(lhs, rhs, Type::COMPARE_TAGS, reason)) return true; // Ignore aliases, except for error messages. @@ -688,7 +667,8 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) // and either LHS or RHS is not a named type. if (((lhs->named_type() != NULL && rhs->named_type() == NULL) || (rhs->named_type() != NULL && lhs->named_type() == NULL)) - && Type::are_identical(lhs->base(), rhs->base(), true, reason)) + && Type::are_identical(lhs->base(), rhs->base(), Type::COMPARE_TAGS, + reason)) return true; // The types are assignable if LHS is an interface type and RHS @@ -715,7 +695,7 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) && (lhs->named_type() == NULL || rhs->named_type() == NULL) && Type::are_identical(lhs->channel_type()->element_type(), rhs->channel_type()->element_type(), - true, + Type::COMPARE_TAGS, reason)) return true; @@ -796,8 +776,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) // The types are convertible if they have identical underlying // types, ignoring struct field tags. if ((lhs->named_type() != NULL || rhs->named_type() != NULL) - && Type::are_identical_cmp_tags(lhs->base(), rhs->base(), IGNORE_TAGS, - true, reason)) + && Type::are_identical(lhs->base(), rhs->base(), 0, reason)) return true; // The types are convertible if they are both unnamed pointer types @@ -809,11 +788,9 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) && rhs->points_to() != NULL && (lhs->points_to()->named_type() != NULL || rhs->points_to()->named_type() != NULL) - && Type::are_identical_cmp_tags(lhs->points_to()->base(), - rhs->points_to()->base(), - IGNORE_TAGS, - true, - reason)) + && Type::are_identical(lhs->points_to()->base(), + rhs->points_to()->base(), + 0, reason)) return true; // Integer and floating point types are convertible to each other. @@ -944,21 +921,21 @@ Type::copy_expressions() // Return a hash code for the type to be used for method lookup. unsigned int -Type::hash_for_method(Gogo* gogo) const +Type::hash_for_method(Gogo* gogo, int flags) const { if (this->named_type() != NULL && this->named_type()->is_alias()) - return this->named_type()->real_type()->hash_for_method(gogo); + return this->named_type()->real_type()->hash_for_method(gogo, flags); unsigned int ret = 0; if (this->classification_ != TYPE_FORWARD) ret += this->classification_; - return ret + this->do_hash_for_method(gogo); + return ret + this->do_hash_for_method(gogo, flags); } // Default implementation of do_hash_for_method. This is appropriate // for types with no subfields. unsigned int -Type::do_hash_for_method(Gogo*) const +Type::do_hash_for_method(Gogo*, int) const { return 0; } @@ -2370,9 +2347,9 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, go_assert(p->is_field_name("hash")); unsigned int h; if (name != NULL) - h = name->hash_for_method(gogo); + h = name->hash_for_method(gogo, Type::COMPARE_TAGS); else - h = this->hash_for_method(gogo); + h = this->hash_for_method(gogo, Type::COMPARE_TAGS); vals->push_back(Expression::make_integer_ul(h, p->type(), bloc)); ++p; @@ -3980,7 +3957,7 @@ Integer_type::is_identical(const Integer_type* t) const // Hash code. unsigned int -Integer_type::do_hash_for_method(Gogo*) const +Integer_type::do_hash_for_method(Gogo*, int) const { return ((this->bits_ << 4) + ((this->is_unsigned_ ? 1 : 0) << 8) @@ -4110,7 +4087,7 @@ Float_type::is_identical(const Float_type* t) const // Hash code. unsigned int -Float_type::do_hash_for_method(Gogo*) const +Float_type::do_hash_for_method(Gogo*, int) const { return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); } @@ -4224,7 +4201,7 @@ Complex_type::is_identical(const Complex_type *t) const // Hash code. unsigned int -Complex_type::do_hash_for_method(Gogo*) const +Complex_type::do_hash_for_method(Gogo*, int) const { return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); } @@ -4443,7 +4420,7 @@ bool Function_type::is_valid_redeclaration(const Function_type* t, std::string* reason) const { - if (!this->is_identical(t, false, COMPARE_TAGS, true, reason)) + if (!this->is_identical(t, false, COMPARE_TAGS, reason)) return false; // A redeclaration of a function is required to use the same names @@ -4521,8 +4498,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, bool Function_type::is_identical(const Function_type* t, bool ignore_receiver, - Cmp_tags cmp_tags, bool errors_are_identical, - std::string* reason) const + int flags, std::string* reason) const { if (this->is_backend_function_type() != t->is_backend_function_type()) return false; @@ -4539,8 +4515,7 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, } if (r1 != NULL) { - if (!Type::are_identical_cmp_tags(r1->type(), r2->type(), cmp_tags, - errors_are_identical, reason)) + if (!Type::are_identical(r1->type(), r2->type(), flags, reason)) { if (reason != NULL && !reason->empty()) *reason = "receiver: " + *reason; @@ -4575,8 +4550,7 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, return false; } - if (!Type::are_identical_cmp_tags(p1->type(), p2->type(), cmp_tags, - errors_are_identical, NULL)) + if (!Type::are_identical(p1->type(), p2->type(), flags, NULL)) { if (reason != NULL) *reason = _("different parameter types"); @@ -4624,9 +4598,7 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, return false; } - if (!Type::are_identical_cmp_tags(res1->type(), res2->type(), - cmp_tags, errors_are_identical, - NULL)) + if (!Type::are_identical(res1->type(), res2->type(), flags, NULL)) { if (reason != NULL) *reason = _("different result types"); @@ -4647,7 +4619,7 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, // Hash code. unsigned int -Function_type::do_hash_for_method(Gogo* gogo) const +Function_type::do_hash_for_method(Gogo* gogo, int flags) const { unsigned int ret = 0; // We ignore the receiver type for hash codes, because we need to @@ -4659,7 +4631,7 @@ Function_type::do_hash_for_method(Gogo* gogo) const for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); p != this->parameters_->end(); ++p, ++shift) - ret += p->type()->hash_for_method(gogo) << shift; + ret += p->type()->hash_for_method(gogo, flags) << shift; } if (this->results_ != NULL) { @@ -4667,7 +4639,7 @@ Function_type::do_hash_for_method(Gogo* gogo) const for (Typed_identifier_list::const_iterator p = this->results_->begin(); p != this->results_->end(); ++p, ++shift) - ret += p->type()->hash_for_method(gogo) << shift; + ret += p->type()->hash_for_method(gogo, flags) << shift; } if (this->is_varargs_) ret += 1; @@ -4687,7 +4659,7 @@ Function_type::Results_hash::operator()(const Typed_identifier_list* t) const { hash <<= 2; hash = Type::hash_string(p->name(), hash); - hash += p->type()->hash_for_method(NULL); + hash += p->type()->hash_for_method(NULL, Type::COMPARE_TAGS); } return hash; } @@ -4707,7 +4679,8 @@ Function_type::Results_equal::operator()(const Typed_identifier_list* a, ++pa, ++pb) { if (pa->name() != pb->name() - || !Type::are_identical(pa->type(), pb->type(), true, NULL)) + || !Type::are_identical(pa->type(), pb->type(), Type::COMPARE_TAGS, + NULL)) return false; } return true; @@ -5269,9 +5242,9 @@ Pointer_type::do_traverse(Traverse* traverse) // Hash code. unsigned int -Pointer_type::do_hash_for_method(Gogo* gogo) const +Pointer_type::do_hash_for_method(Gogo* gogo, int flags) const { - return this->to_type_->hash_for_method(gogo) << 4; + return this->to_type_->hash_for_method(gogo, flags) << 4; } // Get the backend representation for a pointer type. @@ -5723,8 +5696,7 @@ Struct_type::do_has_pointer() const // Whether this type is identical to T. bool -Struct_type::is_identical(const Struct_type* t, Cmp_tags cmp_tags, - bool errors_are_identical) const +Struct_type::is_identical(const Struct_type* t, int flags) const { if (this->is_struct_incomparable_ != t->is_struct_incomparable_) return false; @@ -5742,10 +5714,9 @@ Struct_type::is_identical(const Struct_type* t, Cmp_tags cmp_tags, if (pf1->field_name() != pf2->field_name()) return false; if (pf1->is_anonymous() != pf2->is_anonymous() - || !Type::are_identical_cmp_tags(pf1->type(), pf2->type(), cmp_tags, - errors_are_identical, NULL)) + || !Type::are_identical(pf1->type(), pf2->type(), flags, NULL)) return false; - if (cmp_tags == COMPARE_TAGS) + if ((flags & Type::COMPARE_TAGS) != 0) { if (!pf1->has_tag()) { @@ -5876,7 +5847,7 @@ Struct_type::do_in_heap() // Hash code. unsigned int -Struct_type::do_hash_for_method(Gogo* gogo) const +Struct_type::do_hash_for_method(Gogo* gogo, int flags) const { unsigned int ret = 0; if (this->fields() != NULL) @@ -5884,7 +5855,7 @@ Struct_type::do_hash_for_method(Gogo* gogo) const for (Struct_field_list::const_iterator pf = this->fields()->begin(); pf != this->fields()->end(); ++pf) - ret = (ret << 1) + pf->type()->hash_for_method(gogo); + ret = (ret << 1) + pf->type()->hash_for_method(gogo, flags); } ret <<= 2; if (this->is_struct_incomparable_) @@ -6940,11 +6911,10 @@ Array_type::int_length(int64_t* plen) // Whether two array types are identical. bool -Array_type::is_identical(const Array_type* t, Cmp_tags cmp_tags, - bool errors_are_identical) const +Array_type::is_identical(const Array_type* t, int flags) const { - if (!Type::are_identical_cmp_tags(this->element_type(), t->element_type(), - cmp_tags, errors_are_identical, NULL)) + if (!Type::are_identical(this->element_type(), t->element_type(), + flags, NULL)) return false; if (this->is_array_incomparable_ != t->is_array_incomparable_) @@ -7154,13 +7124,13 @@ Array_type::do_compare_is_identity(Gogo* gogo) // Array type hash code. unsigned int -Array_type::do_hash_for_method(Gogo* gogo) const +Array_type::do_hash_for_method(Gogo* gogo, int flags) const { unsigned int ret; // There is no very convenient way to get a hash code for the // length. - ret = this->element_type_->hash_for_method(gogo) + 1; + ret = this->element_type_->hash_for_method(gogo, flags) + 1; if (this->is_array_incomparable_) ret <<= 1; return ret; @@ -7873,23 +7843,20 @@ Map_type::do_verify() // Whether two map types are identical. bool -Map_type::is_identical(const Map_type* t, Cmp_tags cmp_tags, - bool errors_are_identical) const +Map_type::is_identical(const Map_type* t, int flags) const { - return (Type::are_identical_cmp_tags(this->key_type(), t->key_type(), - cmp_tags, errors_are_identical, NULL) - && Type::are_identical_cmp_tags(this->val_type(), t->val_type(), - cmp_tags, errors_are_identical, - NULL)); + return (Type::are_identical(this->key_type(), t->key_type(), flags, NULL) + && Type::are_identical(this->val_type(), t->val_type(), flags, + NULL)); } // Hash code. unsigned int -Map_type::do_hash_for_method(Gogo* gogo) const +Map_type::do_hash_for_method(Gogo* gogo, int flags) const { - return (this->key_type_->hash_for_method(gogo) - + this->val_type_->hash_for_method(gogo) + return (this->key_type_->hash_for_method(gogo, flags) + + this->val_type_->hash_for_method(gogo, flags) + 2); } @@ -8386,7 +8353,7 @@ Channel_type::do_verify() // Hash code. unsigned int -Channel_type::do_hash_for_method(Gogo* gogo) const +Channel_type::do_hash_for_method(Gogo* gogo, int flags) const { unsigned int ret = 0; if (this->may_send_) @@ -8394,18 +8361,17 @@ Channel_type::do_hash_for_method(Gogo* gogo) const if (this->may_receive_) ret += 2; if (this->element_type_ != NULL) - ret += this->element_type_->hash_for_method(gogo) << 2; + ret += this->element_type_->hash_for_method(gogo, flags) << 2; return ret << 3; } // Whether this type is the same as T. bool -Channel_type::is_identical(const Channel_type* t, Cmp_tags cmp_tags, - bool errors_are_identical) const +Channel_type::is_identical(const Channel_type* t, int flags) const { - if (!Type::are_identical_cmp_tags(this->element_type(), t->element_type(), - cmp_tags, errors_are_identical, NULL)) + if (!Type::are_identical(this->element_type(), t->element_type(), flags, + NULL)) return false; return (this->may_send_ == t->may_send_ && this->may_receive_ == t->may_receive_); @@ -8775,8 +8741,7 @@ Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const // Whether this type is identical with T. bool -Interface_type::is_identical(const Interface_type* t, Cmp_tags cmp_tags, - bool errors_are_identical) const +Interface_type::is_identical(const Interface_type* t, int flags) const { // If methods have not been finalized, then we are asking whether // func redeclarations are the same. This is an error, so for @@ -8806,8 +8771,7 @@ Interface_type::is_identical(const Interface_type* t, Cmp_tags cmp_tags, if (p1 == this->all_methods_->end()) break; if (p1->name() != p2->name() - || !Type::are_identical_cmp_tags(p1->type(), p2->type(), cmp_tags, - errors_are_identical, NULL)) + || !Type::are_identical(p1->type(), p2->type(), flags, NULL)) break; } @@ -8863,7 +8827,8 @@ Interface_type::is_compatible_for_assign(const Interface_type* t, } std::string subreason; - if (!Type::are_identical(p->type(), m->type(), true, &subreason)) + if (!Type::are_identical(p->type(), m->type(), Type::COMPARE_TAGS, + &subreason)) { if (reason != NULL) { @@ -8891,7 +8856,7 @@ Interface_type::is_compatible_for_assign(const Interface_type* t, // Hash code. unsigned int -Interface_type::do_hash_for_method(Gogo*) const +Interface_type::do_hash_for_method(Gogo*, int) const { go_assert(this->methods_are_finalized_); unsigned int ret = 0; @@ -9005,7 +8970,7 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const Function_type* m_fn_type = m->type()->function_type(); go_assert(p_fn_type != NULL && m_fn_type != NULL); std::string subreason; - if (!p_fn_type->is_identical(m_fn_type, true, COMPARE_TAGS, true, + if (!p_fn_type->is_identical(m_fn_type, true, Type::COMPARE_TAGS, &subreason)) { if (reason != NULL) @@ -10427,7 +10392,7 @@ Named_type::do_needs_key_update() // hash on the name itself. unsigned int -Named_type::do_hash_for_method(Gogo* gogo) const +Named_type::do_hash_for_method(Gogo* gogo, int) const { if (this->is_error_) return 0; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 85e7c51c302..9e3f2f36e3c 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -563,30 +563,23 @@ class Type verify() { return this->do_verify(); } - // Return true if two types are identical. If ERRORS_ARE_IDENTICAL, - // returns that an erroneous type is identical to any other type; - // this is used to avoid cascading errors. If this returns false, + // Bit flags to pass to are_identical and friends. + + // Treat error types as their own distinct type. Sometimes we + // ignore error types--treat them as identical to every other + // type--to avoid cascading errors. + static const int COMPARE_ERRORS = 1; + + // Compare struct field tags when comparing structs. We ignore + // struct field tags for purposes of type conversion. + static const int COMPARE_TAGS = 2; + + // Return true if two types are identical. If this returns false, // and REASON is not NULL, it may set *REASON. static bool - are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical, + are_identical(const Type* lhs, const Type* rhs, int flags, std::string* reason); - // An argument to are_identical_cmp_tags, indicating whether or not - // to compare struct field tags. - enum Cmp_tags { - COMPARE_TAGS, - IGNORE_TAGS - }; - - // Return true if two types are identical. This is like the - // are_identical function, but also takes a CMP_TAGS argument - // indicating whether to compare struct tags. Otherwise the - // parameters are as for are_identical. - static bool - are_identical_cmp_tags(const Type* lhs, const Type* rhs, - Cmp_tags, bool errors_are_identical, - std::string* reason); - // Return true if two types are compatible for use in a binary // operation, other than a shift, comparison, or channel send. This // is an equivalence relation. @@ -648,7 +641,7 @@ class Type // Types which are equivalent according to are_identical will have // the same hash code. unsigned int - hash_for_method(Gogo*) const; + hash_for_method(Gogo*, int) const; // Return the type classification. Type_classification @@ -1082,7 +1075,7 @@ class Type { return true; } virtual unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; virtual Btype* do_get_backend(Gogo*) = 0; @@ -1381,14 +1374,18 @@ class Type bool in_heap_; }; -// Type hash table operations. +// Type hash table operations, treating aliases as identical to the +// types that they alias. class Type_hash_identical { public: unsigned int operator()(const Type* type) const - { return type->hash_for_method(NULL); } + { + return type->hash_for_method(NULL, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS); + } }; class Type_identical @@ -1396,7 +1393,11 @@ class Type_identical public: bool operator()(const Type* t1, const Type* t2) const - { return Type::are_identical(t1, t2, false, NULL); } + { + return Type::are_identical(t1, t2, + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL); + } }; // An identifier with a type. @@ -1724,7 +1725,7 @@ protected: { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -1810,7 +1811,7 @@ class Float_type : public Type { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -1888,7 +1889,7 @@ class Complex_type : public Type { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2036,8 +2037,8 @@ class Function_type : public Type // Whether this type is the same as T. bool - is_identical(const Function_type* t, bool ignore_receiver, - Cmp_tags, bool errors_are_identical, std::string*) const; + is_identical(const Function_type* t, bool ignore_receiver, int flags, + std::string*) const; // Record that this is a varargs function. void @@ -2102,7 +2103,7 @@ class Function_type : public Type { return false; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2231,7 +2232,7 @@ class Pointer_type : public Type { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2478,8 +2479,7 @@ class Struct_type : public Type // Whether this type is identical with T. bool - is_identical(const Struct_type* t, Cmp_tags, - bool errors_are_identical) const; + is_identical(const Struct_type* t, int) const; // Return whether NAME is a local field which is not exported. This // is only used for better error reporting. @@ -2498,7 +2498,7 @@ class Struct_type : public Type has_any_methods() const { return this->all_methods_ != NULL; } - // Return the methods for tihs type. This should only be called + // Return the methods for this type. This should only be called // after the finalize_methods pass. const Methods* methods() const @@ -2590,7 +2590,7 @@ class Struct_type : public Type do_in_heap(); unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2684,8 +2684,7 @@ class Array_type : public Type // Whether this type is identical with T. bool - is_identical(const Array_type* t, Cmp_tags, - bool errors_are_identical) const; + is_identical(const Array_type* t, int) const; // Return an expression for the pointer to the values in an array. Expression* @@ -2767,7 +2766,7 @@ class Array_type : public Type { return this->length_ == NULL || this->element_type_->in_heap(); } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2850,8 +2849,7 @@ class Map_type : public Type // Whether this type is identical with T. bool - is_identical(const Map_type* t, Cmp_tags, - bool errors_are_identical) const; + is_identical(const Map_type* t, int) const; // Import a map type. static Map_type* @@ -2885,7 +2883,7 @@ class Map_type : public Type } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -2970,8 +2968,7 @@ class Channel_type : public Type // Whether this type is identical with T. bool - is_identical(const Channel_type* t, Cmp_tags, - bool errors_are_identical) const; + is_identical(const Channel_type* t, int) const; // Import a channel type. static Channel_type* @@ -3000,7 +2997,7 @@ class Channel_type : public Type { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -3090,8 +3087,7 @@ class Interface_type : public Type // Whether this type is identical with T. REASON is as in // implements_interface. bool - is_identical(const Interface_type* t, Cmp_tags, - bool errors_are_identical) const; + is_identical(const Interface_type* t, int) const; // Whether we can assign T to this type. is_identical is known to // be false. @@ -3151,7 +3147,7 @@ class Interface_type : public Type { return true; } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -3476,7 +3472,7 @@ class Named_type : public Type { return this->in_heap_ && this->type_->in_heap(); } unsigned int - do_hash_for_method(Gogo*) const; + do_hash_for_method(Gogo*, int) const; Btype* do_get_backend(Gogo*); @@ -3639,8 +3635,8 @@ class Forward_declaration_type : public Type { return this->real_type()->in_heap(); } unsigned int - do_hash_for_method(Gogo* gogo) const - { return this->real_type()->hash_for_method(gogo); } + do_hash_for_method(Gogo* gogo, int flags) const + { return this->real_type()->hash_for_method(gogo, flags); } Btype* do_get_backend(Gogo* gogo); diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index 52db71046fe..3f0a89f8ceb 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -777,7 +777,9 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, inserter->insert(lhs_temp); lhs = Expression::make_temporary_reference(lhs_temp, loc); - if (!Type::are_identical(type, rhs->type(), false, NULL) + if (!Type::are_identical(type, rhs->type(), + Type::COMPARE_ERRORS | Type::COMPARE_TAGS, + NULL) && rhs->type()->interface_type() != NULL && !rhs->is_variable()) {