This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[drow-cplus-branch] beginnings of support for using directives


Here's some code that starts to support using directives in C++.  It
tries to be a fairly minimal modification to GDB to allow that; in
particular, it does so within GDB's current way of looking at
namespaces, so symbols in a namespace A are just symbols whose names
start with "A::".  (That will probably have to change eventually, but
I think it would be useful to stick with the current framework for a
while; there are lots of useful changes we can make within the current
framework before we start seriously hitting its limits.)

Here's what the patch does:

* It defines some new structures in cp-support.h to support storing a
  linked list of using directives.  It adds a member to struct block
  that contains the using directives that the block in question adds.

* It modifies lookup_symbol_aux and friends to look in the namespaces
  given by using directives associated to the current block and its
  parents, when appropriate.

* It modifies finish_block to initialize the using directives to a
  non-trivial value in one case, namely the case when a function is
  defined within a namespace.

* It adds some tests to gdb.c++/namespace to show off its new
  capabilities.

* And it makes a trivial change to improve the declaration of
  obsavestring to get this to compile correctly.

It's certainly not ready for mainline, but it's at a stage where I'd
like other people to play around with it.  Some obvious flaws:

* It doesn't add enough using directives.  In particular, it doesn't
  yet handle using directives that the programmer actually typed in
  the code; it also doesn't handle anonymous namespaces.  Those will
  be easy to add in next week, I hope; the advantage of showing you
  this patch is so you can concentrate on the basic framework (the new
  data structures, the modifications to lookup_symbol) without having
  to deal with too many changes at once.  (Or without having to patch
  your compiler to generate better debugging info!)

* This patch tries to abstract away the portion of lookup_symbol_aux
  that looks things up in the global symbols, but in doing so it
  ignores minimal symbols.  (It only ignores them when doing the
  special using directive stuff, not when doing the normal part of
  symbol lookup.)  That still seems to need some thought, as far as I
  can tell.

* It only modifies lookup_symbol_aux and friends; corresponding
  changes will also need to be made to other symbol lookup functions.

* There's one place where I know of where this patch gets a false
  positive (i.e. a symbol lookup succeeds when it should fail): see
  the test case.  There might be situations where it would return the
  wrong symbol instead of the right one, though I'm fairly confident
  that they are rare.  Part of the problem will be impossible to fix
  without dramatically changing the way GDB thinks about namespaces;
  part of the problem is perhaps due to my not understanding the
  details of the C++ standard and trying to shoehorn something that's
  not _quite_ a using directive into the using directive framework.

I don't want to overstate the problems, though: this patch should
never hurt people who aren't debugging C++ code, and, when debugging
C++ code, it should be a strict improvement in all but the most
extremely rare of cases.  It should provide a good place to start
from.

David Carlton
carlton@math.stanford.edu

2002-10-11  David Carlton  <carlton@math.stanford.edu>

	* Makefile.in (buildsym.o): Depend on $(gdb_assert_h) and
	$(cp_support_h).
	(cp-support.o): Fix dependencies and add $(gdb_obstack_h) and
	$(gdb_assert_h).
	(symtab.o): Depend on $(cp_support_h).
	* symtab.h: Add opaque declaration for struct using_direct_node.
	(struct block): Add member 'language_specific'.
	(BLOCK_USING): New macro.
	* symtab.c: #include "cp-support.h"
	(lookup_symbol_aux): Call lookup_symbol_aux_nonlocal and
	lookup_symbol_aux_using when appropriate.
	(lookup_symbol_aux_nonlocal): New function.
	(lookup_symbol_aux_using): New function.
	(lookup_symbol_aux_using_loop): New function.
	* symfile.h: Add opaque declaration for struct obstack.
	Declare obsavestring to take a const char *.
	* symfile.c (obsavestring): Make first argument a const char *.
	* jv-lang.c (get_java_class_symtab): Initialize BLOCK_USING.
	* cp-support.h: Opaque declaration for struct obstack.
	(struct using_direct): New struct.
	(struct using_direct_node): New struct.
	Add declarations for cp_add_using, cp_copy_usings, cp_free_usings,
	cp_find_first_component.
	* cp-support.c: #include "gdb_obstack.h", "gdb_assert.h".
	Comment on demangled name pitfalls.
	(cp_add_using): New function.
	(cp_copy_usings): New function.
	(cp_free_usings): New function.
	(cp_find_first_component): New function.
	* buildsym.c: #include "gdb_assert.h", "cp-support.h".
	Change comment after #include "symfile.h".
	(finish_block): Set BLOCK_USING in general case and in C++
	function case.

