From 63d06c5c42c2367dcafe44679742b5435463418b Mon Sep 17 00:00:00 2001 From: David Carlton Date: Wed, 14 Jan 2004 16:54:43 +0000 Subject: [PATCH] 2004-01-14 David Carlton Change symbols for C++ nested types to contain the fully qualified name, if possible. (At least in the DWARF-2 case.) Partial fix for PR's c++/57, c++/488, c++/539, c++/573, c++/609, c++/832, c++/895. * c-exp.y: Update copyright: (qualified_type): Handle types nested within classes. * cp-namespace.c: Update comments. (cp_set_block_scope): Delete #if 0. (cp_lookup_nested_type): Handle types nested within classes. * dwarf2read.c: (scan_partial_symbols): Call add_partial_structure when appropriate. (add_partial_symbol): Add the name of the enclosing namespace to types. (pdi_needs_namespace): New. (add_partial_namespace): Tweak comment. (add_partial_structure): New. (psymtab_to_symtab_1): Initialize processing_current_prefix here... (process_die): instead of here. (read_structure_scope): Try to figure out the name of the class or namespace that the structure might be defined within. (read_enumeration): Generate fully-qualified names, if possible. (read_namespace): Don't set name to NULL. (die_specification): New. (new_symbol): Generate fully-qualified names for types. (read_type_die): Determine appropriate prefix. (determine_prefix): New. (typename_concat): New. (class_name): New. * valops.c: Update copyright. (value_aggregate_elt): Pass NOSIDE to value_struct_elt_for_reference. (value_struct_elt_for_reference): Make static, add NOSIDE parameter, call value_maybe_namespace_elt as a last resort. (value_namespace_elt): Break out code into value_maybe_namespace_elt. (value_maybe_namespace_elt): New. 2004-01-14 David Carlton * gdb.cp/namespace.exp: Add tests involving classes defined within namespaces. * gdb.cp/namespace.cc (C::CClass): New. * gdb.cp/namespace1.cc: Update copyright. (C::OtherFileClass): New. --- gdb/ChangeLog | 38 +++ gdb/c-exp.y | 15 +- gdb/cp-namespace.c | 30 +- gdb/dwarf2read.c | 481 ++++++++++++++++++++++++++--- gdb/testsuite/ChangeLog | 7 + gdb/testsuite/gdb.cp/namespace.cc | 9 + gdb/testsuite/gdb.cp/namespace.exp | 37 ++- gdb/testsuite/gdb.cp/namespace1.cc | 7 +- gdb/valops.c | 67 ++-- 9 files changed, 601 insertions(+), 90 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b9364b276d9..d6e088dc85b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,41 @@ +2004-01-14 David Carlton + + Change symbols for C++ nested types to contain the fully qualified + name, if possible. (At least in the DWARF-2 case.) Partial fix + for PR's c++/57, c++/488, c++/539, c++/573, c++/609, c++/832, + c++/895. + * c-exp.y (qualified_type): Handle types nested within classes. + * cp-namespace.c: Update comments. + (cp_set_block_scope): Delete #if 0. + (cp_lookup_nested_type): Handle types nested within classes. + * dwarf2read.c: (scan_partial_symbols): Call add_partial_structure + when appropriate. + (add_partial_symbol): Add the name of the enclosing namespace to + types. + (pdi_needs_namespace): New. + (add_partial_namespace): Tweak comment. + (add_partial_structure): New. + (psymtab_to_symtab_1): Initialize processing_current_prefix + here... + (process_die): instead of here. + (read_structure_scope): Try to figure out the name of the class or + namespace that the structure might be defined within. + (read_enumeration): Generate fully-qualified names, if possible. + (read_namespace): Don't set name to NULL. + (die_specification): New. + (new_symbol): Generate fully-qualified names for types. + (read_type_die): Determine appropriate prefix. + (determine_prefix): New. + (typename_concat): New. + (class_name): New. + * valops.c (value_aggregate_elt): Pass NOSIDE to + value_struct_elt_for_reference. + (value_struct_elt_for_reference): Make static, add NOSIDE + parameter, call value_maybe_namespace_elt as a last resort. + (value_namespace_elt): Break out code into + value_maybe_namespace_elt. + (value_maybe_namespace_elt): New. + 2004-01-12 Andrew Cagney * mips-tdep.c (mips_convert_register_p): Handle both raw and diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 1f3e6838103..f11b93e3a2b 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1,6 +1,6 @@ /* YACC parser for C expressions, for GDB. Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2003 + 1998, 1999, 2000, 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -939,11 +939,6 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ decode_line_1), but I'm not holding my breath waiting for somebody to get around to cleaning this up... */ -/* FIXME: carlton/2003-09-25: Currently, the only qualified type - symbols that we generate are nested namespaces. Next on my TODO - list is to generate all nested type names properly (or at least as - well as possible, assuming that we're using DWARF-2). */ - qualified_type: typebase COLONCOLON name { struct type *type = $1; @@ -953,14 +948,16 @@ qualified_type: typebase COLONCOLON name memcpy (ncopy, $3.ptr, $3.length); ncopy[$3.length] = '\0'; - if (TYPE_CODE (type) != TYPE_CODE_NAMESPACE) - error ("`%s' is not defined as a namespace.", + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) + error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); new_type = cp_lookup_nested_type (type, ncopy, expression_context_block); if (new_type == NULL) - error ("No type \"%s\" in namespace \"%s\".", + error ("No type \"%s\" within class or namespace \"%s\".", ncopy, TYPE_NAME (type)); $$ = new_type; diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index a766acb470a..fed440ebc50 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -32,9 +32,12 @@ #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 - namespace info itself. */ +/* When set, the file that we're processing is known to have debugging + info for C++ namespaces. */ + +/* NOTE: carlton/2004-01-13: No currently released version of GCC (the + latest of which is 3.3.x at the time of this writing) produces this + debug info. GCC 3.4 should, however. */ unsigned char processing_has_namespace_info; @@ -222,12 +225,6 @@ cp_set_block_scope (const struct symbol *symbol, if (SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL) { -#if 0 - /* FIXME: carlton/2003-06-12: As mentioned above, - 'processing_has_namespace_info' currently isn't entirely - reliable, so let's always use demangled names to get this - information for now. */ - if (processing_has_namespace_info) { block_set_scope @@ -237,7 +234,6 @@ cp_set_block_scope (const struct symbol *symbol, obstack); } else -#endif { /* Try to figure out the appropriate namespace from the demangled name. */ @@ -520,10 +516,6 @@ lookup_symbol_file (const char *name, class or namespace given by PARENT_TYPE, from within the context given by BLOCK. Return NULL if there is no such nested type. */ -/* FIXME: carlton/2003-09-24: For now, this only works for nested - namespaces; the patch to make this work on other sorts of nested - types is next on my TODO list. */ - struct type * cp_lookup_nested_type (struct type *parent_type, const char *nested_name, @@ -531,8 +523,16 @@ cp_lookup_nested_type (struct type *parent_type, { switch (TYPE_CODE (parent_type)) { + case TYPE_CODE_STRUCT: case TYPE_CODE_NAMESPACE: { + /* NOTE: carlton/2003-11-10: We don't treat C++ class members + of classes like, say, data or function members. Instead, + they're just represented by symbols whose names are + qualified by the name of the surrounding class. This is + just like members of namespaces; in particular, + lookup_symbol_namespace works when looking them up. */ + const char *parent_name = TYPE_TAG_NAME (parent_type); struct symbol *sym = cp_lookup_symbol_namespace (parent_name, nested_name, @@ -547,7 +547,7 @@ cp_lookup_nested_type (struct type *parent_type, } default: internal_error (__FILE__, __LINE__, - "cp_lookup_nested_type called on a non-namespace."); + "cp_lookup_nested_type called on a non-aggregate type."); } } diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 765ac7d845d..b2c34a5d9ab 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -666,12 +666,19 @@ static char *scan_partial_symbols (char *, CORE_ADDR *, CORE_ADDR *, static void add_partial_symbol (struct partial_die_info *, struct dwarf2_cu *, const char *namespace); +static int pdi_needs_namespace (enum dwarf_tag tag, const char *namespace); + static char *add_partial_namespace (struct partial_die_info *pdi, char *info_ptr, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu, const char *namespace); +static char *add_partial_structure (struct partial_die_info *struct_pdi, + char *info_ptr, + struct dwarf2_cu *cu, + const char *namespace); + static char *add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr, struct dwarf2_cu *cu, @@ -743,6 +750,8 @@ static struct attribute *dwarf_attr (struct die_info *, unsigned int); static int die_is_declaration (struct die_info *); +static struct die_info *die_specification (struct die_info *die); + static void free_line_header (struct line_header *lh); static struct line_header *(dwarf_decode_line_header @@ -777,6 +786,12 @@ static struct type *tag_type_to_type (struct die_info *, struct dwarf2_cu *); static void read_type_die (struct die_info *, struct dwarf2_cu *); +static char *determine_prefix (struct die_info *die); + +static char *typename_concat (const char *prefix, const char *suffix); + +static char *class_name (struct die_info *die); + static void read_typedef (struct die_info *, struct dwarf2_cu *); static void read_base_type (struct die_info *, struct dwarf2_cu *); @@ -1368,11 +1383,18 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc, case DW_TAG_variable: case DW_TAG_typedef: case DW_TAG_union_type: + if (!pdi.is_declaration) + { + add_partial_symbol (&pdi, cu, namespace); + } + break; case DW_TAG_class_type: case DW_TAG_structure_type: if (!pdi.is_declaration) { - add_partial_symbol (&pdi, cu, namespace); + info_ptr = add_partial_structure (&pdi, info_ptr, cu, + namespace); + info_ptr_updated = 1; } break; case DW_TAG_enumeration_type: @@ -1430,6 +1452,17 @@ add_partial_symbol (struct partial_die_info *pdi, char *actual_name = pdi->name; const struct partial_symbol *psym = NULL; + /* If we're not in the global namespace and if the namespace name + isn't encoded in a mangled actual_name, add it. */ + + if (pdi_needs_namespace (pdi->tag, namespace)) + { + actual_name = alloca (strlen (pdi->name) + 2 + strlen (namespace) + 1); + strcpy (actual_name, namespace); + strcat (actual_name, "::"); + strcat (actual_name, pdi->name); + } + switch (pdi->tag) { case DW_TAG_subprogram: @@ -1507,11 +1540,15 @@ add_partial_symbol (struct partial_die_info *pdi, case DW_TAG_enumeration_type: /* Skip aggregate types without children, these are external references. */ + /* NOTE: carlton/2003-10-07: See comment in new_symbol about + static vs. global. */ if (pdi->has_children == 0) return; add_psymbol_to_list (actual_name, strlen (actual_name), STRUCT_DOMAIN, LOC_TYPEDEF, - &objfile->static_psymbols, + cu_language == language_cplus + ? &objfile->global_psymbols + : &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); if (cu_language == language_cplus) @@ -1519,14 +1556,16 @@ add_partial_symbol (struct partial_die_info *pdi, /* For C++, these implicitly act as typedefs as well. */ add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_TYPEDEF, - &objfile->static_psymbols, + &objfile->global_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); } break; case DW_TAG_enumerator: add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_CONST, - &objfile->static_psymbols, + cu_language == language_cplus + ? &objfile->static_psymbols + : &objfile->global_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); break; default: @@ -1547,6 +1586,30 @@ add_partial_symbol (struct partial_die_info *pdi, objfile); } +/* Determine whether a die of type TAG living in the C++ namespace + NAMESPACE needs to have the name of the namespace prepended to the + name listed in the die. */ + +static int +pdi_needs_namespace (enum dwarf_tag tag, const char *namespace) +{ + if (namespace == NULL || namespace[0] == '\0') + return 0; + + switch (tag) + { + case DW_TAG_typedef: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + case DW_TAG_enumerator: + return 1; + default: + return 0; + } +} + /* 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. */ @@ -1570,9 +1633,10 @@ add_partial_namespace (struct partial_die_info *pdi, char *info_ptr, strcat (full_name, "::"); strcat (full_name, new_name); - /* FIXME: carlton/2003-06-27: Once we build qualified names for more - symbols than just namespaces, we should replace this by a call to - add_partial_symbol. */ + /* FIXME: carlton/2003-10-07: We can't just replace this by a call + to add_partial_symbol, because we don't have a way to pass in the + full name to that function; that might be a flaw in + add_partial_symbol's interface. */ add_psymbol_to_list (full_name, strlen (full_name), VAR_DOMAIN, LOC_TYPEDEF, @@ -1587,6 +1651,63 @@ add_partial_namespace (struct partial_die_info *pdi, char *info_ptr, return info_ptr; } +/* Read a partial die corresponding to a class or structure. */ + +static char * +add_partial_structure (struct partial_die_info *struct_pdi, char *info_ptr, + struct dwarf2_cu *cu, + const char *namespace) +{ + bfd *abfd = cu->objfile->obfd; + char *actual_class_name = NULL; + + if (cu_language == language_cplus + && namespace == NULL + && struct_pdi->name != NULL + && struct_pdi->has_children) + { + /* We don't have namespace debugging information, so see if we + can figure out if this structure lives in a namespace. Look + for a member function; its demangled name will contain + namespace info, if there is any. */ + + /* NOTE: carlton/2003-10-07: Getting the info this way changes + what template types look like, because the demangler + frequently doesn't give the same name as the debug info. We + could fix this by only using the demangled name to get the + prefix (but see comment in read_structure_scope). */ + + char *next_child = info_ptr; + + while (1) + { + struct partial_die_info child_pdi; + + next_child = read_partial_die (&child_pdi, abfd, next_child, + cu); + if (!child_pdi.tag) + break; + if (child_pdi.tag == DW_TAG_subprogram) + { + actual_class_name = class_name_from_physname (child_pdi.name); + if (actual_class_name != NULL) + struct_pdi->name = actual_class_name; + break; + } + else + { + next_child = locate_pdi_sibling (&child_pdi, next_child, + abfd, cu); + } + } + } + + add_partial_symbol (struct_pdi, cu, namespace); + xfree(actual_class_name); + + return locate_pdi_sibling (struct_pdi, info_ptr, abfd, cu); +} + /* Read a partial die corresponding to an enumeration type. */ static char * @@ -1711,6 +1832,9 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) cu_header_offset = offset; info_ptr = dwarf_info_buffer + offset; + /* We're in the global namespace. */ + processing_current_prefix = ""; + obstack_init (&dwarf2_tmp_obstack); back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL); @@ -1864,11 +1988,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) case DW_TAG_common_inclusion: break; case DW_TAG_namespace: - if (!processing_has_namespace_info) - { - processing_has_namespace_info = 1; - processing_current_prefix = ""; - } + processing_has_namespace_info = 1; read_namespace (die, cu); break; case DW_TAG_imported_declaration: @@ -1879,11 +1999,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) shouldn't in the C++ case, but conceivably could in the Fortran case, so we'll have to replace this gdb_assert if Fortran compilers start generating that info. */ - if (!processing_has_namespace_info) - { - processing_has_namespace_info = 1; - processing_current_prefix = ""; - } + processing_has_namespace_info = 1; gdb_assert (die->child == NULL); break; default: @@ -2777,6 +2893,13 @@ read_structure_scope (struct die_info *die, struct dwarf2_cu *cu) struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; + const char *name = NULL; + const char *previous_prefix = processing_current_prefix; + struct cleanup *back_to = NULL; + /* This says whether or not we want to try to update the structure's + name to include enclosing namespace/class information, if + any. */ + int need_to_update_name = 0; type = alloc_type (objfile); @@ -2784,9 +2907,41 @@ read_structure_scope (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf_attr (die, DW_AT_name); if (attr && DW_STRING (attr)) { - TYPE_TAG_NAME (type) = obsavestring (DW_STRING (attr), - strlen (DW_STRING (attr)), - &objfile->type_obstack); + name = DW_STRING (attr); + + if (cu_language == language_cplus) + { + struct die_info *spec_die = die_specification (die); + + if (spec_die != NULL) + { + char *specification_prefix = determine_prefix (spec_die); + processing_current_prefix = specification_prefix; + back_to = make_cleanup (xfree, specification_prefix); + } + } + + if (processing_has_namespace_info) + { + /* FIXME: carlton/2003-11-10: This variable exists only for + const-correctness reasons. When I tried to change + TYPE_TAG_NAME to be a const char *, I ran into a cascade + of changes which would have forced decode_line_1 to take + a const char **. */ + char *new_prefix = obconcat (&objfile->type_obstack, + processing_current_prefix, + processing_current_prefix[0] == '\0' + ? "" : "::", + name); + TYPE_TAG_NAME (type) = new_prefix; + processing_current_prefix = new_prefix; + } + else + { + TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), + &objfile->type_obstack); + need_to_update_name = (cu_language == language_cplus); + } } if (die->tag == DW_TAG_structure_type) @@ -2846,6 +3001,41 @@ read_structure_scope (struct die_info *die, struct dwarf2_cu *cu) /* C++ member function. */ process_die (child_die, cu); dwarf2_add_member_fn (&fi, child_die, type, cu); + if (need_to_update_name) + { + /* The demangled names of member functions contain + information about enclosing namespaces/classes, + if any. */ + + /* FIXME: carlton/2003-11-10: The excessive + demangling here is a bit wasteful, as is the + memory usage for names. */ + + /* NOTE: carlton/2003-11-10: As commented in + add_partial_structure, the demangler sometimes + prints the type info in a different form from the + debug info. We could solve this by using the + demangled name to get the prefix; if doing so, + however, we'd need to be careful when reading a + class that's nested inside a template class. + That would also cause problems when trying to + determine RTTI information, since we use the + demangler to determine the appropriate class + name. */ + char *actual_class_name + = class_name_from_physname (dwarf2_linkage_name + (child_die)); + if (actual_class_name != NULL + && strcmp (actual_class_name, name) != 0) + { + TYPE_TAG_NAME (type) + = obsavestring (actual_class_name, + strlen (actual_class_name), + &objfile->type_obstack); + } + xfree (actual_class_name); + need_to_update_name = 0; + } } else if (child_die->tag == DW_TAG_inheritance) { @@ -2921,6 +3111,10 @@ read_structure_scope (struct die_info *die, struct dwarf2_cu *cu) /* No children, must be stub. */ TYPE_FLAGS (type) |= TYPE_FLAG_STUB; } + + processing_current_prefix = previous_prefix; + if (back_to != NULL) + do_cleanups (back_to); } /* Given a pointer to a die which begins an enumeration, process all @@ -2950,9 +3144,21 @@ read_enumeration (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf_attr (die, DW_AT_name); if (attr && DW_STRING (attr)) { - TYPE_TAG_NAME (type) = obsavestring (DW_STRING (attr), - strlen (DW_STRING (attr)), - &objfile->type_obstack); + const char *name = DW_STRING (attr); + + if (processing_has_namespace_info) + { + TYPE_TAG_NAME (type) = obconcat (&objfile->type_obstack, + processing_current_prefix, + processing_current_prefix[0] == '\0' + ? "" : "::", + name); + } + else + { + TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), + &objfile->type_obstack); + } } attr = dwarf_attr (die, DW_AT_byte_size); @@ -3223,7 +3429,7 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; const char *previous_prefix = processing_current_prefix; - const char *name = NULL; + const char *name; int is_anonymous; struct die_info *current_die; @@ -4679,6 +4885,19 @@ die_is_declaration (struct die_info *die) && ! dwarf_attr (die, DW_AT_specification)); } +/* Return the die giving the specification for DIE, if there is + one. */ + +static struct die_info * +die_specification (struct die_info *die) +{ + struct attribute *spec_attr = dwarf_attr (die, DW_AT_specification); + + if (spec_attr == NULL) + return NULL; + else + return follow_die_ref (dwarf2_get_ref_die_offset (spec_attr)); +} /* Free the line_header structure *LH, and any arrays and strings it refers to. */ @@ -5322,39 +5541,108 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) case DW_TAG_enumeration_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN; - add_symbol_to_list (sym, list_in_scope); - /* The semantics of C++ state that "struct foo { ... }" also - defines a typedef for "foo". Synthesize a typedef symbol so - that "ptype foo" works as expected. */ + /* Make sure that the symbol includes appropriate enclosing + classes/namespaces in its name. These are calculated in + read_structure_scope, and the correct name is saved in + the type. */ + if (cu_language == language_cplus) { - struct symbol *typedef_sym = (struct symbol *) - obstack_alloc (&objfile->symbol_obstack, - sizeof (struct symbol)); - *typedef_sym = *sym; - SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN; - if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) - TYPE_NAME (SYMBOL_TYPE (sym)) = - obsavestring (DEPRECATED_SYMBOL_NAME (sym), - strlen (DEPRECATED_SYMBOL_NAME (sym)), - &objfile->type_obstack); - add_symbol_to_list (typedef_sym, list_in_scope); + struct type *type = SYMBOL_TYPE (sym); + + if (TYPE_TAG_NAME (type) != NULL) + { + /* FIXME: carlton/2003-11-10: Should this use + SYMBOL_SET_NAMES instead? (The same problem also + arises a further down in the function.) */ + SYMBOL_LINKAGE_NAME (sym) + = obsavestring (TYPE_TAG_NAME (type), + strlen (TYPE_TAG_NAME (type)), + &objfile->symbol_obstack); + } } + + { + /* NOTE: carlton/2003-11-10: C++ class symbols shouldn't + really ever be static objects: otherwise, if you try + to, say, break of a class's method and you're in a file + which doesn't mention that class, it won't work unless + the check for all static symbols in lookup_symbol_aux + saves you. See the OtherFileClass tests in + gdb.c++/namespace.exp. */ + + struct pending **list_to_add; + + list_to_add = (list_in_scope == &file_symbols + && cu_language == language_cplus + ? &global_symbols : list_in_scope); + + add_symbol_to_list (sym, list_to_add); + + /* The semantics of C++ state that "struct foo { ... }" also + defines a typedef for "foo". Synthesize a typedef symbol so + that "ptype foo" works as expected. */ + if (cu_language == language_cplus) + { + struct symbol *typedef_sym = (struct symbol *) + obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + *typedef_sym = *sym; + SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) = + obsavestring (SYMBOL_NATURAL_NAME (sym), + strlen (SYMBOL_NATURAL_NAME (sym)), + &objfile->type_obstack); + add_symbol_to_list (typedef_sym, list_to_add); + } + } break; case DW_TAG_typedef: + if (processing_has_namespace_info + && processing_current_prefix[0] != '\0') + { + SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->symbol_obstack, + processing_current_prefix, + "::", + name); + } + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; + add_symbol_to_list (sym, list_in_scope); + break; case DW_TAG_base_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; SYMBOL_DOMAIN (sym) = VAR_DOMAIN; add_symbol_to_list (sym, list_in_scope); break; case DW_TAG_enumerator: + if (processing_has_namespace_info + && processing_current_prefix[0] != '\0') + { + SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->symbol_obstack, + processing_current_prefix, + "::", + name); + } attr = dwarf_attr (die, DW_AT_const_value); if (attr) { dwarf2_const_value (attr, sym, cu); } - add_symbol_to_list (sym, list_in_scope); + { + /* NOTE: carlton/2003-11-10: See comment above in the + DW_TAG_class_type, etc. block. */ + + struct pending **list_to_add; + + list_to_add = (list_in_scope == &file_symbols + && cu_language == language_cplus + ? &global_symbols : list_in_scope); + + add_symbol_to_list (sym, list_to_add); + } break; case DW_TAG_namespace: SYMBOL_CLASS (sym) = LOC_TYPEDEF; @@ -5588,6 +5876,11 @@ tag_type_to_type (struct die_info *die, struct dwarf2_cu *cu) static void read_type_die (struct die_info *die, struct dwarf2_cu *cu) { + char *prefix = determine_prefix (die); + const char *old_prefix = processing_current_prefix; + struct cleanup *back_to = make_cleanup (xfree, prefix); + processing_current_prefix = prefix; + switch (die->tag) { case DW_TAG_class_type: @@ -5634,6 +5927,114 @@ read_type_die (struct die_info *die, struct dwarf2_cu *cu) dwarf_tag_name (die->tag)); break; } + + processing_current_prefix = old_prefix; + do_cleanups (back_to); +} + +/* Return the name of the namespace/class that DIE is defined + within, or NULL if we can't tell. The caller should xfree the + result. */ + +static char * +determine_prefix (struct die_info *die) +{ + struct die_info *parent; + + if (cu_language != language_cplus) + return NULL; + + parent = die->parent; + + if (parent == NULL) + { + return (processing_has_namespace_info ? xstrdup ("") : NULL); + } + else + { + char *parent_prefix = determine_prefix (parent); + char *retval; + + switch (parent->tag) { + case DW_TAG_namespace: + { + int dummy; + + retval = typename_concat (parent_prefix, + namespace_name (parent, &dummy)); + } + break; + case DW_TAG_class_type: + case DW_TAG_structure_type: + { + if (parent_prefix != NULL) + { + const char *parent_name = dwarf2_name (parent); + + if (parent_name != NULL) + retval = typename_concat (parent_prefix, dwarf2_name (parent)); + else + /* FIXME: carlton/2003-11-10: I'm not sure what the + best thing to do here is. */ + retval = typename_concat (parent_prefix, + "<>"); + } + else + retval = class_name (parent); + } + break; + default: + retval = parent_prefix; + break; + } + + if (retval != parent_prefix) + xfree (parent_prefix); + return retval; + } +} + +/* Return a newly-allocated string formed by concatenating PREFIX, + "::", and SUFFIX, except that if PREFIX is NULL or the empty + string, just return a copy of SUFFIX. */ + +static char * +typename_concat (const char *prefix, const char *suffix) +{ + if (prefix == NULL || prefix[0] == '\0') + return xstrdup (suffix); + else + { + char *retval = xmalloc (strlen (prefix) + 2 + strlen (suffix) + 1); + + strcpy (retval, prefix); + strcat (retval, "::"); + strcat (retval, suffix); + + return retval; + } +} + +/* Return a newly-allocated string giving the name of the class given + by DIE. */ + +static char * +class_name (struct die_info *die) +{ + struct die_info *child; + const char *name; + + for (child = die->child; child != NULL; child = sibling_die (child)) + { + if (child->tag == DW_TAG_subprogram) + return class_name_from_physname (dwarf2_linkage_name (child)); + } + + name = dwarf2_name (die); + if (name != NULL) + return xstrdup (name); + else + return xstrdup (""); } static struct type * diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 22af38b1f97..59737777b78 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2004-01-14 David Carlton + + * gdb.cp/namespace.exp: Add tests involving classes defined within + namespaces. + * gdb.cp/namespace.cc (C::CClass): New. + * gdb.cp/namespace1.cc (C::OtherFileClass): New. + 2004-01-14 Elena Zannoni * gdb.base/sepdebug.exp: Bail out of the test if we don't know diff --git a/gdb/testsuite/gdb.cp/namespace.cc b/gdb/testsuite/gdb.cp/namespace.cc index a0814ee707c..6a683739206 100644 --- a/gdb/testsuite/gdb.cp/namespace.cc +++ b/gdb/testsuite/gdb.cp/namespace.cc @@ -88,6 +88,15 @@ namespace C int c = 1; int shadow = 12; + class CClass { + public: + int x; + class NestedClass { + public: + int y; + }; + }; + namespace { int cX = 6; diff --git a/gdb/testsuite/gdb.cp/namespace.exp b/gdb/testsuite/gdb.cp/namespace.exp index fda393e5869..eb03a3edbd7 100644 --- a/gdb/testsuite/gdb.cp/namespace.exp +++ b/gdb/testsuite/gdb.cp/namespace.exp @@ -26,7 +26,7 @@ # Note: The original tests were geared to the HP aCC compiler, # which has an idiosyncratic way of emitting debug info # for namespaces. -# Note: As of 2000-06-03, these pass under g++ - djb +# Note: As of 2000-06-03, they passed under g++ - djb if $tracelevel then { @@ -83,7 +83,7 @@ if ![runto 'marker1'] then { gdb_test "up" ".*main.*" "up from marker1" # Access a data item inside a namespace using colons and -# single quotes :-( +# single quotes. :-( # NOTE: carlton/2003-09-24: the quotes are becoming less necessary (or # even desirable.) For tests where it should still work with quotes, @@ -215,6 +215,15 @@ gdb_expect { timeout { fail "(timeout) print 'BBB::Class::xyzq'" } } +send_gdb "print BBB::Class::xyzq\n" +gdb_expect { + -re "\\$\[0-9\]* = \{char \\((BBB::|)Class \\*( const|), (char|int)\\)\} $hex \r\n$gdb_prompt $" { + pass "print BBB::Class::xyzq" + } + -re ".*$gdb_prompt $" { fail "print BBB::Class::xyzq" } + timeout { fail "(timeout) print BBB::Class::xyzq" } +} + # Break on a function in a class in a namespace send_gdb "break BBB::Class::xyzq\n" @@ -240,15 +249,35 @@ gdb_test "print cc" "No symbol \"cc\" in current context." gdb_test "print 'C::cc'" "\\$\[0-9\].* = 2" gdb_test "print C::cc" "\\$\[0-9\].* = 2" gdb_test "print cd" "\\$\[0-9\].* = 3" -gdb_test "print C::D::cd" "No type \"D\" in namespace \"C::C\"." +gdb_test "print C::D::cd" "No type \"D\" within class or namespace \"C::C\"." gdb_test "print 'E::cde'" "\\$\[0-9\].* = 5" gdb_test "print E::cde" "\\$\[0-9\].* = 5" gdb_test "print shadow" "\\$\[0-9\].* = 13" gdb_test "print E::ce" "No symbol \"ce\" in namespace \"C::D::E\"." -gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" gdb_test "ptype C" "type = namespace C::C" gdb_test "ptype E" "type = namespace C::D::E" +gdb_test "ptype CClass" "type = class C::CClass \{\r\n public:\r\n int x;\r\n\}" +gdb_test "ptype CClass::NestedClass" "type = class C::CClass::NestedClass \{\r\n public:\r\n int y;\r\n\}" +gdb_test "ptype NestedClass" "No symbol \"NestedClass\" in current context." +setup_kfail "gdb/1448" "*-*-*" +gdb_test "ptype ::C::CClass" "type = class C::CClass \{\r\n public:\r\n int x;\r\n\}" +setup_kfail "gdb/1448" "*-*-*" +gdb_test "ptype ::C::CClass::NestedClass" "type = class C::CClass::NestedClass \{\r\n public:\r\n int y;\r\n\}" +setup_kfail "gdb/1448" "*-*-*" +gdb_test "ptype ::C::NestedClass" "No symbol \"NestedClass\" in namespace \"C\"." +gdb_test "ptype C::CClass" "No symbol \"CClass\" in namespace \"C::C\"." +gdb_test "ptype C::CClass::NestedClass" "No type \"CClass\" within class or namespace \"C::C\"." +gdb_test "ptype C::NestedClass" "No symbol \"NestedClass\" in namespace \"C::C\"." + +# Tests involving multiple files + +gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" +gdb_test "ptype OtherFileClass" "type = class C::OtherFileClass \{\r\n public:\r\n int z;\r\n\}" +setup_kfail "gdb/1448" "*-*-*" +gdb_test "ptype ::C::OtherFileClass" "type = class C::OtherFileClass \{\r\n public:\r\n int z;\r\n\}" +gdb_test "ptype C::OtherFileClass" "No symbol \"OtherFileClass\" in namespace \"C::C\"." + # Some anonymous namespace tests. gdb_test "print cX" "\\$\[0-9\].* = 6" diff --git a/gdb/testsuite/gdb.cp/namespace1.cc b/gdb/testsuite/gdb.cp/namespace1.cc index 4a5900a8b3d..5d668106511 100644 --- a/gdb/testsuite/gdb.cp/namespace1.cc +++ b/gdb/testsuite/gdb.cp/namespace1.cc @@ -1,4 +1,4 @@ -/* Copyright 2003 Free Software Foundation, Inc. +/* Copyright 2003, 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 @@ -19,6 +19,11 @@ namespace C { + class OtherFileClass { + public: + int z; + }; + namespace { int cXOtherFile = 29; }; diff --git a/gdb/valops.c b/gdb/valops.c index 5f302ca57ff..14fefd90174 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1,6 +1,6 @@ /* Perform non-arithmetic operations on values, for GDB. Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, - 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -64,17 +64,21 @@ static struct value *search_struct_method (char *, struct value **, static int check_field_in (struct type *, const char *); - static struct value *value_struct_elt_for_reference (struct type *domain, int offset, struct type *curtype, char *name, - struct type *intype); + struct type *intype, + enum noside noside); static struct value *value_namespace_elt (const struct type *curtype, - const char *name, + char *name, enum noside noside); +static struct value *value_maybe_namespace_elt (const struct type *curtype, + char *name, + enum noside noside); + static CORE_ADDR allocate_space_in_inferior (int); static struct value *cast_into_complex (struct type *, struct value *); @@ -2234,7 +2238,8 @@ value_aggregate_elt (struct type *curtype, { case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: - return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL); + return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL, + noside); case TYPE_CODE_NAMESPACE: return value_namespace_elt (curtype, name, noside); default: @@ -2250,10 +2255,11 @@ value_aggregate_elt (struct type *curtype, "pointers to member functions". This function is used to resolve user expressions of the form "DOMAIN::NAME". */ -struct value * +static struct value * value_struct_elt_for_reference (struct type *domain, int offset, struct type *curtype, char *name, - struct type *intype) + struct type *intype, + enum noside noside) { struct type *t = curtype; int i; @@ -2376,11 +2382,17 @@ value_struct_elt_for_reference (struct type *domain, int offset, offset + base_offset, TYPE_BASECLASS (t, i), name, - intype); + intype, + noside); if (v) return v; } - return 0; + + /* As a last chance, pretend that CURTYPE is a namespace, and look + it up that way; this (frequently) works for types nested inside + classes. */ + + return value_maybe_namespace_elt (curtype, name, noside); } /* C++: Return the member NAME of the namespace given by the type @@ -2388,33 +2400,46 @@ value_struct_elt_for_reference (struct type *domain, int offset, static struct value * value_namespace_elt (const struct type *curtype, - const char *name, + char *name, enum noside noside) +{ + struct value *retval = value_maybe_namespace_elt (curtype, name, + noside); + + if (retval == NULL) + error ("No symbol \"%s\" in namespace \"%s\".", name, + TYPE_TAG_NAME (curtype)); + + return retval; +} + +/* A helper function used by value_namespace_elt and + value_struct_elt_for_reference. It looks up NAME inside the + context CURTYPE; this works if CURTYPE is a namespace or if CURTYPE + is a class and NAME refers to a type in CURTYPE itself (as opposed + to, say, some base class of CURTYPE). */ + +static struct value * +value_maybe_namespace_elt (const struct type *curtype, + char *name, + enum noside noside) { const char *namespace_name = TYPE_TAG_NAME (curtype); struct symbol *sym; - struct value *retval; sym = cp_lookup_symbol_namespace (namespace_name, name, NULL, get_selected_block (0), VAR_DOMAIN, NULL); if (sym == NULL) - retval = NULL; + return NULL; else if ((noside == EVAL_AVOID_SIDE_EFFECTS) && (SYMBOL_CLASS (sym) == LOC_TYPEDEF)) - retval = allocate_value (SYMBOL_TYPE (sym)); + return allocate_value (SYMBOL_TYPE (sym)); else - retval = value_of_variable (sym, get_selected_block (0)); - - if (retval == NULL) - error ("No symbol \"%s\" in namespace \"%s\".", name, - TYPE_TAG_NAME (curtype)); - - return retval; + return value_of_variable (sym, get_selected_block (0)); } - /* Given a pointer value V, find the real (RTTI) type of the object it points to. Other parameters FULL, TOP, USING_ENC as with value_rtti_type() -- 2.30.2