Commit a35d6e9f by Ian Lance Taylor

compiler: include transitive imports in the type descriptor list

    
    In CL 179598, we were using Gogo::packages_, when compiling the
    main package, as the list of packages of which we need to
    register the type descriptors. This is not complete. It only
    includes main's direct import and one-level indirect imports. It
    does not include all the packages transitively imported.
    
    To fix that, we need to track all the transitive imports. We
    have almost already done that, for init functions. However, there
    may be packages that don't need init functions but do need to
    register type descriptors. For them, we add a dummy init function
    to its export data. So when we compile the main package we will
    see all the transitive imports. The dummy init functions are not
    real functions and are not called.
    
    Fixes golang/go#32901.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/184717

From-SVN: r273009
parent 6c47a87b
aebd2d6303e4bb970b088e84f6c66279095dfea6 ae7d7e05bce19aefaa27efe2ee797933aafbef06
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -909,6 +909,8 @@ Export::populate_init_graph(Init_graph* init_graph, ...@@ -909,6 +909,8 @@ Export::populate_init_graph(Init_graph* init_graph,
++p) ++p)
{ {
const Import_init* ii = *p; const Import_init* ii = *p;
if (ii->is_dummy())
continue;
std::map<std::string, unsigned>::const_iterator srcit = std::map<std::string, unsigned>::const_iterator srcit =
init_idx.find(ii->init_name()); init_idx.find(ii->init_name());
go_assert(srcit != init_idx.end()); go_assert(srcit != init_idx.end());
...@@ -1007,7 +1009,7 @@ Export::write_imported_init_fns(const std::string& package_name, ...@@ -1007,7 +1009,7 @@ Export::write_imported_init_fns(const std::string& package_name,
// Now add edges from the local init function to each of the // Now add edges from the local init function to each of the
// imported fcns. // imported fcns.
if (!import_init_fn.empty()) if (!import_init_fn.empty() && import_init_fn[0] != '~')
{ {
unsigned src = 0; unsigned src = 0;
go_assert(init_idx[import_init_fn] == 0); go_assert(init_idx[import_init_fn] == 0);
...@@ -1016,6 +1018,8 @@ Export::write_imported_init_fns(const std::string& package_name, ...@@ -1016,6 +1018,8 @@ Export::write_imported_init_fns(const std::string& package_name,
++p) ++p)
{ {
const Import_init* ii = *p; const Import_init* ii = *p;
if (ii->is_dummy())
continue;
unsigned sink = init_idx[ii->init_name()]; unsigned sink = init_idx[ii->init_name()];
add_init_graph_edge(&init_graph, src, sink); add_init_graph_edge(&init_graph, src, sink);
} }
......
...@@ -724,6 +724,9 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts, Bfunction *bfunction) ...@@ -724,6 +724,9 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts, Bfunction *bfunction)
p != this->imported_init_fns_.end(); p != this->imported_init_fns_.end();
++p) ++p)
{ {
// Don't include dummy inits. They are not real functions.
if ((*p)->is_dummy())
continue;
if ((*p)->priority() < 0) if ((*p)->priority() < 0)
go_error_at(Linemap::unknown_location(), go_error_at(Linemap::unknown_location(),
"internal error: failed to set init priority for %s", "internal error: failed to set init priority for %s",
...@@ -941,7 +944,7 @@ Gogo::build_type_descriptor_list() ...@@ -941,7 +944,7 @@ Gogo::build_type_descriptor_list()
Btype* bat = list_type->field(1)->type()->get_backend(this); Btype* bat = list_type->field(1)->type()->get_backend(this);
// Create the variable // Create the variable
std::string name = this->type_descriptor_list_symbol(this->package_); std::string name = this->type_descriptor_list_symbol(this->pkgpath_symbol());
Bvariable* bv = this->backend()->implicit_variable(name, name, bt, Bvariable* bv = this->backend()->implicit_variable(name, name, bt,
false, true, false, false, true, false,
0); 0);
...@@ -986,20 +989,29 @@ Gogo::register_type_descriptors(std::vector<Bstatement*>& init_stmts, ...@@ -986,20 +989,29 @@ Gogo::register_type_descriptors(std::vector<Bstatement*>& init_stmts,
Struct_type* list_type = type_descriptor_list_type(1); Struct_type* list_type = type_descriptor_list_type(1);
Btype* bt = list_type->get_backend(this); Btype* bt = list_type->get_backend(this);
// Collect type lists from transitive imports.
std::vector<std::string> list_names;
for (Import_init_set::iterator it = this->imported_init_fns_.begin();
it != this->imported_init_fns_.end();
++it)
{
std::string pkgpath =
this->pkgpath_from_init_fn_name((*it)->init_name());
list_names.push_back(this->type_descriptor_list_symbol(pkgpath));
}
// Add the main package itself.
list_names.push_back(this->type_descriptor_list_symbol("main"));
// Build a list of lists. // Build a list of lists.
std::vector<unsigned long> indexes; std::vector<unsigned long> indexes;
std::vector<Bexpression*> vals; std::vector<Bexpression*> vals;
unsigned long i = 0; unsigned long i = 0;
for (Packages::iterator it = this->packages_.begin(); for (std::vector<std::string>::iterator p = list_names.begin();
it != this->packages_.end(); p != list_names.end();
++it) ++p)
{ {
if (it->second->pkgpath() == "unsafe")
continue;
std::string name = this->type_descriptor_list_symbol(it->second);
Bvariable* bv = Bvariable* bv =
this->backend()->implicit_variable_reference(name, name, bt); this->backend()->implicit_variable_reference(*p, *p, bt);
Bexpression* bexpr = this->backend()->var_expression(bv, builtin_loc); Bexpression* bexpr = this->backend()->var_expression(bv, builtin_loc);
bexpr = this->backend()->address_expression(bexpr, builtin_loc); bexpr = this->backend()->address_expression(bexpr, builtin_loc);
...@@ -5158,6 +5170,14 @@ Gogo::do_exports() ...@@ -5158,6 +5170,14 @@ Gogo::do_exports()
else else
prefix = "go"; prefix = "go";
std::string init_fn_name;
if (this->is_main_package())
init_fn_name = "";
else if (this->need_init_fn_)
init_fn_name = this->get_init_fn_name();
else
init_fn_name = this->dummy_init_fn_name();
Export exp(&stream); Export exp(&stream);
exp.register_builtin_types(this); exp.register_builtin_types(this);
exp.export_globals(this->package_name(), exp.export_globals(this->package_name(),
...@@ -5165,9 +5185,7 @@ Gogo::do_exports() ...@@ -5165,9 +5185,7 @@ Gogo::do_exports()
pkgpath, pkgpath,
this->packages_, this->packages_,
this->imports_, this->imports_,
(this->need_init_fn_ && !this->is_main_package() init_fn_name,
? this->get_init_fn_name()
: ""),
this->imported_init_fns_, this->imported_init_fns_,
this->package_->bindings()); this->package_->bindings());
......
...@@ -103,6 +103,11 @@ class Import_init ...@@ -103,6 +103,11 @@ class Import_init
precursors() const precursors() const
{ return this->precursor_functions_; } { return this->precursor_functions_; }
// Whether this is a dummy init, which is used only to record transitive import.
bool
is_dummy() const
{ return this->init_name_[0] == '~'; }
private: private:
// The name of the package being imported. // The name of the package being imported.
std::string package_name_; std::string package_name_;
...@@ -912,13 +917,23 @@ class Gogo ...@@ -912,13 +917,23 @@ class Gogo
const std::string& const std::string&
get_init_fn_name(); get_init_fn_name();
// Return the name for a dummy init function, which is not a real
// function but only for tracking transitive import.
std::string
dummy_init_fn_name();
// Return the package path symbol from an init function name, which
// can be a real init function or a dummy one.
std::string
pkgpath_from_init_fn_name(std::string);
// Return the name for a type descriptor symbol. // Return the name for a type descriptor symbol.
std::string std::string
type_descriptor_name(const Type*, Named_type*); type_descriptor_name(const Type*, Named_type*);
// Return the name of the type descriptor list symbol of a package. // Return the name of the type descriptor list symbol of a package.
std::string std::string
type_descriptor_list_symbol(Package*); type_descriptor_list_symbol(std::string);
// Return the name of the list of all type descriptor lists. // Return the name of the list of all type descriptor lists.
std::string std::string
......
...@@ -144,7 +144,8 @@ ...@@ -144,7 +144,8 @@
// //
// The import function for the main package is referenced by C code, // The import function for the main package is referenced by C code,
// and is named __go_init_main. For other packages it is // and is named __go_init_main. For other packages it is
// PKGPATH..import. // PKGPATH..import. If a package doesn't need an init function, it
// will have a dummy one, named ~PKGPATH.
// //
// In each pacakge there is a list of all the type descriptors defined // In each pacakge there is a list of all the type descriptors defined
// in this package. The name of the list is PKGPATH..types. // in this package. The name of the list is PKGPATH..types.
...@@ -531,6 +532,30 @@ Gogo::get_init_fn_name() ...@@ -531,6 +532,30 @@ Gogo::get_init_fn_name()
return this->init_fn_name_; return this->init_fn_name_;
} }
// Return the name for a dummy init function, which is not a real
// function but only for tracking transitive import.
std::string
Gogo::dummy_init_fn_name()
{
return "~" + this->pkgpath_symbol();
}
// Return the package path symbol from an init function name, which
// can be a real init function or a dummy one.
std::string
Gogo::pkgpath_from_init_fn_name(std::string name)
{
go_assert(!name.empty());
if (name[0] == '~')
return name.substr(1);
size_t pos = name.find("..import");
if (pos != std::string::npos)
return name.substr(0, pos);
go_unreachable();
}
// Return a mangled name for a type. These names appear in symbol // Return a mangled name for a type. These names appear in symbol
// names in the assembler file for things like type descriptors and // names in the assembler file for things like type descriptors and
// methods. // methods.
...@@ -994,9 +1019,9 @@ Gogo::type_descriptor_name(const Type* type, Named_type* nt) ...@@ -994,9 +1019,9 @@ Gogo::type_descriptor_name(const Type* type, Named_type* nt)
// Return the name of the type descriptor list symbol of a package. // Return the name of the type descriptor list symbol of a package.
std::string std::string
Gogo::type_descriptor_list_symbol(Package* pkg) Gogo::type_descriptor_list_symbol(std::string pkgpath)
{ {
return pkg->pkgpath_symbol() + "..types"; return pkgpath + "..types";
} }
// Return the name of the list of all type descriptor lists. This is // Return the name of the list of all type descriptor lists. This is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment