[RFA] Anonymous namespaces and linespecs

Keith Seitz
2011-05-19T22:52:41Z

[-- Attachment #1: Type: text/plain, Size: 1511 bytes --]

Hi,

This is actually a patch for symtab/12704, reported by Jan:

(gdb) b 'FOO::(anonymous namespace)::BAR()'
Junk at end of arguments.

This is happening because along with the physname patch, there was also
alot of mucking around with decode_line_1 and decode_compound. This is
fallout from that. [Remember: we used to push almost everything through
decode_variable -- in which the quoting is /required/.]

If we see "(anonymous namespace)", we must keep it as a significant part
of the name. On the upside, we now no longer have to quote this stuff,
either.

This patch also contains one cleanup. The string "(anonymous namespace)"
was beginning to proliferate throughout the sources. I've added a macro
to cp-support.h to define this string and changed all the places it had
been hard-coded.

Tested on the buildbot.

Keith

ChangeLog

2010-05-18 Keith Seitz <keiths@redhat.com>

PR symtab/12704
* cp-namespace.c (ANONYMOUS_NAMESPACE_LEN): Remove.
(cp_scan_for_anonymous_namespaces): Use CP_ANONYMOUS_NAMESPACE_STR
and CP_ANONYMOUS_NAMESPACE_LEN.
(cp_is_anonymous): Likewise.
* cp_support.h (CP_ANONYMOUS_NAMESPACE_STR): Define.
(CP_ANONYMOUS_NAMESPACE_LEN): Define.
* dwarf2read.c (namespace_name): Likewise.
(fixup_partial_die): Likewise.
* linespec.c (decode_compound): If CP_ANONYMOUS_NAMESPACE_STR is
seen in the input, keep it.

testsuite/ChangeLog

2010-05-18 Keith Seitz <keiths@redhat.com>

PR symtab/12704
* gdb.cp/anon-ns.cc: New file.
* gdb.cp/anon-ns.exp: New file.

[-- Attachment #2: 12704.patch --]
[-- Type: text/plain, Size: 8584 bytes --]

diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 00c68b3..7ff7bf7 100644
--- gdb/cp-namespace.c
+++ gdb/cp-namespace.c
@@ -52,10 +52,6 @@ static struct type *cp_lookup_transparent_type_loop (const char *name,
/* Check to see if SYMBOL refers to an object contained within an
anonymous namespace; if so, add an appropriate using directive. */

-/* Optimize away strlen ("(anonymous namespace)"). */
-
-#define ANONYMOUS_NAMESPACE_LEN 21
-
void
cp_scan_for_anonymous_namespaces (const struct symbol *symbol)
{
@@ -76,10 +72,11 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol)

while (name[next_component] == ':')
{
- if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN
+ if (((next_component - previous_component)
+ == CP_ANONYMOUS_NAMESPACE_LEN)
&& strncmp (name + previous_component,
- "(anonymous namespace)",
- ANONYMOUS_NAMESPACE_LEN) == 0)
+ CP_ANONYMOUS_NAMESPACE_STR,
+ CP_ANONYMOUS_NAMESPACE_LEN) == 0)
{
int dest_len = (previous_component == 0
? 0 : previous_component - 2);
@@ -207,7 +204,7 @@ cp_set_block_scope (const struct symbol *symbol,
int
cp_is_anonymous (const char *namespace)
{
- return (strstr (namespace, "(anonymous namespace)")
+ return (strstr (namespace, CP_ANONYMOUS_NAMESPACE_STR)
!= NULL);
}

diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 57aa03a..52d4cb7 100644
--- gdb/cp-support.h
+++ gdb/cp-support.h
@@ -36,6 +36,14 @@ struct objfile;
struct type;
struct demangle_component;

+/* A string representing the name of the anonymous namespace used in GDB. */
+
+#define CP_ANONYMOUS_NAMESPACE_STR "(anonymous namespace)"
+
+/* The length of the string representing the anonymous namespace. */
+
+#define CP_ANONYMOUS_NAMESPACE_LEN 21
+
/* This struct is designed to store data from using directives. It
says that names from namespace IMPORT_SRC should be visible within
namespace IMPORT_DEST. These form a linked list; NEXT is the next
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 658205e..ee27c2d 100644
--- gdb/dwarf2read.c
+++ gdb/dwarf2read.c
@@ -7847,7 +7847,7 @@ namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu)

*is_anonymous = (name == NULL);
if (*is_anonymous)
- name = "(anonymous namespace)";
+ name = CP_ANONYMOUS_NAMESPACE_STR;

return name;
}
@@ -9517,7 +9517,7 @@ fixup_partial_die (struct partial_die_info *part_die,
/* Set default names for some unnamed DIEs. */

if (part_die->name == NULL && part_die->tag == DW_TAG_namespace)
- part_die->name = "(anonymous namespace)";
+ part_die->name = CP_ANONYMOUS_NAMESPACE_STR;

/* If there is no parent die to provide a namespace, and there are
children, see if we can determine the namespace from their linkage
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 871d37d..4658e2d 100644
--- gdb/linespec.c
+++ gdb/linespec.c
@@ -1422,8 +1422,15 @@ decode_compound (char **argptr, int funfirstline,
{
/* PASS2: We'll keep getting here, until P points to one of the
break characters, at which point we exit this loop. */
- if (*p && strchr (break_characters, *p) == NULL)
- p++;
+ if (*p)
+ {
+ if (p[1] == '('
+ && strncmp (&p[1], CP_ANONYMOUS_NAMESPACE_STR,
+ CP_ANONYMOUS_NAMESPACE_LEN) == 0)
+ p += CP_ANONYMOUS_NAMESPACE_LEN;
+ else if (strchr (break_characters, *p) == NULL)
+ ++p;
+ }
}
}

diff --git a/gdb/testsuite/gdb.cp/anon-ns.cc b/gdb/testsuite/gdb.cp/anon-ns.cc
new file mode 100644
index 0000000..949754d
--- /dev/null
+++ gdb/testsuite/gdb.cp/anon-ns.cc
@@ -0,0 +1,92 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ 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 <http://www.gnu.org/licenses/>.
+
+ Contributed by Red Hat, originally written by Keith Seitz. */
+
+#include <stdlib.h>
+
+namespace
+{
+ void doit1 (void) { } // doit1(void)
+ void doit1 (int a) { } // doit1(int)
+ void doit1 (char *a) { } // doit1(char *)
+
+ class one
+ {
+ public:
+ one (void) { } // one::one(void)
+ one (int a) { } // one::one(int)
+ one (char *a) { } // one::one(char *)
+ static void doit (void) { } // one::doit(void)
+ };
+
+ namespace A
+ {
+ void doit2 (void) { } // A::doit2(void)
+ void doit2 (int a) { } // A::doit2(int)
+ void doit2 (char *a) { } // A::doit2(char *)
+
+ class two
+ {
+ public:
+ two (void) { } // A::two::two(void)
+ two (int a) { } // A::two::two(int)
+ two (char *a) { } // A::two::two(char *)
+ static void doit (void) { } // A::two::doit(void)
+ };
+
+ namespace
+ {
+ namespace
+ {
+ void doit3 (void) { } // A::doit3(void)
+ void doit3 (int a) { } // A::doit3(int)
+ void doit3 (char *a) { } // A::doit3(char *)
+
+ class three
+ {
+ public:
+ three (void) { } // A::three::three(void)
+ three (int a) { } // A::three::three(int)
+ three (char *a) { } // A::three::three(char *)
+ static void doit (void) { } // A::three::doit(void)
+ };
+ }
+ }
+ }
+}
+
+int
+main (void)
+{
+ one a, b (3), c (static_cast<char *> (NULL));
+ one::doit ();
+ A::two d, e (3), f (static_cast<char *> (NULL));
+ A::two::doit ();
+ A::three g, h (3), i (static_cast<char *> (NULL));
+ A::three::doit ();
+ doit1 ();
+ doit1 (3);
+ doit1 (static_cast<char *> (NULL));
+ A::doit2 ();
+ A::doit2 (3);
+ A::doit2 (static_cast<char *> (NULL));
+ A::doit3 ();
+ A::doit3 (3);
+ A::doit3 (static_cast<char *> (NULL));
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/anon-ns.exp b/gdb/testsuite/gdb.cp/anon-ns.exp
new file mode 100644
index 0000000..07d804c
--- /dev/null
+++ gdb/testsuite/gdb.cp/anon-ns.exp
@@ -0,0 +1,70 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# Contributed by Red Hat, originally written by Keith Seitz.
+#
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+if {[skip_cplus_tests]} { continue }
+
+# Tests for c++/12750/12704
+set testfile "anon-ns"
+set srcfile $testfile.cc
+
+if {[prepare_for_testing $testfile $testfile $srcfile {c++ debug}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ perror "couldn't run to breakpoint"
+ continue
+}
+
+set ans {(anonymous namespace)}
+set types {"void" "int" "char *"}
+set methods {}
+foreach t $types {
+ lappend methods "${ans}::doit1($t)"
+ lappend methods "${ans}::one::one($t)"
+ lappend methods "${ans}::A::doit2($t)"
+ lappend methods "${ans}::A::two::two($t)"
+ lappend methods "${ans}::A::${ans}::${ans}::doit3($t)"
+ lappend methods "${ans}::A::${ans}::${ans}::three::three($t)"
+}
+
+lappend methods "${ans}::one::doit(void)"
+lappend methods "${ans}::A::two::doit(void)"
+lappend methods "${ans}::A::${ans}::${ans}::three::doit(void)"
+
+gdb_test_no_output "set listsize 1" ""
+
+foreach test $methods {
+ # The result we expect is the source code name of the symbol,
+ # i.e., without "(anonymous namespace)".
+ regsub -all [string_to_regexp "${ans}::"] $test "" expected
+ set result ".*// [string_to_regexp $expected]"
+
+ gdb_test "list $test" $result
+ gdb_test "list '$test'" $result
+ if {[gdb_breakpoint $test]} {
+ pass "break $test"
+ }
+ if {[gdb_breakpoint '$test']} {
+ pass "break '$test'"
+ }
+}
+
+gdb_exit
+return 0