From: ian Date: Sat, 22 Sep 2012 01:15:48 +0000 (+0000) Subject: compiler: Fix unnamed struct type converted to interface type. X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=18f7be2a7d94d68b5317ef664ca0c723c5b4c425 compiler: Fix unnamed struct type converted to interface type. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_7-branch@191628 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 6ab90dda2b8..19acda61897 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -301,19 +301,25 @@ Expression::convert_type_to_interface(Translate_context* context, // object type: a list of function pointers for each interface // method. Named_type* rhs_named_type = rhs_type->named_type(); + Struct_type* rhs_struct_type = rhs_type->struct_type(); bool is_pointer = false; - if (rhs_named_type == NULL) + if (rhs_named_type == NULL && rhs_struct_type == NULL) { rhs_named_type = rhs_type->deref()->named_type(); + rhs_struct_type = rhs_type->deref()->struct_type(); is_pointer = true; } tree method_table; - if (rhs_named_type == NULL) - method_table = null_pointer_node; - else + if (rhs_named_type != NULL) method_table = rhs_named_type->interface_method_table(gogo, lhs_interface_type, is_pointer); + else if (rhs_struct_type != NULL) + method_table = + rhs_struct_type->interface_method_table(gogo, lhs_interface_type, + is_pointer); + else + method_table = null_pointer_node; first_field_value = fold_convert_loc(location.gcc_location(), const_ptr_type_node, method_table); } diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index d7c5f2d0992..ad38e59d6f3 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -2143,8 +2143,7 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count, tree Gogo::interface_method_table_for_type(const Interface_type* interface, - Named_type* type, - bool is_pointer) + Type* type, bool is_pointer) { const Typed_identifier_list* interface_methods = interface->methods(); go_assert(!interface_methods->empty()); @@ -2173,7 +2172,9 @@ Gogo::interface_method_table_for_type(const Interface_type* interface, // interface. If the interface has hidden methods, and the named // type is defined in a different package, then the interface // conversion table will be defined by that other package. - if (has_hidden_methods && type->named_object()->package() != NULL) + if (has_hidden_methods + && type->named_type() != NULL + && type->named_type()->named_object()->package() != NULL) { tree array_type = build_array_type(const_ptr_type_node, NULL); tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); @@ -2201,13 +2202,20 @@ Gogo::interface_method_table_for_type(const Interface_type* interface, Linemap::predeclared_location()); elt->value = fold_convert(const_ptr_type_node, tdp); + Named_type* nt = type->named_type(); + Struct_type* st = type->struct_type(); + go_assert(nt != NULL || st != NULL); size_t i = 1; for (Typed_identifier_list::const_iterator p = interface_methods->begin(); p != interface_methods->end(); ++p, ++i) { bool is_ambiguous; - Method* m = type->method_function(p->name(), &is_ambiguous); + Method* m; + if (nt != NULL) + m = nt->method_function(p->name(), &is_ambiguous); + else + m = st->method_function(p->name(), &is_ambiguous); go_assert(m != NULL); Named_object* no = m->named_object(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 3d542eae058..fa61808ec3c 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2872,7 +2872,8 @@ int Build_method_tables::type(Type* type) { Named_type* nt = type->named_type(); - if (nt != NULL) + Struct_type* st = type->struct_type(); + if (nt != NULL || st != NULL) { for (std::vector::const_iterator p = this->interfaces_.begin(); @@ -2882,10 +2883,23 @@ Build_method_tables::type(Type* type) // We ask whether a pointer to the named type implements the // interface, because a pointer can implement more methods // than a value. - if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL)) + if (nt != NULL) { - nt->interface_method_table(this->gogo_, *p, false); - nt->interface_method_table(this->gogo_, *p, true); + if ((*p)->implements_interface(Type::make_pointer_type(nt), + NULL)) + { + nt->interface_method_table(this->gogo_, *p, false); + nt->interface_method_table(this->gogo_, *p, true); + } + } + else + { + if ((*p)->implements_interface(Type::make_pointer_type(st), + NULL)) + { + st->interface_method_table(this->gogo_, *p, false); + st->interface_method_table(this->gogo_, *p, true); + } } } } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index efd31f1d727..36709f5b45b 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -574,7 +574,7 @@ class Gogo // Build an interface method table for a type: a list of function // pointers, one for each interface method. This returns a decl. tree - interface_method_table_for_type(const Interface_type*, Named_type*, + interface_method_table_for_type(const Interface_type*, Type*, bool is_pointer); // Return a tree which allocate SIZE bytes to hold values of type diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index a03d26510b2..b7fbc91fd8e 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -4563,6 +4563,20 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const return Type::method_function(this->all_methods_, name, is_ambiguous); } +// Return a pointer to the interface method table for this type for +// the interface INTERFACE. IS_POINTER is true if this is for a +// pointer to THIS. + +tree +Struct_type::interface_method_table(Gogo* gogo, + const Interface_type* interface, + bool is_pointer) +{ + return Type::interface_method_table(gogo, this, interface, is_pointer, + &this->interface_method_tables_, + &this->pointer_interface_method_tables_); +} + // 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. @@ -7191,7 +7205,17 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const { if (!p->name().empty()) { - std::string n = Gogo::unpack_hidden_name(p->name()); + std::string n; + if (!Gogo::is_hidden_name(p->name())) + n = p->name(); + else + { + n = "."; + std::string pkgpath = Gogo::hidden_name_pkgpath(p->name()); + n.append(Gogo::pkgpath_for_symbol(pkgpath)); + n.append(1, '.'); + n.append(Gogo::unpack_hidden_name(p->name())); + } char buf[20]; snprintf(buf, sizeof buf, "%u_", static_cast(n.length())); @@ -7744,32 +7768,9 @@ tree Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, bool is_pointer) { - go_assert(!interface->is_empty()); - - Interface_method_tables** pimt = (is_pointer - ? &this->interface_method_tables_ - : &this->pointer_interface_method_tables_); - - if (*pimt == NULL) - *pimt = new Interface_method_tables(5); - - std::pair val(interface, NULL_TREE); - std::pair ins = (*pimt)->insert(val); - - if (ins.second) - { - // This is a new entry in the hash table. - go_assert(ins.first->second == NULL_TREE); - ins.first->second = gogo->interface_method_table_for_type(interface, - this, - is_pointer); - } - - tree decl = ins.first->second; - if (decl == error_mark_node) - return error_mark_node; - go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); - return build_fold_addr_expr(decl); + return Type::interface_method_table(gogo, this, interface, is_pointer, + &this->interface_method_tables_, + &this->pointer_interface_method_tables_); } // Return whether a named type has any hidden fields. @@ -8953,6 +8954,42 @@ Type::method_function(const Methods* methods, const std::string& name, return m; } +// Return a pointer to the interface method table for TYPE for the +// interface INTERFACE. + +tree +Type::interface_method_table(Gogo* gogo, Type* type, + const Interface_type *interface, + bool is_pointer, + Interface_method_tables** method_tables, + Interface_method_tables** pointer_tables) +{ + go_assert(!interface->is_empty()); + + Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables; + + if (*pimt == NULL) + *pimt = new Interface_method_tables(5); + + std::pair val(interface, NULL_TREE); + std::pair ins = (*pimt)->insert(val); + + if (ins.second) + { + // This is a new entry in the hash table. + go_assert(ins.first->second == NULL_TREE); + ins.first->second = gogo->interface_method_table_for_type(interface, + type, + is_pointer); + } + + tree decl = ins.first->second; + if (decl == error_mark_node) + return error_mark_node; + go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); + return build_fold_addr_expr(decl); +} + // Look for field or method NAME for TYPE. Return an Expression for // the field or method bound to EXPR. If there is no such field or // method, give an appropriate error and return an error expression. diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 7b879240e3a..cced68ddd68 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -983,6 +983,19 @@ class Type method_function(const Methods*, const std::string& name, bool* is_ambiguous); + // A mapping from interfaces to the associated interface method + // tables for this type. This maps to a decl. + typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical, + Type_identical) Interface_method_tables; + + // Return a pointer to the interface method table for TYPE for the + // interface INTERFACE. + static tree + interface_method_table(Gogo* gogo, Type* type, + const Interface_type *interface, bool is_pointer, + Interface_method_tables** method_tables, + Interface_method_tables** pointer_tables); + // Return a composite literal for the type descriptor entry for a // type. static Expression* @@ -1994,7 +2007,8 @@ class Struct_type : public Type public: Struct_type(Struct_field_list* fields, Location location) : Type(TYPE_STRUCT), - fields_(fields), location_(location), all_methods_(NULL) + fields_(fields), location_(location), all_methods_(NULL), + interface_method_tables_(NULL), pointer_interface_method_tables_(NULL) { } // Return the field NAME. This only looks at local fields, not at @@ -2076,6 +2090,14 @@ class Struct_type : public Type Method* method_function(const std::string& name, bool* is_ambiguous) const; + // Return a pointer to the interface method table for this type for + // the interface INTERFACE. If IS_POINTER is true, set the type + // descriptor to a pointer to this type, otherwise set it to this + // type. + tree + interface_method_table(Gogo*, const Interface_type* interface, + bool is_pointer); + // Traverse just the field types of a struct type. int traverse_field_types(Traverse* traverse) @@ -2156,6 +2178,13 @@ class Struct_type : public Type Location location_; // If this struct is unnamed, a list of methods. Methods* all_methods_; + // A mapping from interfaces to the associated interface method + // tables for this type. Only used if this struct is unnamed. + Interface_method_tables* interface_method_tables_; + // A mapping from interfaces to the associated interface method + // tables for pointers to this type. Only used if this struct is + // unnamed. + Interface_method_tables* pointer_interface_method_tables_; }; // The type of an array. @@ -2861,11 +2890,6 @@ class Named_type : public Type void create_placeholder(Gogo*); - // A mapping from interfaces to the associated interface method - // tables for this type. This maps to a decl. - typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical, - Type_identical) Interface_method_tables; - // A pointer back to the Named_object for this type. Named_object* named_object_; // If this type is defined in a function, a pointer back to the