This patch to the Go frontend by Cherry Zhang makes a single backend type for methods table of identical interface types. Otherwise identical interface types will get an identical backend type, but can have different method tables, which is inconsistent and can leave incomplete placeholdser around. This patch fixes the problem. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 257415) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -02f11a2d5cf0db2c2675c13d92bb69529f2175dd +5fe998e4a18cc1dbbd4869be5c8202bda55adb33 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 257415) +++ gcc/go/gofrontend/types.cc (working copy) @@ -9096,6 +9096,8 @@ Interface_type::get_backend_empty_interf return empty_interface_type; } +Interface_type::Bmethods_map Interface_type::bmethods_map; + // Return a pointer to the backend representation of the method table. Btype* @@ -9104,6 +9106,21 @@ Interface_type::get_backend_methods(Gogo if (this->bmethods_ != NULL && !this->bmethods_is_placeholder_) return this->bmethods_; + std::pair<Interface_type*, Bmethods_map_entry> val; + val.first = this; + val.second.btype = NULL; + val.second.is_placeholder = false; + std::pair<Bmethods_map::iterator, bool> ins = + Interface_type::bmethods_map.insert(val); + if (!ins.second + && ins.first->second.btype != NULL + && !ins.first->second.is_placeholder) + { + this->bmethods_ = ins.first->second.btype; + this->bmethods_is_placeholder_ = false; + return this->bmethods_; + } + Location loc = this->location(); std::vector<Backend::Btyped_identifier> @@ -9160,10 +9177,14 @@ Interface_type::get_backend_methods(Gogo Btype* st = gogo->backend()->struct_type(mfields); Btype* ret = gogo->backend()->pointer_type(st); - if (this->bmethods_ != NULL && this->bmethods_is_placeholder_) - gogo->backend()->set_placeholder_pointer_type(this->bmethods_, ret); + if (ins.first->second.btype != NULL + && ins.first->second.is_placeholder) + gogo->backend()->set_placeholder_pointer_type(ins.first->second.btype, + ret); this->bmethods_ = ret; + ins.first->second.btype = ret; this->bmethods_is_placeholder_ = false; + ins.first->second.is_placeholder = false; return ret; } @@ -9174,10 +9195,25 @@ Interface_type::get_backend_methods_plac { if (this->bmethods_ == NULL) { + std::pair<Interface_type*, Bmethods_map_entry> val; + val.first = this; + val.second.btype = NULL; + val.second.is_placeholder = false; + std::pair<Bmethods_map::iterator, bool> ins = + Interface_type::bmethods_map.insert(val); + if (!ins.second && ins.first->second.btype != NULL) + { + this->bmethods_ = ins.first->second.btype; + this->bmethods_is_placeholder_ = ins.first->second.is_placeholder; + return this->bmethods_; + } + Location loc = this->location(); - this->bmethods_ = gogo->backend()->placeholder_pointer_type("", loc, - false); + Btype* bt = gogo->backend()->placeholder_pointer_type("", loc, false); + this->bmethods_ = bt; + ins.first->second.btype = bt; this->bmethods_is_placeholder_ = true; + ins.first->second.is_placeholder = true; } return this->bmethods_; } Index: gcc/go/gofrontend/types.h =================================================================== --- gcc/go/gofrontend/types.h (revision 257415) +++ gcc/go/gofrontend/types.h (working copy) @@ -3185,6 +3185,20 @@ class Interface_type : public Type bool assume_identical(const Interface_type*, const Interface_type*) const; + struct Bmethods_map_entry + { + Btype *btype; + bool is_placeholder; + }; + + // A mapping from Interface_type to the backend type of its bmethods_, + // used to ensure that the backend representation of identical types + // is identical. + typedef Unordered_map_hash(const Interface_type*, Bmethods_map_entry, + Type_hash_identical, Type_identical) Bmethods_map; + + static Bmethods_map bmethods_map; + // The list of methods associated with the interface from the // parser. This will be NULL for the empty interface. This may // include unnamed interface types.