From patchwork Sat Sep 22 01:16:40 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 186008 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 2946E2C008D for ; Sat, 22 Sep 2012 11:17:05 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1348881426; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:From:To:Subject:Date:Message-ID:User-Agent: MIME-Version:Content-Type:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=3IIvG4UCk6hZVYzQAXXQqfzyjKo=; b=jRN+jGbZ+4XwR3u 2XPdmP8qILxExCbHEpLsxfr1/QHvzKbuKkuqSwb0tG6Alqzoq5rNr97P0OdyHtbY rsUJB5mpOdci+fA9pmRJXdtvpfiy70BbiR07xF/bgLaXfTagcyB8STT540/zCgCK kQRe22OTYXiUyrRRdyrIssBUUEjI= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version:Content-Type:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=kmU5yJ4MUaFEMC2M1IqL1c+Eu0dRJWlV/PCKonMFdSxuX9wmIMFCEq/yH3RZtV Kz3pCGlH86FSDMtuN05ozM8XCHG/iPbgDAEhvnWBeS6ALltclUEoYBZtZuQXswa1 XwTikiW4qCelA2c+LIZHl+OChSvC9GLBJIPs2yJgjB4So=; Received: (qmail 22677 invoked by alias); 22 Sep 2012 01:17:00 -0000 Received: (qmail 22669 invoked by uid 22791); 22 Sep 2012 01:16:58 -0000 X-SWARE-Spam-Status: No, hits=-4.6 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-pb0-f47.google.com (HELO mail-pb0-f47.google.com) (209.85.160.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 22 Sep 2012 01:16:44 +0000 Received: by pbcwy7 with SMTP id wy7so9285441pbc.20 for ; Fri, 21 Sep 2012 18:16:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version :content-type:x-gm-message-state; bh=AgXHl7fgbk44W0L8icl3yBbSSahsEp/m/fdEKBv6A0o=; b=ibOsUH3XOsZ4HJseP5CvQprTGwsHBDu7jQgm8XputKuzGujYtkbQq9+UR7TP+7wlFe Gp8YVBq0G+2Z2nqXqBooVzdK4T7jZBhuOkYtbIBNA3F882YSPYS/vGXOZeZWA7Zi2ppG eXnuBmsiCcs9aWX5E81NRnqixECrCo986zaCgO5QNOH+vuQaa64Fj+bH7mPeTATSPinH gvHBrGwYTkCCJuam4m3X+pAB0jzDLyLvNZojNk2LhUQyE6ueHHv7VnlJTpN/OkRguOVh 77b+J6b7Sdt6crk263WUSvEy/dEzFaSoglaaGbe3TtmsKJs3aB7TYU8cWFNlydBa2ile IoWg== Received: by 10.66.81.231 with SMTP id d7mr16958234pay.50.1348276603941; Fri, 21 Sep 2012 18:16:43 -0700 (PDT) Received: by 10.66.81.231 with SMTP id d7mr16958225pay.50.1348276603832; Fri, 21 Sep 2012 18:16:43 -0700 (PDT) Received: from coign.google.com ([67.218.104.125]) by mx.google.com with ESMTPS id kt1sm5882988pbc.45.2012.09.21.18.16.41 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 21 Sep 2012 18:16:43 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Fix unnamed struct converted to interface Date: Fri, 21 Sep 2012 18:16:40 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQkCKjCY/84uWGbObsroCj9sFj9bNYXP5kiNmf0kIrpOTe6hhLxBtpBX//OfiPI+0l7u5ivwpKVEDXzwcc/oliAx1ZLRcnaOwVDnJMOJqKLulpvxuGD2odUIbr5+MQTscjMZiNOOGni3cPfvCpkxZ4fIJhFHPi5El8HXdCcK84OMgO0r7apb0wRjEprIeHlFWP5KAbAu X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch to the Go frontend fixes the handling of an unnamed struct type with methods (inherited from embedded fields) converted to an interface type. Previously the interface method table was being stored as NULL, causing a runtime crash. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.7 branch. Ian diff -r 561942122df7 go/expressions.cc --- a/go/expressions.cc Fri Sep 21 15:10:32 2012 -0700 +++ b/go/expressions.cc Fri Sep 21 18:10:51 2012 -0700 @@ -293,19 +293,25 @@ // 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 -r 561942122df7 go/gogo-tree.cc --- a/go/gogo-tree.cc Fri Sep 21 15:10:32 2012 -0700 +++ b/go/gogo-tree.cc Fri Sep 21 18:10:51 2012 -0700 @@ -2128,8 +2128,7 @@ 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()); @@ -2158,7 +2157,9 @@ // 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); @@ -2187,13 +2188,20 @@ 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 -r 561942122df7 go/gogo.cc --- a/go/gogo.cc Fri Sep 21 15:10:32 2012 -0700 +++ b/go/gogo.cc Fri Sep 21 18:10:51 2012 -0700 @@ -2872,7 +2872,8 @@ 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 @@ // 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 -r 561942122df7 go/gogo.h --- a/go/gogo.h Fri Sep 21 15:10:32 2012 -0700 +++ b/go/gogo.h Fri Sep 21 18:10:51 2012 -0700 @@ -574,7 +574,7 @@ // 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 -r 561942122df7 go/types.cc --- a/go/types.cc Fri Sep 21 15:10:32 2012 -0700 +++ b/go/types.cc Fri Sep 21 18:10:51 2012 -0700 @@ -4554,6 +4554,20 @@ 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. @@ -7182,7 +7196,17 @@ { 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())); @@ -7735,32 +7759,9 @@ 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. @@ -8944,6 +8945,42 @@ 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 -r 561942122df7 go/types.h --- a/go/types.h Fri Sep 21 15:10:32 2012 -0700 +++ b/go/types.h Fri Sep 21 18:10:51 2012 -0700 @@ -983,6 +983,19 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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