Commit 4b8d9b23 by Ian Lance Taylor

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
parent 41112d95
170ecdf6b2eab8aac2b8c852fa95d3c36d6bf604
ec754ff4617d564d3dc377121ea9ac5e55f6535a
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -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
......
......@@ -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.
......
......@@ -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
......
......@@ -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_;
};
......
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