Re: backport fix for go hash function names to 4.8

2013-12-02 Thread Ian Lance Taylor
On Wed, Nov 27, 2013 at 3:04 PM, Michael Hudson-Doyle
michael.hud...@linaro.org wrote:

 This patch brings the recent fix for the generated hash functions of
 types that are aliases for structures containing unexported fields to
 the 4.8 branch.

Thanks.  Committed to 4.8 branch.

Ian


backport fix for go hash function names to 4.8

2013-11-27 Thread Michael Hudson-Doyle
Hi,

This patch brings the recent fix for the generated hash functions of
types that are aliases for structures containing unexported fields to
the 4.8 branch.

Cheers,
mwh

diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 59247d6..36383de 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1834,7 +1834,9 @@ Type::write_specific_type_functions(Gogo* gogo, 
Named_type* name,
   bloc);
   gogo-start_block(bloc);
 
-  if (this-struct_type() != NULL)
+  if (name != NULL  name-real_type()-named_type() != NULL)
+this-write_named_hash(gogo, name, hash_fntype, equal_fntype);
+  else if (this-struct_type() != NULL)
 this-struct_type()-write_hash_function(gogo, name, hash_fntype,
 equal_fntype);
   else if (this-array_type() != NULL)
@@ -1852,7 +1854,9 @@ Type::write_specific_type_functions(Gogo* gogo, 
Named_type* name,
false, bloc);
   gogo-start_block(bloc);
 
-  if (this-struct_type() != NULL)
+  if (name != NULL  name-real_type()-named_type() != NULL)
+this-write_named_equal(gogo, name);
+  else if (this-struct_type() != NULL)
 this-struct_type()-write_equal_function(gogo, name);
   else if (this-array_type() != NULL)
 this-array_type()-write_equal_function(gogo, name);
@@ -1865,6 +1869,100 @@ Type::write_specific_type_functions(Gogo* gogo, 
Named_type* name,
   gogo-finish_function(bloc);
 }
 
+// Write a hash function that simply calls the hash function for a
+// named type.  This is used when one named type is defined as
+// another.  This ensures that this case works when the other named
+// type is defined in another package and relies on calling hash
+// functions defined only in that package.
+
+void
+Type::write_named_hash(Gogo* gogo, Named_type* name,
+  Function_type* hash_fntype, Function_type* equal_fntype)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  Named_type* base_type = name-real_type()-named_type();
+  go_assert(base_type != NULL);
+
+  // The pointer to the type we are going to hash.  This is an
+  // unsafe.Pointer.
+  Named_object* key_arg = gogo-lookup(key, NULL);
+  go_assert(key_arg != NULL);
+
+  // The size of the type we are going to hash.
+  Named_object* keysz_arg = gogo-lookup(key_size, NULL);
+  go_assert(keysz_arg != NULL);
+
+  Named_object* hash_fn;
+  Named_object* equal_fn;
+  name-real_type()-type_functions(gogo, base_type, hash_fntype, equal_fntype,
+   hash_fn, equal_fn);
+
+  // Call the hash function for the base type.
+  Expression* key_ref = Expression::make_var_reference(key_arg, bloc);
+  Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc);
+  Expression_list* args = new Expression_list();
+  args-push_back(key_ref);
+  args-push_back(keysz_ref);
+  Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
+  Expression* call = Expression::make_call(func, args, false, bloc);
+
+  // Return the hash of the base type.
+  Expression_list* vals = new Expression_list();
+  vals-push_back(call);
+  Statement* s = Statement::make_return_statement(vals, bloc);
+  gogo-add_statement(s);
+}
+
+// Write an equality function that simply calls the equality function
+// for a named type.  This is used when one named type is defined as
+// another.  This ensures that this case works when the other named
+// type is defined in another package and relies on calling equality
+// functions defined only in that package.
+
+void
+Type::write_named_equal(Gogo* gogo, Named_type* name)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  // The pointers to the types we are going to compare.  These have
+  // type unsafe.Pointer.
+  Named_object* key1_arg = gogo-lookup(key1, NULL);
+  Named_object* key2_arg = gogo-lookup(key2, NULL);
+  go_assert(key1_arg != NULL  key2_arg != NULL);
+
+  Named_type* base_type = name-real_type()-named_type();
+  go_assert(base_type != NULL);
+
+  // Build temporaries with the base type.
+  Type* pt = Type::make_pointer_type(base_type);
+
+  Expression* ref = Expression::make_var_reference(key1_arg, bloc);
+  ref = Expression::make_cast(pt, ref, bloc);
+  Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc);
+  gogo-add_statement(p1);
+
+  ref = Expression::make_var_reference(key2_arg, bloc);
+  ref = Expression::make_cast(pt, ref, bloc);
+  Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc);
+  gogo-add_statement(p2);
+
+  // Compare the values for equality.
+  Expression* t1 = Expression::make_temporary_reference(p1, bloc);
+  t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc);
+
+  Expression* t2 = Expression::make_temporary_reference(p2, bloc);
+  t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc);
+
+  Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc);
+
+  // Return the equality