[rfa] generate symbols associated to namespaces

David Carlton
2003-06-16T20:22:24Z

This is the next part of my thrilling series of namespace patches; it
generates symbols associated to namespaces. The reason why these
symbols are necessary is that, when evaluating an expression like
'C::x', you first evaluate 'C', and then look up 'x' in the class or
namespace referred to by 'C'; if you don't know what namespaces are
floating around, you get into trouble. E.g. given this:

namespace C {
namespace C {
int oops;
}

int x;

void foo()
{
C::x; // error!
}
}

the reference to C::x within C::foo is an error, since 'C' refers to
'C::C', and there's no variable 'C::C::x'. If we don't know that
there's a namespace named 'C::C', we run into trouble when carrying
out this behavior.

This patch doesn't actually use those symbols very much. There will
be a followup patch that modifies the parser and associated functions
to use them, but this patch is already quite complicated enough as it
is.

Unfortunately, if we don't have DW_TAG_namespace, then we have to work
harder. The solution I've chosen here is to look at demangled names
of objects in that situation: if your object's demangled name is
'C::x', then maybe C is a namespace. But the downside is that C might
be a class instead. The solution that I've adopted is to maintain two
collections of namespace symbols: one collection is the ones we know
to exist (because of DW_TAG_namespace), and the other collection is
the ones that might be classes or namespaces (we're not sure, we
deduced their existence via demangled names). Then the C++-specific
version of lookup_symbol only searches this latter collection if it
has tried to look for a class by that name and has failed.

