compiler: include transitive imports in the type descriptor list
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 3 Jul 2019 13:23:39 +0000 (13:23 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 3 Jul 2019 13:23:39 +0000 (13:23 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/export.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/names.cc

index c39a36d269a21a351d7511235cb355f8d2ee7d2c..cc157b704b164de9fd9be5b6308d21cc2d9ac577 100644 (file)
@@ -1,4 +1,4 @@
-aebd2d6303e4bb970b088e84f6c66279095dfea6
+ae7d7e05bce19aefaa27efe2ee797933aafbef06
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 8cbddac1446e77de0386c6de930649e9793f53f1..cb778a0fd8340d628568aa07d9ec05ceef3d3bc1 100644 (file)
@@ -909,6 +909,8 @@ Export::populate_init_graph(Init_graph* init_graph,
        ++p)
     {
       const Import_init* ii = *p;
+      if (ii->is_dummy())
+        continue;
       std::map<std::string, unsigned>::const_iterator srcit =
           init_idx.find(ii->init_name());
       go_assert(srcit != init_idx.end());
@@ -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
   // imported fcns.
-  if (!import_init_fn.empty())
+  if (!import_init_fn.empty() && import_init_fn[0] != '~')
     {
       unsigned src = 0;
       go_assert(init_idx[import_init_fn] == 0);
@@ -1016,6 +1018,8 @@ Export::write_imported_init_fns(const std::string& package_name,
            ++p)
        {
           const Import_init* ii = *p;
+          if (ii->is_dummy())
+            continue;
          unsigned sink = init_idx[ii->init_name()];
          add_init_graph_edge(&init_graph, src, sink);
        }
index d190ec2f3f02e64a3bb38fb3fec5fc64e51793c8..fcf9a93c78530b214acf81a97031123e46ed1eef 100644 (file)
@@ -724,6 +724,9 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts, Bfunction *bfunction)
        p != this->imported_init_fns_.end();
        ++p)
     {
+      // Don't include dummy inits. They are not real functions.
+      if ((*p)->is_dummy())
+        continue;
       if ((*p)->priority() < 0)
        go_error_at(Linemap::unknown_location(),
                    "internal error: failed to set init priority for %s",
@@ -941,7 +944,7 @@ Gogo::build_type_descriptor_list()
   Btype* bat = list_type->field(1)->type()->get_backend(this);
 
   // 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,
                                                      false, true, false,
                                                      0);
@@ -986,20 +989,29 @@ Gogo::register_type_descriptors(std::vector<Bstatement*>& init_stmts,
   Struct_type* list_type = type_descriptor_list_type(1);
   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.
   std::vector<unsigned long> indexes;
   std::vector<Bexpression*> vals;
   unsigned long i = 0;
-  for (Packages::iterator it = this->packages_.begin();
-       it != this->packages_.end();
-       ++it)
+  for (std::vector<std::string>::iterator p = list_names.begin();
+       p != list_names.end();
+       ++p)
     {
-      if (it->second->pkgpath() == "unsafe")
-        continue;
-
-      std::string name = this->type_descriptor_list_symbol(it->second);
       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);
       bexpr = this->backend()->address_expression(bexpr, builtin_loc);
 
@@ -5158,6 +5170,14 @@ Gogo::do_exports()
   else
     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);
   exp.register_builtin_types(this);
   exp.export_globals(this->package_name(),
@@ -5165,9 +5185,7 @@ Gogo::do_exports()
                     pkgpath,
                     this->packages_,
                     this->imports_,
-                    (this->need_init_fn_ && !this->is_main_package()
-                     ? this->get_init_fn_name()
-                     : ""),
+                    init_fn_name,
                     this->imported_init_fns_,
                     this->package_->bindings());
 
index 84b6e8e37d0ba94a96b5d9983c0dd154da8e36d7..c4d5bab7681ee0dce123ebcb9ced26b83ba2d413 100644 (file)
@@ -103,6 +103,11 @@ class Import_init
   precursors() const
   { 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:
   // The name of the package being imported.
   std::string package_name_;
@@ -912,13 +917,23 @@ class Gogo
   const std::string&
   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.
   std::string
   type_descriptor_name(const Type*, Named_type*);
 
   // Return the name of the type descriptor list symbol of a package.
   std::string
-  type_descriptor_list_symbol(Package*);
+  type_descriptor_list_symbol(std::string);
 
   // Return the name of the list of all type descriptor lists.
   std::string
index c622067c2208d07430a1b118e6d97a6d0cbf7d06..91cbb4bcad0a758bae14f3eb679bd4fa86129a5c 100644 (file)
 //
 // The import function for the main package is referenced by C code,
 // 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 this package.  The name of the list is PKGPATH..types.
@@ -531,6 +532,30 @@ Gogo::get_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
 // names in the assembler file for things like type descriptors and
 // methods.
@@ -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.
 
 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