Commit 7d2f2a6b by Ian Lance Taylor

compiler: ignore struct field tags for type conversion

    
    Go 1.8 includes a language change (https://golang.org/doc/go1.8#language):
    in an explicit conversion from one struct type to another, any field
    tags are ignored.
    
    This CL implements this language change in the gofrontend.  The tests
    for this are in the gc testsuite, which will be copied into the gccgo
    repository in due course.
    
    Updates golang/go#16085.
    
    Reviewed-on: https://go-review.googlesource.com/43614

From-SVN: r248248
parent e4171e10
ba68a42618d1e8516e38da093d3af731d7fd4f06 369e1efe19adfc5393d2235992327f39360e0554
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -317,6 +317,16 @@ bool ...@@ -317,6 +317,16 @@ bool
Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
std::string* reason) 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) if (t1 == NULL || t2 == NULL)
{ {
// Something is wrong. // Something is wrong.
...@@ -387,31 +397,33 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, ...@@ -387,31 +397,33 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
case TYPE_FUNCTION: case TYPE_FUNCTION:
return t1->function_type()->is_identical(t2->function_type(), return t1->function_type()->is_identical(t2->function_type(),
false, false,
cmp_tags,
errors_are_identical, errors_are_identical,
reason); reason);
case TYPE_POINTER: case TYPE_POINTER:
return Type::are_identical(t1->points_to(), t2->points_to(), return Type::are_identical_cmp_tags(t1->points_to(), t2->points_to(),
errors_are_identical, reason); cmp_tags, errors_are_identical,
reason);
case TYPE_STRUCT: case TYPE_STRUCT:
return t1->struct_type()->is_identical(t2->struct_type(), return t1->struct_type()->is_identical(t2->struct_type(), cmp_tags,
errors_are_identical); errors_are_identical);
case TYPE_ARRAY: case TYPE_ARRAY:
return t1->array_type()->is_identical(t2->array_type(), return t1->array_type()->is_identical(t2->array_type(), cmp_tags,
errors_are_identical); errors_are_identical);
case TYPE_MAP: case TYPE_MAP:
return t1->map_type()->is_identical(t2->map_type(), return t1->map_type()->is_identical(t2->map_type(), cmp_tags,
errors_are_identical); errors_are_identical);
case TYPE_CHANNEL: case TYPE_CHANNEL:
return t1->channel_type()->is_identical(t2->channel_type(), return t1->channel_type()->is_identical(t2->channel_type(), cmp_tags,
errors_are_identical); errors_are_identical);
case TYPE_INTERFACE: case TYPE_INTERFACE:
return t1->interface_type()->is_identical(t2->interface_type(), return t1->interface_type()->is_identical(t2->interface_type(), cmp_tags,
errors_are_identical); errors_are_identical);
case TYPE_CALL_MULTIPLE_RESULT: case TYPE_CALL_MULTIPLE_RESULT:
...@@ -735,23 +747,26 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) ...@@ -735,23 +747,26 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
return true; return true;
// The types are convertible if they have identical underlying // The types are convertible if they have identical underlying
// types. // types, ignoring struct field tags.
if ((lhs->named_type() != NULL || rhs->named_type() != NULL) if ((lhs->named_type() != NULL || rhs->named_type() != NULL)
&& Type::are_identical(lhs->base(), rhs->base(), true, reason)) && Type::are_identical_cmp_tags(lhs->base(), rhs->base(), IGNORE_TAGS,
true, reason))
return true; return true;
// The types are convertible if they are both unnamed pointer types // The types are convertible if they are both unnamed pointer types
// and their pointer base types have identical underlying types. // and their pointer base types have identical underlying types,
// ignoring struct field tags.
if (lhs->named_type() == NULL if (lhs->named_type() == NULL
&& rhs->named_type() == NULL && rhs->named_type() == NULL
&& lhs->points_to() != NULL && lhs->points_to() != NULL
&& rhs->points_to() != NULL && rhs->points_to() != NULL
&& (lhs->points_to()->named_type() != NULL && (lhs->points_to()->named_type() != NULL
|| rhs->points_to()->named_type() != NULL) || rhs->points_to()->named_type() != NULL)
&& Type::are_identical(lhs->points_to()->base(), && Type::are_identical_cmp_tags(lhs->points_to()->base(),
rhs->points_to()->base(), rhs->points_to()->base(),
true, IGNORE_TAGS,
reason)) true,
reason))
return true; return true;
// Integer and floating point types are convertible to each other. // Integer and floating point types are convertible to each other.
...@@ -4502,7 +4517,7 @@ bool ...@@ -4502,7 +4517,7 @@ bool
Function_type::is_valid_redeclaration(const Function_type* t, Function_type::is_valid_redeclaration(const Function_type* t,
std::string* reason) const std::string* reason) const
{ {
if (!this->is_identical(t, false, true, reason)) if (!this->is_identical(t, false, COMPARE_TAGS, true, reason))
return false; return false;
// A redeclaration of a function is required to use the same names // A redeclaration of a function is required to use the same names
...@@ -4580,7 +4595,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, ...@@ -4580,7 +4595,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
bool bool
Function_type::is_identical(const Function_type* t, bool ignore_receiver, Function_type::is_identical(const Function_type* t, bool ignore_receiver,
bool errors_are_identical, Cmp_tags cmp_tags, bool errors_are_identical,
std::string* reason) const std::string* reason) const
{ {
if (!ignore_receiver) if (!ignore_receiver)
...@@ -4595,8 +4610,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, ...@@ -4595,8 +4610,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
} }
if (r1 != NULL) if (r1 != NULL)
{ {
if (!Type::are_identical(r1->type(), r2->type(), errors_are_identical, if (!Type::are_identical_cmp_tags(r1->type(), r2->type(), cmp_tags,
reason)) errors_are_identical, reason))
{ {
if (reason != NULL && !reason->empty()) if (reason != NULL && !reason->empty())
*reason = "receiver: " + *reason; *reason = "receiver: " + *reason;
...@@ -4627,8 +4642,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, ...@@ -4627,8 +4642,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
return false; return false;
} }
if (!Type::are_identical(p1->type(), p2->type(), if (!Type::are_identical_cmp_tags(p1->type(), p2->type(), cmp_tags,
errors_are_identical, NULL)) errors_are_identical, NULL))
{ {
if (reason != NULL) if (reason != NULL)
*reason = _("different parameter types"); *reason = _("different parameter types");
...@@ -4672,8 +4687,9 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver, ...@@ -4672,8 +4687,9 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
return false; return false;
} }
if (!Type::are_identical(res1->type(), res2->type(), if (!Type::are_identical_cmp_tags(res1->type(), res2->type(),
errors_are_identical, NULL)) cmp_tags, errors_are_identical,
NULL))
{ {
if (reason != NULL) if (reason != NULL)
*reason = _("different result types"); *reason = _("different result types");
...@@ -5803,7 +5819,7 @@ Struct_type::do_has_pointer() const ...@@ -5803,7 +5819,7 @@ Struct_type::do_has_pointer() const
// Whether this type is identical to T. // Whether this type is identical to T.
bool bool
Struct_type::is_identical(const Struct_type* t, Struct_type::is_identical(const Struct_type* t, Cmp_tags cmp_tags,
bool errors_are_identical) const bool errors_are_identical) const
{ {
if (this->is_struct_incomparable_ != t->is_struct_incomparable_) if (this->is_struct_incomparable_ != t->is_struct_incomparable_)
...@@ -5822,20 +5838,23 @@ Struct_type::is_identical(const Struct_type* t, ...@@ -5822,20 +5838,23 @@ Struct_type::is_identical(const Struct_type* t,
if (pf1->field_name() != pf2->field_name()) if (pf1->field_name() != pf2->field_name())
return false; return false;
if (pf1->is_anonymous() != pf2->is_anonymous() if (pf1->is_anonymous() != pf2->is_anonymous()
|| !Type::are_identical(pf1->type(), pf2->type(), || !Type::are_identical_cmp_tags(pf1->type(), pf2->type(), cmp_tags,
errors_are_identical, NULL)) errors_are_identical, NULL))
return false; return false;
if (!pf1->has_tag()) if (cmp_tags == COMPARE_TAGS)
{ {
if (pf2->has_tag()) if (!pf1->has_tag())
return false; {
} if (pf2->has_tag())
else return false;
{ }
if (!pf2->has_tag()) else
return false; {
if (pf1->tag() != pf2->tag()) if (!pf2->has_tag())
return false; return false;
if (pf1->tag() != pf2->tag())
return false;
}
} }
} }
if (pf2 != fields2->end()) if (pf2 != fields2->end())
...@@ -7061,10 +7080,11 @@ Array_type::int_length(int64_t* plen) ...@@ -7061,10 +7080,11 @@ Array_type::int_length(int64_t* plen)
// Whether two array types are identical. // Whether two array types are identical.
bool bool
Array_type::is_identical(const Array_type* t, bool errors_are_identical) const Array_type::is_identical(const Array_type* t, Cmp_tags cmp_tags,
bool errors_are_identical) const
{ {
if (!Type::are_identical(this->element_type(), t->element_type(), if (!Type::are_identical_cmp_tags(this->element_type(), t->element_type(),
errors_are_identical, NULL)) cmp_tags, errors_are_identical, NULL))
return false; return false;
if (this->is_array_incomparable_ != t->is_array_incomparable_) if (this->is_array_incomparable_ != t->is_array_incomparable_)
...@@ -7986,12 +8006,14 @@ Map_type::do_verify() ...@@ -7986,12 +8006,14 @@ Map_type::do_verify()
// Whether two map types are identical. // Whether two map types are identical.
bool bool
Map_type::is_identical(const Map_type* t, bool errors_are_identical) const Map_type::is_identical(const Map_type* t, Cmp_tags cmp_tags,
bool errors_are_identical) const
{ {
return (Type::are_identical(this->key_type(), t->key_type(), return (Type::are_identical_cmp_tags(this->key_type(), t->key_type(),
errors_are_identical, NULL) cmp_tags, errors_are_identical, NULL)
&& Type::are_identical(this->val_type(), t->val_type(), && Type::are_identical_cmp_tags(this->val_type(), t->val_type(),
errors_are_identical, NULL)); cmp_tags, errors_are_identical,
NULL));
} }
// Hash code. // Hash code.
...@@ -8510,11 +8532,11 @@ Channel_type::do_hash_for_method(Gogo* gogo) const ...@@ -8510,11 +8532,11 @@ Channel_type::do_hash_for_method(Gogo* gogo) const
// Whether this type is the same as T. // Whether this type is the same as T.
bool bool
Channel_type::is_identical(const Channel_type* t, Channel_type::is_identical(const Channel_type* t, Cmp_tags cmp_tags,
bool errors_are_identical) const bool errors_are_identical) const
{ {
if (!Type::are_identical(this->element_type(), t->element_type(), if (!Type::are_identical_cmp_tags(this->element_type(), t->element_type(),
errors_are_identical, NULL)) cmp_tags, errors_are_identical, NULL))
return false; return false;
return (this->may_send_ == t->may_send_ return (this->may_send_ == t->may_send_
&& this->may_receive_ == t->may_receive_); && this->may_receive_ == t->may_receive_);
...@@ -8920,7 +8942,7 @@ Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const ...@@ -8920,7 +8942,7 @@ Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
// Whether this type is identical with T. // Whether this type is identical with T.
bool bool
Interface_type::is_identical(const Interface_type* t, Interface_type::is_identical(const Interface_type* t, Cmp_tags cmp_tags,
bool errors_are_identical) const bool errors_are_identical) const
{ {
// If methods have not been finalized, then we are asking whether // If methods have not been finalized, then we are asking whether
...@@ -8951,8 +8973,8 @@ Interface_type::is_identical(const Interface_type* t, ...@@ -8951,8 +8973,8 @@ Interface_type::is_identical(const Interface_type* t,
if (p1 == this->all_methods_->end()) if (p1 == this->all_methods_->end())
break; break;
if (p1->name() != p2->name() if (p1->name() != p2->name()
|| !Type::are_identical(p1->type(), p2->type(), || !Type::are_identical_cmp_tags(p1->type(), p2->type(), cmp_tags,
errors_are_identical, NULL)) errors_are_identical, NULL))
break; break;
} }
...@@ -9150,7 +9172,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const ...@@ -9150,7 +9172,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
Function_type* m_fn_type = m->type()->function_type(); Function_type* m_fn_type = m->type()->function_type();
go_assert(p_fn_type != NULL && m_fn_type != NULL); go_assert(p_fn_type != NULL && m_fn_type != NULL);
std::string subreason; std::string subreason;
if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason)) if (!p_fn_type->is_identical(m_fn_type, true, COMPARE_TAGS, true,
&subreason))
{ {
if (reason != NULL) if (reason != NULL)
{ {
......
...@@ -568,6 +568,22 @@ class Type ...@@ -568,6 +568,22 @@ class Type
are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical, are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical,
std::string* reason); 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 // Return true if two types are compatible for use in a binary
// operation, other than a shift, comparison, or channel send. This // operation, other than a shift, comparison, or channel send. This
// is an equivalence relation. // is an equivalence relation.
...@@ -1899,7 +1915,7 @@ class Function_type : public Type ...@@ -1899,7 +1915,7 @@ class Function_type : public Type
// Whether this type is the same as T. // Whether this type is the same as T.
bool bool
is_identical(const Function_type* t, bool ignore_receiver, is_identical(const Function_type* t, bool ignore_receiver,
bool errors_are_identical, std::string*) const; Cmp_tags, bool errors_are_identical, std::string*) const;
// Record that this is a varargs function. // Record that this is a varargs function.
void void
...@@ -2293,7 +2309,8 @@ class Struct_type : public Type ...@@ -2293,7 +2309,8 @@ class Struct_type : public Type
// Whether this type is identical with T. // Whether this type is identical with T.
bool bool
is_identical(const Struct_type* t, bool errors_are_identical) const; is_identical(const Struct_type* t, Cmp_tags,
bool errors_are_identical) const;
// Return whether NAME is a local field which is not exported. This // Return whether NAME is a local field which is not exported. This
// is only used for better error reporting. // is only used for better error reporting.
...@@ -2495,7 +2512,8 @@ class Array_type : public Type ...@@ -2495,7 +2512,8 @@ class Array_type : public Type
// Whether this type is identical with T. // Whether this type is identical with T.
bool bool
is_identical(const Array_type* t, bool errors_are_identical) const; is_identical(const Array_type* t, Cmp_tags,
bool errors_are_identical) const;
// Return an expression for the pointer to the values in an array. // Return an expression for the pointer to the values in an array.
Expression* Expression*
...@@ -2656,7 +2674,8 @@ class Map_type : public Type ...@@ -2656,7 +2674,8 @@ class Map_type : public Type
// Whether this type is identical with T. // Whether this type is identical with T.
bool bool
is_identical(const Map_type* t, bool errors_are_identical) const; is_identical(const Map_type* t, Cmp_tags,
bool errors_are_identical) const;
// Import a map type. // Import a map type.
static Map_type* static Map_type*
...@@ -2773,7 +2792,8 @@ class Channel_type : public Type ...@@ -2773,7 +2792,8 @@ class Channel_type : public Type
// Whether this type is identical with T. // Whether this type is identical with T.
bool bool
is_identical(const Channel_type* t, bool errors_are_identical) const; is_identical(const Channel_type* t, Cmp_tags,
bool errors_are_identical) const;
// Import a channel type. // Import a channel type.
static Channel_type* static Channel_type*
...@@ -2883,7 +2903,8 @@ class Interface_type : public Type ...@@ -2883,7 +2903,8 @@ class Interface_type : public Type
// Whether this type is identical with T. REASON is as in // Whether this type is identical with T. REASON is as in
// implements_interface. // implements_interface.
bool bool
is_identical(const Interface_type* t, bool errors_are_identical) const; is_identical(const Interface_type* t, Cmp_tags,
bool errors_are_identical) const;
// Whether we can assign T to this type. is_identical is known to // Whether we can assign T to this type. is_identical is known to
// be false. // be false.
......
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