There's (at least) one other piece of strangeness in the
implementation. Normally, we store symbols in the symtab associated
to a file. But I chose not to do that with namespace symbols, for a
few reasons. The main reason is that it makes the machinery to deduce
possible namespace names from demangled names much more complicated
and wasteful of memory. A secondary reason is that namespaces really
aren't associated to a single file, so why pretend that they are?
(Also, it saves memory that way, too, since you only ever have one
symbol associated to a namespace, instead of one symbol for each file
that mentions the namespace.) So I put namespaces in an artificial
block in an artificial symtab; my recent dictionary patch makes this
quite easy. (I think that, in the long term, we should consider a
similar process for C++ classes, especially templated classes, but
that's a separate issue.) These symbols are actually created by the
DWARF 2 psymtab reader instead of the symtab reader.

The dwarf2read.c part of the patch is hard to read: you might just
want to apply it and compare it to the original. I've reorganized
scan_partial_symbols to behave recursively instead of using that
nesting_level and file_scope_level stuff; it's cleaner this way.

I've tested this on GCC 3.2, DWARF 2, i686-pc-linux-gnu. I also
tested gdb.c++/namespace.exp on a version of GCC 3.2 hacked to
generated DW_TAG_namespace entries. And I've been using this stuff on
my branch for months.

This needs symtab and C++ approval. I'll be on vacation until next
Tuesday or Wednesday.

David Carlton
carlton@kealia.com

2003-06-16 David Carlton <carlton@kealia.com>

* gdbtypes.h: Add TYPE_CODE_NAMESPACE.
* gdbtypes.c (init_type): Handle TYPE_CODE_NAMESPACE.
(recursive_dump_type): Ditto.
* printcmd.c (print_formatted): Ditto.
* typeprint.c (print_type_scalar): Ditto.
* c-typeprint.c (c_type_print_varspec_prefix): Ditto.
(c_type_print_varspec_suffix, c_type_print_base): Ditto.
* cp-support.h: Declare cp_check_namespace_symbol,
cp_check_possible_namespace_symbols, maint_cplus_cmd_list.
* cp-support.c: Make maint_cplus_cmd_list extern.
* cp-namespace.c: Include objfiles.h, dictionary.h, command.h.
(lookup_symbol_file): Look in namespace blocks when appropriate.
(initialize_namespace_blocks): New.
(get_namespace_block, get_possible_namespace_block)
(free_namespace_blocks, get_namespace_objfile)
(cp_check_namespace_symbol, check_namespace_symbol_block)
(lookup_namespace_symbol, cp_check_possible_namespace_symbols)
(check_possible_namespace_symbols_loop)
(check_one_possible_namespace_symbol)
(lookup_possible_namespace_symbol)
(maintenance_cplus_namespace, _initialize_cp_namespace): Ditto.
* block.h: Declare allocate_block.
* block.c (allocate_block): New.
* jv-lang.c (get_java_class_symtab): Allocate blocks via
allocate_block.
* symfile.h: Update declaration of add_psymbol_to_list.
* symfile.c (add_psymbol_to_list): Return the partial symbol in
question.
* dwarf2read.c (dwarf2_build_psymtabs_hard): Do initial setting
lowpc and highpc ourselves. Add argument to
scan_partial_symbols_call.
(scan_partial_symbols): Restructure into a recursive version,
calling add_partial_namespace and add_partial_enumeration when
appropriate.
(add_partial_symbol): If necessary, scan mangled names for names
of namespaces.
(add_partial_namespace): New.
(add_partial_enumeration, locate_pdi_sibling): Ditto.
* Makefile.in (cp-namespace.o): Depend on objfiles_h, gdbtypes_h,
dictionary_h, command_h.

2003-06-16 David Carlton <carlton@kealia.com>

* gdb.c++/namespace.exp: Add tests for namespace types and maint
cp namespace.
* gdb.c++/maint.exp (test_help): Test 'help maint cp namespace'.
(test_namespace): New.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.407
diff -u -p -r1.407 Makefile.in
--- Makefile.in 15 Jun 2003 20:56:46 -0000 1.407
+++ Makefile.in 16 Jun 2003 19:55:41 -0000
@@ -1641,7 +1641,8 @@ corelow.o: corelow.c $(defs_h) $(gdb_str
cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) \
$(gdbcmd_h) $(ui_out_h) $(gdb_string_h)
cp-namespace.o: cp-namespace.c $(defs_h) $(cp_support_h) $(gdb_obstack_h) \
- $(symtab_h) $(symfile_h) $(gdb_assert_h) $(block_h)
+ $(symtab_h) $(symfile_h) $(gdb_assert_h) $(block_h) $(objfiles_h) \
+ $(gdbtypes_h) $(dictionary_h) $(command_h)
cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
$(demangle_h) $(gdb_assert_h) $(gdbcmd_h) $(dictionary_h) \
$(objfiles_h) $(frame_h) $(block_h)
Index: block.c
===================================================================
RCS file: /cvs/src/src/gdb/block.c,v
retrieving revision 1.7
diff -u -p -r1.7 block.c
--- block.c 2 Jun 2003 18:36:33 -0000 1.7
+++ block.c 16 Jun 2003 19:55:41 -0000
@@ -268,3 +268,28 @@ block_global_block (const struct block *

return block;
}
+
+/* Allocate a block on OBSTACK, and initialize its elements to
+ zero/NULL. This is useful for creating "dummy" blocks that don't
+ correspond to actual source files.
+
+ Warning: it sets the block's BLOCK_DICT to NULL, which isn't a
+ valid value. If you really don't want the block to have a
+ dictionary, then you should subsequently set its BLOCK_DICT to
+ dict_create_linear (obstack, NULL). */
+
+struct block *
+allocate_block (struct obstack *obstack)
+{
+ struct block *bl = obstack_alloc (obstack, sizeof (struct block));
+
+ BLOCK_START (bl) = 0;
+ BLOCK_END (bl) = 0;
+ BLOCK_FUNCTION (bl) = NULL;
+ BLOCK_SUPERBLOCK (bl) = NULL;
+ BLOCK_DICT (bl) = NULL;
+ BLOCK_NAMESPACE (bl) = NULL;
+ BLOCK_GCC_COMPILED (bl) = 0;
+
+ return bl;
+}
Index: block.h
===================================================================
RCS file: /cvs/src/src/gdb/block.h,v
retrieving revision 1.8
diff -u -p -r1.8 block.h
--- block.h 11 Jun 2003 23:29:46 -0000 1.8
+++ block.h 16 Jun 2003 19:55:41 -0000
@@ -171,4 +171,6 @@ extern const struct block *block_static_

extern const struct block *block_global_block (const struct block *block);

+extern struct block *allocate_block (struct obstack *obstack);
+
#endif /* BLOCK_H */
Index: c-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-typeprint.c,v
retrieving revision 1.26
diff -u -p -r1.26 c-typeprint.c
--- c-typeprint.c 4 Jan 2003 21:54:54 -0000 1.26
+++ c-typeprint.c 16 Jun 2003 19:55:43 -0000
@@ -284,6 +284,7 @@ c_type_print_varspec_prefix (struct type
case TYPE_CODE_BITSTRING:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TEMPLATE:
+ case TYPE_CODE_NAMESPACE:
/* These types need no prefix. They are listed here so that
gcc -Wall will reveal any types that haven't been handled. */
break;
@@ -624,6 +625,7 @@ c_type_print_varspec_suffix (struct type
case TYPE_CODE_BITSTRING:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TEMPLATE:
+ case TYPE_CODE_NAMESPACE:
/* These types do not need a suffix. They are listed so that
gcc -Wall will report types that may not have been considered. */
break;
@@ -1180,6 +1182,11 @@ c_type_print_base (struct type *type, st
fprintf_filtered (stream, "\n");
}
}
+ break;
+
+ case TYPE_CODE_NAMESPACE:
+ fputs_filtered ("namespace ", stream);
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
break;

default:
Index: cp-namespace.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-namespace.c,v
retrieving revision 1.3
diff -u -p -r1.3 cp-namespace.c
--- cp-namespace.c 13 Jun 2003 00:55:43 -0000 1.3
+++ cp-namespace.c 16 Jun 2003 19:55:43 -0000
@@ -27,6 +27,10 @@
#include "symfile.h"
#include "gdb_assert.h"
#include "block.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "dictionary.h"
+#include "command.h"

/* When set, the file that we're processing seems to have debugging
info for C++ namespaces, so cp-namespace.c shouldn't try to guess
@@ -70,6 +74,42 @@ static struct symbol *lookup_symbol_file
struct symtab **symtab,
int anonymous_namespace);

+/* The next three variables are used to store symbols associated to
+ namespaces. Don't refer to them directly: use
+ get_namespace_block(), get_possible_namespace_block(), and
+ get_namespace_objfile() instead. */
+
+static struct block *namespace_block = NULL;
+
+static struct block *possible_namespace_block = NULL;
+
+static struct objfile *namespace_objfile = NULL;
+
+static void initialize_namespace_blocks (void);
+
+static struct block *get_namespace_block (void);
+
+static struct block *get_possible_namespace_block (void);
+
+static void free_namespace_blocks (struct symtab *symtab);
+
+static struct objfile *get_namespace_objfile (void);
+
+static int check_namespace_symbol_block (const char *name, int len,
+ struct block *block);
+
+static struct symbol *lookup_namespace_symbol (const char *name);
+
+static int check_possible_namespace_symbols_loop (const char *name,
+ int len);
+
+static int check_one_possible_namespace_symbol (const char *name,
+ int len);
+
+static struct symbol *lookup_possible_namespace_symbol (const char *name);
+
+static void maintenance_print_namespace (char *args, int from_tty);
+
/* Set up support for dealing with C++ namespace info in the current
symtab. */

@@ -453,13 +493,323 @@ lookup_symbol_file (const char *name,
const struct block *global_block = block_global_block (block);

if (global_block != NULL)
- return lookup_symbol_aux_block (name, linkage_name, global_block,
- domain, symtab);
- else
- return NULL;
+ sym = lookup_symbol_aux_block (name, linkage_name, global_block,
+ domain, symtab);
+
+ if (sym == NULL || global_block == NULL)
+ {
+ sym = lookup_namespace_symbol (name);
+ if (sym != NULL && symtab != NULL)
+ *symtab = NULL;
+ }
}
else
{
- return lookup_symbol_global (name, linkage_name, domain, symtab);
+ sym = lookup_symbol_global (name, linkage_name, domain, symtab);
+ }
+
+ if (sym != NULL)
+ return sym;
+
+ /* Now call "lookup_possible_namespace_symbol". Symbols in here
+ claim to be associated to namespaces, whereas the names in
+ question might actually correspond to either namespaces or to
+ classes. But if they correspond to classes, then we should have
+ found a match to them above. So if we find them now, they should
+ be genuine. */
+
+ /* FIXME: carlton/2003-06-12: This is a hack and should eventually
+ be deleted: see comments below. */
+
+ if (domain == VAR_DOMAIN)
+ {
+ sym = lookup_possible_namespace_symbol (name);
+ if (sym != NULL)
+ {
+ if (symtab != NULL)
+ *symtab = NULL;
+ return sym;
+ }
+ }
+
+ return NULL;
+}
+
+/* Now come functions for dealing with symbols associated to
+ namespaces. (They're used to store the namespaces themselves, not
+ objects that live in the namespaces.) Since namespaces span files,
+ we create special blocks to store those symbols in instead of
+ storing them in blocks associated to actual files. That avoids
+ duplication of symbols, among other issues.
+
+ Unfortunately, versions of GCC through at least 3.3 don't generate
+ debugging information to tell us about the existence of namespaces.
+ Our solution is to try to guess their existence by looking at
+ demangled names. This might cause us to misidentify classes as
+ namespaces, however. So we put those symbols in
+ 'possible_namespace_block' instead of 'namespace_block', and we
+ only search that block as a last resort. */
+
+/* FIXME: carlton/2003-06-12: Once versions of GCC that generate
+ DW_TAG_namespace have been out for a year or two, we should get rid
+ of possible_namespace_block and everything associated to it. */
+
+/* Allocate everything necessary for namespace_block and
+ possible_namespace_block. */
+
+static void
+initialize_namespace_blocks (void)
+{
+ struct objfile *objfile = get_namespace_objfile ();
+ struct symtab *namespace_symtab;
+ struct blockvector *bv;
+ struct block *bl;
+
+ namespace_symtab = allocate_symtab ("<C++-namespaces>", objfile);
+ namespace_symtab->language = language_cplus;
+ namespace_symtab->free_code = free_nothing;
+ namespace_symtab->dirname = NULL;
+
+ /* 2 = three blocks (global = namespace_block, static = NULL, third
+ block = possible_namespace_block), minus the one block that's
+ always part of struct blockvector. */
+ bv = obstack_alloc (&objfile->symbol_obstack,
+ sizeof (struct blockvector)
+ + 2 * sizeof (struct block *));
+ BLOCKVECTOR_NBLOCKS (bv) = 3;
+ BLOCKVECTOR (namespace_symtab) = bv;
+
+ /* Allocate dummy STATIC_BLOCK. */
+ bl = allocate_block (&objfile->symbol_obstack);
+ BLOCK_DICT (bl) = dict_create_linear (&objfile->symbol_obstack,
+ NULL);
+ BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+ /* Allocate GLOBAL_BLOCK, which is namespace_block. */
+ bl = allocate_block (&objfile->symbol_obstack);
+ BLOCK_DICT (bl) = dict_create_hashed_expandable ();
+ BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+ namespace_block = bl;
+
+ /* Allocate possible_namespace_block; we put it where the first
+ local block will live, though I don't think there's any need to
+ pretend that it's actually a local block (e.g. by setting
+ BLOCK_SUPERBLOCK appropriately). */
+ bl = allocate_block (&objfile->symbol_obstack);
+ BLOCK_DICT (bl) = dict_create_hashed_expandable ();
+ BLOCKVECTOR_BLOCK (bv, 2) = bl;
+ possible_namespace_block = bl;
+
+ namespace_symtab->free_func = free_namespace_blocks;
+}
+
+/* Locate namespace_block, allocating it if necessary. */
+
+static struct block *
+get_namespace_block (void)
+{
+ if (namespace_block == NULL)
+ initialize_namespace_blocks ();
+
+ return namespace_block;
+}
+
+/* Locate possible_namespace_block, allocating it if necessary. */
+
+static struct block *
+get_possible_namespace_block (void)
+{
+ if (namespace_block == NULL)
+ initialize_namespace_blocks ();
+
+ return possible_namespace_block;
+}
+
+/* Free the dictionary associated to the namespace block. */
+
+static void
+free_namespace_blocks (struct symtab *symtab)
+{
+ gdb_assert (namespace_block != NULL);
+ dict_free (BLOCK_DICT (namespace_block));
+ namespace_block = NULL;
+ dict_free (BLOCK_DICT (possible_namespace_block));
+ possible_namespace_block = NULL;
+ namespace_objfile = NULL;
+}
+
+/* Locate the namespace objfile, allocating it if necessary. */
+
+static struct objfile *
+get_namespace_objfile (void)
+{
+ if (namespace_objfile == NULL)
+ {
+ namespace_objfile = allocate_objfile (NULL, 0);
+ namespace_objfile->name
+ = mstrsave (namespace_objfile->md, "<<C++-namespaces>>");
}
+
+ return namespace_objfile;
+}
+
+/* Check to see if there's already a namespace symbol whose name is
+ NAME. If there isn't one, allocate one and add it to the namespace
+ symtab. */
+
+void
+cp_check_namespace_symbol (const char *name)
+{
+ check_namespace_symbol_block (name, strlen (name),
+ get_namespace_block ());
+}
+
+/* A helper function used by cp_check_namespace_symbol and
+ check_one_possible_namespace_symbol. Looks to see if there is a
+ symbol whose name is the initial substring of NAME of length LEN in
+ block BLOCK; if not, adds it. Return 1 if the symbol was already
+ in there, 0 otherwise. */
+
+static int
+check_namespace_symbol_block (const char *name, int len,
+ struct block *block)
+{
+ struct objfile *objfile = get_namespace_objfile ();
+ char *name_copy = obsavestring (name, len, &objfile->symbol_obstack);
+ struct symbol *sym = lookup_block_symbol (block, name_copy, NULL,
+ VAR_DOMAIN);
+
+ if (sym == NULL)
+ {
+ struct type *type = init_type (TYPE_CODE_NAMESPACE, 0, 0,
+ name_copy, objfile);
+ TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+ sym = obstack_alloc (&objfile->symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_LANGUAGE (sym) = language_cplus;
+ SYMBOL_SET_NAMES (sym, name_copy, len, objfile);
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+
+ dict_add_symbol (BLOCK_DICT (block), sym);
+
+ return 0;
+ }
+ else
+ {
+ obstack_free (&objfile->symbol_obstack, name_copy);
+
+ return 1;
+ }
+}
+
+/* Look for a symbol in namespace_block named NAME. */
+
+static struct symbol *
+lookup_namespace_symbol (const char *name)
+{
+ return lookup_block_symbol (get_namespace_block (), name, NULL,
+ VAR_DOMAIN);
+}
+
+/* Ensure that there are symbols in possible_namespace_block for all
+ initial substrings of NAME that look like namespaces or classes.
+ NAME should end in a member variable: it shouldn't consist solely
+ of namespaces. */
+
+void
+cp_check_possible_namespace_symbols (const char *name)
+{
+ check_possible_namespace_symbols_loop (name,
+ cp_find_first_component (name));
+}
+
+/* This is a helper loop for cp_check_possible_namespace_symbols; it
+ ensures that there are namespace symbols for all namespaces that
+ are initial substrings of NAME of length at least LEN. It returns
+ 1 if a previous loop had already created the shortest such symbol
+ and 0 otherwise.
+
+ This function assumes that if there is already a symbol associated
+ to a substring of NAME of a given length, then there are already
+ symbols associated to all substrings of NAME whose length is less
+ than that length. So if cp_check_possible_namespace_symbols has
+ been called once with argument "A::B::C::member", then that will
+ create symbols "A", "A::B", and "A::B::C". If it is then later
+ called with argument "A::B::D::member", then the new call will
+ generate a new symbol for "A::B::D", but once it sees that "A::B"
+ has already been created, it doesn't bother checking to see if "A"
+ has also been created. */
+
+static int
+check_possible_namespace_symbols_loop (const char *name, int len)
+{
+ if (name[len] == ':')
+ {
+ int done;
+ int next_len = len + 2;
+
+ next_len += cp_find_first_component (name + next_len);
+ done = check_possible_namespace_symbols_loop (name, next_len);
+
+ if (!done)
+ {
+ done = check_one_possible_namespace_symbol (name, len);
+ }
+
+ return done;
+ }
+ else
+ return 0;
+}
+
+/* Check to see if there's already a possible namespace symbol whose
+ name is the initial substring of NAME of length LEN. If not,
+ create one and return 0; otherwise, return 1. */
+
+static int
+check_one_possible_namespace_symbol (const char *name, int len)
+{
+ return check_namespace_symbol_block (name, len,
+ get_possible_namespace_block ());
+}
+
+/* Look for a symbol in possible_namespace_block named NAME. */
+
+static struct symbol *
+lookup_possible_namespace_symbol (const char *name)
+{
+ return lookup_block_symbol (get_possible_namespace_block (),
+ name, NULL, VAR_DOMAIN);
+}
+
+static void
+maintenance_cplus_namespace (char *args, int from_tty)
+{
+ const struct block *namespace_block = get_namespace_block ();
+ const struct block *possible_namespace_block
+ = get_possible_namespace_block ();
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ printf_unfiltered ("Definite namespaces:\n");
+ ALL_BLOCK_SYMBOLS (namespace_block, iter, sym)
+ {
+ printf_unfiltered ("%s\n", SYMBOL_PRINT_NAME (sym));
+ }
+ printf_unfiltered ("Possible namespaces:\n");
+ ALL_BLOCK_SYMBOLS (possible_namespace_block, iter, sym)
+ {
+ printf_unfiltered ("%s\n", SYMBOL_PRINT_NAME (sym));
+ }
+}
+
+void
+_initialize_cp_namespace (void)
+{
+ add_cmd ("namespace", class_maintenance, maintenance_cplus_namespace,
+ "Print the list of current known C++ namespaces.",
+ &maint_cplus_cmd_list);
}
Index: cp-support.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.c,v
retrieving revision 1.5
diff -u -p -r1.5 cp-support.c
--- cp-support.c 12 Jun 2003 15:33:45 -0000 1.5
+++ cp-support.c 16 Jun 2003 19:55:44 -0000
@@ -45,7 +45,7 @@ static void overload_list_add_symbol (st

/* The list of "maint cplus" commands. */

-static struct cmd_list_element *maint_cplus_cmd_list = NULL;
+struct cmd_list_element *maint_cplus_cmd_list = NULL;

/* The actual commands. */

Index: cp-support.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.h,v
retrieving revision 1.6
diff -u -p -r1.6 cp-support.h
--- cp-support.h 12 Jun 2003 15:33:45 -0000 1.6
+++ cp-support.h 16 Jun 2003 19:55:44 -0000
@@ -96,4 +96,12 @@ extern struct symbol *cp_lookup_symbol_n
const domain_enum domain,
struct symtab **symtab);

+extern void cp_check_namespace_symbol (const char *name);
+
+extern void cp_check_possible_namespace_symbols (const char *name);
+
+/* The list of "maint cplus" commands. */
+
+extern struct cmd_list_element *maint_cplus_cmd_list;
+
#endif /* CP_SUPPORT_H */
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.96
diff -u -p -r1.96 dwarf2read.c
--- dwarf2read.c 11 Jun 2003 22:27:11 -0000 1.96
+++ dwarf2read.c 16 Jun 2003 19:55:52 -0000
@@ -678,10 +678,30 @@ static void dwarf2_build_psymtabs_hard (

static char *scan_partial_symbols (char *, struct objfile *,
CORE_ADDR *, CORE_ADDR *,
- const struct comp_unit_head *);
+ const struct comp_unit_head *,
+ const char *namespace);

static void add_partial_symbol (struct partial_die_info *, struct objfile *,
- const struct comp_unit_head *);
+ const struct comp_unit_head *,
+ const char *namespace);
+
+static char *add_partial_namespace (struct partial_die_info *pdi,
+ char *info_ptr,
+ struct objfile *objfile,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ const struct comp_unit_head *cu_header,
+ const char *namespace);
+
+static char *add_partial_enumeration (struct partial_die_info *enum_pdi,
+ char *info_ptr,
+ struct objfile *objfile,
+ const struct comp_unit_head *cu_header,
+ const char *namespace);
+
+static char *locate_pdi_sibling (struct partial_die_info *orig_pdi,
+ char *info_ptr,
+ bfd *abfd,
+ const struct comp_unit_head *cu_header);

static void dwarf2_psymtab_to_symtab (struct partial_symtab *);

@@ -1323,9 +1343,17 @@ dwarf2_build_psymtabs_hard (struct objfi
If not, there's no more debug_info for this comp unit. */
if (comp_unit_die.has_children)
{
+ lowpc = ((CORE_ADDR) -1);
+ highpc = ((CORE_ADDR) 0);
+
info_ptr = scan_partial_symbols (info_ptr, objfile, &lowpc, &highpc,
- &cu_header);
+ &cu_header, NULL);

+ /* If we didn't find a lowpc, set it to highpc to avoid
+ complaints from `maint check'. */
+ if (lowpc == ((CORE_ADDR) -1))
+ lowpc = highpc;
+
/* If the compilation unit didn't have an explicit address range,
then use the information extracted from its child dies. */
if (! comp_unit_die.has_pc_info)
@@ -1354,45 +1382,40 @@ dwarf2_build_psymtabs_hard (struct objfi
do_cleanups (back_to);
}

-/* Read in all interesting dies to the end of the compilation unit. */
+/* Read in all interesting dies to the end of the compilation unit or
+ to the end of the current namespace. NAMESPACE is NULL if we
+ haven't yet encountered any DW_TAG_namespace entries; otherwise,
+ it's the name of the current namespace. In particular, it's the
+ empty string if we're currently in the global namespace but have
+ previously encountered a DW_TAG_namespace. */

static char *
scan_partial_symbols (char *info_ptr, struct objfile *objfile,
CORE_ADDR *lowpc, CORE_ADDR *highpc,
- const struct comp_unit_head *cu_header)
+ const struct comp_unit_head *cu_header,
+ const char *namespace)
{
bfd *abfd = objfile->obfd;
struct partial_die_info pdi;

- /* This function is called after we've read in the comp_unit_die in
- order to read its children. We start the nesting level at 1 since
- we have pushed 1 level down in order to read the comp unit's children.
- The comp unit itself is at level 0, so we stop reading when we pop
- back to that level. */
-
- int nesting_level = 1;
-
- /* We only want to read in symbols corresponding to variables or
- other similar objects that are global or static. Normally, these
- are all children of the DW_TAG_compile_unit die, so are all at
- level 1. But C++ namespaces give ries to DW_TAG_namespace dies
- whose children are global objects. So we keep track of what
- level we currently think of as referring to file scope; this
- should always equal 1 plus the number of namespaces that we are
- currently nested within. */
-
- int file_scope_level = 1;
-
- *lowpc = ((CORE_ADDR) -1);
- *highpc = ((CORE_ADDR) 0);
+ /* Now, march along the PDI's, descending into ones which have
+ interesting children but skipping the children of the other ones,
+ until we reach the end of the compilation unit. */

- while (nesting_level)
+ while (1)
{
+ /* This flag tells whether or not info_ptr has gotten updated
+ inside the loop. */
+ int info_ptr_updated = 0;
+
info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header);

- /* Anonymous namespaces have no name but are interesting. */
+ /* Anonymous namespaces have no name but have interesting
+ children, so we need to look at them. Ditto for anonymous
+ enums. */

- if (pdi.name != NULL || pdi.tag == DW_TAG_namespace)
+ if (pdi.name != NULL || pdi.tag == DW_TAG_namespace
+ || pdi.tag == DW_TAG_enumeration_type)
{
switch (pdi.tag)
{
@@ -1407,93 +1430,77 @@ scan_partial_symbols (char *info_ptr, st
{
*highpc = pdi.highpc;
}
- if ((pdi.is_external || nesting_level == file_scope_level)
- && !pdi.is_declaration)
+ if (!pdi.is_declaration)
{
- add_partial_symbol (&pdi, objfile, cu_header);
+ add_partial_symbol (&pdi, objfile, cu_header, namespace);
}
}
break;
case DW_TAG_variable:
case DW_TAG_typedef:
+ case DW_TAG_union_type:
case DW_TAG_class_type:
case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_enumeration_type:
- if ((pdi.is_external || nesting_level == file_scope_level)
- && !pdi.is_declaration)
+ if (!pdi.is_declaration)
{
- add_partial_symbol (&pdi, objfile, cu_header);
+ add_partial_symbol (&pdi, objfile, cu_header, namespace);
}
break;
- case DW_TAG_enumerator:
- /* File scope enumerators are added to the partial
- symbol table. They're children of the enumeration
- type die, so they occur at a level one higher than we
- normally look for. */
- if (nesting_level == file_scope_level + 1)
- add_partial_symbol (&pdi, objfile, cu_header);
+ case DW_TAG_enumeration_type:
+ if (!pdi.is_declaration)
+ {
+ info_ptr = add_partial_enumeration (&pdi, info_ptr,
+ objfile, cu_header,
+ namespace);
+ info_ptr_updated = 1;
+ }
break;
case DW_TAG_base_type:
/* File scope base type definitions are added to the partial
symbol table. */
- if (nesting_level == file_scope_level)
- add_partial_symbol (&pdi, objfile, cu_header);
+ add_partial_symbol (&pdi, objfile, cu_header, namespace);
break;
case DW_TAG_namespace:
- /* FIXME: carlton/2002-10-16: we're not yet doing
- anything useful with this, but for now make sure that
- these tags at least don't cause us to miss any
- important symbols. */
- if (pdi.has_children)
- file_scope_level++;
+ /* We've hit a DW_TAG_namespace entry, so we know this
+ file has been compiled using a compiler that
+ generates them; update NAMESPACE to reflect that. */
+ if (namespace == NULL)
+ namespace = "";
+ info_ptr = add_partial_namespace (&pdi, info_ptr, objfile,
+ lowpc, highpc, cu_header,
+ namespace);
+ info_ptr_updated = 1;
+ break;
default:
break;
}
}

- /* If the die has a sibling, skip to the sibling. Do not skip
- enumeration types, we want to record their enumerators. Do
- not skip namespaces, we want to record symbols inside
- them. */
- if (pdi.sibling
- && pdi.tag != DW_TAG_enumeration_type
- && pdi.tag != DW_TAG_namespace)
- {
- info_ptr = pdi.sibling;
- }
- else if (pdi.has_children)
- {
- /* Die has children, but either the optional DW_AT_sibling
- attribute is missing or we want to look at them. */
- nesting_level++;
- }
-
if (pdi.tag == 0)
- {
- nesting_level--;
- /* If this is the end of a DW_TAG_namespace entry, then
- decrease the file_scope_level, too. */
- if (nesting_level < file_scope_level)
- {
- file_scope_level--;
- gdb_assert (nesting_level == file_scope_level);
- }
- }
+ break;
+
+ /* If the die has a sibling, skip to the sibling, unless another
+ function has already updated info_ptr for us. */
+
+ /* NOTE: carlton/2003-06-16: This is a bit hackish, but whether
+ or not we want to update this depends on enough stuff (not
+ only pdi.tag but also whether or not pdi.name is NULL) that
+ this seems like the easiest way to handle the issue. */
+
+ if (!info_ptr_updated)
+ info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu_header);
}

