From 4b8d9b23371d3ee0f7a9c1d99e80745400542930 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 10 Jul 2019 18:12:54 +0000 Subject: [PATCH] compiler: finalize methods when importing types 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 | 2 +- gcc/go/gofrontend/gogo.cc | 18 ----------------- gcc/go/gofrontend/gogo.h | 18 +++++++++++++++++ gcc/go/gofrontend/import.cc | 39 ++++++++++++++++++++++++++++++++++++- gcc/go/gofrontend/import.h | 10 ++++++++-- 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 582ded36f3e..7b3f874123d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 3abf7ea9762..234a4f44a4b 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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 diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index c4d5bab7681..cb8e25f446f 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index abf0b540bd0..ad7ba7fe3a4 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -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 diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index db51f726bf9..ea01bbcfb46 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -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 builtin_types_; // Mapping from exported type codes to Type structures. std::vector types_; + // Helper for finalizing methods. + Finalize_methods* finalizer_; // Version of export data we're reading. Export_data_version version_; }; -- 2.30.2