compiler: finalize methods when importing types
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 10 Jul 2019 18:12:54 +0000 (18:12 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 10 Jul 2019 18:12:54 +0000 (18:12 +0000)
    This patch changes the compiler to be more aggressive about finalizing
    methods on imported types, to avoid problems with interface types that
    are imported but remain unreachable until a later stage in the compilation.

    The normal pattern prior to this change was that the import process would
    leave imported interface types alone, and rely on Gogo::finalize_methods
    to locate and finalize all interface types at a later point. This way
    of doing things was not working in all cases due to the fact that we can
    import an interface type that is only reachable from the body of an
    inlinable function, meaning that we can't "find" the type during
    the methods finalize phase.

    The importer's Import::read_types() now makes a pass over all imported
    types to finalize methods on any newly imported type, which takes care
    of the issue.

    New test case for this problem in CL 185517.

    Fixes golang/go#33013

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/185518

From-SVN: r273364

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/import.cc
gcc/go/gofrontend/import.h

index 582ded36f3e09052011740dd4e24f110c40f1809..7b3f874123da409f818dda759c0ebbcf2f775aa0 100644 (file)
@@ -1,4 +1,4 @@
-170ecdf6b2eab8aac2b8c852fa95d3c36d6bf604
+ec754ff4617d564d3dc377121ea9ac5e55f6535a
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 3abf7ea9762fd2a14381886aa4a2718dc032d1b6..234a4f44a4bdcb2dd5f5e6b2f6d8bc2f93a34665 100644 (file)
@@ -3422,24 +3422,6 @@ Gogo::create_function_descriptors()
   this->traverse(&cfd);
 }
 
-// Look for interface types to finalize methods of inherited
-// interfaces.
-
-class Finalize_methods : public Traverse
-{
- public:
-  Finalize_methods(Gogo* gogo)
-    : Traverse(traverse_types),
-      gogo_(gogo)
-  { }
-
-  int
-  type(Type*);
-
- private:
-  Gogo* gogo_;
-};
-
 // Finalize the methods of an interface type.
 
 int
index c4d5bab7681ee0dce123ebcb9ced26b83ba2d413..cb8e25f446f926de499ed5d5a3ec4da14293e4ed 100644 (file)
@@ -3556,6 +3556,24 @@ class Traverse
   Expressions_seen* expressions_seen_;
 };
 
+// This class looks for interface types to finalize methods of inherited
+// interfaces.
+
+class Finalize_methods : public Traverse
+{
+ public:
+  Finalize_methods(Gogo* gogo)
+    : Traverse(traverse_types),
+      gogo_(gogo)
+  { }
+
+  int
+  type(Type*);
+
+ private:
+  Gogo* gogo_;
+};
+
 // A class which makes it easier to insert new statements before the
 // current statement during a traversal.
 
index abf0b540bd0be1cfb181abd64da5d92bf01b8974..ad7ba7fe3a4d251e8fe9944e25b15e616c930113 100644 (file)
@@ -290,10 +290,16 @@ Import::Import(Stream* stream, Location location)
   : gogo_(NULL), stream_(stream), location_(location), package_(NULL),
     add_to_globals_(false), packages_(), type_data_(), type_pos_(0),
     type_offsets_(), builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
-    types_(), version_(EXPORT_FORMAT_UNKNOWN)
+    types_(), finalizer_(NULL), version_(EXPORT_FORMAT_UNKNOWN)
 {
 }
 
+Import::~Import()
+{
+  if (this->finalizer_ != NULL)
+    delete this->finalizer_;
+}
+
 // Import the data in the associated stream.
 
 Package*
@@ -672,9 +678,40 @@ Import::read_types()
        this->gogo_->add_named_type(nt);
     }
 
+  // Finalize methods for any imported types. This is done after most of
+  // read_types() is complete so as to avoid method finalization of a type
+  // whose methods refer to types that are only partially read in.
+  // See issue #33013 for more on why this is needed.
+  this->finalize_methods();
+
   return true;
 }
 
+void
+Import::finalize_methods()
+{
+  if (this->finalizer_ == NULL)
+    this->finalizer_ = new Finalize_methods(gogo_);
+  Unordered_set(Type*) real_for_named;
+  for (size_t i = 1; i < this->types_.size(); i++)
+    {
+      Type* type = this->types_[i];
+      if (type != NULL && type->named_type() != NULL)
+        {
+          this->finalizer_->type(type);
+          real_for_named.insert(type->named_type()->real_type());
+        }
+    }
+  for (size_t i = 1; i < this->types_.size(); i++)
+    {
+      Type* type = this->types_[i];
+      if (type != NULL
+          && type->named_type() == NULL
+          && real_for_named.find(type) == real_for_named.end())
+        this->finalizer_->type(type);
+    }
+}
+
 // Import a constant.
 
 void
index db51f726bf956b89d17482073ab2fb64dd2ce485..ea01bbcfb4616e54edee296b5ecd8311602e164f 100644 (file)
@@ -20,6 +20,7 @@ class Expression;
 class Import_function_body;
 class Temporary_statement;
 class Unnamed_label;
+class Finalize_methods;
 
 // Expressions can be imported either directly from import data (for
 // simple constant expressions that can appear in a const declaration
@@ -207,8 +208,7 @@ class Import : public Import_expression
   // Constructor.
   Import(Stream*, Location);
 
-  virtual ~Import()
-  {}
+  virtual ~Import();
 
   // Register the builtin types.
   void
@@ -423,6 +423,10 @@ class Import : public Import_expression
     return true;
   }
 
+  // Finalize methods for newly imported types.
+  void
+  finalize_methods();
+
   // The general IR.
   Gogo* gogo_;
   // The stream from which to read import data.
@@ -446,6 +450,8 @@ class Import : public Import_expression
   std::vector<Named_type*> builtin_types_;
   // Mapping from exported type codes to Type structures.
   std::vector<Type*> types_;
+  // Helper for finalizing methods.
+  Finalize_methods* finalizer_;
   // Version of export data we're reading.
   Export_data_version version_;
 };