[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