PR c++/7539
authorKeith Seitz <keiths@redhat.com>
Wed, 13 Nov 2013 20:33:34 +0000 (12:33 -0800)
committerKeith Seitz <keiths@redhat.com>
Wed, 13 Nov 2013 20:33:34 +0000 (12:33 -0800)
PR c++/10541

This patch fixes some namespace alias bugs reported in the above bugs.
Links to all mailing list discussion:

https://sourceware.org/ml/gdb-patches/2013-07/msg00649.html
https://sourceware.org/ml/gdb-patches/2013-09/msg00557.html
https://sourceware.org/ml/gdb-patches/2013-11/msg00156.html

gdb/ChangeLog
gdb/cp-support.c
gdb/dwarf2read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.cp/nsalias.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/nsalias.exp [new file with mode: 0644]
gdb/testsuite/gdb.cp/nsrecurs.exp

index f15c36a..8351b72 100644 (file)
@@ -1,5 +1,21 @@
 2013-11-13  Keith Seitz  <keiths@redhat.com>
 
+       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.
+
+2013-11-13  Keith Seitz  <keiths@redhat.com>
+
        * p-exp.y (uptok): Make first parameter const.
        (yylex): Make `tokstart' and `tokptr' const.
        Don't copy the lexer input to a temporary buffer.
index 86f19de..b91bcdc 100644 (file)
@@ -198,8 +198,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;
@@ -210,6 +211,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
index c5c3b5c..ee6c4c7 100644 (file)
@@ -1612,6 +1612,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);
 
@@ -6517,6 +6519,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;
            }
@@ -6788,6 +6793,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,
@@ -8061,6 +8067,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
@@ -8103,6 +8113,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:
@@ -8522,6 +8533,66 @@ 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)
+    {
+      int num;
+      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.  */
+#define MAX_NESTED_IMPORTED_DECLARATIONS 100
+      for (num = 0; num  < MAX_NESTED_IMPORTED_DECLARATIONS; ++num)
+       {
+         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 (num == MAX_NESTED_IMPORTED_DECLARATIONS)
+       {
+         complaint (&symfile_complaints,
+                    _("DIE at 0x%x has too many recursively imported "
+                      "declarations"), d->offset.sect_off);
+         return 0;
+       }
+
+      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
@@ -14882,7 +14953,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);
@@ -17613,6 +17685,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;
index 5c9d579..5d1de05 100644 (file)
@@ -1,3 +1,12 @@
+2013-09-17  Keith Seitz  <keiths@redhat.com>
+
+       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.
+
 2013-11-13  Tom Tromey  <tromey@redhat.com>
 
        * gdb.multi/multi-arch-exec.exp: Define BASEDIR when compiling.
diff --git a/gdb/testsuite/gdb.cp/nsalias.cc b/gdb/testsuite/gdb.cp/nsalias.cc
new file mode 100644 (file)
index 0000000..be2dfbe
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.  */
+
+int
+main ()
+{
+  return 0;
+}
+
diff --git a/gdb/testsuite/gdb.cp/nsalias.exp b/gdb/testsuite/gdb.cp/nsalias.exp
new file mode 100644 (file)
index 0000000..61bf72f
--- /dev/null
@@ -0,0 +1,322 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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
+}
+
+# Generate another objfile with nested imported declarations.
+
+set imports {
+    declare_labels n0_label
+
+    n0_label: DW_TAG_namespace {
+       {name n0}
+    } {
+       DW_TAG_variable {
+           {name x}
+           {type :$int_label}
+           {const_value 3 DW_FORM_data1}
+       }
+    }
+
+    declare_labels n0_import
+    n0_import: imported_declaration {
+       {name N0}
+       {import :$n0_label}
+    }
+}
+
+for {set i 1} {$i <= 100} {incr i} {
+    append imports [format "
+       declare_labels n%d_import
+       n%d_import: imported_declaration {
+           {name N%d}
+           {import :\$n%d_import}
+       }" $i $i $i [expr {$i - 1}]]
+}
+
+standard_testfile .cc nsalias-r-dw.S
+
+set asm_file [standard_output_file $srcfile2]
+set the_dwarf [format {
+    cu {} {
+       compile_unit {{language @DW_LANG_C_plus_plus}} {
+           declare_labels int_label n0_label
+
+           int_label: base_type {
+               {name int}
+               {encoding @DW_ATE_signed}
+               {byte_size 4 DW_FORM_sdata}
+           }
+
+%s
+       }
+    }
+} $imports]
+
+Dwarf::assemble $asm_file $the_dwarf
+
+if {[gdb_compile $asm_file ${binfile}3.o object {nodebug}] != ""} {
+    return -1
+}
+
+if {[gdb_compile [list ${binfile}1.o ${binfile}3.o] \
+        ${binfile}-r executable {c++}] != ""} {
+    return -1
+}
+
+clean_restart ${testfile}-r
+
+gdb_test_no_output "set complaints 1"
+gdb_test "print N100::x" \
+    ".* has too many recursively imported declarations.*" \
+    "compaint for too many recursively imported declarations"
index 0537e89..9cf4331 100644 (file)
@@ -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"
+    }
+}