From 6df020c0d10c41d8a7bd61714e445ccfa66b99e6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 16 Feb 2012 06:44:36 +0000 Subject: compiler: Fix crash: type T1 struct { F *[1]T2 } where T2 is a struct. This will become bug417.go. From-SVN: r184299 --- gcc/go/gofrontend/expressions.cc | 4 +- gcc/go/gofrontend/gogo.cc | 2 - gcc/go/gofrontend/types.cc | 386 ++++++++++++++++++++++++++++++++------- gcc/go/gofrontend/types.h | 41 +++-- 4 files changed, 352 insertions(+), 81 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 8357ad7..0b53f72 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -522,8 +522,8 @@ Expression::convert_interface_to_interface(Translate_context* context, // first field is just the type descriptor of the object. go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__type_descriptor") == 0); - go_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor)); - elt->value = rhs_type_descriptor; + elt->value = fold_convert_loc(location.gcc_location(), + TREE_TYPE(field), rhs_type_descriptor); } else { diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index a1b03ac..a90ce1d 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2929,8 +2929,6 @@ Gogo::convert_named_types() Runtime::convert_types(this); - Function_type::convert_types(this); - this->named_types_are_converted_ = true; } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 1a35e54d..13cd48a 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -34,10 +34,28 @@ extern "C" #include "backend.h" #include "types.h" +// Forward declarations so that we don't have to make types.h #include +// backend.h. + +static void +get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, + bool use_placeholder, + std::vector* bfields); + +static void +get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder, + std::vector* bfields); + +static void +get_backend_interface_fields(Gogo* gogo, Interface_type* type, + bool use_placeholder, + std::vector* bfields); + // Class Type. Type::Type(Type_classification classification) - : classification_(classification), btype_(NULL), type_descriptor_var_(NULL) + : classification_(classification), btype_is_placeholder_(false), + btype_(NULL), type_descriptor_var_(NULL) { } @@ -895,7 +913,11 @@ Btype* Type::get_backend(Gogo* gogo) { if (this->btype_ != NULL) - return this->btype_; + { + 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) @@ -966,6 +988,189 @@ Type::get_btype_without_hash(Gogo* gogo) return this->btype_; } +// Get the backend representation of a type without forcing the +// creation of the backend representation of all supporting types. +// This will return a backend type that has the correct size but may +// be incomplete. E.g., a pointer will just be a placeholder pointer, +// and will not contain the final representation of the type to which +// it points. This is used while converting all named types to the +// backend representation, to avoid problems with indirect references +// to types which are not yet complete. When this is called, the +// sizes of all direct references (e.g., a struct field) should be +// known, but the sizes of indirect references (e.g., the type to +// which a pointer points) may not. + +Btype* +Type::get_backend_placeholder(Gogo* gogo) +{ + if (gogo->named_types_are_converted()) + return this->get_backend(gogo); + if (this->btype_ != NULL) + return this->btype_; + + Btype* bt; + switch (this->classification_) + { + case TYPE_ERROR: + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_INTEGER: + case TYPE_FLOAT: + case TYPE_COMPLEX: + case TYPE_STRING: + case TYPE_NIL: + // These are simple types that can just be created directly. + return this->get_backend(gogo); + + case TYPE_FUNCTION: + { + Location loc = this->function_type()->location(); + bt = gogo->backend()->placeholder_pointer_type("", loc, true); + } + break; + + case TYPE_POINTER: + { + Location loc = Linemap::unknown_location(); + bt = gogo->backend()->placeholder_pointer_type("", loc, false); + } + break; + + case TYPE_STRUCT: + // We don't have to make the struct itself be a placeholder. We + // are promised that we know the sizes of the struct fields. + // But we may have to use a placeholder for any particular + // struct field. + { + std::vector bfields; + get_backend_struct_fields(gogo, this->struct_type()->fields(), + true, &bfields); + bt = gogo->backend()->struct_type(bfields); + } + break; + + case TYPE_ARRAY: + if (this->is_slice_type()) + { + std::vector bfields; + get_backend_slice_fields(gogo, this->array_type(), true, &bfields); + bt = gogo->backend()->struct_type(bfields); + } + else + { + Btype* element = this->array_type()->get_backend_element(gogo, true); + Bexpression* len = this->array_type()->get_backend_length(gogo); + bt = gogo->backend()->array_type(element, len); + } + 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); + } + 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: + default: + go_unreachable(); + } + + this->btype_ = bt; + this->btype_is_placeholder_ = true; + return bt; +} + +// Complete the backend representation. This is called for a type +// using a placeholder type. + +void +Type::finish_backend(Gogo* gogo) +{ + go_assert(this->btype_ != NULL); + if (!this->btype_is_placeholder_) + return; + + switch (this->classification_) + { + case TYPE_ERROR: + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_INTEGER: + case TYPE_FLOAT: + case TYPE_COMPLEX: + case TYPE_STRING: + case TYPE_NIL: + go_unreachable(); + + case TYPE_FUNCTION: + { + Btype* bt = this->do_get_backend(gogo); + if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt)) + go_assert(saw_errors()); + } + break; + + case TYPE_POINTER: + { + Btype* bt = this->do_get_backend(gogo); + if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt)) + go_assert(saw_errors()); + } + break; + + case TYPE_STRUCT: + // The struct type itself is done, but we have to make sure that + // all the field types are converted. + this->struct_type()->finish_backend_fields(gogo); + break; + + case TYPE_ARRAY: + // The array type itself is done, but make sure the element type + // is converted. + this->array_type()->finish_backend_element(gogo); + break; + + case TYPE_MAP: + case TYPE_CHANNEL: + go_unreachable(); + + case TYPE_INTERFACE: + // The interface type itself is done, but make sure the method + // types are converted. + this->interface_type()->finish_backend_methods(gogo); + break; + + case TYPE_NAMED: + case TYPE_FORWARD: + go_unreachable(); + + case TYPE_SINK: + case TYPE_CALL_MULTIPLE_RESULT: + default: + go_unreachable(); + } + + this->btype_is_placeholder_ = false; +} + // Return a pointer to the type descriptor for this type. tree @@ -2059,7 +2264,8 @@ Type::backend_type_size(Gogo* gogo, unsigned int *psize) { if (!this->is_backend_type_size_known(gogo)) return false; - size_t size = gogo->backend()->type_size(this->get_backend(gogo)); + Btype* bt = this->get_backend_placeholder(gogo); + size_t size = gogo->backend()->type_size(bt); *psize = static_cast(size); if (*psize != size) return false; @@ -2074,7 +2280,8 @@ Type::backend_type_align(Gogo* gogo, unsigned int *palign) { if (!this->is_backend_type_size_known(gogo)) return false; - size_t align = gogo->backend()->type_alignment(this->get_backend(gogo)); + Btype* bt = this->get_backend_placeholder(gogo); + size_t align = gogo->backend()->type_alignment(bt); *palign = static_cast(align); if (*palign != align) return false; @@ -2089,7 +2296,8 @@ Type::backend_type_field_align(Gogo* gogo, unsigned int *palign) { if (!this->is_backend_type_size_known(gogo)) return false; - size_t a = gogo->backend()->type_field_alignment(this->get_backend(gogo)); + Btype* bt = this->get_backend_placeholder(gogo); + size_t a = gogo->backend()->type_field_alignment(bt); *palign = static_cast(a); if (*palign != a) return false; @@ -2712,6 +2920,15 @@ String_type::do_get_backend(Gogo* gogo) Type* b = gogo->lookup_global("byte")->type_value(); Type* pb = Type::make_pointer_type(b); + + // We aren't going to get back to this field to finish the + // backend representation, so force it to be finished now. + if (!gogo->named_types_are_converted()) + { + pb->get_backend_placeholder(gogo); + pb->finish_backend(gogo); + } + fields[0].name = "__data"; fields[0].btype = pb->get_backend(gogo); fields[0].location = Linemap::predeclared_location(); @@ -3117,7 +3334,7 @@ Function_type::do_hash_for_method(Gogo* gogo) const // Get the backend representation for a function type. Btype* -Function_type::get_function_backend(Gogo* gogo) +Function_type::do_get_backend(Gogo* gogo) { Backend::Btyped_identifier breceiver; if (this->receiver_ != NULL) @@ -3169,46 +3386,6 @@ Function_type::get_function_backend(Gogo* gogo) this->location()); } -// A hash table mapping function types to their backend placeholders. - -Function_type::Placeholders Function_type::placeholders; - -// Get the backend representation for a function type. If we are -// still converting types, and this types has multiple results, return -// a placeholder instead. We do this because for multiple results we -// build a struct, and we need to make sure that all the types in the -// struct are valid before we create the struct. - -Btype* -Function_type::do_get_backend(Gogo* gogo) -{ - if (!gogo->named_types_are_converted() - && this->results_ != NULL - && this->results_->size() > 1) - { - Btype* placeholder = - gogo->backend()->placeholder_pointer_type("", this->location(), true); - Function_type::placeholders.push_back(std::make_pair(this, placeholder)); - return placeholder; - } - return this->get_function_backend(gogo); -} - -// Convert function types after all named types are converted. - -void -Function_type::convert_types(Gogo* gogo) -{ - for (Placeholders::const_iterator p = Function_type::placeholders.begin(); - p != Function_type::placeholders.end(); - ++p) - { - Btype* bt = p->first->get_function_backend(gogo); - if (!gogo->backend()->set_placeholder_function_type(p->second, bt)) - go_assert(saw_errors()); - } -} - // The type of a function type descriptor. Type* @@ -4346,6 +4523,7 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const static void get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, + bool use_placeholder, std::vector* bfields) { bfields->resize(fields->size()); @@ -4355,7 +4533,9 @@ get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, ++p, ++i) { (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name()); - (*bfields)[i].btype = p->type()->get_backend(gogo); + (*bfields)[i].btype = (use_placeholder + ? p->type()->get_backend_placeholder(gogo) + : p->type()->get_backend(gogo)); (*bfields)[i].location = p->location(); } go_assert(i == fields->size()); @@ -4367,10 +4547,25 @@ Btype* Struct_type::do_get_backend(Gogo* gogo) { std::vector bfields; - get_backend_struct_fields(gogo, this->fields_, &bfields); + get_backend_struct_fields(gogo, this->fields_, false, &bfields); return gogo->backend()->struct_type(bfields); } +// Finish the backend representation of the fields of a struct. + +void +Struct_type::finish_backend_fields(Gogo* gogo) +{ + const Struct_field_list* fields = this->fields_; + if (fields != NULL) + { + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + ++p) + p->type()->get_backend(gogo); + } +} + // The type of a struct type descriptor. Type* @@ -4776,8 +4971,8 @@ Struct_type::backend_field_offset(Gogo* gogo, unsigned int index, { if (!this->is_backend_type_size_known(gogo)) return false; - size_t offset = gogo->backend()->type_field_offset(this->get_backend(gogo), - index); + Btype* bt = this->get_backend_placeholder(gogo); + size_t offset = gogo->backend()->type_field_offset(bt, index); *poffset = static_cast(offset); if (*poffset != offset) return false; @@ -5295,13 +5490,15 @@ Array_type::get_length_tree(Gogo* gogo) // size which does not fit in int. static void -get_backend_slice_fields(Gogo* gogo, Array_type* type, +get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder, std::vector* bfields) { bfields->resize(3); Type* pet = Type::make_pointer_type(type->element_type()); - Btype* pbet = pet->get_backend(gogo); + Btype* pbet = (use_placeholder + ? pet->get_backend_placeholder(gogo) + : pet->get_backend(gogo)); Location ploc = Linemap::predeclared_location(); Backend::Btyped_identifier* p = &(*bfields)[0]; @@ -5333,12 +5530,12 @@ Array_type::do_get_backend(Gogo* gogo) if (this->length_ == NULL) { std::vector bfields; - get_backend_slice_fields(gogo, this, &bfields); + get_backend_slice_fields(gogo, this, false, &bfields); return gogo->backend()->struct_type(bfields); } else { - Btype* element = this->get_backend_element(gogo); + Btype* element = this->get_backend_element(gogo, false); Bexpression* len = this->get_backend_length(gogo); return gogo->backend()->array_type(element, len); } @@ -5347,9 +5544,12 @@ Array_type::do_get_backend(Gogo* gogo) // Return the backend representation of the element type. Btype* -Array_type::get_backend_element(Gogo* gogo) +Array_type::get_backend_element(Gogo* gogo, bool use_placeholder) { - return this->element_type_->get_backend(gogo); + if (use_placeholder) + return this->element_type_->get_backend_placeholder(gogo); + else + return this->element_type_->get_backend(gogo); } // Return the backend representation of the length. @@ -5360,6 +5560,22 @@ Array_type::get_backend_length(Gogo* gogo) return tree_to_expr(this->get_length_tree(gogo)); } +// Finish backend representation of the array. + +void +Array_type::finish_backend_element(Gogo* gogo) +{ + Type* et = this->array_type()->element_type(); + et->get_backend(gogo); + if (this->is_slice_type()) + { + // This relies on the fact that we always use the same + // structure for a pointer to any given type. + Type* pet = Type::make_pointer_type(et); + pet->get_backend(gogo); + } +} + // Return a tree for a pointer to the values in ARRAY. tree @@ -6652,6 +6868,7 @@ Interface_type::get_backend_empty_interface_type(Gogo* gogo) static void get_backend_interface_fields(Gogo* gogo, Interface_type* type, + bool use_placeholder, std::vector* bfields) { Location loc = type->location(); @@ -6670,7 +6887,9 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type, ++p, ++i) { mfields[i].name = Gogo::unpack_hidden_name(p->name()); - mfields[i].btype = p->type()->get_backend(gogo); + mfields[i].btype = (use_placeholder + ? p->type()->get_backend_placeholder(gogo) + : p->type()->get_backend(gogo)); mfields[i].location = loc; // Sanity check: the names should be sorted. go_assert(p->name() > last_name); @@ -6710,7 +6929,7 @@ Interface_type::do_get_backend(Gogo* gogo) this->interface_btype_ = gogo->backend()->placeholder_struct_type("", this->location_); std::vector bfields; - get_backend_interface_fields(gogo, this, &bfields); + get_backend_interface_fields(gogo, this, false, &bfields); if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_, bfields)) this->interface_btype_ = gogo->backend()->error_type(); @@ -6718,6 +6937,24 @@ Interface_type::do_get_backend(Gogo* gogo) } } +// Finish the backend representation of the methods. + +void +Interface_type::finish_backend_methods(Gogo* gogo) +{ + if (!this->interface_type()->is_empty()) + { + const Typed_identifier_list* methods = this->methods(); + if (methods != NULL) + { + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + p->type()->get_backend(gogo); + } + } +} + // The type of an interface type descriptor. Type* @@ -7751,7 +7988,7 @@ Named_type::convert(Gogo* gogo) { std::vector bfields; get_backend_struct_fields(gogo, base->struct_type()->fields(), - &bfields); + true, &bfields); if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) bt = gogo->backend()->error_type(); } @@ -7761,7 +7998,7 @@ Named_type::convert(Gogo* gogo) // Slice types were completed in create_placeholder. if (!base->is_slice_type()) { - Btype* bet = base->array_type()->get_backend_element(gogo); + Btype* bet = base->array_type()->get_backend_element(gogo, true); Bexpression* blen = base->array_type()->get_backend_length(gogo); if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen)) bt = gogo->backend()->error_type(); @@ -7893,7 +8130,7 @@ Named_type::create_placeholder(Gogo* gogo) // because we can fill them in completely here with the final // size. std::vector bfields; - get_backend_slice_fields(gogo, base->array_type(), &bfields); + get_backend_slice_fields(gogo, base->array_type(), true, &bfields); if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) this->named_btype_ = gogo->backend()->error_type(); } @@ -7904,7 +8141,8 @@ Named_type::create_placeholder(Gogo* gogo) // because we can fill them in completely here with the final // size. std::vector bfields; - get_backend_interface_fields(gogo, base->interface_type(), &bfields); + get_backend_interface_fields(gogo, base->interface_type(), true, + &bfields); if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) this->named_btype_ = gogo->backend()->error_type(); } @@ -7963,9 +8201,33 @@ Named_type::do_get_backend(Gogo* gogo) case TYPE_NIL: case TYPE_MAP: case TYPE_CHANNEL: + return bt; + case TYPE_STRUCT: + if (!this->seen_in_get_backend_) + { + this->seen_in_get_backend_ = true; + base->struct_type()->finish_backend_fields(gogo); + this->seen_in_get_backend_ = false; + } + return bt; + case TYPE_ARRAY: + if (!this->seen_in_get_backend_) + { + this->seen_in_get_backend_ = true; + base->array_type()->finish_backend_element(gogo); + this->seen_in_get_backend_ = false; + } + return bt; + case TYPE_INTERFACE: + if (!this->seen_in_get_backend_) + { + this->seen_in_get_backend_ = true; + base->interface_type()->finish_backend_methods(gogo); + this->seen_in_get_backend_ = false; + } return bt; case TYPE_FUNCTION: diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 4398ef1..72c42eb 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -852,6 +852,16 @@ class Type Btype* get_backend(Gogo*); + // Return a placeholder for the backend representation of the type. + // This will return a type of the correct size, but for which some + // of the fields may still need to be completed. + Btype* + get_backend_placeholder(Gogo*); + + // Finish the backend representation of a placeholder. + void + finish_backend(Gogo*); + // Build a type descriptor entry for this type. Return a pointer to // it. The location is the location which causes us to need the // entry. @@ -1179,6 +1189,9 @@ 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_; @@ -1730,10 +1743,6 @@ class Function_type : public Type Function_type* copy_with_receiver(Type*) const; - // Finishing converting function types. - static void - convert_types(Gogo*); - static Type* make_function_type_descriptor_type(); @@ -1773,16 +1782,6 @@ class Function_type : public Type type_descriptor_params(Type*, const Typed_identifier*, const Typed_identifier_list*); - Btype* - get_function_backend(Gogo*); - - // A list of function types with multiple results and their - // placeholder backend representations, used to postpone building - // the structs we use for multiple results until all types are - // converted. - typedef std::vector > Placeholders; - static Placeholders placeholders; - // The receiver name and type. This will be NULL for a normal // function, non-NULL for a method. Typed_identifier* receiver_; @@ -2079,6 +2078,10 @@ class Struct_type : public Type bool backend_field_offset(Gogo*, unsigned int index, unsigned int* poffset); + // Finish the backend representation of all the fields. + void + finish_backend_fields(Gogo*); + // Import a struct type. static Struct_type* do_import(Import*); @@ -2193,12 +2196,16 @@ class Array_type : public Type // Return the backend representation of the element type. Btype* - get_backend_element(Gogo*); + get_backend_element(Gogo*, bool use_placeholder); // Return the backend representation of the length. Bexpression* get_backend_length(Gogo*); + // Finish the backend representation of the element type. + void + finish_backend_element(Gogo*); + static Type* make_array_type_descriptor_type(); @@ -2521,6 +2528,10 @@ class Interface_type : public Type static Btype* get_backend_empty_interface_type(Gogo*); + // Finish the backend representation of the method types. + void + finish_backend_methods(Gogo*); + static Type* make_interface_type_descriptor_type(); -- cgit v1.1