- /* If we didn't find a lowpc, set it to highpc to avoid complaints
- from `maint check'. */
- if (*lowpc == ((CORE_ADDR) -1))
- *lowpc = *highpc;
return info_ptr;
}

static void
add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile,
- const struct comp_unit_head *cu_header)
+ const struct comp_unit_head *cu_header,
+ const char *namespace)
{
CORE_ADDR addr = 0;
+ const struct partial_symbol *psym = NULL;

switch (pdi->tag)
{
@@ -1502,19 +1509,21 @@ add_partial_symbol (struct partial_die_i
{
/*prim_record_minimal_symbol (pdi->name, pdi->lowpc + baseaddr,
mst_text, objfile); */
- add_psymbol_to_list (pdi->name, strlen (pdi->name),
- VAR_DOMAIN, LOC_BLOCK,
- &objfile->global_psymbols,
- 0, pdi->lowpc + baseaddr, cu_language, objfile);
+ psym = add_psymbol_to_list (pdi->name, strlen (pdi->name),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, pdi->lowpc + baseaddr,
+ cu_language, objfile);
}
else
{
/*prim_record_minimal_symbol (pdi->name, pdi->lowpc + baseaddr,
mst_file_text, objfile); */
- add_psymbol_to_list (pdi->name, strlen (pdi->name),
- VAR_DOMAIN, LOC_BLOCK,
- &objfile->static_psymbols,
- 0, pdi->lowpc + baseaddr, cu_language, objfile);
+ psym = add_psymbol_to_list (pdi->name, strlen (pdi->name),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, pdi->lowpc + baseaddr,
+ cu_language, objfile);
}
break;
case DW_TAG_variable:
@@ -1536,10 +1545,11 @@ add_partial_symbol (struct partial_die_i
if (pdi->locdesc)
addr = decode_locdesc (pdi->locdesc, objfile, cu_header);
if (pdi->locdesc || pdi->has_type)
- add_psymbol_to_list (pdi->name, strlen (pdi->name),
- VAR_DOMAIN, LOC_STATIC,
- &objfile->global_psymbols,
- 0, addr + baseaddr, cu_language, objfile);
+ psym = add_psymbol_to_list (pdi->name, strlen (pdi->name),
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, addr + baseaddr,
+ cu_language, objfile);
}
else
{
@@ -1549,10 +1559,11 @@ add_partial_symbol (struct partial_die_i
addr = decode_locdesc (pdi->locdesc, objfile, cu_header);
/*prim_record_minimal_symbol (pdi->name, addr + baseaddr,
mst_file_data, objfile); */
- add_psymbol_to_list (pdi->name, strlen (pdi->name),
- VAR_DOMAIN, LOC_STATIC,
- &objfile->static_psymbols,
- 0, addr + baseaddr, cu_language, objfile);
+ psym = add_psymbol_to_list (pdi->name, strlen (pdi->name),
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->static_psymbols,
+ 0, addr + baseaddr,
+ cu_language, objfile);
}
break;
case DW_TAG_typedef:
@@ -1592,6 +1603,117 @@ add_partial_symbol (struct partial_die_i
break;
default:
break;
+ }
+
+ /* Check to see if we should scan the name for possible namespace
+ info. Only do this if this is C++, if we don't have namespace
+ debugging info in the file, if the psym is of an appropriate type
+ (otherwise we'll have psym == NULL), and if we actually had a
+ mangled name to begin with. */
+
+ if (cu_language == language_cplus
+ && namespace == NULL
+ && psym != NULL
+ && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL)
+ cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym));
+}
+
+/* Read a partial die corresponding to a namespace; also, add a symbol
+ corresponding to that namespace to the symbol table. NAMESPACE is
+ the name of the enclosing namespace. */
+
+static char *
+add_partial_namespace (struct partial_die_info *pdi, char *info_ptr,
+ struct objfile *objfile,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ const struct comp_unit_head *cu_header,
+ const char *namespace)
+{
+ /* Calculate the full name of the namespace that we just entered. */
+
+ const char *new_name = pdi->name;
+ char *full_name;
+
+ if (new_name == NULL)
+ new_name = "(anonymous namespace)";
+ full_name = alloca (strlen (namespace) + 2 + strlen (new_name) + 1);
+ strcpy (full_name, namespace);
+ if (*namespace != '\0')
+ strcat (full_name, "::");
+ strcat (full_name, new_name);
+
+ /* Make sure that there's a symbol associated to that namespace. */
+
+ cp_check_namespace_symbol (full_name);
+
+ /* Now scan partial symbols in that namespace. */
+
+ if (pdi->has_children)
+ info_ptr = scan_partial_symbols (info_ptr, objfile,
+ lowpc, highpc,
+ cu_header, full_name);
+
+ return info_ptr;
+}
+
+/* Read a partial die corresponding to an enumeration type. */
+
+static char *
+add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr,
+ struct objfile *objfile,
+ const struct comp_unit_head *cu_header,
+ const char *namespace)
+{
+ bfd *abfd = objfile->obfd;
+ struct partial_die_info pdi;
+
+ if (enum_pdi->name != NULL)
+ add_partial_symbol (enum_pdi, objfile, cu_header, namespace);
+
+ while (1)
+ {
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header);
+ if (pdi.tag == 0)
+ break;
+ gdb_assert (pdi.tag == DW_TAG_enumerator);
+ gdb_assert (pdi.name != NULL);
+ add_partial_symbol (&pdi, objfile, cu_header, namespace);
+ }
+
+ return info_ptr;
+}
+
+/* Locate ORIG_PDI's sibling; INFO_PTR should point to the next PDI
+ after ORIG_PDI. */
+
+static char *
+locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr,
+ bfd *abfd, const struct comp_unit_head *cu_header)
+{
+ /* Do we know the sibling already? */
+
+ if (orig_pdi->sibling)
+ return orig_pdi->sibling;
+
+ /* Are there any children to deal with? */
+
+ if (!orig_pdi->has_children)
+ return info_ptr;
+
+ /* Okay, we don't know the sibling, but we have children that we
+ want to skip. So read children until we run into one without a
+ tag; return whatever follows it. */
+
+ while (1)
+ {
+ struct partial_die_info pdi;
+
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header);
+
+ if (pdi.tag == 0)
+ return info_ptr;
+ else
+ info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu_header);
}
}

