Commit 0efaba3c by Ian Lance Taylor

compiler: Fix unnamed struct type converted to interface type.

From-SVN: r191627
parent bab51373
......@@ -293,19 +293,25 @@ Expression::convert_type_to_interface(Translate_context* context,
// object type: a list of function pointers for each interface
// method.
Named_type* rhs_named_type = rhs_type->named_type();
Struct_type* rhs_struct_type = rhs_type->struct_type();
bool is_pointer = false;
if (rhs_named_type == NULL)
if (rhs_named_type == NULL && rhs_struct_type == NULL)
{
rhs_named_type = rhs_type->deref()->named_type();
rhs_struct_type = rhs_type->deref()->struct_type();
is_pointer = true;
}
tree method_table;
if (rhs_named_type == NULL)
method_table = null_pointer_node;
else
if (rhs_named_type != NULL)
method_table =
rhs_named_type->interface_method_table(gogo, lhs_interface_type,
is_pointer);
else if (rhs_struct_type != NULL)
method_table =
rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
is_pointer);
else
method_table = null_pointer_node;
first_field_value = fold_convert_loc(location.gcc_location(),
const_ptr_type_node, method_table);
}
......
......@@ -2128,8 +2128,7 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
tree
Gogo::interface_method_table_for_type(const Interface_type* interface,
Named_type* type,
bool is_pointer)
Type* type, bool is_pointer)
{
const Typed_identifier_list* interface_methods = interface->methods();
go_assert(!interface_methods->empty());
......@@ -2158,7 +2157,9 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
// interface. If the interface has hidden methods, and the named
// type is defined in a different package, then the interface
// conversion table will be defined by that other package.
if (has_hidden_methods && type->named_object()->package() != NULL)
if (has_hidden_methods
&& type->named_type() != NULL
&& type->named_type()->named_object()->package() != NULL)
{
tree array_type = build_array_type(const_ptr_type_node, NULL);
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
......@@ -2187,13 +2188,20 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
Linemap::predeclared_location());
elt->value = fold_convert(const_ptr_type_node, tdp);
Named_type* nt = type->named_type();
Struct_type* st = type->struct_type();
go_assert(nt != NULL || st != NULL);
size_t i = 1;
for (Typed_identifier_list::const_iterator p = interface_methods->begin();
p != interface_methods->end();
++p, ++i)
{
bool is_ambiguous;
Method* m = type->method_function(p->name(), &is_ambiguous);
Method* m;
if (nt != NULL)
m = nt->method_function(p->name(), &is_ambiguous);
else
m = st->method_function(p->name(), &is_ambiguous);
go_assert(m != NULL);
Named_object* no = m->named_object();
......
......@@ -2872,7 +2872,8 @@ int
Build_method_tables::type(Type* type)
{
Named_type* nt = type->named_type();
if (nt != NULL)
Struct_type* st = type->struct_type();
if (nt != NULL || st != NULL)
{
for (std::vector<Interface_type*>::const_iterator p =
this->interfaces_.begin();
......@@ -2882,10 +2883,23 @@ Build_method_tables::type(Type* type)
// We ask whether a pointer to the named type implements the
// interface, because a pointer can implement more methods
// than a value.
if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL))
if (nt != NULL)
{
nt->interface_method_table(this->gogo_, *p, false);
nt->interface_method_table(this->gogo_, *p, true);
if ((*p)->implements_interface(Type::make_pointer_type(nt),
NULL))
{
nt->interface_method_table(this->gogo_, *p, false);
nt->interface_method_table(this->gogo_, *p, true);
}
}
else
{
if ((*p)->implements_interface(Type::make_pointer_type(st),
NULL))
{
st->interface_method_table(this->gogo_, *p, false);
st->interface_method_table(this->gogo_, *p, true);
}
}
}
}
......
......@@ -574,7 +574,7 @@ class Gogo
// Build an interface method table for a type: a list of function
// pointers, one for each interface method. This returns a decl.
tree
interface_method_table_for_type(const Interface_type*, Named_type*,
interface_method_table_for_type(const Interface_type*, Type*,
bool is_pointer);
// Return a tree which allocate SIZE bytes to hold values of type
......
......@@ -4554,6 +4554,20 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
return Type::method_function(this->all_methods_, name, is_ambiguous);
}
// Return a pointer to the interface method table for this type for
// the interface INTERFACE. IS_POINTER is true if this is for a
// pointer to THIS.
tree
Struct_type::interface_method_table(Gogo* gogo,
const Interface_type* interface,
bool is_pointer)
{
return Type::interface_method_table(gogo, this, interface, is_pointer,
&this->interface_method_tables_,
&this->pointer_interface_method_tables_);
}
// Convert struct fields to the backend representation. This is not
// declared in types.h so that types.h doesn't have to #include
// backend.h.
......@@ -7182,7 +7196,17 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
if (!p->name().empty())
{
std::string n = Gogo::unpack_hidden_name(p->name());
std::string n;
if (!Gogo::is_hidden_name(p->name()))
n = p->name();
else
{
n = ".";
std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
n.append(Gogo::pkgpath_for_symbol(pkgpath));
n.append(1, '.');
n.append(Gogo::unpack_hidden_name(p->name()));
}
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
......@@ -7735,32 +7759,9 @@ tree
Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
bool is_pointer)
{
go_assert(!interface->is_empty());
Interface_method_tables** pimt = (is_pointer
? &this->interface_method_tables_
: &this->pointer_interface_method_tables_);
if (*pimt == NULL)
*pimt = new Interface_method_tables(5);
std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
if (ins.second)
{
// This is a new entry in the hash table.
go_assert(ins.first->second == NULL_TREE);
ins.first->second = gogo->interface_method_table_for_type(interface,
this,
is_pointer);
}
tree decl = ins.first->second;
if (decl == error_mark_node)
return error_mark_node;
go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
return build_fold_addr_expr(decl);
return Type::interface_method_table(gogo, this, interface, is_pointer,
&this->interface_method_tables_,
&this->pointer_interface_method_tables_);
}
// Return whether a named type has any hidden fields.
......@@ -8944,6 +8945,42 @@ Type::method_function(const Methods* methods, const std::string& name,
return m;
}
// Return a pointer to the interface method table for TYPE for the
// interface INTERFACE.
tree
Type::interface_method_table(Gogo* gogo, Type* type,
const Interface_type *interface,
bool is_pointer,
Interface_method_tables** method_tables,
Interface_method_tables** pointer_tables)
{
go_assert(!interface->is_empty());
Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables;
if (*pimt == NULL)
*pimt = new Interface_method_tables(5);
std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
if (ins.second)
{
// This is a new entry in the hash table.
go_assert(ins.first->second == NULL_TREE);
ins.first->second = gogo->interface_method_table_for_type(interface,
type,
is_pointer);
}
tree decl = ins.first->second;
if (decl == error_mark_node)
return error_mark_node;
go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
return build_fold_addr_expr(decl);
}
// Look for field or method NAME for TYPE. Return an Expression for
// the field or method bound to EXPR. If there is no such field or
// method, give an appropriate error and return an error expression.
......
......@@ -983,6 +983,19 @@ class Type
method_function(const Methods*, const std::string& name,
bool* is_ambiguous);
// A mapping from interfaces to the associated interface method
// tables for this type. This maps to a decl.
typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
Type_identical) Interface_method_tables;
// Return a pointer to the interface method table for TYPE for the
// interface INTERFACE.
static tree
interface_method_table(Gogo* gogo, Type* type,
const Interface_type *interface, bool is_pointer,
Interface_method_tables** method_tables,
Interface_method_tables** pointer_tables);
// Return a composite literal for the type descriptor entry for a
// type.
static Expression*
......@@ -1994,7 +2007,8 @@ class Struct_type : public Type
public:
Struct_type(Struct_field_list* fields, Location location)
: Type(TYPE_STRUCT),
fields_(fields), location_(location), all_methods_(NULL)
fields_(fields), location_(location), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL)
{ }
// Return the field NAME. This only looks at local fields, not at
......@@ -2076,6 +2090,14 @@ class Struct_type : public Type
Method*
method_function(const std::string& name, bool* is_ambiguous) const;
// Return a pointer to the interface method table for this type for
// the interface INTERFACE. If IS_POINTER is true, set the type
// descriptor to a pointer to this type, otherwise set it to this
// type.
tree
interface_method_table(Gogo*, const Interface_type* interface,
bool is_pointer);
// Traverse just the field types of a struct type.
int
traverse_field_types(Traverse* traverse)
......@@ -2156,6 +2178,13 @@ class Struct_type : public Type
Location location_;
// If this struct is unnamed, a list of methods.
Methods* all_methods_;
// A mapping from interfaces to the associated interface method
// tables for this type. Only used if this struct is unnamed.
Interface_method_tables* interface_method_tables_;
// A mapping from interfaces to the associated interface method
// tables for pointers to this type. Only used if this struct is
// unnamed.
Interface_method_tables* pointer_interface_method_tables_;
};
// The type of an array.
......@@ -2861,11 +2890,6 @@ class Named_type : public Type
void
create_placeholder(Gogo*);
// A mapping from interfaces to the associated interface method
// tables for this type. This maps to a decl.
typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
Type_identical) Interface_method_tables;
// A pointer back to the Named_object for this type.
Named_object* named_object_;
// If this type is defined in a function, a pointer back to the
......
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