diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b603f1a4f383..7142db00865f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -eaf4afbabcd91df55d31955500b6db55b07f6de5 +4b857cde45939f0e9f3cf89b9e347b6f6ebe0f8f The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a656b0681a18..eaf492f3501e 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -15430,27 +15430,32 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) + "__" + this->type_->mangled_name(gogo)); - // See whether this interface has any hidden methods. - bool has_hidden_methods = false; - for (Typed_identifier_list::const_iterator p = interface_methods->begin(); - p != interface_methods->end(); - ++p) + // Set is_public if we are converting a named type to an interface + // type that is defined in the same package as the named type, and + // the interface has hidden methods. In that case the interface + // method table will be defined by the package that defines the + // types. + bool is_public = false; + if (this->type_->named_type() != NULL + && (this->type_->named_type()->named_object()->package() + == this->itype_->package())) { - if (Gogo::is_hidden_name(p->name())) + for (Typed_identifier_list::const_iterator p = interface_methods->begin(); + p != interface_methods->end(); + ++p) { - has_hidden_methods = true; - break; + if (Gogo::is_hidden_name(p->name())) + { + is_public = true; + break; + } } } - // We already know that the named type is convertible to the - // interface. If the interface has hidden methods, and the named - // type is defined in a different package, then the interface - // conversion table will be defined by that other package. - if (has_hidden_methods - && this->type_->named_type() != NULL + if (is_public && this->type_->named_type()->named_object()->package() != NULL) { + // The interface conversion table is defined elsewhere. Btype* btype = this->type()->get_backend(gogo); std::string asm_name(go_selectively_encode_id(mangled_name)); this->bvar_ = @@ -15517,7 +15522,6 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Bexpression* ctor = gogo->backend()->constructor_expression(btype, ctor_bexprs, loc); - bool is_public = has_hidden_methods && this->type_->named_type() != NULL; std::string asm_name(go_selectively_encode_id(mangled_name)); this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false, !is_public, btype, loc); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 26f6441d5b16..9071bc8f62df 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1688,6 +1688,16 @@ Gogo::register_package(const std::string& pkgpath, return package; } +// Return the pkgpath symbol for a package, given the pkgpath. + +std::string +Gogo::pkgpath_symbol_for_package(const std::string& pkgpath) +{ + Packages::iterator p = this->packages_.find(pkgpath); + go_assert(p != this->packages_.end()); + return p->second->pkgpath_symbol(); +} + // Start compiling a function. Named_object* @@ -5418,8 +5428,8 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) // use the pkgpath of the imported package to avoid // a possible name collision. See bug478 for a test // case. - pkgpath = Gogo::hidden_name_pkgpath(no->name()); - pkgpath = Gogo::pkgpath_for_symbol(pkgpath); + std::string p = Gogo::hidden_name_pkgpath(no->name()); + pkgpath = gogo->pkgpath_symbol_for_package(p); } asm_name = pkgpath; @@ -5514,8 +5524,19 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) if (this->asm_name_.empty()) { asm_name = (no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); + ? gogo->pkgpath_symbol() + : no->package()->pkgpath_symbol()); + if (this->fntype_->is_method() + && Gogo::is_hidden_name(no->name()) + && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath()) + { + // This is a method created for an unexported method of + // an imported embedded type. Use the pkgpath of the + // imported package. This matches code in + // Function::get_or_make_decl, above. + std::string p = Gogo::hidden_name_pkgpath(no->name()); + asm_name = gogo->pkgpath_symbol_for_package(p); + } asm_name.append(1, '.'); asm_name.append(Gogo::unpack_hidden_name(no->name())); if (this->fntype_->is_method()) diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 787a3e3658f0..c3e3f30131de 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -362,6 +362,10 @@ class Gogo register_package(const std::string& pkgpath, const std::string& pkgpath_symbol, Location); + // Look up a package by pkgpath, and return its pkgpath_symbol. + std::string + pkgpath_symbol_for_package(const std::string&); + // Start compiling a function. ADD_METHOD_TO_TYPE is true if a // method function should be added to the type of its receiver. Named_object* diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index a3ec52c45cc3..61a33635c128 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -9816,7 +9816,9 @@ Interface_type::do_import(Import* imp) methods = NULL; } - return Type::make_interface_type(methods, imp->location()); + Interface_type* ret = Type::make_interface_type(methods, imp->location()); + ret->package_ = imp->package(); + return ret; } // Make an interface type. diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 53d6a2cd84f1..3f6240b9fd25 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2854,9 +2854,9 @@ class Interface_type : public Type Interface_type(Typed_identifier_list* methods, Location location) : Type(TYPE_INTERFACE), parse_methods_(methods), all_methods_(NULL), location_(location), - interface_btype_(NULL), bmethods_(NULL), assume_identical_(NULL), - methods_are_finalized_(false), bmethods_is_placeholder_(false), - seen_(false) + package_(NULL), interface_btype_(NULL), bmethods_(NULL), + assume_identical_(NULL), methods_are_finalized_(false), + bmethods_is_placeholder_(false), seen_(false) { go_assert(methods == NULL || !methods->empty()); } // The location where the interface type was defined. @@ -2864,6 +2864,12 @@ class Interface_type : public Type location() const { return this->location_; } + // The package where the interface type was defined. Returns NULL + // for the package currently being compiled. + Package* + package() const + { return this->package_; } + // Return whether this is an empty interface. bool is_empty() const @@ -3008,6 +3014,9 @@ class Interface_type : public Type Typed_identifier_list* all_methods_; // The location where the interface was defined. Location location_; + // The package where the interface was defined. This is NULL for + // the package being compiled. + Package* package_; // The backend representation of this type during backend conversion. Btype* interface_btype_; // The backend representation of the pointer to the method table.