Index: gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.73
diff -u -p -r1.73 gdbtypes.c
--- gdbtypes.c 8 Jun 2003 18:27:13 -0000 1.73
+++ gdbtypes.c 16 Jun 2003 19:55:56 -0000
@@ -1896,7 +1896,8 @@ init_type (enum type_code code, int leng
if (name && strcmp (name, "char") == 0)
TYPE_FLAGS (type) |= TYPE_FLAG_NOSIGN;

- if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
+ if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_NAMESPACE)
{
INIT_CPLUS_SPECIFIC (type);
}
@@ -3143,6 +3144,9 @@ recursive_dump_type (struct type *type,
break;
case TYPE_CODE_TEMPLATE_ARG:
printf_filtered ("(TYPE_CODE_TEMPLATE_ARG)");
+ break;
+ case TYPE_CODE_NAMESPACE:
+ printf_filtered ("(TYPE_CODE_NAMESPACE)");
break;
default:
printf_filtered ("(UNKNOWN TYPE CODE)");
Index: gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.47
diff -u -p -r1.47 gdbtypes.h
--- gdbtypes.h 14 May 2003 17:43:17 -0000 1.47
+++ gdbtypes.h 16 Jun 2003 19:55:57 -0000
@@ -134,8 +134,9 @@ enum type_code

TYPE_CODE_TYPEDEF,
TYPE_CODE_TEMPLATE, /* C++ template */
- TYPE_CODE_TEMPLATE_ARG /* C++ template arg */
+ TYPE_CODE_TEMPLATE_ARG, /* C++ template arg */

+ TYPE_CODE_NAMESPACE, /* C++ namespace. */
};

