X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgo%2Fgofrontend%2Ftypes.cc;h=9e64a6ac84a176d5614d9ab370a3be61796c1b9a;hb=88b6c6b482354107ba74374327825742da01eecb;hp=21dac51b3708c58c9b3de9c425ce5e87a0535055;hpb=2d61f90a099b049b171356cd7c3e65bd65376314;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 21dac51b370..9e64a6ac84a 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) { } @@ -192,7 +210,10 @@ Type::make_non_abstract_type() switch (this->classification()) { case TYPE_INTEGER: - return Type::lookup_integer_type("int"); + if (this->integer_type()->is_rune()) + return Type::lookup_integer_type("int32"); + else + return Type::lookup_integer_type("int"); case TYPE_FLOAT: return Type::lookup_float_type("float64"); case TYPE_COMPLEX: @@ -320,6 +341,12 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, t1 = t1->forwarded(); t2 = t2->forwarded(); + // Ignore aliases for purposes of type identity. + if (t1->named_type() != NULL && t1->named_type()->is_alias()) + t1 = t1->named_type()->real_type(); + if (t2->named_type() != NULL && t2->named_type()->is_alias()) + t2 = t2->named_type()->real_type(); + if (t1 == t2) return true; @@ -571,7 +598,8 @@ Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1, } else if (t1->array_type() != NULL) { - if (!t1->array_type()->element_type()->is_comparable()) + if (t1->array_type()->length()->is_nil_expression() + || !t1->array_type()->element_type()->is_comparable()) { if (reason != NULL) *reason = _("invalid comparison of non-comparable array"); @@ -594,16 +622,24 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, std::string* reason) { // Do some checks first. Make sure the types are defined. - if (rhs != NULL - && rhs->forwarded()->forward_declaration_type() == NULL - && rhs->is_void_type()) + if (rhs != NULL && !rhs->is_undefined()) { - if (reason != NULL) - *reason = "non-value used as value"; - return false; + if (rhs->is_void_type()) + { + if (reason != NULL) + *reason = "non-value used as value"; + return false; + } + if (rhs->is_call_multiple_result_type()) + { + if (reason != NULL) + reason->assign(_("multiple value function call in " + "single value context")); + return false; + } } - if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL) + if (lhs != NULL && !lhs->is_undefined()) { // Any value may be assigned to the blank identifier. if (lhs->is_sink_type()) @@ -611,9 +647,7 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, // All fields of a struct must be exported, or the assignment // must be in the same package. - if (check_hidden_fields - && rhs != NULL - && rhs->forwarded()->forward_declaration_type() == NULL) + if (check_hidden_fields && rhs != NULL && !rhs->is_undefined()) { if (lhs->has_hidden_fields(NULL, reason) || rhs->has_hidden_fields(NULL, reason)) @@ -687,9 +721,6 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, { if (rhs->interface_type() != NULL) reason->assign(_("need explicit conversion")); - else if (rhs->is_call_multiple_result_type()) - reason->assign(_("multiple value function call in " - "single value context")); else if (lhs->named_type() != NULL && rhs->named_type() != NULL) { size_t len = (lhs->named_type()->name().length() @@ -766,7 +797,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) if (lhs->complex_type() != NULL && rhs->complex_type() != NULL) return true; - // An integer, or []byte, or []int, may be converted to a string. + // An integer, or []byte, or []rune, may be converted to a string. if (lhs->is_string_type()) { if (rhs->integer_type() != NULL) @@ -775,19 +806,18 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) { const Type* e = rhs->array_type()->element_type()->forwarded(); if (e->integer_type() != NULL - && (e == Type::lookup_integer_type("uint8") - || e == Type::lookup_integer_type("int"))) + && (e->integer_type()->is_byte() + || e->integer_type()->is_rune())) return true; } } - // A string may be converted to []byte or []int. + // A string may be converted to []byte or []rune. if (rhs->is_string_type() && lhs->is_slice_type()) { const Type* e = lhs->array_type()->element_type()->forwarded(); if (e->integer_type() != NULL - && (e == Type::lookup_integer_type("uint8") - || e == Type::lookup_integer_type("int"))) + && (e->integer_type()->is_byte() || e->integer_type()->is_rune())) return true; } @@ -886,7 +916,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) @@ -957,12 +991,197 @@ 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 Type::type_descriptor_pointer(Gogo* gogo, Location location) { Type* t = this->forwarded(); + if (t->named_type() != NULL && t->named_type()->is_alias()) + t = t->named_type()->real_type(); if (t->type_descriptor_var_ == NULL) { t->make_type_descriptor_var(gogo); @@ -1372,7 +1591,7 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, const char* hash_fnname; const char* equal_fnname; - if (this->compare_is_identity()) + if (this->compare_is_identity(gogo)) { hash_fnname = "__go_type_hash_identity"; equal_fnname = "__go_type_equal_identity"; @@ -1571,6 +1790,12 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, { Location bloc = Linemap::predeclared_location(); + if (gogo->specific_type_functions_are_written()) + { + go_assert(saw_errors()); + return; + } + Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false, bloc); gogo->start_block(bloc); @@ -1647,7 +1872,12 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, ++p; go_assert(p->is_field_name("hash")); - mpz_set_ui(iv, this->hash_for_method(gogo)); + unsigned int h; + if (name != NULL) + h = name->hash_for_method(gogo); + else + h = this->hash_for_method(gogo); + mpz_set_ui(iv, h); vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); ++p; @@ -1963,7 +2193,7 @@ Type::mangled_name(Gogo* gogo) const // Return whether the backend size of the type is known. bool -Type::is_backend_type_size_known(Gogo* gogo) const +Type::is_backend_type_size_known(Gogo* gogo) { switch (this->classification_) { @@ -2000,25 +2230,26 @@ Type::is_backend_type_size_known(Gogo* gogo) const return true; else { + Numeric_constant nc; + if (!at->length()->numeric_constant_value(&nc)) + return false; mpz_t ival; - mpz_init(ival); - Type* dummy; - bool length_known = at->length()->integer_constant_value(true, - ival, - &dummy); - mpz_clear(ival); - if (!length_known) + if (!nc.to_int(&ival)) return false; + mpz_clear(ival); return at->element_type()->is_backend_type_size_known(gogo); } } case TYPE_NAMED: + // Begin converting this type to the backend representation. + // This will create a placeholder if necessary. + this->get_backend(gogo); return this->named_type()->is_named_backend_type_size_known(); case TYPE_FORWARD: { - const Forward_declaration_type* fdt = this->forward_declaration_type(); + Forward_declaration_type* fdt = this->forward_declaration_type(); return fdt->real_type()->is_backend_type_size_known(gogo); } @@ -2038,10 +2269,10 @@ Type::is_backend_type_size_known(Gogo* gogo) const bool Type::backend_type_size(Gogo* gogo, unsigned int *psize) { - Btype* btype = this->get_backend(gogo); if (!this->is_backend_type_size_known(gogo)) return false; - size_t size = gogo->backend()->type_size(btype); + Btype* bt = this->get_backend_placeholder(gogo); + size_t size = gogo->backend()->type_size(bt); *psize = static_cast(size); if (*psize != size) return false; @@ -2054,10 +2285,10 @@ Type::backend_type_size(Gogo* gogo, unsigned int *psize) bool Type::backend_type_align(Gogo* gogo, unsigned int *palign) { - Btype* btype = this->get_backend(gogo); if (!this->is_backend_type_size_known(gogo)) return false; - size_t align = gogo->backend()->type_alignment(btype); + Btype* bt = this->get_backend_placeholder(gogo); + size_t align = gogo->backend()->type_alignment(bt); *palign = static_cast(align); if (*palign != align) return false; @@ -2070,10 +2301,10 @@ Type::backend_type_align(Gogo* gogo, unsigned int *palign) bool Type::backend_type_field_align(Gogo* gogo, unsigned int *palign) { - Btype* btype = this->get_backend(gogo); if (!this->is_backend_type_size_known(gogo)) return false; - size_t a = gogo->backend()->type_field_alignment(btype); + 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; @@ -2126,7 +2357,7 @@ class Error_type : public Type protected: bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return false; } Btype* @@ -2164,7 +2395,7 @@ class Void_type : public Type protected: bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return false; } Btype* @@ -2202,7 +2433,7 @@ class Boolean_type : public Type protected: bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return true; } Btype* @@ -2317,6 +2548,21 @@ Integer_type::create_abstract_integer_type() return abstract_type; } +// Create a new abstract character type. + +Integer_type* +Integer_type::create_abstract_character_type() +{ + static Integer_type* abstract_type; + if (abstract_type == NULL) + { + abstract_type = new Integer_type(true, false, 32, + RUNTIME_TYPE_KIND_INT32); + abstract_type->set_is_rune(); + } + return abstract_type; +} + // Integer type compatibility. bool @@ -2356,7 +2602,7 @@ Integer_type::do_get_backend(Gogo* gogo) Expression* Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - go_assert(name != NULL); + go_assert(name != NULL || saw_errors()); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -2399,6 +2645,14 @@ Type::make_abstract_integer_type() return Integer_type::create_abstract_integer_type(); } +// Make an abstract character type. + +Integer_type* +Type::make_abstract_character_type() +{ + return Integer_type::create_abstract_character_type(); +} + // Look up an integer type. Named_type* @@ -2483,7 +2737,7 @@ Float_type::do_get_backend(Gogo* gogo) Expression* Float_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - go_assert(name != NULL); + go_assert(name != NULL || saw_errors()); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -2610,7 +2864,7 @@ Complex_type::do_get_backend(Gogo* gogo) Expression* Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - go_assert(name != NULL); + go_assert(name != NULL || saw_errors()); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -2673,6 +2927,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(); @@ -2793,7 +3056,7 @@ class Sink_type : public Type protected: bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return false; } Btype* @@ -2855,9 +3118,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, // A redeclaration of a function is required to use the same names // for the receiver and parameters. if (this->receiver() != NULL - && this->receiver()->name() != t->receiver()->name() - && this->receiver()->name() != Import::import_marker - && t->receiver()->name() != Import::import_marker) + && this->receiver()->name() != t->receiver()->name()) { if (reason != NULL) *reason = "receiver name changed"; @@ -2873,9 +3134,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, p2 != parms2->end(); ++p2, ++p1) { - if (p1->name() != p2->name() - && p1->name() != Import::import_marker - && p2->name() != Import::import_marker) + if (p1->name() != p2->name()) { if (reason != NULL) *reason = "parameter name changed"; @@ -2904,9 +3163,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, res2 != results2->end(); ++res2, ++res1) { - if (res1->name() != res2->name() - && res1->name() != Import::import_marker - && res2->name() != Import::import_marker) + if (res1->name() != res2->name()) { if (reason != NULL) *reason = "result name changed"; @@ -3078,7 +3335,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) @@ -3130,46 +3387,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* @@ -3393,6 +3610,8 @@ Function_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); if (!is_varargs || p + 1 != this->parameters_->end()) exp->write_type(p->type()); else @@ -3408,7 +3627,7 @@ Function_type::do_export(Export* exp) const if (results != NULL) { exp->write_c_string(" "); - if (results->size() == 1) + if (results->size() == 1 && results->begin()->name().empty()) exp->write_type(results->begin()->type()); else { @@ -3422,6 +3641,8 @@ Function_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); exp->write_type(p->type()); } exp->write_c_string(")"); @@ -3444,6 +3665,9 @@ Function_type::do_import(Import* imp) parameters = new Typed_identifier_list(); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); + if (imp->match_c_string("...")) { imp->advance(3); @@ -3453,8 +3677,8 @@ Function_type::do_import(Import* imp) Type* ptype = imp->read_type(); if (is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(Import::import_marker, - ptype, imp->location())); + parameters->push_back(Typed_identifier(name, ptype, + imp->location())); if (imp->peek_char() != ',') break; go_assert(!is_varargs); @@ -3473,17 +3697,18 @@ Function_type::do_import(Import* imp) if (imp->peek_char() != '(') { Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, rtype, - imp->location())); + results->push_back(Typed_identifier("", rtype, imp->location())); } else { imp->advance(1); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier(name, rtype, + imp->location())); if (imp->peek_char() != ',') break; imp->require_c_string(", "); @@ -3523,8 +3748,12 @@ Function_type::copy_with_receiver(Type* receiver_type) const go_assert(!this->is_method()); Typed_identifier* receiver = new Typed_identifier("", receiver_type, this->location_); - return Type::make_function_type(receiver, this->parameters_, - this->results_, this->location_); + Function_type* ret = Type::make_function_type(receiver, this->parameters_, + this->results_, + this->location_); + if (this->is_varargs_) + ret->set_is_varargs(); + return ret; } // Make a function type. @@ -3556,7 +3785,7 @@ Pointer_type::do_hash_for_method(Gogo* gogo) const return this->to_type_->hash_for_method(gogo) << 4; } -// The tree for a pointer type. +// Get the backend representation for a pointer type. Btype* Pointer_type::do_get_backend(Gogo* gogo) @@ -3705,7 +3934,7 @@ class Nil_type : public Type protected: bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return false; } Btype* @@ -3756,7 +3985,7 @@ class Call_multiple_result_type : public Type } bool - do_compare_is_identity() const + do_compare_is_identity(Gogo*) const { return false; } Btype* @@ -3898,7 +4127,6 @@ Struct_type::do_verify() Struct_field_list* fields = this->fields_; if (fields == NULL) return true; - bool ret = true; for (Struct_field_list::iterator p = fields->begin(); p != fields->end(); ++p) @@ -3908,7 +4136,6 @@ Struct_type::do_verify() { error_at(p->location(), "struct field type is incomplete"); p->set_type(Type::make_error_type()); - ret = false; } else if (p->is_anonymous()) { @@ -3916,19 +4143,17 @@ Struct_type::do_verify() { error_at(p->location(), "embedded type may not be a pointer"); p->set_type(Type::make_error_type()); - return false; } - if (t->points_to() != NULL - && t->points_to()->interface_type() != NULL) + else if (t->points_to() != NULL + && t->points_to()->interface_type() != NULL) { error_at(p->location(), "embedded type may not be pointer to interface"); p->set_type(Type::make_error_type()); - return false; } } } - return ret; + return true; } // Whether this contains a pointer. @@ -4037,16 +4262,35 @@ Struct_type::struct_has_hidden_fields(const Named_type* within, // comparisons. bool -Struct_type::do_compare_is_identity() const +Struct_type::do_compare_is_identity(Gogo* gogo) const { const Struct_field_list* fields = this->fields_; if (fields == NULL) return true; + unsigned int offset = 0; for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf) - if (!pf->type()->compare_is_identity()) - return false; + { + if (!pf->type()->compare_is_identity(gogo)) + return false; + + unsigned int field_align; + if (!pf->type()->backend_type_align(gogo, &field_align)) + return false; + if ((offset & (field_align - 1)) != 0) + { + // This struct has padding. We don't guarantee that that + // padding is zero-initialized for a stack variable, so we + // can't use memcmp to compare struct values. + return false; + } + + unsigned int field_size; + if (!pf->type()->backend_type_size(gogo, &field_size)) + return false; + offset += field_size; + } return true; } @@ -4231,7 +4475,7 @@ Struct_type::total_field_count() const pf != this->fields_->end(); ++pf) { - if (!pf->is_anonymous() || pf->type()->deref()->struct_type() == NULL) + if (!pf->is_anonymous() || pf->type()->struct_type() == NULL) ++ret; else ret += pf->type()->struct_type()->total_field_count(); @@ -4267,17 +4511,6 @@ Struct_type::is_unexported_local_field(Gogo* gogo, void Struct_type::finalize_methods(Gogo* gogo) { - // If this type needs explicit comparison and hash functions, create - // them now. It would be a bit better to do this only if the - // functions are needed, but they will be static so the backend can - // discard them if they are not used. - if (!this->compare_is_identity() && this->is_comparable()) - { - Named_object* hash_fn; - Named_object* equal_fn; - this->type_functions(gogo, NULL, NULL, NULL, &hash_fn, &equal_fn); - } - if (this->all_methods_ != NULL) return; Type::finalize_methods(gogo, this, this->location_, &this->all_methods_); @@ -4299,6 +4532,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()); @@ -4308,7 +4542,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()); @@ -4320,10 +4556,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* @@ -4727,10 +4978,10 @@ bool Struct_type::backend_field_offset(Gogo* gogo, unsigned int index, unsigned int* poffset) { - Btype* btype = this->get_backend(gogo); if (!this->is_backend_type_size_known(gogo)) return false; - size_t offset = gogo->backend()->type_field_offset(btype, 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; @@ -4853,17 +5104,22 @@ Array_type::is_identical(const Array_type* t, bool errors_are_identical) const // Try to determine the lengths. If we can't, assume the arrays // are not identical. bool ret = false; - mpz_t v1; - mpz_init(v1); - Type* type1; - mpz_t v2; - mpz_init(v2); - Type* type2; - if (l1->integer_constant_value(true, v1, &type1) - && l2->integer_constant_value(true, v2, &type2)) - ret = mpz_cmp(v1, v2) == 0; - mpz_clear(v1); - mpz_clear(v2); + Numeric_constant nc1, nc2; + if (l1->numeric_constant_value(&nc1) + && l2->numeric_constant_value(&nc2)) + { + mpz_t v1; + if (nc1.to_int(&v1)) + { + mpz_t v2; + if (nc2.to_int(&v2)) + { + ret = mpz_cmp(v1, v2) == 0; + mpz_clear(v2); + } + mpz_clear(v1); + } + } return ret; } @@ -4871,25 +5127,6 @@ Array_type::is_identical(const Array_type* t, bool errors_are_identical) const return false; } -// If this type needs explicit comparison and hash functions, create -// them now. It would be a bit better to do this only if the -// functions are needed, but they will be static so the backend can -// discard them if they are not used. - -void -Array_type::finalize_methods(Gogo* gogo) -{ - if (this->length_ != NULL - && !this->length_->is_nil_expression() - && !this->compare_is_identity() - && this->is_comparable()) - { - Named_object* hash_fn; - Named_object* equal_fn; - this->type_functions(gogo, NULL, NULL, NULL, &hash_fn, &equal_fn); - } -} - // Traversal. int @@ -4920,58 +5157,44 @@ Array_type::verify_length() return false; } - mpz_t val; - mpz_init(val); - Type* vt; - if (!this->length_->integer_constant_value(true, val, &vt)) + Numeric_constant nc; + if (!this->length_->numeric_constant_value(&nc)) { - mpfr_t fval; - mpfr_init(fval); - if (!this->length_->float_constant_value(fval, &vt)) - { - if (this->length_->type()->integer_type() != NULL - || this->length_->type()->float_type() != NULL) - error_at(this->length_->location(), - "array bound is not constant"); - else - error_at(this->length_->location(), - "array bound is not numeric"); - mpfr_clear(fval); - mpz_clear(val); - return false; - } - if (!mpfr_integer_p(fval)) - { - error_at(this->length_->location(), - "array bound truncated to integer"); - mpfr_clear(fval); - mpz_clear(val); - return false; - } - mpz_init(val); - mpfr_get_z(val, fval, GMP_RNDN); - mpfr_clear(fval); + if (this->length_->type()->integer_type() != NULL + || this->length_->type()->float_type() != NULL) + error_at(this->length_->location(), "array bound is not constant"); + else + error_at(this->length_->location(), "array bound is not numeric"); + return false; } - if (mpz_sgn(val) < 0) + unsigned long val; + switch (nc.to_unsigned_long(&val)) { + case Numeric_constant::NC_UL_VALID: + break; + case Numeric_constant::NC_UL_NOTINT: + error_at(this->length_->location(), "array bound truncated to integer"); + return false; + case Numeric_constant::NC_UL_NEGATIVE: error_at(this->length_->location(), "negative array bound"); - mpz_clear(val); return false; + case Numeric_constant::NC_UL_BIG: + error_at(this->length_->location(), "array bound overflows"); + return false; + default: + go_unreachable(); } Type* int_type = Type::lookup_integer_type("int"); - int tbits = int_type->integer_type()->bits(); - int vbits = mpz_sizeinbase(val, 2); - if (vbits + 1 > tbits) + unsigned int tbits = int_type->integer_type()->bits(); + if (sizeof(val) <= tbits * 8 + && val >> (tbits - 1) != 0) { error_at(this->length_->location(), "array bound overflows"); - mpz_clear(val); return false; } - mpz_clear(val); - return true; } @@ -4981,10 +5204,34 @@ bool Array_type::do_verify() { if (!this->verify_length()) - { - this->length_ = Expression::make_error(this->length_->location()); - return false; - } + this->length_ = Expression::make_error(this->length_->location()); + return true; +} + +// Whether we can use memcmp to compare this array. + +bool +Array_type::do_compare_is_identity(Gogo* gogo) const +{ + if (this->length_ == NULL) + return false; + + // Check for [...], which indicates that this is not a real type. + if (this->length_->is_nil_expression()) + return false; + + if (!this->element_type_->compare_is_identity(gogo)) + return false; + + // If there is any padding, then we can't use memcmp. + unsigned int size; + unsigned int align; + if (!this->element_type_->backend_type_size(gogo, &size) + || !this->element_type_->backend_type_align(gogo, &align)) + return false; + if ((size & (align - 1)) != 0) + return false; + return true; } @@ -5199,11 +5446,11 @@ Array_type::get_length_tree(Gogo* gogo) go_assert(this->length_ != NULL); if (this->length_tree_ == NULL_TREE) { + Numeric_constant nc; mpz_t val; - mpz_init(val); - Type* t; - if (this->length_->integer_constant_value(true, val, &t)) + if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val)) { + Type* t = nc.type(); if (t == NULL) t = Type::lookup_integer_type("int"); else if (t->is_abstract()) @@ -5214,8 +5461,6 @@ Array_type::get_length_tree(Gogo* gogo) } else { - mpz_clear(val); - // Make up a translation context for the array length // expression. FIXME: This won't work in general. Translate_context context(gogo, NULL, NULL, NULL); @@ -5240,13 +5485,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]; @@ -5278,22 +5525,26 @@ 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); } } // 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. @@ -5304,6 +5555,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 @@ -5366,7 +5633,8 @@ tree Array_type::capacity_tree(Gogo* gogo, tree array) { if (this->length_ != NULL) - return omit_one_operand(sizetype, this->get_length_tree(gogo), array); + return omit_one_operand(integer_type_node, this->get_length_tree(gogo), + array); // This is an open array. We need to read the capacity field. @@ -5543,23 +5811,17 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const ret->push_back('['); if (this->length_ != NULL) { - mpz_t val; - mpz_init(val); - Type* type; - if (!this->length_->integer_constant_value(true, val, &type)) - error_at(this->length_->location(), - "array length must be integer constant expression"); - else if (mpz_cmp_si(val, 0) < 0) - error_at(this->length_->location(), "array length is negative"); - else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0) - error_at(this->length_->location(), "array length is too large"); + Numeric_constant nc; + unsigned long val; + if (!this->length_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID) + error_at(this->length_->location(), "invalid array length"); else { char buf[50]; - snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val)); + snprintf(buf, sizeof buf, "%lu", val); ret->append(buf); } - mpz_clear(val); } ret->push_back(']'); @@ -5575,23 +5837,17 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const this->append_mangled_name(this->element_type_, gogo, ret); if (this->length_ != NULL) { - mpz_t val; - mpz_init(val); - Type* type; - if (!this->length_->integer_constant_value(true, val, &type)) - error_at(this->length_->location(), - "array length must be integer constant expression"); - else if (mpz_cmp_si(val, 0) < 0) - error_at(this->length_->location(), "array length is negative"); - else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0) - error_at(this->length_->location(), "array size is too large"); + Numeric_constant nc; + unsigned long val; + if (!this->length_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID) + error_at(this->length_->location(), "invalid array length"); else { char buf[50]; - snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val)); + snprintf(buf, sizeof buf, "%lu", val); ret->append(buf); } - mpz_clear(val); } ret->push_back('e'); } @@ -5624,10 +5880,7 @@ Map_type::do_verify() { // The runtime support uses "map[void]void". if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type()) - { - error_at(this->location_, "invalid map key type"); - return false; - } + error_at(this->location_, "invalid map key type"); return true; } @@ -6132,9 +6385,12 @@ Type::make_channel_type(bool send, bool receive, Type* element_type) int Interface_type::do_traverse(Traverse* traverse) { - if (this->methods_ == NULL) + Typed_identifier_list* methods = (this->methods_are_finalized_ + ? this->all_methods_ + : this->parse_methods_); + if (methods == NULL) return TRAVERSE_CONTINUE; - return this->methods_->traverse(traverse); + return methods->traverse(traverse); } // Finalize the methods. This handles interface inheritance. @@ -6142,130 +6398,97 @@ Interface_type::do_traverse(Traverse* traverse) void Interface_type::finalize_methods() { - if (this->methods_ == NULL) + if (this->methods_are_finalized_) + return; + this->methods_are_finalized_ = true; + if (this->parse_methods_ == NULL) return; + + this->all_methods_ = new Typed_identifier_list(); + this->all_methods_->reserve(this->parse_methods_->size()); + Typed_identifier_list inherit; + for (Typed_identifier_list::const_iterator pm = + this->parse_methods_->begin(); + pm != this->parse_methods_->end(); + ++pm) + { + const Typed_identifier* p = &*pm; + if (p->name().empty()) + inherit.push_back(*p); + else if (this->find_method(p->name()) == NULL) + this->all_methods_->push_back(*p); + else + error_at(p->location(), "duplicate method %qs", + Gogo::message_name(p->name()).c_str()); + } + std::vector seen; - bool is_recursive = false; - size_t from = 0; - size_t to = 0; - while (from < this->methods_->size()) + seen.reserve(inherit.size()); + bool issued_recursive_error = false; + while (!inherit.empty()) { - const Typed_identifier* p = &this->methods_->at(from); - if (!p->name().empty()) - { - size_t i; - for (i = 0; i < to; ++i) - { - if (this->methods_->at(i).name() == p->name()) - { - error_at(p->location(), "duplicate method %qs", - Gogo::message_name(p->name()).c_str()); - break; - } - } - if (i == to) - { - if (from != to) - this->methods_->set(to, *p); - ++to; - } - ++from; - continue; - } + Type* t = inherit.back().type(); + Location tl = inherit.back().location(); + inherit.pop_back(); - Interface_type* it = p->type()->interface_type(); + Interface_type* it = t->interface_type(); if (it == NULL) { - error_at(p->location(), "interface contains embedded non-interface"); - ++from; + if (!t->is_error()) + error_at(tl, "interface contains embedded non-interface"); continue; } if (it == this) { - if (!is_recursive) + if (!issued_recursive_error) { - error_at(p->location(), "invalid recursive interface"); - is_recursive = true; + error_at(tl, "invalid recursive interface"); + issued_recursive_error = true; } - ++from; continue; } - Named_type* nt = p->type()->named_type(); - if (nt != NULL) + Named_type* nt = t->named_type(); + if (nt != NULL && it->parse_methods_ != NULL) { std::vector::const_iterator q; for (q = seen.begin(); q != seen.end(); ++q) { if (*q == nt) { - error_at(p->location(), "inherited interface loop"); + error_at(tl, "inherited interface loop"); break; } } if (q != seen.end()) - { - ++from; - continue; - } + continue; seen.push_back(nt); } - const Typed_identifier_list* methods = it->methods(); - if (methods == NULL) - { - ++from; - continue; - } - for (Typed_identifier_list::const_iterator q = methods->begin(); - q != methods->end(); + const Typed_identifier_list* imethods = it->parse_methods_; + if (imethods == NULL) + continue; + for (Typed_identifier_list::const_iterator q = imethods->begin(); + q != imethods->end(); ++q) { if (q->name().empty()) - { - if (q->type()->forwarded() == p->type()->forwarded()) - error_at(p->location(), "interface inheritance loop"); - else - { - size_t i; - for (i = from + 1; i < this->methods_->size(); ++i) - { - const Typed_identifier* r = &this->methods_->at(i); - if (r->name().empty() - && r->type()->forwarded() == q->type()->forwarded()) - { - error_at(p->location(), - "inherited interface listed twice"); - break; - } - } - if (i == this->methods_->size()) - this->methods_->push_back(Typed_identifier(q->name(), - q->type(), - p->location())); - } - } + inherit.push_back(*q); else if (this->find_method(q->name()) == NULL) - this->methods_->push_back(Typed_identifier(q->name(), q->type(), - p->location())); + this->all_methods_->push_back(Typed_identifier(q->name(), + q->type(), tl)); else - { - if (!is_recursive) - error_at(p->location(), "inherited method %qs is ambiguous", - Gogo::message_name(q->name()).c_str()); - } + error_at(tl, "inherited method %qs is ambiguous", + Gogo::message_name(q->name()).c_str()); } - ++from; - } - if (to == 0) - { - delete this->methods_; - this->methods_ = NULL; } + + if (!this->all_methods_->empty()) + this->all_methods_->sort_by_name(); else { - this->methods_->resize(to); - this->methods_->sort_by_name(); + delete this->all_methods_; + this->all_methods_ = NULL; } } @@ -6274,10 +6497,11 @@ Interface_type::finalize_methods() const Typed_identifier* Interface_type::find_method(const std::string& name) const { - if (this->methods_ == NULL) + go_assert(this->methods_are_finalized_); + if (this->all_methods_ == NULL) return NULL; - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); + p != this->all_methods_->end(); ++p) if (p->name() == name) return &*p; @@ -6289,10 +6513,10 @@ Interface_type::find_method(const std::string& name) const size_t Interface_type::method_index(const std::string& name) const { - go_assert(this->methods_ != NULL); + go_assert(this->methods_are_finalized_ && this->all_methods_ != NULL); size_t ret = 0; - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); + p != this->all_methods_->end(); ++p, ++ret) if (p->name() == name) return ret; @@ -6305,10 +6529,11 @@ Interface_type::method_index(const std::string& name) const bool Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const { - if (this->methods_ == NULL) + go_assert(this->methods_are_finalized_); + if (this->all_methods_ == NULL) return false; - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); + p != this->all_methods_->end(); ++p) { const std::string& method_name(p->name()); @@ -6326,26 +6551,53 @@ bool Interface_type::is_identical(const Interface_type* t, bool errors_are_identical) const { + go_assert(this->methods_are_finalized_ && t->methods_are_finalized_); + // We require the same methods with the same types. The methods // have already been sorted. - if (this->methods() == NULL || t->methods() == NULL) - return this->methods() == t->methods(); + if (this->all_methods_ == NULL || t->all_methods_ == NULL) + return this->all_methods_ == t->all_methods_; - Typed_identifier_list::const_iterator p1 = this->methods()->begin(); - for (Typed_identifier_list::const_iterator p2 = t->methods()->begin(); - p2 != t->methods()->end(); - ++p1, ++p2) + if (this->assume_identical(this, t) || t->assume_identical(t, this)) + return true; + + Assume_identical* hold_ai = this->assume_identical_; + Assume_identical ai; + ai.t1 = this; + ai.t2 = t; + ai.next = hold_ai; + this->assume_identical_ = &ai; + + Typed_identifier_list::const_iterator p1 = this->all_methods_->begin(); + Typed_identifier_list::const_iterator p2; + for (p2 = t->all_methods_->begin(); p2 != t->all_methods_->end(); ++p1, ++p2) { - if (p1 == this->methods()->end()) - return false; + if (p1 == this->all_methods_->end()) + break; if (p1->name() != p2->name() || !Type::are_identical(p1->type(), p2->type(), errors_are_identical, NULL)) - return false; + break; } - if (p1 != this->methods()->end()) - return false; - return true; + + this->assume_identical_ = hold_ai; + + return p1 == this->all_methods_->end() && p2 == t->all_methods_->end(); +} + +// Return true if T1 and T2 are assumed to be identical during a type +// comparison. + +bool +Interface_type::assume_identical(const Interface_type* t1, + const Interface_type* t2) const +{ + for (Assume_identical* p = this->assume_identical_; + p != NULL; + p = p->next) + if ((p->t1 == t1 && p->t2 == t2) || (p->t1 == t2 && p->t2 == t1)) + return true; + return false; } // Whether we can assign the interface type T to this type. The types @@ -6357,10 +6609,11 @@ bool Interface_type::is_compatible_for_assign(const Interface_type* t, std::string* reason) const { - if (this->methods() == NULL) + go_assert(this->methods_are_finalized_ && t->methods_are_finalized_); + if (this->all_methods_ == NULL) return true; - for (Typed_identifier_list::const_iterator p = this->methods()->begin(); - p != this->methods()->end(); + for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); + p != this->all_methods_->end(); ++p) { const Typed_identifier* m = t->find_method(p->name()); @@ -6407,17 +6660,23 @@ Interface_type::is_compatible_for_assign(const Interface_type* t, // Hash code. unsigned int -Interface_type::do_hash_for_method(Gogo* gogo) const +Interface_type::do_hash_for_method(Gogo*) const { + go_assert(this->methods_are_finalized_); unsigned int ret = 0; - if (this->methods_ != NULL) + if (this->all_methods_ != NULL) { - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = + this->all_methods_->begin(); + p != this->all_methods_->end(); ++p) { ret = Type::hash_string(p->name(), ret); - ret += p->type()->hash_for_method(gogo); + // We don't use the method type in the hash, to avoid + // infinite recursion if an interface method uses a type + // which is an interface which inherits from the interface + // itself. + // type T interface { F() interface {T}} ret <<= 1; } } @@ -6430,7 +6689,8 @@ Interface_type::do_hash_for_method(Gogo* gogo) const bool Interface_type::implements_interface(const Type* t, std::string* reason) const { - if (this->methods_ == NULL) + go_assert(this->methods_are_finalized_); + if (this->all_methods_ == NULL) return true; bool is_pointer = false; @@ -6483,8 +6743,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const return false; } - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); + p != this->all_methods_->end(); ++p) { bool is_ambiguous = false; @@ -6588,6 +6848,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(); @@ -6605,8 +6866,37 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type, p != type->methods()->end(); ++p, ++i) { + // The type of the method in Go only includes the parameters. + // The actual method also has a receiver, which is always a + // pointer. We need to add that pointer type here in order to + // generate the correct type for the backend. + Function_type* ft = p->type()->function_type(); + go_assert(ft->receiver() == NULL); + + const Typed_identifier_list* params = ft->parameters(); + Typed_identifier_list* mparams = new Typed_identifier_list(); + if (params != NULL) + mparams->reserve(params->size() + 1); + Type* vt = Type::make_pointer_type(Type::make_void_type()); + mparams->push_back(Typed_identifier("", vt, ft->location())); + if (params != NULL) + { + for (Typed_identifier_list::const_iterator pp = params->begin(); + pp != params->end(); + ++pp) + mparams->push_back(*pp); + } + + Typed_identifier_list* mresults = (ft->results() == NULL + ? NULL + : ft->results()->copy()); + Function_type* mft = Type::make_function_type(NULL, mparams, mresults, + ft->location()); + mfields[i].name = Gogo::unpack_hidden_name(p->name()); - mfields[i].btype = p->type()->get_backend(gogo); + mfields[i].btype = (use_placeholder + ? mft->get_backend_placeholder(gogo) + : mft->get_backend(gogo)); mfields[i].location = loc; // Sanity check: the names should be sorted. go_assert(p->name() > last_name); @@ -6637,13 +6927,38 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type, Btype* Interface_type::do_get_backend(Gogo* gogo) { - if (this->methods_ == NULL) + if (this->is_empty()) return Interface_type::get_backend_empty_interface_type(gogo); else { + if (this->interface_btype_ != NULL) + return this->interface_btype_; + this->interface_btype_ = + gogo->backend()->placeholder_struct_type("", this->location_); std::vector bfields; - get_backend_interface_fields(gogo, this, &bfields); - return gogo->backend()->struct_type(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(); + return this->interface_btype_; + } +} + +// 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); + } } } @@ -6705,13 +7020,14 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) go_assert(pif->is_field_name("methods")); Expression_list* methods = new Expression_list(); - if (this->methods_ != NULL && !this->methods_->empty()) + if (this->all_methods_ != NULL) { Type* elemtype = pif->type()->array_type()->element_type(); - methods->reserve(this->methods_->size()); - for (Typed_identifier_list::const_iterator pm = this->methods_->begin(); - pm != this->methods_->end(); + methods->reserve(this->all_methods_->size()); + for (Typed_identifier_list::const_iterator pm = + this->all_methods_->begin(); + pm != this->all_methods_->end(); ++pm) { const Struct_field_list* mfields = elemtype->struct_type()->fields(); @@ -6764,29 +7080,35 @@ void Interface_type::do_reflection(Gogo* gogo, std::string* ret) const { ret->append("interface {"); - if (this->methods_ != NULL) + const Typed_identifier_list* methods = this->parse_methods_; + if (methods != NULL) { ret->push_back(' '); - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); ++p) { - if (p != this->methods_->begin()) + if (p != methods->begin()) ret->append("; "); - if (!Gogo::is_hidden_name(p->name())) - ret->append(p->name()); + if (p->name().empty()) + this->append_reflection(p->type(), gogo, ret); else { - // This matches what the gc compiler does. - std::string prefix = Gogo::hidden_name_prefix(p->name()); - ret->append(prefix.substr(prefix.find('.') + 1)); - ret->push_back('.'); - ret->append(Gogo::unpack_hidden_name(p->name())); + if (!Gogo::is_hidden_name(p->name())) + ret->append(p->name()); + else + { + // This matches what the gc compiler does. + std::string prefix = Gogo::hidden_name_prefix(p->name()); + ret->append(prefix.substr(prefix.find('.') + 1)); + ret->push_back('.'); + ret->append(Gogo::unpack_hidden_name(p->name())); + } + std::string sub = p->type()->reflection(gogo); + go_assert(sub.compare(0, 4, "func") == 0); + sub = sub.substr(4); + ret->append(sub); } - std::string sub = p->type()->reflection(gogo); - go_assert(sub.compare(0, 4, "func") == 0); - sub = sub.substr(4); - ret->append(sub); } ret->push_back(' '); } @@ -6798,23 +7120,30 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const void Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const { + go_assert(this->methods_are_finalized_); + ret->push_back('I'); - const Typed_identifier_list* methods = this->methods_; - if (methods != NULL) + const Typed_identifier_list* methods = this->all_methods_; + if (methods != NULL && !this->seen_) { + this->seen_ = true; for (Typed_identifier_list::const_iterator p = methods->begin(); p != methods->end(); ++p) { - std::string n = Gogo::unpack_hidden_name(p->name()); - char buf[20]; - snprintf(buf, sizeof buf, "%u_", - static_cast(n.length())); - ret->append(buf); - ret->append(n); + if (!p->name().empty()) + { + std::string n = Gogo::unpack_hidden_name(p->name()); + char buf[20]; + snprintf(buf, sizeof buf, "%u_", + static_cast(n.length())); + ret->append(buf); + ret->append(n); + } this->append_mangled_name(p->type(), gogo, ret); } + this->seen_ = false; } ret->push_back('e'); @@ -6827,67 +7156,79 @@ Interface_type::do_export(Export* exp) const { exp->write_c_string("interface { "); - const Typed_identifier_list* methods = this->methods_; + const Typed_identifier_list* methods = this->parse_methods_; if (methods != NULL) { for (Typed_identifier_list::const_iterator pm = methods->begin(); pm != methods->end(); ++pm) { - exp->write_string(pm->name()); - exp->write_c_string(" ("); - - const Function_type* fntype = pm->type()->function_type(); - - bool first = true; - const Typed_identifier_list* parameters = fntype->parameters(); - if (parameters != NULL) + if (pm->name().empty()) { - bool is_varargs = fntype->is_varargs(); - for (Typed_identifier_list::const_iterator pp = - parameters->begin(); - pp != parameters->end(); - ++pp) - { - if (first) - first = false; - else - exp->write_c_string(", "); - if (!is_varargs || pp + 1 != parameters->end()) - exp->write_type(pp->type()); - else - { - exp->write_c_string("..."); - Type *pptype = pp->type(); - exp->write_type(pptype->array_type()->element_type()); - } - } + exp->write_c_string("? "); + exp->write_type(pm->type()); } + else + { + exp->write_string(pm->name()); + exp->write_c_string(" ("); - exp->write_c_string(")"); + const Function_type* fntype = pm->type()->function_type(); - const Typed_identifier_list* results = fntype->results(); - if (results != NULL) - { - exp->write_c_string(" "); - if (results->size() == 1) - exp->write_type(results->begin()->type()); - else + bool first = true; + const Typed_identifier_list* parameters = fntype->parameters(); + if (parameters != NULL) { - first = true; - exp->write_c_string("("); - for (Typed_identifier_list::const_iterator p = - results->begin(); - p != results->end(); - ++p) + bool is_varargs = fntype->is_varargs(); + for (Typed_identifier_list::const_iterator pp = + parameters->begin(); + pp != parameters->end(); + ++pp) { if (first) first = false; else exp->write_c_string(", "); - exp->write_type(p->type()); + exp->write_name(pp->name()); + exp->write_c_string(" "); + if (!is_varargs || pp + 1 != parameters->end()) + exp->write_type(pp->type()); + else + { + exp->write_c_string("..."); + Type *pptype = pp->type(); + exp->write_type(pptype->array_type()->element_type()); + } + } + } + + exp->write_c_string(")"); + + const Typed_identifier_list* results = fntype->results(); + if (results != NULL) + { + exp->write_c_string(" "); + if (results->size() == 1 && results->begin()->name().empty()) + exp->write_type(results->begin()->type()); + else + { + first = true; + exp->write_c_string("("); + for (Typed_identifier_list::const_iterator p = + results->begin(); + p != results->end(); + ++p) + { + if (first) + first = false; + else + exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); + exp->write_type(p->type()); + } + exp->write_c_string(")"); } - exp->write_c_string(")"); } } @@ -6909,6 +7250,16 @@ Interface_type::do_import(Import* imp) while (imp->peek_char() != '}') { std::string name = imp->read_identifier(); + + if (name == "?") + { + imp->require_c_string(" "); + Type* t = imp->read_type(); + methods->push_back(Typed_identifier("", t, imp->location())); + imp->require_c_string("; "); + continue; + } + imp->require_c_string(" ("); Typed_identifier_list* parameters; @@ -6920,6 +7271,9 @@ Interface_type::do_import(Import* imp) parameters = new Typed_identifier_list; while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); + if (imp->match_c_string("...")) { imp->advance(3); @@ -6929,8 +7283,8 @@ Interface_type::do_import(Import* imp) Type* ptype = imp->read_type(); if (is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(Import::import_marker, - ptype, imp->location())); + parameters->push_back(Typed_identifier(name, ptype, + imp->location())); if (imp->peek_char() != ',') break; go_assert(!is_varargs); @@ -6949,17 +7303,18 @@ Interface_type::do_import(Import* imp) if (imp->peek_char() != '(') { Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier("", rtype, imp->location())); } else { imp->advance(1); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier(name, rtype, + imp->location())); if (imp->peek_char() != ',') break; imp->require_c_string(", "); @@ -6998,6 +7353,16 @@ Type::make_interface_type(Typed_identifier_list* methods, return new Interface_type(methods, location); } +// Make an empty interface type. + +Interface_type* +Type::make_empty_interface_type(Location location) +{ + Interface_type* ret = new Interface_type(NULL, location); + ret->finalize_methods(); + return ret; +} + // Class Method. // Bind a method to an object. @@ -7143,6 +7508,18 @@ Named_type::message_name() const return this->named_object_->message_name(); } +// Whether this is an alias. There are currently only two aliases so +// we just recognize them by name. + +bool +Named_type::is_alias() const +{ + if (!this->is_builtin()) + return false; + const std::string& name(this->name()); + return name == "byte" || name == "rune"; +} + // Return the base type for this type. We have to be careful about // circular type definitions, which are invalid but may be seen here. @@ -7272,20 +7649,6 @@ Named_type::is_unexported_local_method(Gogo* gogo, void Named_type::finalize_methods(Gogo* gogo) { - // If this type needs explicit comparison and hash functions, create - // them now. It would be a bit better to do this only if the - // functions are needed, but they will be static so the backend can - // discard them if they are not used. - if ((this->struct_type() != NULL - || (this->array_type() != NULL && !this->is_slice_type())) - && !this->compare_is_identity() - && this->is_comparable()) - { - Named_object* hash_fn; - Named_object* equal_fn; - this->type_functions(gogo, this, NULL, NULL, &hash_fn, &equal_fn); - } - if (this->all_methods_ != NULL) return; @@ -7457,6 +7820,11 @@ Find_type_use::type(Type* type) this->find_type_->add_dependency(type->named_type()); break; + case Type::TYPE_NAMED: + case Type::TYPE_FORWARD: + go_assert(saw_errors()); + break; + case Type::TYPE_VOID: case Type::TYPE_SINK: case Type::TYPE_FUNCTION: @@ -7465,8 +7833,6 @@ Find_type_use::type(Type* type) case Type::TYPE_MAP: case Type::TYPE_CHANNEL: case Type::TYPE_INTERFACE: - case Type::TYPE_NAMED: - case Type::TYPE_FORWARD: default: go_unreachable(); } @@ -7497,7 +7863,6 @@ Named_type::do_verify() if (this->local_methods_ != NULL) { Struct_type* st = this->type_->struct_type(); - bool found_dup = false; if (st != NULL) { for (Bindings::const_declarations_iterator p = @@ -7511,12 +7876,9 @@ Named_type::do_verify() error_at(p->second->location(), "method %qs redeclares struct field name", Gogo::message_name(name).c_str()); - found_dup = true; } } } - if (found_dup) - return false; } return true; @@ -7539,13 +7901,15 @@ Named_type::do_has_pointer() const // function. bool -Named_type::do_compare_is_identity() const +Named_type::do_compare_is_identity(Gogo* gogo) const { - if (this->seen_) + // We don't use this->seen_ here because compare_is_identity may + // call base() later, and that will mess up if seen_ is set here. + if (this->seen_in_compare_is_identity_) return false; - this->seen_ = true; - bool ret = this->type_->compare_is_identity(); - this->seen_ = false; + this->seen_in_compare_is_identity_ = true; + bool ret = this->type_->compare_is_identity(gogo); + this->seen_in_compare_is_identity_ = false; return ret; } @@ -7555,6 +7919,9 @@ Named_type::do_compare_is_identity() const unsigned int Named_type::do_hash_for_method(Gogo* gogo) const { + if (this->is_alias()) + return this->type_->named_type()->do_hash_for_method(gogo); + const std::string& name(this->named_object()->name()); unsigned int ret = Type::hash_string(name, 0); @@ -7632,7 +7999,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(); } @@ -7642,7 +8009,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(); @@ -7774,7 +8141,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(); } @@ -7785,7 +8152,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(); } @@ -7844,9 +8212,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: @@ -7899,6 +8291,9 @@ Named_type::do_get_backend(Gogo* gogo) Expression* Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) { + if (name == NULL && this->is_alias()) + return this->type_->type_descriptor(gogo, this->type_); + // If NAME is not NULL, then we don't really want the type // descriptor for this type; we want the descriptor for the // underlying type, giving it the name NAME. @@ -7913,7 +8308,12 @@ Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) void Named_type::do_reflection(Gogo* gogo, std::string* ret) const { - if (!Linemap::is_predeclared_location(this->location())) + if (this->is_alias()) + { + this->append_reflection(this->type_, gogo, ret); + return; + } + if (!this->is_builtin()) { const Package* package = this->named_object_->package(); if (package != NULL) @@ -7935,9 +8335,14 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const void Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const { + if (this->is_alias()) + { + this->append_mangled_name(this->type_, gogo, ret); + return; + } Named_object* no = this->named_object_; std::string name; - if (Linemap::is_predeclared_location(this->location())) + if (this->is_builtin()) go_assert(this->in_function_ == NULL); else { @@ -8483,6 +8888,7 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, // If this is a pointer to a pointer, then it is possible that the // pointed-to type has methods. + bool dereferenced = false; if (nt == NULL && st == NULL && it == NULL @@ -8495,6 +8901,7 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, return Expression::make_error(location); nt = type->points_to()->named_type(); st = type->points_to()->struct_type(); + dereferenced = true; } bool receiver_can_be_pointer = (expr->type()->points_to() != NULL @@ -8534,6 +8941,12 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, else go_unreachable(); go_assert(m != NULL); + if (dereferenced && m->is_value_method()) + { + error_at(location, + "calling value method requires explicit dereference"); + return Expression::make_error(location); + } if (!m->is_value_method() && expr->type()->points_to() == NULL) expr = Expression::make_unary(OPERATOR_AND, expr, location); ret = m->bind_method(expr, location); @@ -8985,6 +9398,7 @@ Forward_declaration_type::add_method(const std::string& name, Named_object* Forward_declaration_type::add_method_declaration(const std::string& name, + Package* package, Function_type* type, Location location) { @@ -8992,7 +9406,7 @@ Forward_declaration_type::add_method_declaration(const std::string& name, if (no->is_unknown()) no->declare_as_type(); Type_declaration* td = no->type_declaration_value(); - return td->add_method_declaration(name, type, location); + return td->add_method_declaration(name, package, type, location); } // Traversal. @@ -9033,7 +9447,7 @@ Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name) { Location ploc = Linemap::predeclared_location(); if (!this->is_defined()) - return Expression::make_nil(ploc); + return Expression::make_error(ploc); else { Type* t = this->real_type();