compiler: Fix bug converting unnamed types with placeholders.

From-SVN: r194011
This commit is contained in:
Ian Lance Taylor 2012-12-01 00:15:16 +00:00
parent 55ad8d77ab
commit 8ccaff35d4
2 changed files with 98 additions and 57 deletions

View File

@ -45,8 +45,7 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
// Class Type.
Type::Type(Type_classification classification)
: classification_(classification), btype_is_placeholder_(false),
btype_(NULL), type_descriptor_var_(NULL)
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
{
}
@ -910,11 +909,7 @@ Btype*
Type::get_backend(Gogo* gogo)
{
if (this->btype_ != NULL)
{
if (this->btype_is_placeholder_ && gogo->named_types_are_converted())
this->finish_backend(gogo);
return this->btype_;
}
if (this->forward_declaration_type() != NULL
|| this->named_type() != NULL)
@ -928,20 +923,36 @@ Type::get_backend(Gogo* gogo)
// that. There is no need to use the hash table for named types, as
// named types are only identical to themselves.
std::pair<Type*, Btype*> val(this, NULL);
std::pair<Type*, Type_btype_entry> val;
val.first = this;
val.second.btype = NULL;
val.second.is_placeholder = false;
std::pair<Type_btypes::iterator, bool> ins =
Type::type_btypes.insert(val);
if (!ins.second && ins.first->second != NULL)
if (!ins.second && ins.first->second.btype != NULL)
{
if (gogo != NULL && gogo->named_types_are_converted())
this->btype_ = ins.first->second;
return ins.first->second;
// Note that GOGO can be NULL here, but only when the GCC
// middle-end is asking for a frontend type. That will only
// happen for simple types, which should never require
// placeholders.
if (!ins.first->second.is_placeholder)
this->btype_ = ins.first->second.btype;
else if (gogo->named_types_are_converted())
{
this->finish_backend(gogo, ins.first->second.btype);
ins.first->second.is_placeholder = false;
}
return ins.first->second.btype;
}
Btype* bt = this->get_btype_without_hash(gogo);
if (ins.first->second == NULL)
ins.first->second = bt;
if (ins.first->second.btype == NULL)
{
ins.first->second.btype = bt;
ins.first->second.is_placeholder = false;
}
else
{
// We have already created a backend representation for this
@ -949,10 +960,9 @@ Type::get_backend(Gogo* gogo)
// a named type which in turns uses an identical unnamed type.
// Use the tree we created earlier and ignore the one we just
// built.
bt = ins.first->second;
if (gogo == NULL || !gogo->named_types_are_converted())
return bt;
this->btype_ = bt;
if (this->btype_ == bt)
this->btype_ = ins.first->second.btype;
bt = ins.first->second.btype;
}
return bt;
@ -1019,6 +1029,37 @@ Type::get_backend_placeholder(Gogo* gogo)
// These are simple types that can just be created directly.
return this->get_backend(gogo);
case TYPE_MAP:
case TYPE_CHANNEL:
// All maps and channels have the same backend representation.
return this->get_backend(gogo);
case TYPE_NAMED:
case TYPE_FORWARD:
// Named types keep track of their own dependencies and manage
// their own placeholders.
return this->get_backend(gogo);
case TYPE_INTERFACE:
if (this->interface_type()->is_empty())
return Interface_type::get_backend_empty_interface_type(gogo);
break;
default:
break;
}
std::pair<Type*, Type_btype_entry> val;
val.first = this;
val.second.btype = NULL;
val.second.is_placeholder = false;
std::pair<Type_btypes::iterator, bool> ins =
Type::type_btypes.insert(val);
if (!ins.second && ins.first->second.btype != NULL)
return ins.first->second.btype;
switch (this->classification_)
{
case TYPE_FUNCTION:
{
Location loc = this->function_type()->location();
@ -1061,16 +1102,9 @@ Type::get_backend_placeholder(Gogo* gogo)
}
break;
case TYPE_MAP:
case TYPE_CHANNEL:
// All maps and channels have the same backend representation.
return this->get_backend(gogo);
case TYPE_INTERFACE:
if (this->interface_type()->is_empty())
return Interface_type::get_backend_empty_interface_type(gogo);
else
{
go_assert(!this->interface_type()->is_empty());
std::vector<Backend::Btyped_identifier> bfields;
get_backend_interface_fields(gogo, this->interface_type(), true,
&bfields);
@ -1078,20 +1112,26 @@ Type::get_backend_placeholder(Gogo* gogo)
}
break;
case TYPE_NAMED:
case TYPE_FORWARD:
// Named types keep track of their own dependencies and manage
// their own placeholders.
return this->get_backend(gogo);
case TYPE_SINK:
case TYPE_CALL_MULTIPLE_RESULT:
/* Note that various classifications were handled in the earlier
switch. */
default:
go_unreachable();
}
this->btype_ = bt;
this->btype_is_placeholder_ = true;
if (ins.first->second.btype == NULL)
{
ins.first->second.btype = bt;
ins.first->second.is_placeholder = true;
}
else
{
// A placeholder for this type got created along the way. Use
// that one and ignore the one we just built.
bt = ins.first->second.btype;
}
return bt;
}
@ -1099,12 +1139,8 @@ Type::get_backend_placeholder(Gogo* gogo)
// using a placeholder type.
void
Type::finish_backend(Gogo* gogo)
Type::finish_backend(Gogo* gogo, Btype *placeholder)
{
go_assert(this->btype_ != NULL);
if (!this->btype_is_placeholder_)
return;
switch (this->classification_)
{
case TYPE_ERROR:
@ -1120,7 +1156,7 @@ Type::finish_backend(Gogo* gogo)
case TYPE_FUNCTION:
{
Btype* bt = this->do_get_backend(gogo);
if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt))
if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
go_assert(saw_errors());
}
break;
@ -1128,7 +1164,7 @@ Type::finish_backend(Gogo* gogo)
case TYPE_POINTER:
{
Btype* bt = this->do_get_backend(gogo);
if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt))
if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
go_assert(saw_errors());
}
break;
@ -1165,7 +1201,7 @@ Type::finish_backend(Gogo* gogo)
go_unreachable();
}
this->btype_is_placeholder_ = false;
this->btype_ = placeholder;
}
// Return a pointer to the type descriptor for this type.
@ -2968,8 +3004,8 @@ String_type::do_get_backend(Gogo* gogo)
// backend representation, so force it to be finished now.
if (!gogo->named_types_are_converted())
{
pb->get_backend_placeholder(gogo);
pb->finish_backend(gogo);
Btype* bt = pb->get_backend_placeholder(gogo);
pb->finish_backend(gogo, bt);
}
fields[0].name = "__data";

View File

@ -888,7 +888,7 @@ class Type
// Finish the backend representation of a placeholder.
void
finish_backend(Gogo*);
finish_backend(Gogo*, Btype*);
// Build a type descriptor entry for this type. Return a pointer to
// it. The location is the location which causes us to need the
@ -1210,10 +1210,18 @@ class Type
Btype*
get_btype_without_hash(Gogo*);
// A backend type that may be a placeholder.
struct Type_btype_entry
{
Btype *btype;
bool is_placeholder;
};
// A mapping from Type to Btype*, used to ensure that the backend
// representation of identical types is identical.
typedef Unordered_map_hash(const Type*, Btype*, Type_hash_identical,
Type_identical) Type_btypes;
// representation of identical types is identical. This is only
// used for unnamed types.
typedef Unordered_map_hash(const Type*, Type_btype_entry,
Type_hash_identical, Type_identical) Type_btypes;
static Type_btypes type_btypes;
@ -1230,9 +1238,6 @@ class Type
// The type classification.
Type_classification classification_;
// Whether btype_ is a placeholder type used while named types are
// being converted.
bool btype_is_placeholder_;
// The backend representation of the type, once it has been
// determined.
Btype* btype_;