/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
Index: jv-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/jv-lang.c,v
retrieving revision 1.21
diff -u -p -r1.21 jv-lang.c
--- jv-lang.c 11 Jun 2003 23:29:47 -0000 1.21
+++ jv-lang.c 16 Jun 2003 19:55:59 -0000
@@ -111,22 +111,13 @@ get_java_class_symtab (void)
BLOCKVECTOR (class_symtab) = bv;

/* Allocate dummy STATIC_BLOCK. */
- bl = (struct block *)
- obstack_alloc (&objfile->symbol_obstack, sizeof (struct block));
+ bl = allocate_block (&objfile->symbol_obstack);
BLOCK_DICT (bl) = dict_create_linear (&objfile->symbol_obstack,
NULL);
- BLOCK_START (bl) = 0;
- BLOCK_END (bl) = 0;
- BLOCK_FUNCTION (bl) = NULL;
- BLOCK_SUPERBLOCK (bl) = NULL;
- BLOCK_NAMESPACE (bl) = NULL;
- BLOCK_GCC_COMPILED (bl) = 0;
BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;

- /* Allocate GLOBAL_BLOCK. This has to be relocatable. */
- bl = (struct block *)
- obstack_alloc (&objfile->symbol_obstack, sizeof (struct block));
- *bl = *BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ /* Allocate GLOBAL_BLOCK. */
+ bl = allocate_block (&objfile->symbol_obstack);
BLOCK_DICT (bl) = dict_create_hashed_expandable ();
BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
class_symtab->free_func = free_class_block;
Index: printcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/printcmd.c,v
retrieving revision 1.63
diff -u -p -r1.63 printcmd.c
--- printcmd.c 9 Jun 2003 15:20:21 -0000 1.63
+++ printcmd.c 16 Jun 2003 19:56:01 -0000
@@ -315,7 +315,8 @@ print_formatted (struct value *val, regi
|| TYPE_CODE (type) == TYPE_CODE_ARRAY
|| TYPE_CODE (type) == TYPE_CODE_STRING
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
- || TYPE_CODE (type) == TYPE_CODE_UNION)
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_NAMESPACE)
/* If format is 0, use the 'natural' format for
* that type of value. If the type is non-scalar,
* we have to use language rules to print it as
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.98
diff -u -p -r1.98 symfile.c
--- symfile.c 11 Jun 2003 22:27:13 -0000 1.98
+++ symfile.c 16 Jun 2003 19:56:05 -0000
@@ -2635,9 +2635,10 @@ start_psymtab_common (struct objfile *ob
}
\f
/* Add a symbol with a long value to a psymtab.
- Since one arg is a struct, we pass in a ptr and deref it (sigh). */
+ Since one arg is a struct, we pass in a ptr and deref it (sigh).
+ Return the partial symbol that has been added. */

