When gccgo saw multiple identical unnamed structs with methods assigned to interfaces that used those methods, it would emit multiple copies of the interface method table, causing a duplicate symbol error from the assembler. This patch fixes the bug. I added a test case to the master testsuite that will be copied in the gccgo testsuite in due course. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch.
Ian
diff -r 6791d7b7151c go/types.cc --- a/go/types.cc Wed Sep 18 11:34:51 2013 -0700 +++ b/go/types.cc Wed Sep 18 14:50:19 2013 -0700 @@ -4229,6 +4229,11 @@ Struct_type::Identical_structs Struct_type::identical_structs; +// A hash table used to merge method sets for identical unnamed +// structs. + +Struct_type::Struct_method_tables Struct_type::struct_method_tables; + // Traversal. int @@ -4693,9 +4698,24 @@ const Interface_type* interface, bool is_pointer) { + std::pair<Struct_type*, Struct_type::Struct_method_table_pair*> + val(this, NULL); + std::pair<Struct_type::Struct_method_tables::iterator, bool> ins = + Struct_type::struct_method_tables.insert(val); + + Struct_method_table_pair* smtp; + if (!ins.second) + smtp = ins.first->second; + else + { + smtp = new Struct_method_table_pair(); + smtp->first = NULL; + smtp->second = NULL; + ins.first->second = smtp; + } + return Type::interface_method_table(gogo, this, interface, is_pointer, - &this->interface_method_tables_, - &this->pointer_interface_method_tables_); + &smtp->first, &smtp->second); } // Convert struct fields to the backend representation. This is not diff -r 6791d7b7151c go/types.h --- a/go/types.h Wed Sep 18 11:34:51 2013 -0700 +++ b/go/types.h Wed Sep 18 14:50:19 2013 -0700 @@ -2041,8 +2041,7 @@ public: Struct_type(Struct_field_list* fields, Location location) : Type(TYPE_STRUCT), - fields_(fields), location_(location), all_methods_(NULL), - interface_method_tables_(NULL), pointer_interface_method_tables_(NULL) + fields_(fields), location_(location), all_methods_(NULL) { } // Return the field NAME. This only looks at local fields, not at @@ -2200,6 +2199,16 @@ static Identical_structs identical_structs; + // Used to manage method tables for identical unnamed structs. + typedef std::pair<Interface_method_tables*, Interface_method_tables*> + Struct_method_table_pair; + + typedef Unordered_map_hash(Struct_type*, Struct_method_table_pair*, + Type_hash_identical, Type_identical) + Struct_method_tables; + + static Struct_method_tables struct_method_tables; + // Used to avoid infinite loops in field_reference_depth. struct Saw_named_type { @@ -2218,13 +2227,6 @@ Location location_; // If this struct is unnamed, a list of methods. Methods* all_methods_; - // A mapping from interfaces to the associated interface method - // tables for this type. Only used if this struct is unnamed. - Interface_method_tables* interface_method_tables_; - // A mapping from interfaces to the associated interface method - // tables for pointers to this type. Only used if this struct is - // unnamed. - Interface_method_tables* pointer_interface_method_tables_; }; // The type of an array.