From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4343 invoked by alias); 30 Jul 2013 22:44:41 -0000 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 Received: (qmail 4331 invoked by uid 89); 30 Jul 2013 22:44:40 -0000 X-Spam-SWARE-Status: No, score=-4.3 required=5.0 tests=AWL,BAYES_50,KAM_STOCKGEN,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,RDNS_NONE,SPF_HELO_PASS,SPF_PASS autolearn=no version=3.3.1 Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 30 Jul 2013 22:44:39 +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 r6UMiWnS010250 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 30 Jul 2013 18:44:32 -0400 Received: from valrhona.uglyboxes.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r6UMiVS2023822 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 30 Jul 2013 18:44:31 -0400 Message-ID: <51F841CF.9030301@redhat.com> Date: Tue, 30 Jul 2013 22:44:00 -0000 From: Keith Seitz User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 MIME-Version: 1.0 To: Tom Tromey CC: "gdb-patches@sourceware.org ml" Subject: Re: [RFA] Fix namespace aliases (c++/7539, c++/10541) References: <51F2CAB9.2030604@redhat.com> <877gg9nm9x.fsf@fleche.redhat.com> In-Reply-To: <877gg9nm9x.fsf@fleche.redhat.com> Content-Type: multipart/mixed; boundary="------------080406010201070506050400" X-Virus-Found: No X-SW-Source: 2013-07/txt/msg00802.txt.bz2 This is a multi-part message in MIME format. --------------080406010201070506050400 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 2922 On 07/29/2013 01:28 PM, Tom Tromey wrote: > Ok, I think I see what is going on here. For an alias A we have a > symbol named A, whose type is the type of the referent. > > I think the comment here is a bit confusing since it says "its name", > but really it means the symbol's type's name. I've updated the comment to make this less ambiguous. > I'm curious how this copes with some other situations. > > For example, an import of a declaration from another namespace, where > the imported declaration is itself an import. I wouldn't expect a compiler to actually do this (gcc does not), but I've updated the code to handle this case. BTW, while investigating this, I found a buglet in my original patch. At the last minute, I thought I'd be paranoid and add a test for DW_AT_name. Unfortunately, in my haste, I fetched DW_AT_name /after/ DW_AT_import. That was bad. Very bad. I've fixed this in this version. > Or, if the program is stopped in a function inside a namespace, can the > user use the "local" (not fully qualified) alias? This particular feature is c++/13884. That is an entirely different problem. I've updated the bug with some comments explaining what's going on. > I don't think either of these situations is tested. I've added tests for the recursive alias. If/when I get around to fixing 13384, I'll add tests for that. > > Keith> @@ -7732,6 +7736,32 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) > Keith> read_module (die, cu); > Keith> break; > Keith> case DW_TAG_imported_declaration: > Keith> + { > Keith> + struct attribute *attr; > Keith> + > Keith> + attr = dwarf2_attr (die, DW_AT_import, cu); > Keith> + if (attr != NULL) > Keith> + { > Keith> + /* If the die does not have a name, this is not a namespace > Keith> + alias. */ > Keith> + attr = dwarf2_attr (die, DW_AT_name, cu); > Keith> + if (attr != NULL) > Keith> + { > > It's customary not to have a body of code in process_die, but to instead > call a helper function. Done. Updated patch attached. Keith ChangeLog 2013-07-30 Keith Seitz PR c++/7539 PR c++/10541 * cp-support.c (insepct_type): Add support for substituting namespace aliases, too. * dwarf2read.c (scan_partial_symbols): Add a partial symbol for DW_TAG_imported_declaration. (add_partial_symbol): Likewise. (process_die): Handle namespace aliases with read_namespace_alias. (die_needs_namespace): Add DW_TAG_imported_declaration. (read_namespace_alias): New function. (load_partial_dies): Load DW_TAG_imported_declaration, too. (new_symbol_full): Handle DW_TAG_imported_declaration. testsuite/ChangeLog 2013-07-30 Keith Seitz PR c++/7935 PR c++/10541 * gdb.cp/nsalias.exp: New file. * gdb.cp/nsalias.cc: New file. * gdb.cp/nsrecurs.exp: Remove kfails. Conditionally run tests only on known, working compiler versions. --------------080406010201070506050400 Content-Type: text/x-patch; name="namespace-aliases.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="namespace-aliases.patch" Content-length: 13098 diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 3c1442d..087bf0b 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -200,8 +200,9 @@ inspect_type (struct demangle_parse_info *info, return 0; } - /* If the type is a typedef, replace it. */ - if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF) + /* If the type is a typedef or namespace alias, replace it. */ + if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF + || TYPE_CODE (otype) == TYPE_CODE_NAMESPACE) { long len; int is_anon; @@ -212,6 +213,13 @@ inspect_type (struct demangle_parse_info *info, /* Get the real type of the typedef. */ type = check_typedef (otype); + /* If the symbol is a namespace and its type name is no different + than the name we looked up, this symbol is not a namespace + alias and does not need to be substituted. */ + if (TYPE_CODE (otype) == TYPE_CODE_NAMESPACE + && strcmp (TYPE_NAME (type), name) == 0) + return 0; + is_anon = (TYPE_TAG_NAME (type) == NULL && (TYPE_CODE (type) == TYPE_CODE_ENUM || TYPE_CODE (type) == TYPE_CODE_STRUCT diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 04993c2..89799e9 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -1537,6 +1537,8 @@ static void read_module (struct die_info *die, struct dwarf2_cu *cu); static void read_import_statement (struct die_info *die, struct dwarf2_cu *); +static int read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu); + static struct type *read_module_type (struct die_info *die, struct dwarf2_cu *cu); @@ -6244,6 +6246,9 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, cu->per_cu->imported_symtabs, per_cu); } break; + case DW_TAG_imported_declaration: + add_partial_symbol (pdi, cu); + break; default: break; } @@ -6515,6 +6520,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); break; + case DW_TAG_imported_declaration: case DW_TAG_namespace: add_psymbol_to_list (actual_name, strlen (actual_name), built_actual_name != NULL, @@ -7732,6 +7738,10 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) read_module (die, cu); break; case DW_TAG_imported_declaration: + cu->processing_has_namespace_info = 1; + if (read_namespace_alias (die, cu)) + break; + /* The declaration is not a global namespace alias: fall through. */ case DW_TAG_imported_module: cu->processing_has_namespace_info = 1; if (die->child != NULL && (die->tag == DW_TAG_imported_declaration @@ -7774,6 +7784,7 @@ die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu) case DW_TAG_enumerator: case DW_TAG_subprogram: case DW_TAG_member: + case DW_TAG_imported_declaration: return 1; case DW_TAG_variable: @@ -8192,6 +8203,56 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu) return retval; } +/* Inspect DIE in CU for a namespace alias. If one exists, record + a new symbol for it. + + Returns 1 if a namespace alias was recorded, 0 otherwise. */ + +static int +read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + /* If the die does not have a name, this is not a namespace + alias. */ + attr = dwarf2_attr (die, DW_AT_name, cu); + if (attr != NULL) + { + struct die_info *d = die; + struct dwarf2_cu *imported_cu = cu; + + /* If the compiler has nested DW_AT_imported_declaration DIEs, + keep inspecting DIEs until we hit the underlying import. */ + while (1) + { + attr = dwarf2_attr (d, DW_AT_import, cu); + if (attr == NULL) + break; + + d = follow_die_ref (d, attr, &imported_cu); + if (d->tag != DW_TAG_imported_declaration) + break; + } + + if (attr != NULL) + { + struct type *type; + sect_offset offset = dwarf2_get_ref_die_offset (attr); + + type = get_die_type_at_offset (offset, cu->per_cu); + if (type != NULL && TYPE_CODE (type) == TYPE_CODE_NAMESPACE) + { + /* This declaration is a global namespace alias. Add + a symbol for it whose type is the aliased namespace. */ + new_symbol (die, type, cu); + return 1; + } + } + } + + return 0; +} + /* Read the import statement specified by the given die and record it. */ static void @@ -14013,7 +14074,8 @@ load_partial_dies (const struct die_reader_specs *reader, && abbrev->tag != DW_TAG_namespace && abbrev->tag != DW_TAG_module && abbrev->tag != DW_TAG_member - && abbrev->tag != DW_TAG_imported_unit) + && abbrev->tag != DW_TAG_imported_unit + && abbrev->tag != DW_TAG_imported_declaration) { /* Otherwise we skip to the next sibling, if any. */ info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev); @@ -16731,6 +16793,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, ? &global_symbols : cu->list_in_scope); } break; + case DW_TAG_imported_declaration: case DW_TAG_namespace: SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF; list_to_add = &global_symbols; diff --git a/gdb/testsuite/gdb.cp/nsalias.cc b/gdb/testsuite/gdb.cp/nsalias.cc new file mode 100644 index 0000000..be2dfbe --- /dev/null +++ b/gdb/testsuite/gdb.cp/nsalias.cc @@ -0,0 +1,23 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 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 . */ + +int +main () +{ + return 0; +} + diff --git a/gdb/testsuite/gdb.cp/nsalias.exp b/gdb/testsuite/gdb.cp/nsalias.exp new file mode 100644 index 0000000..18f32b2 --- /dev/null +++ b/gdb/testsuite/gdb.cp/nsalias.exp @@ -0,0 +1,254 @@ +# Copyright 2013 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 . + +# Test namespace aliases. +# PRs c++/7935, c++/10541 + +load_lib dwarf.exp + +if {![dwarf2_support]} { + return 0 +} + +if {[skip_cplus_tests]} { + continue +} + +standard_testfile .cc nsalias-dw.S + +# Make the DWARF used for the test. This is necessary to work +# around compiler issues. Not all versions of gcc output the +# correct debuginfo we need. +# +# This should create the equivalent DWARF to: +# +# namespace outer +# { +# namespace inner +# { +# namespace innermost +# { +# const int x = 2; +# int foo (void) { return x; } +# } +# +# namespace Innermost = innermost; +# +# const int x = 1; +# int foo (void) { return x + Innermost::foo (); } +# } +# +# namespace Inner = inner; +# +# const int x = 0; +# int foo (void) { return x + Inner::foo (); } +# } +# +# namespace Outer = outer; +# namespace oi = Outer::Inner; + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + compile_unit {{language @DW_LANG_C_plus_plus}} { + declare_labels int_label outer_label inner_label innermost_label + declare_labels im_foo_label i_foo_label o_foo_label + declare_labels OuterInner_label oi1_label oi2_label + + int_label: base_type { + {name int} + {encoding @DW_ATE_signed} + {byte_size 4 DW_FORM_sdata} + } + + outer_label: DW_TAG_namespace { + {name outer} + } { + inner_label: DW_TAG_namespace { + {name inner} + } { + innermost_label: DW_TAG_namespace { + {name innermost} + } { + DW_TAG_variable { + {name x} + {type :$int_label} + {const_value 2 DW_FORM_data1} + } + + im_foo_label: DW_TAG_subprogram { + {name foo} + {external 1} + {declaration 1} + } + } + + imported_declaration { + {name Innermost} + {import :$innermost_label} + } + + DW_TAG_variable { + {name x} + {type :$int_label} + {const_value 1 DW_FORM_data1} + } + + i_foo_label: subprogram { + {name foo} + {external 1} + {declaration 1} + } + } + + OuterInner_label: imported_declaration { + {name Inner} + {import :$inner_label} + } + + DW_TAG_variable { + {name x} + {type :$int_label} + {const_value 0 DW_FORM_data1} + } + + o_foo_label: subprogram { + {name foo} + {external 1} + {declaration 1} + } + } + + imported_declaration { + {name Outer} + {import :$outer_label} + } + + oi1_label: imported_declaration { + {name oi1} + {import :$OuterInner_label} + } + + oi2_label: imported_declaration { + {name oi2} + {import :$oi1_label} + } + + imported_declaration { + {name oi3} + {import :$oi2_label} + } + + subprogram { + {specification :$im_foo_label} + {low_pc 0x0} + {high_pc 0x1} + } + + subprogram { + {specification :$i_foo_label} + {low_pc 0x2} + {high_pc 0x3} + } + + subprogram { + {specification :$o_foo_label} + {low_pc 0x4} + {high_pc 0x5} + } + } + } +} + +if {[gdb_compile $srcdir/$subdir/$srcfile ${binfile}1.o \ + object {c++ debug}] != ""} { + return -1 +} + +if {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \ + $binfile executable {c++}] != ""} { + return -1 +} + +clean_restart $testfile + +# A procedure to run various tests on aliased namespaces. +proc do_alias_tests {ns {real ""} {x ""}} { + + # The "real" namespace is simply NS in all lowercase. + if {$real == ""} { + set real [string tolower $ns] + } + + # The value of `x' is the number of '::' in NS. + if {$x == ""} { + set x [expr {[llength [split $ns ":"]] / 2}] + } + + # Test "whatis" + gdb_test "whatis $ns" "type = $real" + + # Test "ptype" + gdb_test "ptype $ns" "type = namespace $real" + + # Print 'x' + send_log "expecting x = $x\n" + gdb_test "print ${ns}::x" " = $x" + + # Attempt to list the function. + gdb_test_no_output "list ${ns}::foo" + + # Attempt to break on the start of the function. + gdb_breakpoint "*${ns}::foo" + + # And then erase it + with_test_prefix "($ns)" { + gdb_test_no_output "delete \$bpnum" + } +} + +# This is a list of all the permutations to be tested. For troubleshooting +# purposes, this list is explicitly enumerated. + +set permutations {} +lappend permutations "outer" +lappend permutations "Outer" +lappend permutations "outer::inner" +lappend permutations "Outer::inner" +lappend permutations "outer::Inner" +lappend permutations "Outer::Inner" +lappend permutations "outer::inner::innermost" +lappend permutations "outer::inner::Innermost" +lappend permutations "outer::Inner::innermost" +lappend permutations "outer::Inner::Innermost" +lappend permutations "Outer::inner::innermost" +lappend permutations "Outer::inner::Innermost" +lappend permutations "Outer::Inner::innermost" +lappend permutations "Outer::Inner::Innermost" + +foreach p $permutations { + do_alias_tests $p +} + +# Test recursively imported aliases. +foreach ns {"oi1" "oi2" "oi3"} { + do_alias_tests $ns "outer::inner" 1 + do_alias_tests "${ns}::innermost" "outer::inner::innermost" 2 + do_alias_tests "${ns}::Innermost" "outer::inner::innermost" 2 +} diff --git a/gdb/testsuite/gdb.cp/nsrecurs.exp b/gdb/testsuite/gdb.cp/nsrecurs.exp index 0537e89..9cf4331 100644 --- a/gdb/testsuite/gdb.cp/nsrecurs.exp +++ b/gdb/testsuite/gdb.cp/nsrecurs.exp @@ -52,8 +52,10 @@ gdb_test "print xx" "= 999" # Test printing using recursive namespace # aliases. -setup_kfail "gdb/10541" "*-*-*" -gdb_test "ptype G::GF" "= namespace F" +if {![test_compiler_info {gcc-[0-3]-*}]} { + gdb_test "ptype G::GF" "= namespace F" -setup_kfail "gdb/10541" "*-*-*" -gdb_test "print G::GF::FE::ex" "= 9999" + if {![test_compiler_info {gcc-4-[0-3]-*}]} { + gdb_test "print G::GF::FE::ex" "= 9999" + } +} --------------080406010201070506050400--