-void
+const struct partial_symbol *
add_psymbol_to_list (char *name, int namelength, domain_enum domain,
enum address_class class,
struct psymbol_allocation_list *list, long val, /* Value as a long */
@@ -2680,6 +2681,8 @@ add_psymbol_to_list (char *name, int nam
}
*list->next++ = psym;
OBJSTAT (objfile, n_psyms++);
+
+ return psym;
}

/* Add a symbol with a long value to a psymtab. This differs from
Index: symfile.h
===================================================================
RCS file: /cvs/src/src/gdb/symfile.h,v
retrieving revision 1.24
diff -u -p -r1.24 symfile.h
--- symfile.h 11 Jun 2003 22:27:13 -0000 1.24
+++ symfile.h 16 Jun 2003 19:56:05 -0000
@@ -152,9 +152,12 @@ extern void extend_psymbol_list (struct

/* #include "demangle.h" */

-extern void add_psymbol_to_list (char *, int, domain_enum, enum address_class,
- struct psymbol_allocation_list *, long,
- CORE_ADDR, enum language, struct objfile *);
+extern const
+struct partial_symbol *add_psymbol_to_list (char *, int, domain_enum,
+ enum address_class,
+ struct psymbol_allocation_list *,
+ long, CORE_ADDR,
+ enum language, struct objfile *);

