From 8ccaff35d4219fa37ca83d9021710a5c4e532221 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 1 Dec 2012 00:15:16 +0000 Subject: [PATCH] compiler: Fix bug converting unnamed types with placeholders. From-SVN: r194011 --- gcc/go/gofrontend/types.cc | 136 +++++++++++++++++++++++-------------- gcc/go/gofrontend/types.h | 19 ++++-- 2 files changed, 98 insertions(+), 57 deletions(-) diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 7a4345dfa2c..c79181b7a60 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -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_; - } + 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 val(this, NULL); + std::pair val; + val.first = this; + val.second.btype = NULL; + val.second.is_placeholder = false; std::pair 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 val; + val.first = this; + val.second.btype = NULL; + val.second.is_placeholder = false; + std::pair 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,37 +1102,36 @@ 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 - { - std::vector bfields; - get_backend_interface_fields(gogo, this->interface_type(), true, - &bfields); - bt = gogo->backend()->struct_type(bfields); - } + { + go_assert(!this->interface_type()->is_empty()); + std::vector bfields; + get_backend_interface_fields(gogo, this->interface_type(), true, + &bfields); + bt = gogo->backend()->struct_type(bfields); + } 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"; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 2ab21f65355..fc84db039bb 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -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_;