[rfa] teach linespec about nested classes
David Carlton
carlton@kealia.com
Fri Feb 6 19:36:00 GMT 2004
Here's the last of my namespace/nested class patches. It modifies
decode_compound in linespec.c to change the order in which it does
stuff. Specifically, what it tries now is: given a name A::B::C,
it says:
* Is A a class? If so, look for a method B in it.
* If A isn't a class, is A::B a class? If so, look for a method C in
it.
* Otherwise, just look up A::B::C.
This is, of course, screwy - the last thing we want to do is look for
a method named 'B' in a class named 'A'. In particular, this fails if
we have a class A with a nested class A::B.
This patch remedies the situation: rather than looping through all the
double-colons and stopping at each stage to ask if the symbol there is
a class, it only asks that question when it reaches the last set of
double-colons. So it's pretty mechanical - basically, all I did was
move the code for looking up a class outside of the loop looking for
double-colons, and then reindent. While I was at it, I deleted some
dead code; if this patch is approved, I'll commit that part of the
patch first before committing the rest of it.
This patch actually isn't on carlton_dictionary-branch, so it hasn't
gotten quite as much testing as my other recent patches. The reason
for that is that the way I handled this issue on the branch is more
complex, involves more linespec refactoring, and has known bugs
associated to it. I like this simpler patch a lot better.
Tested on i686-pc-linux-gnu, with 5 different GCC/debug format
combinations. No regressions on any of them; the new test passes on
all of them. OK to commit?
David Carlton
carlton@kealia.com
2004-02-06 David Carlton <carlton@kealia.com>
* linespec.c (decode_compound): Remove commented-out code. Only
look for a class symbol when considering all but the rightmost
component.
2004-02-06 David Carlton <carlton@kealia.com>
* gdb.cp/breakpoint.exp: New.
* gdb.cp/breakpoint.cc: New.
Index: linespec.c
===================================================================
RCS file: /cvs/src/src/gdb/linespec.c,v
retrieving revision 1.54
diff -u -p -r1.54 linespec.c
--- linespec.c 20 Jan 2004 02:04:19 -0000 1.54
+++ linespec.c 6 Feb 2004 18:14:46 -0000
@@ -1149,9 +1149,6 @@ decode_compound (char **argptr, int funf
{
struct symtabs_and_lines values;
char *p2;
-#if 0
- char *q, *q1;
-#endif
char *saved_arg2 = *argptr;
char *temp_end;
struct symbol *sym;
@@ -1169,91 +1166,22 @@ decode_compound (char **argptr, int funf
&& ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
saved_arg2 += 2;
- /* We have what looks like a class or namespace
- scope specification (A::B), possibly with many
- levels of namespaces or classes (A::B::C::D).
-
- Some versions of the HP ANSI C++ compiler (as also possibly
- other compilers) generate class/function/member names with
- embedded double-colons if they are inside namespaces. To
- handle this, we loop a few times, considering larger and
- larger prefixes of the string as though they were single
- symbols. So, if the initially supplied string is
- A::B::C::D::foo, we have to look up "A", then "A::B",
- then "A::B::C", then "A::B::C::D", and finally
- "A::B::C::D::foo" as single, monolithic symbols, because
- A, B, C or D may be namespaces.
-
- Note that namespaces can nest only inside other
- namespaces, and not inside classes. So we need only
- consider *prefixes* of the string; there is no need to look up
- "B::C" separately as a symbol in the previous example. */
+ /* We have what looks like a class or namespace scope specification
+ (A::B), possibly with many levels of namespaces or classes
+ (A::B::C::D). We have two cases:
+
+ 1) A::B::C is a class. In this case, we expect D to be a method
+ of this class, so we look it up using find_method.
+
+ 2) A::B::C isn't a class. In this case, either the user made a
+ typo or A::B::C is a namespace containing a function called D.
+ Either way, we just look up A::B::C::D. */
+
+ /* Loop through the name looking for double-colons. */
p2 = p; /* Save for restart. */
while (1)
{
- sym_class = lookup_prefix_sym (argptr, p);
-
- if (sym_class &&
- (t = check_typedef (SYMBOL_TYPE (sym_class)),
- (TYPE_CODE (t) == TYPE_CODE_STRUCT
- || TYPE_CODE (t) == TYPE_CODE_UNION)))
- {
- /* Arg token is not digits => try it as a function name.
- Find the next token (everything up to end or next
- blank). */
- if (**argptr
- && strchr (get_gdb_completer_quote_characters (),
- **argptr) != NULL)
- {
- p = skip_quoted (*argptr);
- *argptr = *argptr + 1;
- }
- else
- {
- p = *argptr;
- while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
- p++;
- }
-/*
- q = operator_chars (*argptr, &q1);
- if (q1 - q)
- {
- char *opname;
- char *tmp = alloca (q1 - q + 1);
- memcpy (tmp, q, q1 - q);
- tmp[q1 - q] = '\0';
- opname = cplus_mangle_opname (tmp, DMGL_ANSI);
- if (opname == NULL)
- {
- cplusplus_error (saved_arg, "no mangling for \"%s\"\n", tmp);
- }
- copy = (char*) alloca (3 + strlen(opname));
- sprintf (copy, "__%s", opname);
- p = q1;
- }
- else
- */
- {
- copy = (char *) alloca (p - *argptr + 1);
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = '\0';
- if (p != *argptr
- && copy[p - *argptr - 1]
- && strchr (get_gdb_completer_quote_characters (),
- copy[p - *argptr - 1]) != NULL)
- copy[p - *argptr - 1] = '\0';
- }
-
- /* No line number may be specified. */
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
-
- return find_method (funfirstline, canonical, saved_arg,
- copy, t, sym_class);
- }
-
/* Move pointer up to next possible class/namespace token. */
p = p2 + 1; /* Restart with old value +1. */
/* Move pointer ahead to next double-colon. */
@@ -1279,9 +1207,55 @@ decode_compound (char **argptr, int funf
*argptr = saved_arg2; /* Restore argptr. */
} /* while (1) */
- /* Last chance attempt -- check entire name as a symbol. Use "copy"
- in preparation for jumping out of this block, to be consistent
- with usage following the jump target. */
+ /* At this point, P2 points at the end of the next-to-last component
+ of the name (A::B::C in our example above), and P points to the
+ end of the entire name (A::B::C::D). */
+
+ sym_class = lookup_prefix_sym (argptr, p2);
+
+ if (sym_class &&
+ (t = check_typedef (SYMBOL_TYPE (sym_class)),
+ (TYPE_CODE (t) == TYPE_CODE_STRUCT
+ || TYPE_CODE (t) == TYPE_CODE_UNION)))
+ {
+ /* Arg token is not digits => try it as a function name.
+ Find the next token (everything up to end or next
+ blank). */
+ if (**argptr
+ && strchr (get_gdb_completer_quote_characters (),
+ **argptr) != NULL)
+ {
+ p = skip_quoted (*argptr);
+ *argptr = *argptr + 1;
+ }
+ else
+ {
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
+ p++;
+ }
+
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (p != *argptr
+ && copy[p - *argptr - 1]
+ && strchr (get_gdb_completer_quote_characters (),
+ copy[p - *argptr - 1]) != NULL)
+ copy[p - *argptr - 1] = '\0';
+
+ /* No line number may be specified. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ return find_method (funfirstline, canonical, saved_arg,
+ copy, t, sym_class);
+ }
+
+ /* We couldn't find a class, so check the entire name as a symbol
+ instead. */
+
copy = (char *) alloca (p - saved_arg2 + 1);
memcpy (copy, saved_arg2, p - saved_arg2);
/* Note: if is_quoted should be true, we snuff out quote here
--- /dev/null 2002-08-30 16:31:37.000000000 -0700
+++ breakpoint.exp 2004-02-06 09:56:52.000000000 -0800
@@ -0,0 +1,65 @@
+# Copyright 2004 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file is part of the gdb testsuite.
+
+# This contains tests for breakpoints in C++.
+
+if $tracelevel then {
+ strace $tracelevel
+ }
+
+if { [skip_cplus_tests] } { continue }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "breakpoint"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile} "c++"] {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+proc test_breakpoint {name} {
+ # Restart the program every time, so that a single failure doesn't
+ # lead to a cascade.
+ if ![runto_main] then {
+ perror "couldn't run to main when testing ${name}"
+ continue
+ } else {
+ gdb_breakpoint "${name}"
+ gdb_test "continue" "Continuing.\r\n\r\nBreakpoint \[0-9\]*, ${name}.*" "continue to ${name}"
+ }
+}
+
+test_breakpoint "C1::Nested::foo"
+
+gdb_exit
+return 0
--- /dev/null 2002-08-30 16:31:37.000000000 -0700
+++ breakpoint.cc 2004-02-05 16:17:29.000000000 -0800
@@ -0,0 +1,44 @@
+/* Code to go along with tests in breakpoint.exp.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ Contributed by David Carlton <carlton@bactrian.org> and by Kealia,
+ Inc.
+
+ This file is part of GDB.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+class C1 {
+public:
+ class Nested {
+ public:
+ int
+ foo ()
+ {
+ return 1;
+ }
+ };
+};
+
+int main ()
+{
+ C1::Nested c1;
+
+ c1.foo();
+
+ return 0;
+}
More information about the Gdb
mailing list