extern void add_psymbol_with_dem_name_to_list (char *, int, char *, int,
domain_enum,
Index: typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/typeprint.c,v
retrieving revision 1.18
diff -u -p -r1.18 typeprint.c
--- typeprint.c 8 Jun 2003 18:27:14 -0000 1.18
+++ typeprint.c 16 Jun 2003 19:56:06 -0000
@@ -307,6 +307,7 @@ print_type_scalar (struct type *type, LO
case TYPE_CODE_MEMBER:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
+ case TYPE_CODE_NAMESPACE:
error ("internal error: unhandled type in print_type_scalar");
break;

Index: testsuite/gdb.c++/maint.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.c++/maint.exp,v
retrieving revision 1.2
diff -u -p -r1.2 maint.exp
--- testsuite/gdb.c++/maint.exp 23 Apr 2003 23:45:24 -0000 1.2
+++ testsuite/gdb.c++/maint.exp 16 Jun 2003 19:56:21 -0000
@@ -29,13 +29,19 @@ if $tracelevel then {
# Test the help messages.

proc test_help {} {
- gdb_test "help maintenance cplus" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
+ set first_component_help "Print the first class/namespace component of NAME"
+ set namespace_help "Print the list of current known C\\+\\+ namespaces"

- gdb_test "help maint cp" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
+ set multiple_help_body "List of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- ${first_component_help}\r\nmaintenance cplus namespace -- ${namespace_help}\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."

- gdb_test "maint cp" "\"maintenance cplus\" must be followed by the name of a command.\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
+ set help_maint_cp "C\\+\\+ maintenance commands.\r\n\r\n${multiple_help_body}"

- gdb_test "help maint cp first_component" "Print the first class/namespace component of NAME."
+ gdb_test "help maintenance cplus" "${help_maint_cp}"
+ gdb_test "help maint cp" "${help_maint_cp}"
+ gdb_test "maint cp" "\"maintenance cplus\" must be followed by the name of a command.\r\n${multiple_help_body}"
+
+ gdb_test "help maint cp first_component" "${first_component_help}."
+ gdb_test "help maint cp namespace" "${namespace_help}."
}

# This is used when NAME should contain only a single component. Be
@@ -79,6 +85,12 @@ proc test_first_component {} {
gdb_test "maint cp first_component foo::bar::baz" "foo"
gdb_test "maint cp first_component C::bar" "C"
gdb_test "maint cp first_component C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >::bar" "C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >"
+}
+
+proc test_namespace {} {
+ # There are some more tests for this command in namespace.exp.
+
+ gdb_test "maint cp namespace" "Definite namespaces:\r\nPossible namespaces:"
}

gdb_exit
Index: testsuite/gdb.c++/namespace.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.c++/namespace.exp,v
retrieving revision 1.13
diff -u -p -r1.13 namespace.exp
--- testsuite/gdb.c++/namespace.exp 20 May 2003 03:56:29 -0000 1.13
+++ testsuite/gdb.c++/namespace.exp 16 Jun 2003 19:56:21 -0000
@@ -208,6 +208,8 @@ gdb_test "print cd" "\\$\[0-9\].* = 3"
gdb_test "print 'E::cde'" "\\$\[0-9\].* = 5"
gdb_test "print shadow" "\\$\[0-9\].* = 13"
gdb_test "print cOtherFile" "\\$\[0-9\].* = 316"
+gdb_test "ptype C" "type = namespace C::C"
+gdb_test "ptype E" "type = namespace C::D::E"

# Some anonymous namespace tests.

@@ -217,3 +219,18 @@ gdb_test "print X" "\\$\[0-9\].* = 9"
gdb_test "print 'G::Xg'" "\\$\[0-9\].* = 10"
gdb_test "print cXOtherFile" "No symbol \"cXOtherFile\" in current context."
gdb_test "print XOtherFile" "No symbol \"XOtherFile\" in current context."
+
+# Test to make sure that 'maint cplus namespace' is at least picking
+# up one of the namespaces in this file.
+
+# FIXME: carlton/2003-06-16: We should check to make sure it picks up
+# all of the namespaces. Unfortunately, I can't guarantee what order
+# they'll be listed in when you do 'maint cplus namespace'. Probably
+# I should stash the output of that command in a variable somewhere
+# and examine that variable for all of the relevant namespaces.
+
+# FIXME: carlton/2003-06-16: This test (like many others in this file,
+# doubtless) will fail in non-DWARF-2 situations; I need to go through
+# and audit the tests accordingly at some point.
+
+gdb_test "maint cplus namespace" ".*C::C.*"