aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-06-08 16:40:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-06-08 16:40:21 +0000
commitdadcc51c88b86487f0145e8db7ff751463be1aff (patch)
treee826bea61ab1506b51f9cb5c4f9f593b7e98e3eb /gcc
parent77db6c1549c8e8d831a5fa0a246415e7572678e2 (diff)
downloadgcc-dadcc51c88b86487f0145e8db7ff751463be1aff.zip
gcc-dadcc51c88b86487f0145e8db7ff751463be1aff.tar.gz
gcc-dadcc51c88b86487f0145e8db7ff751463be1aff.tar.bz2
compiler: fix undefined symbol error with unexported method
When an interface I1 in an imported package has an unexported method, and is then embedded into another interface I2, in a different package, that has other methods, and a type T2 is converted to I2, we failed to ever define the required interface method table. Naturally T2 must implement the unexported method, and must therefore either be defined in the same package as I1, or embed a type from that package. In this case the compiler was assuming that that package would define the interface method table, but of course, since I2 was not defined in that package, that did not happen. The fix is to only assume that the interface method table will be defined elsewhere in the case where T2 and I2 are defined in the same package. The compiler ensures that all such interface method tables are created, in Gogo::build_interface_method_tables. This requires knowing the package in which an interface type is defined, a simple tweak to the importer. Testing this revealed that the special case for stub methods created for the embedded unexported methods of T2 needs to be done for function declarations as it currently is for function definitions, so that the newly created interface method tables use the correct name. Testing that revealed that the code to determine the pkgpath symbol for such stub methods was wrong. It assumed that one could call pkgpath_for_symbol on the pkgpath to get the pkgpath symbol. Would that it twere so simple. Instead, add a function to look up the package, which must be known, and fetch the pkgpath symbol. The test for this is https://golang.org/cl/45085. Reviewed-on: https://go-review.googlesource.com/45086 From-SVN: r249024
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc36
-rw-r--r--gcc/go/gofrontend/gogo.cc29
-rw-r--r--gcc/go/gofrontend/gogo.h4
-rw-r--r--gcc/go/gofrontend/types.cc4
-rw-r--r--gcc/go/gofrontend/types.h15
6 files changed, 65 insertions, 25 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index b603f1a..7142db0 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 a656b06..eaf492f 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)
- {
- if (Gogo::is_hidden_name(p->name()))
+ // 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()))
+ {
+ 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 26f6441..9071bc8 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 787a3e3..c3e3f30 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 a3ec52c..61a3363 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 53d6a2c..3f6240b 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.