diff mbox

Go patch committed: separate comparable and incomparable types

Message ID CAOyqgcUSfsjGTiNV+QEA2Zocxgt++Xr7AVj8hTtoU8J6b8J0Dw@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Nov. 16, 2016, 2:47 p.m. UTC
This patch to the Go frontend separates comparable and incomparable
types.  Otherwise we can create an incomparable type for, say, a map
bucket, and have that mislead us into creating an incomparable user
type.  If the user type is then used in a map, the program crashes.

This fixes the gccgo version of https://golang.org/issue/17752.  The
test case for gccgo is https://golang.org/cl/33249.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 242403)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-eb716b515356166d3177e6244619be5901f31162
+31ff8c31d33c3e77cae4fd55445f12825eb92af5
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 241384)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -4792,6 +4792,8 @@  bool
 Struct_type::is_identical(const Struct_type* t,
 			  bool errors_are_identical) const
 {
+  if (this->is_struct_incomparable_ != t->is_struct_incomparable_)
+    return false;
   const Struct_field_list* fields1 = this->fields();
   const Struct_field_list* fields2 = t->fields();
   if (fields1 == NULL || fields2 == NULL)
@@ -4929,7 +4931,10 @@  Struct_type::do_hash_for_method(Gogo* go
 	   ++pf)
 	ret = (ret << 1) + pf->type()->hash_for_method(gogo);
     }
-  return ret <<= 2;
+  ret <<= 2;
+  if (this->is_struct_incomparable_)
+    ret <<= 1;
+  return ret;
 }
 
 // Find the local field NAME.
@@ -5659,6 +5664,9 @@  Struct_type::do_mangled_name(Gogo* gogo,
 	}
     }
 
+  if (this->is_struct_incomparable_)
+    ret->push_back('x');
+
   ret->push_back('e');
 }
 
@@ -6052,6 +6060,9 @@  Array_type::is_identical(const Array_typ
 			   errors_are_identical, NULL))
     return false;
 
+  if (this->is_array_incomparable_ != t->is_array_incomparable_)
+    return false;
+
   Expression* l1 = this->length();
   Expression* l2 = t->length();
 
@@ -6216,9 +6227,14 @@  Array_type::do_compare_is_identity(Gogo*
 unsigned int
 Array_type::do_hash_for_method(Gogo* gogo) const
 {
+  unsigned int ret;
+
   // There is no very convenient way to get a hash code for the
   // length.
-  return this->element_type_->hash_for_method(gogo) + 1;
+  ret = this->element_type_->hash_for_method(gogo) + 1;
+  if (this->is_array_incomparable_)
+    ret <<= 1;
+  return ret;
 }
 
 // Write the hash function for an array which can not use the identify
@@ -6916,6 +6932,8 @@  Array_type::do_mangled_name(Gogo* gogo,
       ret->append(s);
       free(s);
       mpz_clear(val);
+      if (this->is_array_incomparable_)
+	ret->push_back('x');
     }
   ret->push_back('e');
 }