compiler: If type defined as type, forward hash/equal functions.

Fixes http://golang.org/issue/6789 .

From-SVN: r205404
This commit is contained in:
Ian Lance Taylor 2013-11-26 18:09:09 +00:00
parent 08af82b017
commit 304cfd9a7b
2 changed files with 107 additions and 2 deletions

View File

@ -1833,7 +1833,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)
@ -1851,7 +1853,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);
@ -1864,6 +1868,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 comparison.
Expression_list* vals = new Expression_list();
vals->push_back(cond);
Statement* s = Statement::make_return_statement(vals, bloc);
gogo->add_statement(s);
}
// Return a composite literal for the type descriptor for a plain type
// of kind RUNTIME_TYPE_KIND named NAME.

View File

@ -1138,6 +1138,13 @@ class Type
Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn);
void
write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype,
Function_type* equal_fntype);
void
write_named_equal(Gogo*, Named_type*);
// Build a composite literal for the uncommon type information.
Expression*
uncommon_type_constructor(Gogo*, Type* uncommon_type,