From 2e29434de909a71522122f18fc66efd40c23ce8b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 30 Jan 2015 00:35:44 +0000 Subject: [PATCH] compiler: Fix -fgo-prefix handling. There was bug in the fix for PR 61880: it only worked fully correctly for code compiled with -fgo-pkgpath. For code that used -fgo-prefix, or that used neither option, the '.' separating the prefix and the package name was converted to an underscore, which did not happen before. This broke SWIG and any other code that expected specific symbol names. Fortunately all code compiled in libgo and all code compiled by the go tool uses -fgo-pkgpath, so this probably did not affect very many people. This is an incomplete fix that does not modify the package file format, for use on both mainline and the GCC 4.9 branch. A follow on patch will fully fix the problem. From-SVN: r220268 --- gcc/go/gofrontend/export.cc | 16 ++++++-- gcc/go/gofrontend/export.h | 5 ++- gcc/go/gofrontend/gogo.cc | 79 +++++++++++++++++++++++++++++++------ gcc/go/gofrontend/gogo.h | 16 +++++--- gcc/go/gofrontend/import.cc | 10 +++-- gcc/go/gofrontend/unsafe.cc | 2 +- 6 files changed, 103 insertions(+), 25 deletions(-) diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 13c61a589fe..e37f03446c1 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -91,6 +91,7 @@ should_export(Named_object* no) void Export::export_globals(const std::string& package_name, + const std::string& prefix, const std::string& pkgpath, int package_priority, const std::map& imports, @@ -140,9 +141,18 @@ Export::export_globals(const std::string& package_name, this->write_string(package_name); this->write_c_string(";\n"); - // The package path, used for all global symbols. - this->write_c_string("pkgpath "); - this->write_string(pkgpath); + // The prefix or package path, used for all global symbols. + if (prefix.empty()) + { + go_assert(!pkgpath.empty()); + this->write_c_string("pkgpath "); + this->write_string(pkgpath); + } + else + { + this->write_c_string("prefix "); + this->write_string(prefix); + } this->write_c_string(";\n"); // The package priority. diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index c6a4810510a..c010a14686c 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -117,14 +117,17 @@ class Export : public String_dump // Export the identifiers in BINDINGS which are marked for export. // The exporting is done via a series of calls to THIS->STREAM_. If // is nothing to export, this->stream_->write will not be called. - // PKGPATH is the package path. + // PREFIX is the package prefix. PKGPATH is the package path. + // Only one of PREFIX and PKGPATH will be non-empty. // PACKAGE_PRIORITY is the priority to use for this package. + // IMPORTS is the explicitly imported packages. // IMPORT_INIT_FN is the name of the import initialization function // for this package; it will be empty if none is needed. // IMPORTED_INIT_FNS is the list of initialization functions for // imported packages. void export_globals(const std::string& package_name, + const std::string& prefix, const std::string& pkgpath, int package_priority, const std::map& imports, diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 252560d9e35..9039ce3ab9d 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -341,22 +341,28 @@ Gogo::set_package_name(const std::string& package_name, // Now that we know the name of the package we are compiling, set // the package path to use for reflect.Type.PkgPath and global // symbol names. - if (!this->pkgpath_set_) + if (this->pkgpath_set_) + this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_); + else { if (!this->prefix_from_option_ && package_name == "main") - this->pkgpath_ = package_name; + { + this->pkgpath_ = package_name; + this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(package_name); + } else { if (!this->prefix_from_option_) this->prefix_ = "go"; this->pkgpath_ = this->prefix_ + '.' + package_name; + this->pkgpath_symbol_ = (Gogo::pkgpath_for_symbol(this->prefix_) + '.' + + Gogo::pkgpath_for_symbol(package_name)); } this->pkgpath_set_ = true; } - this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_); - - this->package_ = this->register_package(this->pkgpath_, location); + this->package_ = this->register_package(this->pkgpath_, + this->pkgpath_symbol_, location); this->package_->set_package_name(package_name, location); if (this->is_main_package()) @@ -1524,10 +1530,11 @@ Gogo::add_imported_package(const std::string& real_name, const std::string& alias_arg, bool is_alias_exported, const std::string& pkgpath, + const std::string& pkgpath_symbol, Location location, bool* padd_to_globals) { - Package* ret = this->register_package(pkgpath, location); + Package* ret = this->register_package(pkgpath, pkgpath_symbol, location); ret->set_package_name(real_name, location); *padd_to_globals = false; @@ -1556,10 +1563,13 @@ Gogo::add_imported_package(const std::string& real_name, // Register a package. This package may or may not be imported. This // returns the Package structure for the package, creating if it // necessary. LOCATION is the location of the import statement that -// led us to see this package. +// led us to see this package. PKGPATH_SYMBOL is the symbol to use +// for names in the package; it may be the empty string, in which case +// we either get it later or make a guess when we need it. Package* -Gogo::register_package(const std::string& pkgpath, Location location) +Gogo::register_package(const std::string& pkgpath, + const std::string& pkgpath_symbol, Location location) { Package* package = NULL; std::pair ins = @@ -1569,13 +1579,15 @@ Gogo::register_package(const std::string& pkgpath, Location location) // We have seen this package name before. package = ins.first->second; go_assert(package != NULL && package->pkgpath() == pkgpath); + if (!pkgpath_symbol.empty()) + package->set_pkgpath_symbol(pkgpath_symbol); if (Linemap::is_unknown_location(package->location())) package->set_location(location); } else { // First time we have seen this package name. - package = new Package(pkgpath, location); + package = new Package(pkgpath, pkgpath_symbol, location); go_assert(ins.first->second == NULL); ins.first->second = package; } @@ -4333,10 +4345,24 @@ Gogo::do_exports() // support streaming to a separate file. Stream_to_section stream; + // Write out either the prefix or pkgpath depending on how we were + // invoked. + std::string prefix; + std::string pkgpath; + if (this->pkgpath_from_option_) + pkgpath = this->pkgpath_; + else if (this->prefix_from_option_) + prefix = this->prefix_; + else if (this->is_main_package()) + pkgpath = "main"; + else + prefix = "go"; + Export exp(&stream); exp.register_builtin_types(this); exp.export_globals(this->package_name(), - this->pkgpath(), + prefix, + pkgpath, this->package_priority(), this->imports_, (this->need_init_fn_ && !this->is_main_package() @@ -7478,8 +7504,9 @@ Unnamed_label::get_goto(Translate_context* context, Location location) // Class Package. -Package::Package(const std::string& pkgpath, Location location) - : pkgpath_(pkgpath), pkgpath_symbol_(Gogo::pkgpath_for_symbol(pkgpath)), +Package::Package(const std::string& pkgpath, + const std::string& pkgpath_symbol, Location location) + : pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol), package_name_(), bindings_(new Bindings(NULL)), priority_(0), location_(location), used_(false), is_imported_(false), uses_sink_alias_(false) @@ -7503,6 +7530,34 @@ Package::set_package_name(const std::string& package_name, Location location) package_name.c_str()); } +// Return the pkgpath symbol, which is a prefix for symbols defined in +// this package. + +std::string +Package::pkgpath_symbol() const +{ + if (this->pkgpath_symbol_.empty()) + { + // In the general case, this is wrong, because the package might + // have been compiled with -fprefix. However, it is what we + // used to do, so it is no more wrong than we were before. + return Gogo::pkgpath_for_symbol(this->pkgpath_); + } + return this->pkgpath_symbol_; +} + +// Set the package path symbol. + +void +Package::set_pkgpath_symbol(const std::string& pkgpath_symbol) +{ + go_assert(!pkgpath_symbol.empty()); + if (this->pkgpath_symbol_.empty()) + this->pkgpath_symbol_ = pkgpath_symbol; + else + go_assert(this->pkgpath_symbol_ == pkgpath_symbol); +} + // Set the priority. We may see multiple priorities for an imported // package; we want to use the largest one. diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 8a1663703aa..c5a71abea94 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -276,6 +276,7 @@ class Gogo add_imported_package(const std::string& real_name, const std::string& alias, bool is_alias_exported, const std::string& pkgpath, + const std::string& pkgpath_symbol, Location location, bool* padd_to_globals); @@ -283,7 +284,8 @@ class Gogo // This returns the Package structure for the package, creating if // it necessary. Package* - register_package(const std::string& pkgpath, Location); + register_package(const std::string& pkgpath, + const std::string& pkgpath_symbol, Location); // Start compiling a function. ADD_METHOD_TO_TYPE is true if a // method function should be added to the type of its receiver. @@ -2622,7 +2624,8 @@ class Unnamed_label class Package { public: - Package(const std::string& pkgpath, Location location); + Package(const std::string& pkgpath, const std::string& pkgpath_symbol, + Location location); // Get the package path used for all symbols exported from this // package. @@ -2631,9 +2634,12 @@ class Package { return this->pkgpath_; } // Return the package path to use for a symbol name. - const std::string& - pkgpath_symbol() const - { return this->pkgpath_symbol_; } + std::string + pkgpath_symbol() const; + + // Set the package path symbol. + void + set_pkgpath_symbol(const std::string&); // Return the location of the import statement. Location diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index c83ebe29853..cfc042976f3 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -301,23 +301,27 @@ Import::import(Gogo* gogo, const std::string& local_name, this->require_c_string(";\n"); std::string pkgpath; + std::string pkgpath_symbol; if (this->match_c_string("prefix ")) { this->advance(7); std::string unique_prefix = this->read_identifier(); this->require_c_string(";\n"); pkgpath = unique_prefix + '.' + package_name; + pkgpath_symbol = (Gogo::pkgpath_for_symbol(unique_prefix) + '.' + + Gogo::pkgpath_for_symbol(package_name)); } else { this->require_c_string("pkgpath "); pkgpath = this->read_identifier(); this->require_c_string(";\n"); + pkgpath_symbol = Gogo::pkgpath_for_symbol(pkgpath); } this->package_ = gogo->add_imported_package(package_name, local_name, is_local_name_exported, - pkgpath, + pkgpath, pkgpath_symbol, this->location_, &this->add_to_globals_); if (this->package_ == NULL) @@ -392,7 +396,7 @@ Import::read_one_import() stream->advance(1); this->require_c_string("\";\n"); - Package* p = this->gogo_->register_package(pkgpath, + Package* p = this->gogo_->register_package(pkgpath, "", Linemap::unknown_location()); p->set_package_name(package_name, this->location()); } @@ -649,7 +653,7 @@ Import::read_type() package = this->package_; else { - package = this->gogo_->register_package(pkgpath, + package = this->gogo_->register_package(pkgpath, "", Linemap::unknown_location()); if (!package_name.empty()) package->set_package_name(package_name, this->location()); diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc index 9b5ec44ad09..ca9622569bd 100644 --- a/gcc/go/gofrontend/unsafe.cc +++ b/gcc/go/gofrontend/unsafe.cc @@ -22,7 +22,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, bool add_to_globals; Package* package = this->add_imported_package("unsafe", local_name, is_local_name_exported, - "unsafe", location, + "unsafe", "unsafe", location, &add_to_globals); if (package == NULL) -- 2.30.2