2002-10-11  David Carlton  <carlton@math.stanford.edu>

	* gdb.c++/namespace.exp: Add tests from within C::D::marker2.
	* gdb.c++/namespace.cc: Add namespace C and its contents.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.268
diff -u -p -r1.268 Makefile.in
--- Makefile.in	2 Oct 2002 21:33:58 -0000	1.268
+++ Makefile.in	11 Oct 2002 21:23:44 -0000
@@ -1541,7 +1541,7 @@ buildsym.o: buildsym.c $(defs_h) $(bfd_h
 	$(symfile_h) $(objfiles_h) $(gdbtypes_h) $(complaints_h) \
 	$(gdb_string_h) $(expression_h) $(language_h) $(bcache_h) \
 	$(filenames_h) $(macrotab_h) $(demangle_h) $(buildsym_h) \
-	$(stabsread_h)
+	$(stabsread_h) $(gdb_assert_h) $(cp_support_h)
 builtin-regs.o: builtin-regs.c $(defs_h) $(builtin_regs_h) $(gdbtypes_h) \
 	$(gdb_string_h) $(gdb_assert_h)
 c-lang.o: c-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
@@ -1586,7 +1586,8 @@ corelow.o: corelow.c $(defs_h) $(gdb_str
 	$(symtab_h) $(command_h) $(bfd_h) $(target_h) $(gdbcore_h) \
 	$(gdbthread_h) $(regcache_h) $(symfile_h)
 cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(gdb_string_h)
-cp-support.o: cp-support.c $(defs_h) $(cp_support_h)
+cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
+	$(demangle_h) $(gdb_obstack_h) $(gdb_assert_h)
 cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
 	$(gdbtypes_h) $(expression_h) $(value_h) $(command_h) $(gdbcmd_h) \
 	$(demangle_h) $(annotate_h) $(gdb_string_h) $(c_lang_h) $(target_h) \
@@ -2202,7 +2203,7 @@ symtab.o: symtab.c $(defs_h) $(symtab_h)
 	$(gdbcmd_h) $(call_cmds_h) $(gdb_regex_h) $(expression_h) \
 	$(language_h) $(demangle_h) $(inferior_h) $(linespec_h) \
 	$(filenames_h) $(gdb_obstack_h) $(gdb_string_h) $(gdb_stat_h) \
-	$(cp_abi_h) $(source_h)
+	$(cp_abi_h) $(source_h) $(cp_support_h)
 target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
 	$(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
 	$(gdb_wait_h) $(dcache_h) $(regcache_h)
Index: buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.20
diff -u -p -r1.20 buildsym.c
--- buildsym.c	10 Sep 2002 23:45:26 -0000	1.20
+++ buildsym.c	11 Oct 2002 21:24:58 -0000
@@ -30,7 +30,7 @@
 #include "bfd.h"
 #include "gdb_obstack.h"
 #include "symtab.h"
-#include "symfile.h"		/* Needed for "struct complaint" */
+#include "symfile.h"		/* Needed for "struct complaint", obsavestring */
 #include "objfiles.h"
 #include "gdbtypes.h"
 #include "complaints.h"
@@ -41,6 +41,8 @@
 #include "filenames.h"		/* For DOSish file names */
 #include "macrotab.h"
 #include "demangle.h"		/* Needed by SYMBOL_INIT_DEMANGLED_NAME.  */
+#include "gdb_assert.h"
+#include "cp-support.h"
 /* Ask buildsym.h to define the vars it normally declares `extern'.  */
 #define	EXTERN
 /**/
@@ -294,6 +296,7 @@ finish_block (struct symbol *symbol, str
   BLOCK_END (block) = end;
   /* Superblock filled in when containing block is made */
   BLOCK_SUPERBLOCK (block) = NULL;
+  BLOCK_USING (block) = NULL;
 
   BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
 
@@ -381,6 +384,36 @@ finish_block (struct symbol *symbol, str
 		    }
 		}
 	    }
+	}
+
+      /* If we're in the C++ case, make sure that we add 'using'
+	 directives for all of the namespaces in which this function
+	 lives.  Also, make sure that the name was originally mangled:
+	 if not, there certainly isn't any namespace information to
+	 worry about!  (Also, if not, the gdb_assert will fail.)  */
+      if (SYMBOL_LANGUAGE (symbol) == language_cplus
+	  && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+	{
+	  const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
+	  const char *next;
+
+	  for (next = cp_find_first_component (name);
+	       *next == ':';
+	       /* The '+ 2' is to skip the '::'.  */
+	       next = cp_find_first_component (next + 2))
+	    {
+	      const char *namespace_name
+		= obsavestring (name, next - name,
+				&objfile->symbol_obstack);
+	      BLOCK_USING (block)
+		= cp_add_using ("", namespace_name, BLOCK_USING (block),
+				&objfile->symbol_obstack);
+	    }
+
+	  /* FIMXE: carlton/2002-10-09: Until I understand the
+	     possible pitfalls of demangled names a lot better, I want
+	     to make sure I'm not running into surprises.  */
+	  gdb_assert (*next == '\0');
 	}
     }
   else
Index: cp-support.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.c,v
retrieving revision 1.1
diff -u -p -r1.1 cp-support.c
--- cp-support.c	14 Sep 2002 02:09:39 -0000	1.1
+++ cp-support.c	11 Oct 2002 21:24:47 -0000
@@ -24,6 +24,36 @@
 #include "cp-support.h"
 #include "gdb_string.h"
 #include "demangle.h"
+#include "gdb_obstack.h"
+#include "gdb_assert.h"
+
+/* Here are some random pieces of trivia to keep in mind while trying
+   to take apart demangled names:
+
+   - Names can contain function arguments or templates, so the process
+     has to be, to some extent recursive: maybe keep track of your
+     depth based on encountering <> and ().
+
+   - Parentheses don't just have to happen at the end of a name: they
+     can occur even if the name in question isn't a function, because
+     a template argument might be a type that's a function.
+
+   - Conversely, even if you're trying to deal with a function, its
+     demangled name might not end with ')': it could be a const (or
+     volatile, I suppose) class method, in which case it ends with
+     "const".
+
+   - Parentheses are also used in anonymous namespaces: a variable
+     'foo' in an anonymous namespace gets demangled as "(anonymous
+     namespace)::foo".
+
+   - And operator names can contain parentheses or angle brackets.
+     Fortunately, I _think_ that operator names can only occur in a
+     fairly restrictive set of locations (in particular, they have be
+     at depth 0, don't they?).  */
+
+/* FIXME: carlton/2002-10-09: Do all the functions here handle all the
+   above considerations correctly?  */
 
 /* Find the last component of the demangled C++ name NAME.  NAME
    must be a method name including arguments, in order to correctly
@@ -138,4 +168,144 @@ method_name_from_physname (const char *p
 
   xfree (demangled_name);
   return ret;
+}
+
+/* This allocates a new using_direct structure initialized to contain
+   OUTER and INNER, and puts it at the beginning of the linked list
+   given by NEXT.  It returns the resulting struct using_direct_node.
+   All memory is allocated using OBSTACK.  */
+
+struct using_direct_node *
+cp_add_using (const char *outer, const char *inner,
+	      struct using_direct_node *next,
+	      struct obstack *obstack)
+{
+  struct using_direct *current
+    = obstack_alloc (obstack, sizeof (struct using_direct));
+  struct using_direct_node *retval
+    = obstack_alloc (obstack, sizeof (struct using_direct_node));
+
+  current->outer = outer;
+  current->inner = inner;
+  retval->current = current;
+  retval->next = next;
+
+  return retval;
+}
+
+/* This copies the using_direct_nodes in TOCOPY, using xmalloc, and
+   sticks them onto a list ending in TAIL.  */
+struct using_direct_node *
+cp_copy_usings (struct using_direct_node *tocopy,
+		struct using_direct_node *tail)
+{
+  struct using_direct_node *new_node;
+  
+  if (tocopy == NULL)
+    return tail;
+
+  new_node = xmalloc (sizeof (struct using_direct_node));
+  new_node->current = tocopy->current;
+  new_node->next = cp_copy_usings (tocopy->next, tail);
+
+  return new_node;
+}
+
+/* This xfree's all the using_direct_nodes in USING (but not their
+   using_directs!)  */
+void
+cp_free_usings (struct using_direct_node *using)
+{
+  struct using_direct_node *next;
+
+  if (using != NULL)
+    {
+      for (next = using->next; next;
+	   using = next, next = next->next)
+	xfree (using);
+      
+      xfree (using);
+    }
+}
+
+
+/* This returns the first component of NAME, which should be the
+   demangled name of a C++ variable/function/method/etc.
+   Specifically, it returns a pointer to the first colon forming the
+   boundary of the first component: so, given 'A::foo' or 'A::B::foo'
+   it returns a pointer to the first :, and given 'foo', it returns a
+   pointer to the trailing '\0'.  */
+
+/* Well, that's what it should do when called externally, but to make
+   the recursion easier, it also stops if it reaches an unexpected ')'
+   or '>'.  */
+
+/* Let's optimize away calls to strlen("operator").  */
+
+#define LENGTH_OF_OPERATOR 8
+
+const char *
+cp_find_first_component (const char *name)
+{
+  /* Names like 'operator<<' screw up the recursion, so let's
+     special-case them.  I _hope_ they can only occur at the start of
+     a component.  */
+
+  if (strncmp (name, "operator", LENGTH_OF_OPERATOR) == 0)
+    {
+      name += LENGTH_OF_OPERATOR;
+      switch (*name)
+	{
+	case '<':
+	  if (name[1] == '<')
+	    name += 2;
+	  else
+	    name += 1;
+	  break;
+	case '>':
+	case '-':
+	  if (name[1] == '>')
+	    name +=2;
+	  else
+	    name += 1;
+	  break;
+	case '(':
+	  name += 2;
+	  break;
+	default:
+	  name += 1;
+	  break;
+	}
+    }
+
+  for (;; ++name)
+    {
+      switch (*name)
+	{
+	case '<':
+	  /* Template; eat it up.  The calls to cp_first_component
+	     should only return (I hope!) when they reach the '>'
+	     terminating the component or a '::' between two
+	     components.  (Hence the '+ 2'.)  */
+	  for (name = cp_find_first_component (name + 1);
+	       *name != '>';
+	       name = cp_find_first_component (name + 2))
+	    gdb_assert (*name == ':');
+	  break;
+	case '(':
+	  /* Similar comment as to '<'.  */
+	  for (name = cp_find_first_component (name + 1);
+	       *name != ')';
+	       name = cp_find_first_component (name + 2))
+	    gdb_assert (*name == ':');
+	  break;
+	case '>':
+	case ')':
+	case '\0':
+	case ':':
+	  return name;
+	default:
+	  break;
+	}
+    }
 }
Index: cp-support.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.h,v
retrieving revision 1.1
diff -u -p -r1.1 cp-support.h
--- cp-support.h	14 Sep 2002 02:09:39 -0000	1.1
+++ cp-support.h	11 Oct 2002 21:24:42 -0000
@@ -20,6 +20,55 @@
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+/* Opaque declarations.  */
+
+struct obstack;
+
 extern char *class_name_from_physname (const char *physname);
 
 extern char *method_name_from_physname (const char *physname);
+
+extern const char *cp_find_first_component (const char *name);
+
+/* This is a struct to store data from "using directives" and similar
+   language constructs.  It contains two strings, OUTER and INNER;
+   both should be fully-qualified namespace names, OUTER should be a
+   strict initial substring of INNER, and it says that names in the
+   namespace INNER should be imported into namespace OUTER.  For
+   example, if it is used to represent the directive "using namespace
+   std;" then INNER should be "std" and new should be "".  For a more
+   complicated example, if there is an anonymous namespace with a
+   named namespace A, then INNER should be "A::(anonymous namespace)"
+   and new should be "A".  */
+
+/* FIXME: carlton/2002-10-07: That anonymous namespace example isn't
+   that great, since it really depends not only on what the
+   demangler's output is but also on the fact that the demangler's
+   output doesn't depend on the name of the file in question.  Which,
+   alas, it doesn't, but should, leaving us with no way to distinguish
+   between anonymous namespaces in different files.  Sigh...  */
+
+struct using_direct
+{
+  const char *outer;
+  const char *inner;
+};
+
+/* This is a struct for a linked list of using_direct's.  */
+
+struct using_direct_node
+{
+  struct using_direct *current;
+  struct using_direct_node *next;
+};
+
+extern struct using_direct_node *cp_add_using (const char *outer,
+					       const char *inner,
+					       struct using_direct_node *next,
+					       struct obstack *obstack);
+
+extern
+struct using_direct_node *cp_copy_usings (struct using_direct_node *tocopy,
+					  struct using_direct_node *tail);
+
+extern void cp_free_usings (struct using_direct_node *using);
Index: jv-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/jv-lang.c,v
retrieving revision 1.12
diff -u -p -r1.12 jv-lang.c
--- jv-lang.c	11 Jul 2002 20:46:19 -0000	1.12
+++ jv-lang.c	11 Oct 2002 21:24:31 -0000
@@ -111,6 +111,7 @@ get_java_class_symtab (void)
       BLOCK_END (bl) = 0;
       BLOCK_FUNCTION (bl) = NULL;
       BLOCK_SUPERBLOCK (bl) = NULL;
+      BLOCK_USING (bl) = NULL;
       BLOCK_GCC_COMPILED (bl) = 0;
       BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
 
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.69
diff -u -p -r1.69 symfile.c
--- symfile.c	20 Sep 2002 14:58:58 -0000	1.69
+++ symfile.c	11 Oct 2002 21:24:24 -0000
@@ -299,16 +299,16 @@ sort_symtab_syms (register struct symtab
    may be part of a larger string and we are only saving a substring. */
 
 char *
-obsavestring (char *ptr, int size, struct obstack *obstackp)
+obsavestring (const char *ptr, int size, struct obstack *obstackp)
 {
   register char *p = (char *) obstack_alloc (obstackp, size + 1);
   /* Open-coded memcpy--saves function call time.  These strings are usually
      short.  FIXME: Is this really still true with a compiler that can
      inline memcpy? */
   {
-    register char *p1 = ptr;
+    register const char *p1 = ptr;
     register char *p2 = p;
-    char *end = ptr + size;
+    const char *end = ptr + size;
     while (p1 != end)
       *p2++ = *p1++;
   }
Index: symfile.h
===================================================================
RCS file: /cvs/src/src/gdb/symfile.h,v
retrieving revision 1.13
diff -u -p -r1.13 symfile.h
--- symfile.h	22 Apr 2002 10:19:04 -0000	1.13
+++ symfile.h	11 Oct 2002 21:24:12 -0000
@@ -25,6 +25,10 @@
 
 /* This file requires that you first include "bfd.h".  */
 
+/* Opaque declarations.  */
+
+struct obstack;
+
 /* Partial symbols are stored in the psymbol_cache and pointers to them
    are kept in a dynamically grown array that is obtained from malloc and
    grown as necessary via realloc.  Each objfile typically has two of these,
@@ -208,7 +212,7 @@ extern void sort_symtab_syms (struct sym
    (and add a null character at the end in the copy).
    Returns the address of the copy.  */
 
-extern char *obsavestring (char *, int, struct obstack *);
+extern char *obsavestring (const char *, int, struct obstack *);
 
 /* Concatenate strings S1, S2 and S3; return the new string.
    Space is found in the symbol_obstack.  */
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.70.4.1
diff -u -p -r1.70.4.1 symtab.c
--- symtab.c	11 Oct 2002 16:20:45 -0000	1.70.4.1
+++ symtab.c	11 Oct 2002 21:24:02 -0000
@@ -49,6 +49,7 @@
 #include "gdb_stat.h"
 #include <ctype.h>
 #include "cp-abi.h"
+#include "cp-support.h"
 
 /* Prototype for one function in parser-defs.h,
    instead of including that entire file. */
@@ -95,6 +96,13 @@ static struct symbol *lookup_symbol_aux_
 					       struct symtab **symtab);
 
 static
+struct symbol *lookup_symbol_aux_nonlocal (int block_index,
+					   const char *name,
+					   const char *mangled_name,
+					   const namespace_enum namespace,
+					   struct symtab **symtab);
+
+static
 struct symbol *lookup_symbol_aux_symtabs (int block_index,
 					  const char *name,
 					  const char *mangled_name,
@@ -107,6 +115,22 @@ struct symbol *lookup_symbol_aux_psymtab
 					   const char *mangled_name,
 					   const namespace_enum namespace,
 					   struct symtab **symtab);
+
+static
+struct symbol *lookup_symbol_aux_using (const char *name,
+					const char *mangled_name,
+					const struct block *block,
+					const namespace_enum namespace,
+					struct symtab **symtab);
+
+static
+struct symbol *lookup_symbol_aux_using_loop (const char *prefix,
+					     const char *rest,
+					     struct using_direct_node *using,
+					     const char *mangled_name,
+					     namespace_enum namespace,
+					     struct symtab **symtab);
+
 static
 struct symbol *lookup_symbol_aux_minsyms (const char *name,
 					  const char *mangled_name,
@@ -785,16 +809,27 @@ lookup_symbol_aux (const char *name, con
      of the desired name as a global, then do psymtab-to-symtab
      conversion on the fly and return the found symbol. */
 
-  sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, mangled_name,
-				   namespace, symtab);
-  if (sym != NULL)
-    return sym;
-
-  sym = lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, mangled_name,
+  sym = lookup_symbol_aux_nonlocal (GLOBAL_BLOCK, name, mangled_name,
 				    namespace, symtab);
   if (sym != NULL)
     return sym;
 
+  /* If we're in the C++ case, check to see if the symbol is defined
+     in a namespace accessible via a "using" declaration.  */
+
+  /* FIXME: carlton/2002-10-10: is "is_a_field_of_this" always
+     non-NULL if we're in the C++ case?  Maybe we should always do
+     this, and delete the two previous searches: this will always
+     search the global namespace, after all.  */
+
+  if (is_a_field_of_this)
+    {
+      sym = lookup_symbol_aux_using (name, mangled_name, block, namespace,
+				     symtab);
+      if (sym != NULL)
+	return sym;
+    }
+
 #ifndef HPUXHPPA
 
   /* Check for the possibility of the symbol being a function or a
@@ -816,17 +851,11 @@ lookup_symbol_aux (const char *name, con
      desired name as a file-level static, then do psymtab-to-symtab
      conversion on the fly and return the found symbol. */
 
-  sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, mangled_name,
-				   namespace, symtab);
-  if (sym != NULL)
-    return sym;
-  
-  sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, mangled_name,
+  sym = lookup_symbol_aux_nonlocal (STATIC_BLOCK, name, mangled_name,
 				    namespace, symtab);
   if (sym != NULL)
     return sym;
 
-
 #ifdef HPUXHPPA
 
   /* Check for the possibility of the symbol being a function or a
@@ -903,6 +932,32 @@ lookup_symbol_aux_local (const char *nam
   return NULL;
 }
 
+/* Check to see if the symbol is defined in one of the symtabs or
+   psymtabs.  BLOCK_INDEX should be either GLOBAL_BLOCK or
+   STATIC_BLOCK, depending on whether or not we want to search global
+   symbols or static symbols.  */
+
+/* FIXME: carlton/2002-10-11: Should this also do some minsym
+   lookup?  */
+
+static struct symbol *
+lookup_symbol_aux_nonlocal (int block_index,
+			    const char *name,
+			    const char *mangled_name,
+			    const namespace_enum namespace,
+			    struct symtab **symtab)
+{
+  struct symbol *sym;
+
+  sym = lookup_symbol_aux_symtabs (block_index, name, mangled_name,
+				   namespace, symtab);
+  if (sym != NULL)
+    return sym;
+
+  return lookup_symbol_aux_psymtabs (block_index, name, mangled_name,
+				     namespace, symtab);
+}
+
 /* Check to see if the symbol is defined in one of the symtabs.
    BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK,
    depending on whether or not we want to search global symbols or
@@ -994,6 +1049,131 @@ lookup_symbol_aux_psymtabs (int block_in
   }
 
   return NULL;
+}
+
+/* This function gathers using directives from BLOCK and its
+   superblocks, and then searches for symbols in the global namespace
+   by trying to apply those various using directives.  */
+static struct symbol *lookup_symbol_aux_using (const char *name,
+					       const char *mangled_name,
+					       const struct block *block,
+					       const namespace_enum namespace,
+					       struct symtab **symtab)
+{
+  struct using_direct_node *using = NULL;
+  struct symbol *sym;
+
+  while (block != NULL)
+    {
+      using = cp_copy_usings (BLOCK_USING (block), using);
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  sym = lookup_symbol_aux_using_loop ("", name, using, mangled_name,
+				      namespace, symtab);
+  cp_free_usings (using);
+  
+  return sym;
+}
+
+/* This tries to look up a symbol whose name is the concatenation of
+   PREFIX, "::", and REST, where "::" is ommitted if PREFIX is the
+   empty string, applying the various using directives given in USING.
+   When applying the using directives, however, it assumes that the
+   part of the name given by PREFIX is immutable, so it only adds
+   symbols to namespaces whose names contain PREFIX.
+
+   Basically, assume that we have using directives adding A to the
+   global namespace, adding A::inner to namespace A, and adding B to
+   the global namespace.  Then, when looking up a symbol "foo", we
+   want to recurse by looking up stuff in A::foo and seeing which
+   using directives still apply.  The only one that still applies
+   converts that to A::inner::foo: we _don't_ want to then look at
+   B::A::foo (let alone A::A::foo!).  So we end up just looking at
+   A::foo, A::inner::foo, and B::foo.  (Though if the original caller
+   to lookup_symbol had specified A::foo, we would want to look up
+   stuff in A::A::foo, A::inner::A::foo, A::inner::foo, and
+   B::A::foo).
+
+   The reason why this treates the case of PREFIX = "" specially is to
+   avoid having to create temporary strings with "::" stuck on the end
+   of them.  */
+
+/* FIXME: carlton/2002-10-11: There are still some places where this
+   will return false positives.  For example, if you have namespaces
+   C, C::D, C::E, and C::D::E, then, from a function defined in C::D,
+   all references to variables E::var _should_ be treated as
+   C::D::E::var, but this function will also see variables in
+   C::E::var.  I don't think this can be fixed without making
+   namespaces first-class objects.  (Which is certainly a good idea
+   for other reasons, but it will take a little while.)  */
+
+static struct symbol *
+lookup_symbol_aux_using_loop (const char *prefix, const char *rest,
+			      struct using_direct_node *using,
+			      const char *mangled_name,
+			      namespace_enum namespace,
+			      struct symtab **symtab)
+{
+  struct using_direct_node *current;
+  struct symbol *sym;
+  int prefix_len = strlen (prefix);
+
+  for (current = using; current; current = current->next)
+    {
+      /* First, see if the prefix matches the start of this using
+	 directive.  */
+      if (strncmp (prefix, current->current->outer, prefix_len) == 0)
+	{
+	  /* Great, it matches: now does the rest of the using
+	     directive match the rest of the name?  */
+	  
+	  const char *rest_of_outer = current->current->outer + prefix_len;
+	  /* Should we skip some colons?  */
+	  if (*rest_of_outer == ':')
+	    rest_of_outer += 2;
+	  int rest_of_outer_len = strlen (rest_of_outer);
+	  if (strncmp (rest_of_outer, rest, rest_of_outer_len) == 0)
+	    {
+	      /* Everything matches!  Yippee!  So apply the using
+		 directive and recurse.  */
+	      const char *new_rest = rest + rest_of_outer_len;
+	      if (*new_rest == ':')
+		new_rest += 2;
+
+	      sym = lookup_symbol_aux_using_loop (current->current->inner,
+						  new_rest,
+						  using,
+						  mangled_name,
+						  namespace,
+						  symtab);
+	      if (sym != NULL)
+		return sym;
+	    }
+	}
+    }
+
+  /* We didn't find anything by applying any of the using directives
+     that are still applicable; so let's see if we've got a match
+     using the current name.  */
+  if (prefix_len == 0)
+    {
+      return lookup_symbol_aux_nonlocal (GLOBAL_BLOCK, rest, mangled_name,
+					 namespace, symtab);
+    }
+  else
+    {
+      char *concatenated_name
+	= xmalloc (prefix_len + 2 + strlen (rest) + 1);
+      strcpy (concatenated_name, prefix);
+      strcpy (concatenated_name + prefix_len, "::");
+      strcpy (concatenated_name + prefix_len + 2, rest);
+      sym = lookup_symbol_aux_nonlocal (GLOBAL_BLOCK, concatenated_name,
+					mangled_name, namespace, symtab);
+
+      xfree (concatenated_name);
+      return sym;
+    }
 }
 
 /* Check for the possibility of the symbol being a function or a
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.42
diff -u -p -r1.42 symtab.h
--- symtab.h	20 Sep 2002 14:58:58 -0000	1.42
+++ symtab.h	11 Oct 2002 21:23:53 -0000
@@ -25,6 +25,7 @@
 
 /* Opaque declarations.  */
 struct obstack;
+struct using_direct_node;
 
 /* Don't do this; it means that if some .o's are compiled with GNU C
    and some are not (easy to do accidentally the way we configure
@@ -373,6 +374,23 @@ struct block
 
   struct block *superblock;
 
+  /* Used for language-specific info.  */
+
+  union
+  {
+    struct
+    {
+      /* Contains information about what using directives or other
+	 similar features are added by this block.  This should always
+	 be NULL for global blocks: if there are using directives that
+	 affect an entire file, put it in the static block.  */
+      
+      struct using_direct_node *using;
+    }
+    cplus_specific;
+  }
+  language_specific;
+
   /* Version of GCC used to compile the function corresponding
      to this block, or 0 if not compiled with GCC.  When possible,
      GCC should be compatible with the native compiler, or if that
@@ -418,6 +436,7 @@ struct block
 #define BLOCK_END(bl)		(bl)->endaddr
 #define BLOCK_FUNCTION(bl)	(bl)->function
 #define BLOCK_SUPERBLOCK(bl)	(bl)->superblock
+#define BLOCK_USING(bl)		(bl)->language_specific.cplus_specific.using
 #define BLOCK_GCC_COMPILED(bl)	(bl)->gcc_compile_flag
 #define BLOCK_HASHTABLE(bl)	(bl)->hashtable
 
Index: namespace.cc
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.c++/namespace.cc,v
retrieving revision 1.1
diff -u -p -r1.1 namespace.cc
--- namespace.cc	12 Jun 2000 01:31:41 -0000	1.1
+++ namespace.cc	11 Oct 2002 21:26:53 -0000
@@ -68,6 +68,47 @@ void marker1(void)
   return;
 }
 
+namespace C
+{
+  int c = 1;
+
+  namespace C
+  {
+    int cc = 2;
+  }
+
+  namespace E
+  {
+    int ce = 4;
+  }
+
+  namespace D
+  {
+    int cd = 3;
+
+    namespace E
+    {
+      int cde = 5;
+    }
+
+    void marker2 (void)
+    {
+      // NOTE: carlton/2002-10-11: I'm listing the expressions that I
+      // plan to have GDB try to print out, just to make sure that the
+      // compiler and I agree which ones should be legal!  It's easy
+      // to screw up when testing the boundaries of namespace stuff.
+      c;
+      //cc;
+      C::cc;
+      cd;
+      E::cde;
+      //E::ce;
+      return;
+    }
+
+  }
+}
+
 
 int main ()
 {
@@ -94,7 +135,8 @@ int main ()
   c1 = cl.xyzq('e');
 
   marker1();
-  
+
+  C::D::marker2 ();
 }
 
   
Index: namespace.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.c++/namespace.exp,v
retrieving revision 1.12
diff -u -p -r1.12 namespace.exp
--- namespace.exp	10 Jan 2002 20:46:16 -0000	1.12
+++ namespace.exp	11 Oct 2002 21:26:58 -0000
@@ -186,3 +186,22 @@ gdb_expect {
    timeout { fail "(timeout) break BBB::Class::xyzq" }
 }
 
+# Now, test to see if the appropriate namespaces are in scope when
+# trying to print out stuff from within a function defined within a
+# namespace.
+
+if ![runto "'C::D::marker2'"] then {
+    perror "couldn't run to marker2"
+    continue
+}
+
+gdb_test "print c" "\\$\[0-9\].* = 1" "print c"
+gdb_test "print cc" "No symbol \"cc\" in current context." "print cc"
+gdb_test "print 'C::cc'" "\\$\[0-9\].* = 2" "print C::cc"
+gdb_test "print cd" "\\$\[0-9\].* = 3" "print cd"
+gdb_test "print 'C::D::cd'" "\\$\[0-9\].* = 3" "print C::D::cd"
+gdb_test "print 'E::cde'" "\\$\[0-9\].* = 5" "print E::cde"
+
+# FIXME: carlton/2002-10-11: It would be nice to test printing
+# "E::ce", but unfortunately GDB will print it out even though it
+# shouldn't.  Oops.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]