From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23560 invoked by alias); 2 Feb 2011 20:21:38 -0000 Received: (qmail 23508 invoked by uid 22791); 2 Feb 2011 20:21:35 -0000 X-SWARE-Spam-Status: No, hits=-6.9 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 02 Feb 2011 20:21:30 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p12KLTxh014172 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 2 Feb 2011 15:21:29 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p12KLSYJ009617; Wed, 2 Feb 2011 15:21:28 -0500 Received: from opsy.redhat.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p12KLR2Q012887; Wed, 2 Feb 2011 15:21:28 -0500 Received: by opsy.redhat.com (Postfix, from userid 500) id A3AD53783AD; Wed, 2 Feb 2011 13:21:27 -0700 (MST) From: Tom Tromey To: gdb-patches@sourceware.org Subject: RFC: handle case arising from GCC PR 47510 Date: Wed, 02 Feb 2011 20:21:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-02/txt/msg00029.txt.bz2 I plan to check this in. GCC PR 47510 concerns an odd case in C++, where a typedef can give a name to an anonymous struct. This matters because the struct may have a synthesized constructor and destructor; for gdb to handle this properly we have to also give the name to the anonymous struct. I think the pending GCC patch does this in way that is difficult for debuggers. I think it would probably be better to just give up on exactly representing this case and instead just emit a struct type with a name. However, others disagree, so in case the GCC patch goes in, I came up with this patch to change gdb to deal with the resulting DWARF. The valops.c part of the patch is, as far as I can tell, a latent bug that ought to be committed regardless. Without it, it is possible to end up with j==-1, causing us to read invalid memory. Built and regtested on x86-64 (compile farm). New test included, though of course it will only trigger with the correct version of GCC. Tom 2011-02-02 Tom Tromey * valops.c (value_struct_elt_for_reference): Refine artificial type logic. Call error if j==-1. * dwarf2read.c (maybe_smash_one_typedef): New function. (process_die) : Use maybe_smash_one_typedef. 2011-02-02 Tom Tromey * gdb.cp/anon-struct.cc: New file. * gdb.cp/anon-struct.exp: New file. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 6a98d57..c894732a 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -4621,6 +4621,40 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) do_cleanups (back_to); } +/* Fix up a typedef to an anonymous structure, for C++. + Return 1 if the smashing was done, 0 otherwise. + + In C++, a typedef can give a name to an anonymous structure. See + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510. + + We detect this situation and smash a name into the anonymous + struct. */ + +static int +maybe_smash_one_typedef (struct type *typedef_type, const char *base_name) +{ + struct type *struct_type = TYPE_TARGET_TYPE (typedef_type); + int i; + + for (i = 0; i < TYPE_NFN_FIELDS (struct_type); ++i) + { + if (TYPE_FN_FIELDLIST_NAME (struct_type, i) + && TYPE_FN_FIELDLIST_NAME (struct_type, i)[0] == '~' + && strcmp (TYPE_FN_FIELDLIST_NAME (struct_type, i) + 1, + base_name) == 0) + { + /* Found a destructor with the same name as our typedef, so + proceed with smashing. */ + TYPE_TAG_NAME (struct_type) = TYPE_NAME (typedef_type); + TYPE_NAME (struct_type) = TYPE_NAME (typedef_type); + + return 1; + } + } + + return 0; +} + /* Process a die and its children. */ static void @@ -4669,11 +4703,37 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) case DW_TAG_base_type: case DW_TAG_subrange_type: - case DW_TAG_typedef: /* Add a typedef symbol for the type definition, if it has a DW_AT_name. */ new_symbol (die, read_type_die (die, cu), cu); break; + + case DW_TAG_typedef: + { + struct type *this_type = read_type_die (die, cu); + + if (cu->language == language_cplus + && TYPE_CODE (TYPE_TARGET_TYPE (this_type)) == TYPE_CODE_STRUCT + && TYPE_TAG_NAME (TYPE_TARGET_TYPE (this_type)) == NULL + && maybe_smash_one_typedef (this_type, dwarf2_name (die, cu))) + { + /* We turned this typedef into a real structure type, so + make a pretend DIE to get new_symbol to do the right + thing. */ + struct die_info fake = *die; + + fake.tag = DW_TAG_structure_type; + new_symbol (&fake, TYPE_TARGET_TYPE (this_type), cu); + } + else + { + /* Add a typedef symbol for the type definition, if it has + a DW_AT_name. */ + new_symbol (die, this_type, cu); + } + } + break; + case DW_TAG_common_block: read_common_block (die, cu); break; diff --git a/gdb/testsuite/gdb.cp/anon-struct.cc b/gdb/testsuite/gdb.cp/anon-struct.cc new file mode 100644 index 0000000..a266d90 --- /dev/null +++ b/gdb/testsuite/gdb.cp/anon-struct.cc @@ -0,0 +1,15 @@ +class C { +public: + C() {} + ~C() {} +}; + +typedef struct { + C m; +} t; +typedef t S; +S v; + +int main() +{ +} diff --git a/gdb/testsuite/gdb.cp/anon-struct.exp b/gdb/testsuite/gdb.cp/anon-struct.exp new file mode 100644 index 0000000..a250d19 --- /dev/null +++ b/gdb/testsuite/gdb.cp/anon-struct.exp @@ -0,0 +1,25 @@ +# Tests for anonymous union support. +# Copyright 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile anon-struct +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } { + return -1 +} + +gdb_test "ptype t::t" "type = void \\(t \\* const\\)" \ + "print type of t::t" diff --git a/gdb/valops.c b/gdb/valops.c index 24c2269..0287092 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -3238,25 +3238,32 @@ value_struct_elt_for_reference (struct type *domain, int offset, int ii; j = -1; - for (ii = 0; ii < TYPE_FN_FIELDLIST_LENGTH (t, i); - ++ii) + for (ii = 0; ii < len; ++ii) { /* Skip artificial methods. This is necessary if, for example, the user wants to "print subclass::subclass" with only one user-defined - constructor. There is no ambiguity in this - case. */ + constructor. There is no ambiguity in this case. + We are careful here to allow artificial methods + if they are the unique result. */ if (TYPE_FN_FIELD_ARTIFICIAL (f, ii)) - continue; + { + if (j == -1) + j = ii; + continue; + } /* Desired method is ambiguous if more than one method is defined. */ - if (j != -1) + if (j != -1 && !TYPE_FN_FIELD_ARTIFICIAL (f, j)) error (_("non-unique member `%s' requires " "type instantiation"), name); j = ii; } + + if (j == -1) + error (_("no matching member function")); } if (TYPE_FN_FIELD_STATIC_P (f, j))