diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index f9eccd5238f..6c53224083e 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,20 @@ +2011-05-04 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::struct_type): Call fill_in_struct. + (Gcc_backend::fill_in_struct): New function. + (Gcc_backend::array_type): Implement. + (Gcc_backend::fill_in_array): New function. + (Gcc_backend::placeholder_pointer_type): New function. + (Gcc_backend::set_placeholder_pointer_type): New function. + (Gcc_backend::set_placeholder_function_type): New function. + (Gcc_backend::placeholder_struct_type): New function. + (Gcc_backend::set_placeholder_struct_type): New function. + (Gcc_backend::placeholder_array_type): New function. + (Gcc_backend::set_placeholder_array_type): New function. + (Gcc_backend::named_type): New function. + (Gcc_backend::circular_pointer_type): New function. + (Gcc_backend::is_circular_pointer_type): New function. + 2011-04-26 Ian Lance Taylor * go-gcc.cc (Gcc_backend::struct_type): Implement. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 7751fb81ab4..18c0bbae52e 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -161,8 +161,38 @@ class Gcc_backend : public Backend struct_type(const std::vector&); Btype* - array_type(const Btype* /* element_type */, const Bexpression* /* length */) - { gcc_unreachable(); } + array_type(Btype*, Bexpression*); + + Btype* + placeholder_pointer_type(const std::string&, source_location, bool); + + bool + set_placeholder_pointer_type(Btype*, Btype*); + + bool + set_placeholder_function_type(Btype*, Btype*); + + Btype* + placeholder_struct_type(const std::string&, source_location); + + bool + set_placeholder_struct_type(Btype* placeholder, + const std::vector&); + + Btype* + placeholder_array_type(const std::string&, source_location); + + bool + set_placeholder_array_type(Btype*, Btype*, Bexpression*); + + Btype* + named_type(const std::string&, Btype*, source_location); + + Btype* + circular_pointer_type(Btype*, bool); + + bool + is_circular_pointer_type(Btype*); // Statements. @@ -270,6 +300,12 @@ class Gcc_backend : public Backend Btype* make_type(tree t) { return new Btype(t); } + + Btype* + fill_in_struct(Btype*, const std::vector&); + + Btype* + fill_in_array(Btype*, Btype*, Bexpression*); }; // A helper function. @@ -453,7 +489,16 @@ Gcc_backend::function_type(const Btyped_identifier& receiver, Btype* Gcc_backend::struct_type(const std::vector& fields) { - tree ret = make_node(RECORD_TYPE); + return this->fill_in_struct(this->make_type(make_node(RECORD_TYPE)), fields); +} + +// Fill in the fields of a struct type. + +Btype* +Gcc_backend::fill_in_struct(Btype* fill, + const std::vector& fields) +{ + tree fill_tree = fill->get_tree(); tree field_trees = NULL_TREE; tree* pp = &field_trees; for (std::vector::const_iterator p = fields.begin(); @@ -465,15 +510,192 @@ Gcc_backend::struct_type(const std::vector& fields) if (type_tree == error_mark_node) return this->error_type(); tree field = build_decl(p->location, FIELD_DECL, name_tree, type_tree); - DECL_CONTEXT(field) = ret; + DECL_CONTEXT(field) = fill_tree; *pp = field; pp = &DECL_CHAIN(field); } - TYPE_FIELDS(ret) = field_trees; - layout_type(ret); + TYPE_FIELDS(fill_tree) = field_trees; + layout_type(fill_tree); + return fill; +} + +// Make an array type. + +Btype* +Gcc_backend::array_type(Btype* element_btype, Bexpression* length) +{ + return this->fill_in_array(this->make_type(make_node(ARRAY_TYPE)), + element_btype, length); +} + +// Fill in an array type. + +Btype* +Gcc_backend::fill_in_array(Btype* fill, Btype* element_type, + Bexpression* length) +{ + tree element_type_tree = element_type->get_tree(); + tree length_tree = length->get_tree(); + if (element_type_tree == error_mark_node || length_tree == error_mark_node) + return this->error_type(); + + gcc_assert(TYPE_SIZE(element_type_tree) != NULL_TREE); + + length_tree = fold_convert(sizetype, length_tree); + + // build_index_type takes the maximum index, which is one less than + // the length. + tree index_type_tree = build_index_type(fold_build2(MINUS_EXPR, sizetype, + length_tree, + size_one_node)); + + tree fill_tree = fill->get_tree(); + TREE_TYPE(fill_tree) = element_type_tree; + TYPE_DOMAIN(fill_tree) = index_type_tree; + TYPE_ADDR_SPACE(fill_tree) = TYPE_ADDR_SPACE(element_type_tree); + layout_type(fill_tree); + + if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree)) + SET_TYPE_STRUCTURAL_EQUALITY(fill_tree); + else if (TYPE_CANONICAL(element_type_tree) != element_type_tree + || TYPE_CANONICAL(index_type_tree) != index_type_tree) + TYPE_CANONICAL(fill_tree) = + build_array_type(TYPE_CANONICAL(element_type_tree), + TYPE_CANONICAL(index_type_tree)); + + return fill; +} + +// Create a placeholder for a pointer type. + +Btype* +Gcc_backend::placeholder_pointer_type(const std::string& name, + source_location location, bool) +{ + tree ret = build_variant_type_copy(ptr_type_node); + tree decl = build_decl(location, TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; return this->make_type(ret); } +// Set the real target type for a placeholder pointer type. + +bool +Gcc_backend::set_placeholder_pointer_type(Btype* placeholder, + Btype* to_type) +{ + tree pt = placeholder->get_tree(); + if (pt == error_mark_node) + return false; + gcc_assert(TREE_CODE(pt) == POINTER_TYPE); + tree tt = to_type->get_tree(); + if (tt == error_mark_node) + { + TREE_TYPE(pt) = tt; + return false; + } + gcc_assert(TREE_CODE(tt) == POINTER_TYPE); + TREE_TYPE(pt) = TREE_TYPE(tt); + return true; +} + +// Set the real values for a placeholder function type. + +bool +Gcc_backend::set_placeholder_function_type(Btype* placeholder, Btype* ft) +{ + return this->set_placeholder_pointer_type(placeholder, ft); +} + +// Create a placeholder for a struct type. + +Btype* +Gcc_backend::placeholder_struct_type(const std::string& name, + source_location location) +{ + tree ret = make_node(RECORD_TYPE); + tree decl = build_decl(location, TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; + return this->make_type(ret); +} + +// Fill in the fields of a placeholder struct type. + +bool +Gcc_backend::set_placeholder_struct_type( + Btype* placeholder, + const std::vector& fields) +{ + tree t = placeholder->get_tree(); + gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE); + Btype* r = this->fill_in_struct(placeholder, fields); + return r->get_tree() != error_mark_node; +} + +// Create a placeholder for an array type. + +Btype* +Gcc_backend::placeholder_array_type(const std::string& name, + source_location location) +{ + tree ret = make_node(ARRAY_TYPE); + tree decl = build_decl(location, TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; + return this->make_type(ret); +} + +// Fill in the fields of a placeholder array type. + +bool +Gcc_backend::set_placeholder_array_type(Btype* placeholder, + Btype* element_btype, + Bexpression* length) +{ + tree t = placeholder->get_tree(); + gcc_assert(TREE_CODE(t) == ARRAY_TYPE && TREE_TYPE(t) == NULL_TREE); + Btype* r = this->fill_in_array(placeholder, element_btype, length); + return r->get_tree() != error_mark_node; +} + +// Return a named version of a type. + +Btype* +Gcc_backend::named_type(const std::string& name, Btype* btype, + source_location location) +{ + tree type = btype->get_tree(); + if (type == error_mark_node) + return this->error_type(); + type = build_variant_type_copy(type); + tree decl = build_decl(location, TYPE_DECL, + get_identifier_from_string(name), + type); + TYPE_NAME(type) = decl; + return this->make_type(type); +} + +// Return a pointer type used as a marker for a circular type. + +Btype* +Gcc_backend::circular_pointer_type(Btype*, bool) +{ + return this->make_type(ptr_type_node); +} + +// Return whether we might be looking at a circular type. + +bool +Gcc_backend::is_circular_pointer_type(Btype* btype) +{ + return btype->get_tree() == ptr_type_node; +} + // An expression as a statement. Bstatement* diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 33f4e585952..d3154c59628 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -108,7 +108,93 @@ class Backend // Get an array type. virtual Btype* - array_type(const Btype* element_type, const Bexpression* length) = 0; + array_type(Btype* element_type, Bexpression* length) = 0; + + // Create a placeholder pointer type. This is used for a named + // pointer type, since in Go a pointer type may refer to itself. + // NAME is the name of the type, and the location is where the named + // type is defined. FOR_FUNCTION is true if this is for a Go + // function type, which corresponds to a C/C++ pointer to function + // type. The return value will later be passed as the first + // parameter to set_placeholder_pointer_type or + // set_placeholder_function_type. + virtual Btype* + placeholder_pointer_type(const std::string& name, source_location, + bool for_function) = 0; + + // Fill in a placeholder pointer type as a pointer. This takes a + // type returned by placeholder_pointer_type and arranges for it to + // point to to_type. Returns true on success, false on failure. + virtual bool + set_placeholder_pointer_type(Btype* placeholder, Btype* to_type) = 0; + + // Fill in a placeholder pointer type as a function. This takes a + // type returned by placeholder_pointer_type and arranges for it to + // become a real Go function type (which corresponds to a C/C++ + // pointer to function type). FT will be something returned by the + // function_type method. Returns true on success, false on failure. + virtual bool + set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0; + + // Create a placeholder struct type. This is used for a named + // struct type, as with placeholder_pointer_type. + virtual Btype* + placeholder_struct_type(const std::string& name, source_location) = 0; + + // Fill in a placeholder struct type. This takes a type returned by + // placeholder_struct_type and arranges for it to become a real + // struct type. The parameter is as for struct_type. Returns true + // on success, false on failure. + virtual bool + set_placeholder_struct_type(Btype* placeholder, + const std::vector& fields) + = 0; + + // Create a placeholder array type. This is used for a named array + // type, as with placeholder_pointer_type, to handle cases like + // type A []*A. + virtual Btype* + placeholder_array_type(const std::string& name, source_location) = 0; + + // Fill in a placeholder array type. This takes a type returned by + // placeholder_array_type and arranges for it to become a real array + // type. The parameters are as for array_type. Returns true on + // success, false on failure. + virtual bool + set_placeholder_array_type(Btype* placeholder, Btype* element_type, + Bexpression* length) = 0; + + // Return a named version of a type. The location is the location + // of the type definition. This will not be called for a type + // created via placeholder_pointer_type, placeholder_struct_type, or + // placeholder_array_type.. (It may be called for a pointer, + // struct, or array type in a case like "type P *byte; type Q P".) + virtual Btype* + named_type(const std::string& name, Btype*, source_location) = 0; + + // Create a marker for a circular pointer type. Go pointer and + // function types can refer to themselves in ways that are not + // permitted in C/C++. When a circular type is found, this function + // is called for the circular reference. This permits the backend + // to decide how to handle such a type. PLACEHOLDER is the + // placeholder type which has already been created; if the backend + // is prepared to handle a circular pointer type, it may simply + // return PLACEHOLDER. FOR_FUNCTION is true if this is for a + // function type. + // + // For "type P *P" the sequence of calls will be + // bt1 = placeholder_pointer_type(); + // bt2 = circular_pointer_type(bt1, false); + // set_placeholder_pointer_type(bt1, bt2); + virtual Btype* + circular_pointer_type(Btype* placeholder, bool for_function) = 0; + + // Return whether the argument could be a special type created by + // circular_pointer_type. This is used to introduce explicit type + // conversions where needed. If circular_pointer_type returns its + // PLACEHOLDER parameter, this may safely always return false. + virtual bool + is_circular_pointer_type(Btype*) = 0; // Statements. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 09f80c07ea1..fed14473d69 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -896,10 +896,11 @@ Type::get_tree_without_hash(Gogo* gogo) tree t = this->do_get_tree(gogo); // For a recursive function or pointer type, we will temporarily - // return ptr_type_node during the recursion. We don't want to - // record that for a forwarding type, as it may confuse us - // later. - if (t == ptr_type_node && this->forward_declaration_type() != NULL) + // return a circular pointer type during the recursion. We + // don't want to record that for a forwarding type, as it may + // confuse us later. + if (this->forward_declaration_type() != NULL + && gogo->backend()->is_circular_pointer_type(tree_to_type(t))) return t; if (gogo == NULL || !gogo->named_types_are_converted()) @@ -912,6 +913,16 @@ Type::get_tree_without_hash(Gogo* gogo) return this->tree_; } +// Return the backend representation for a type without looking in the +// hash table for identical types. This is used for named types, +// since a named type is never identical to any other type. + +Btype* +Type::get_btype_without_hash(Gogo* gogo) +{ + return tree_to_type(this->get_tree_without_hash(gogo)); +} + // Return a tree representing a zero initialization for this type. tree @@ -3748,60 +3759,38 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const return Type::method_function(this->all_methods_, name, is_ambiguous); } +// 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. + +static void +get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, + std::vector* bfields) +{ + bfields->resize(fields->size()); + size_t i = 0; + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + ++p, ++i) + { + (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name()); + (*bfields)[i].btype = tree_to_type(p->type()->get_tree(gogo)); + (*bfields)[i].location = p->location(); + } + go_assert(i == fields->size()); +} + // Get the tree for a struct type. tree Struct_type::do_get_tree(Gogo* gogo) { - std::vector fields; - fields.resize(this->fields_->size()); - size_t i = 0; - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p, ++i) - { - fields[i].name = Gogo::unpack_hidden_name(p->field_name()); - fields[i].btype = tree_to_type(p->type()->get_tree(gogo)); - fields[i].location = p->location(); - } - go_assert(i == this->fields_->size()); - Btype* btype = gogo->backend()->struct_type(fields); + std::vector bfields; + get_backend_struct_fields(gogo, this->fields_, &bfields); + Btype* btype = gogo->backend()->struct_type(bfields); return type_to_tree(btype); } -// Fill in the fields for a struct type. - -tree -Struct_type::fill_in_tree(Gogo* gogo, tree type) -{ - tree field_trees = NULL_TREE; - tree* pp = &field_trees; - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p) - { - std::string name = Gogo::unpack_hidden_name(p->field_name()); - tree name_tree = get_identifier_with_length(name.data(), name.length()); - - tree field_type_tree = p->type()->get_tree(gogo); - if (field_type_tree == error_mark_node) - return error_mark_node; - go_assert(TYPE_SIZE(field_type_tree) != NULL_TREE); - - tree field = build_decl(p->location(), FIELD_DECL, name_tree, - field_type_tree); - DECL_CONTEXT(field) = type; - *pp = field; - pp = &DECL_CHAIN(field); - } - - TYPE_FIELDS(type) = field_trees; - - layout_type(type); - - return type; -} - // Initialize struct fields. tree @@ -4425,50 +4414,26 @@ Array_type::do_get_tree(Gogo* gogo) } else { - tree array_type = make_node(ARRAY_TYPE); - return this->fill_in_array_tree(gogo, array_type); + Btype* element = this->get_backend_element(gogo); + Bexpression* len = this->get_backend_length(gogo); + Btype* ret = gogo->backend()->array_type(element, len); + return type_to_tree(ret); } } -// Fill in the fields for an array type. This is used for named array -// types. - -tree -Array_type::fill_in_array_tree(Gogo* gogo, tree array_type) +// Return the backend representation of the element type. +Btype* +Array_type::get_backend_element(Gogo* gogo) { - go_assert(this->length_ != NULL); + return tree_to_type(this->element_type_->get_tree(gogo)); +} - tree element_type_tree = this->element_type_->get_tree(gogo); - tree length_tree = this->get_length_tree(gogo); - if (element_type_tree == error_mark_node - || length_tree == error_mark_node) - return error_mark_node; +// Return the backend representation of the length. - go_assert(TYPE_SIZE(element_type_tree) != NULL_TREE); - - length_tree = fold_convert(sizetype, length_tree); - - // build_index_type takes the maximum index, which is one less than - // the length. - tree index_type = build_index_type(fold_build2(MINUS_EXPR, sizetype, - length_tree, - size_one_node)); - - TREE_TYPE(array_type) = element_type_tree; - TYPE_DOMAIN(array_type) = index_type; - TYPE_ADDR_SPACE(array_type) = TYPE_ADDR_SPACE(element_type_tree); - layout_type(array_type); - - if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree) - || TYPE_STRUCTURAL_EQUALITY_P(index_type)) - SET_TYPE_STRUCTURAL_EQUALITY(array_type); - else if (TYPE_CANONICAL(element_type_tree) != element_type_tree - || TYPE_CANONICAL(index_type) != index_type) - TYPE_CANONICAL(array_type) = - build_array_type(TYPE_CANONICAL(element_type_tree), - TYPE_CANONICAL(index_type)); - - return array_type; +Bexpression* +Array_type::get_backend_length(Gogo* gogo) +{ + return tree_to_expr(this->get_length_tree(gogo)); } // Fill in the fields for a slice type. This is used for named slice @@ -7073,7 +7038,7 @@ Named_type::convert(Gogo* gogo) (*p)->convert(gogo); // Complete this type. - tree t = this->named_tree_; + Btype* bt = this->named_btype_; Type* base = this->type_->base(); switch (base->classification()) { @@ -7092,21 +7057,37 @@ Named_type::convert(Gogo* gogo) case TYPE_FUNCTION: case TYPE_POINTER: - // The size of these types is already correct. + // The size of these types is already correct. We don't worry + // about filling them in until later, when we also track + // circular references. break; case TYPE_STRUCT: - t = base->struct_type()->fill_in_tree(gogo, t); + { + std::vector bfields; + get_backend_struct_fields(gogo, base->struct_type()->fields(), + &bfields); + if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) + bt = gogo->backend()->error_type(); + } break; case TYPE_ARRAY: if (!base->is_open_array_type()) - t = base->array_type()->fill_in_array_tree(gogo, t); + { + Btype* bet = base->array_type()->get_backend_element(gogo); + Bexpression* blen = base->array_type()->get_backend_length(gogo); + if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen)) + bt = gogo->backend()->error_type(); + } break; case TYPE_INTERFACE: if (!base->interface_type()->is_empty()) - t = base->interface_type()->fill_in_tree(gogo, t); + { + tree t = type_to_tree(bt); + bt = tree_to_type(base->interface_type()->fill_in_tree(gogo, t)); + } break; case TYPE_ERROR: @@ -7120,13 +7101,7 @@ Named_type::convert(Gogo* gogo) go_unreachable(); } - this->named_tree_ = t; - - if (t == error_mark_node) - this->is_error_ = true; - else - go_assert(TYPE_SIZE(t) != NULL_TREE); - + this->named_btype_ = bt; this->is_converted_ = true; } @@ -7137,9 +7112,9 @@ void Named_type::create_placeholder(Gogo* gogo) { if (this->is_error_) - this->named_tree_ = error_mark_node; + this->named_btype_ = gogo->backend()->error_type(); - if (this->named_tree_ != NULL_TREE) + if (this->named_btype_ != NULL) return; // Create the structure for this type. Note that because we call @@ -7147,12 +7122,13 @@ Named_type::create_placeholder(Gogo* gogo) // as another named type. Instead both named types will point to // different base representations. Type* base = this->type_->base(); - tree t; + Btype* bt; + bool set_name = true; switch (base->classification()) { case TYPE_ERROR: this->is_error_ = true; - this->named_tree_ = error_mark_node; + this->named_btype_ = gogo->backend()->error_type(); return; case TYPE_VOID: @@ -7164,55 +7140,50 @@ Named_type::create_placeholder(Gogo* gogo) case TYPE_NIL: // These are simple basic types, we can just create them // directly. - t = Type::get_named_type_tree(gogo, base); - if (t == error_mark_node) - { - this->is_error_ = true; - this->named_tree_ = error_mark_node; - return; - } - t = build_variant_type_copy(t); + bt = Type::get_named_base_btype(gogo, base); break; case TYPE_MAP: case TYPE_CHANNEL: - // All maps and channels have the same type in GENERIC. - t = Type::get_named_type_tree(gogo, base); - if (t == error_mark_node) - { - this->is_error_ = true; - this->named_tree_ = error_mark_node; - return; - } - t = build_variant_type_copy(t); + // All maps and channels have the same backend representation. + bt = Type::get_named_base_btype(gogo, base); break; case TYPE_FUNCTION: case TYPE_POINTER: - t = build_variant_type_copy(ptr_type_node); + { + bool for_function = base->classification() == TYPE_FUNCTION; + bt = gogo->backend()->placeholder_pointer_type(this->name(), + this->location_, + for_function); + set_name = false; + } break; case TYPE_STRUCT: - t = make_node(RECORD_TYPE); + bt = gogo->backend()->placeholder_struct_type(this->name(), + this->location_); + set_name = false; break; case TYPE_ARRAY: if (base->is_open_array_type()) - t = gogo->slice_type_tree(void_type_node); + bt = tree_to_type(gogo->slice_type_tree(void_type_node)); else - t = make_node(ARRAY_TYPE); + { + bt = gogo->backend()->placeholder_array_type(this->name(), + this->location_); + set_name = false; + } break; case TYPE_INTERFACE: if (base->interface_type()->is_empty()) - { - t = Interface_type::empty_type_tree(gogo); - t = build_variant_type_copy(t); - } + bt = tree_to_type(Interface_type::empty_type_tree(gogo)); else { source_location loc = base->interface_type()->location(); - t = Interface_type::non_empty_type_tree(loc); + bt = tree_to_type(Interface_type::non_empty_type_tree(loc)); } break; @@ -7224,13 +7195,10 @@ Named_type::create_placeholder(Gogo* gogo) go_unreachable(); } - // Create the named type. + if (set_name) + bt = gogo->backend()->named_type(this->name(), bt, this->location_); - tree id = this->named_object_->get_id(gogo); - tree decl = build_decl(this->location_, TYPE_DECL, id, t); - TYPE_NAME(t) = decl; - - this->named_tree_ = t; + this->named_btype_ = bt; } // Get a tree for a named type. @@ -7241,24 +7209,22 @@ Named_type::do_get_tree(Gogo* gogo) if (this->is_error_) return error_mark_node; - tree t = this->named_tree_; + Btype* bt = this->named_btype_; - // FIXME: GOGO can be NULL when called from go_type_for_size, which - // is only used for basic types. - if (gogo == NULL || !gogo->named_types_are_converted()) + if (!gogo->named_types_are_converted()) { - // We have not completed converting named types. NAMED_TREE_ is - // a placeholder and we shouldn't do anything further. - if (t != NULL_TREE) - return t; + // We have not completed converting named types. NAMED_BTYPE_ + // is a placeholder and we shouldn't do anything further. + if (bt != NULL) + return type_to_tree(bt); // We don't build dependencies for types whose sizes do not // change or are not relevant, so we may see them here while // converting types. this->create_placeholder(gogo); - t = this->named_tree_; - go_assert(t != NULL_TREE); - return t; + bt = this->named_btype_; + go_assert(bt != NULL); + return type_to_tree(bt); } // We are not converting types. This should only be called if the @@ -7269,11 +7235,11 @@ Named_type::do_get_tree(Gogo* gogo) return error_mark_node; } - go_assert(t != NULL_TREE && TYPE_SIZE(t) != NULL_TREE); + go_assert(bt != NULL); // Complete the tree. Type* base = this->type_->base(); - tree t1; + Btype* bt1; switch (base->classification()) { case TYPE_ERROR: @@ -7290,7 +7256,7 @@ Named_type::do_get_tree(Gogo* gogo) case TYPE_CHANNEL: case TYPE_STRUCT: case TYPE_INTERFACE: - return t; + return type_to_tree(bt); case TYPE_FUNCTION: // Don't build a circular data structure. GENERIC can't handle @@ -7298,19 +7264,17 @@ Named_type::do_get_tree(Gogo* gogo) if (this->seen_ > 0) { this->is_circular_ = true; - return ptr_type_node; + bt1 = gogo->backend()->circular_pointer_type(bt, true); + return type_to_tree(bt1); } ++this->seen_; - t1 = Type::get_named_type_tree(gogo, base); + bt1 = Type::get_named_base_btype(gogo, base); --this->seen_; - if (t1 == error_mark_node) - return error_mark_node; if (this->is_circular_) - t1 = ptr_type_node; - go_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE); - go_assert(TREE_CODE(t1) == POINTER_TYPE); - TREE_TYPE(t) = TREE_TYPE(t1); - return t; + bt1 = gogo->backend()->circular_pointer_type(bt, true); + if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1)) + bt = gogo->backend()->error_type(); + return type_to_tree(bt); case TYPE_POINTER: // Don't build a circular data structure. GENERIC can't handle @@ -7318,33 +7282,33 @@ Named_type::do_get_tree(Gogo* gogo) if (this->seen_ > 0) { this->is_circular_ = true; - return ptr_type_node; + bt1 = gogo->backend()->circular_pointer_type(bt, false); + return type_to_tree(bt1); } ++this->seen_; - t1 = Type::get_named_type_tree(gogo, base); + bt1 = Type::get_named_base_btype(gogo, base); --this->seen_; - if (t1 == error_mark_node) - return error_mark_node; if (this->is_circular_) - t1 = ptr_type_node; - go_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE); - go_assert(TREE_CODE(t1) == POINTER_TYPE); - TREE_TYPE(t) = TREE_TYPE(t1); - return t; + bt1 = gogo->backend()->circular_pointer_type(bt, false); + if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1)) + bt = gogo->backend()->error_type(); + return type_to_tree(bt); case TYPE_ARRAY: if (base->is_open_array_type()) { if (this->seen_ > 0) - return t; + return type_to_tree(bt); else { ++this->seen_; - t = base->array_type()->fill_in_slice_tree(gogo, t); + tree t = base->array_type()->fill_in_slice_tree(gogo, + type_to_tree(bt)); + bt = tree_to_type(t); --this->seen_; } } - return t; + return type_to_tree(bt); default: case TYPE_SINK: @@ -8467,7 +8431,7 @@ tree Forward_declaration_type::do_get_tree(Gogo* gogo) { if (this->is_defined()) - return Type::get_named_type_tree(gogo, this->real_type()); + return type_to_tree(Type::get_named_base_btype(gogo, this->real_type())); if (this->warned_) return error_mark_node; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 5e6da62e514..3b4d5f22953 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -42,6 +42,8 @@ class Function; class Translate_context; class Export; class Import; +class Btype; +class Bexpression; // Type codes used in type descriptors. These must match the values // in libgo/runtime/go-type.h. They also match the values in the gc @@ -973,10 +975,11 @@ class Type static unsigned int hash_string(const std::string&, unsigned int); - // Return a tree for the underlying type of a named type. - static tree - get_named_type_tree(Gogo* gogo, Type* base_type) - { return base_type->get_tree_without_hash(gogo); } + // Return the backend representation for the underlying type of a + // named type. + static Btype* + get_named_base_btype(Gogo* gogo, Type* base_type) + { return base_type->get_btype_without_hash(gogo); } private: // Convert to the desired type classification, or return NULL. This @@ -1100,6 +1103,11 @@ class Type tree get_tree_without_hash(Gogo*); + // Get the backend representation for a type without looking in the + // hash table for identical types. + Btype* + get_btype_without_hash(Gogo*); + // A mapping from Type to tree, used to ensure that the GIMPLE // representation of identical types is identical. typedef Unordered_map_hash(const Type*, tree, Type_hash_identical, @@ -1952,10 +1960,6 @@ class Struct_type : public Type static Struct_type* do_import(Import*); - // Fill in the fields for a named struct type. - tree - fill_in_tree(Gogo*, tree); - static Type* make_struct_type_descriptor_type(); @@ -2056,9 +2060,13 @@ class Array_type : public Type static Array_type* do_import(Import*); - // Fill in the fields for a named array type. - tree - fill_in_array_tree(Gogo*, tree); + // Return the backend representation of the element type. + Btype* + get_backend_element(Gogo*); + + // Return the backend representation of the length. + Bexpression* + get_backend_length(Gogo*); // Fill in the fields for a named slice type. tree @@ -2430,7 +2438,7 @@ class Named_type : public Type named_object_(named_object), in_function_(NULL), type_(type), local_methods_(NULL), all_methods_(NULL), interface_method_tables_(NULL), pointer_interface_method_tables_(NULL), - location_(location), named_tree_(NULL), dependencies_(), + location_(location), named_btype_(NULL), dependencies_(), is_visible_(true), is_error_(false), is_converted_(false), is_circular_(false), seen_(0) { } @@ -2676,9 +2684,10 @@ class Named_type : public Type Interface_method_tables* pointer_interface_method_tables_; // The location where this type was defined. source_location location_; - // The tree for this type while converting to GENERIC. This is used - // to avoid endless recursion when a named type refers to itself. - tree named_tree_; + // The backend representation of this type during backend + // conversion. This is used to avoid endless recursion when a named + // type refers to itself. + Btype* named_btype_; // A list of types which must be converted to the backend // representation before this type can be converted. This is for // cases like