From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15625 invoked by alias); 14 Jan 2004 17:02:29 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 15570 invoked from network); 14 Jan 2004 17:02:19 -0000 Received: from unknown (HELO hawaii.kealia.com) (209.3.10.89) by sources.redhat.com with SMTP; 14 Jan 2004 17:02:19 -0000 Received: by hawaii.kealia.com (Postfix, from userid 2049) id AC5E0C6CC; Wed, 14 Jan 2004 09:02:07 -0800 (PST) To: gdb-patches@sources.redhat.com Cc: Elena Zannoni Subject: Re: [rfa] generate fully-qualified names for types References: <20031117165209.GA15811@nevyn.them.org> <16381.46983.936264.534767@localhost.redhat.com> <16383.11745.817295.969440@localhost.redhat.com> From: David Carlton Date: Wed, 14 Jan 2004 17:02:00 -0000 In-Reply-To: <16383.11745.817295.969440@localhost.redhat.com> (Elena Zannoni's message of "Fri, 9 Jan 2004 17:40:33 -0500") Message-ID: User-Agent: Gnus/5.1002 (Gnus v5.10.2) XEmacs/21.4 (Rational FORTRAN, linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2004-01/txt/msg00378.txt.bz2 On Fri, 9 Jan 2004 17:40:33 -0500, Elena Zannoni said: > you can check those in. Thanks! I've done so (patch below, just for reference; no changes other than copyright dates). And later today I'll file PR's for the testsuite changes and update the testsuite accordingly. For reference, the most important changes that remain are: * Changes to lookup_transparent_type (sigh). A hack, but probably an important one; I'll try to generate this one quickly. * Changes to function overloading. Probably not that important in practice, but it shouldn't be too hard to generate this one. * Changes to linespec to expect namespace. A bit trickier, especially since a user found a bug in this code on Monday. Perhaps it's a bit less important, however, though: linespec is surprisingly resilient. At any rate, I'll certainly try to get this in to 6.1 as well. Other changes on my branch that are less important: * A change to dwarf2read.c involving code ranges and namespaces. I'm not sure if this will be important for GCC 3.4 or not, but better safe than sorry. (It's a small patch, so I'll probably try to get it in for 6.1, too.) * General linespec cleanup; a good idea, though not necessary for correctness. * Const-correctness stuff; I don't know if I'll merge this in or not. David Carlton carlton@kealia.com 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. Index: c-exp.y =================================================================== RCS file: /cvs/src/src/gdb/c-exp.y,v retrieving revision 1.24 diff -u -p -r1.24 c-exp.y --- c-exp.y 6 Nov 2003 22:54:00 -0000 1.24 +++ c-exp.y 14 Jan 2004 16:50:46 -0000 @@ -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): 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; Index: cp-namespace.c =================================================================== RCS file: /cvs/src/src/gdb/cp-namespace.c,v retrieving revision 1.8 diff -u -p -r1.8 cp-namespace.c --- cp-namespace.c 9 Jan 2004 22:22:07 -0000 1.8 +++ cp-namespace.c 14 Jan 2004 16:50:46 -0000 @@ -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 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 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 *pare { 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 *pare } default: internal_error (__FILE__, __LINE__, - "cp_lookup_nested_type called on a non-namespace."); + "cp_lookup_nested_type called on a non-aggregate type."); } } Index: dwarf2read.c =================================================================== RCS file: /cvs/src/src/gdb/dwarf2read.c,v retrieving revision 1.119 diff -u -p -r1.119 dwarf2read.c --- dwarf2read.c 9 Jan 2004 22:22:07 -0000 1.119 +++ dwarf2read.c 14 Jan 2004 16:50:49 -0000 @@ -666,12 +666,19 @@ static char *scan_partial_symbols (char 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 (str 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 (st 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, CO 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_i 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_i 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_i /* 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_i 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_di 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_di 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_symt 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, struc 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, struc 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 *d 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 *d 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 *d /* 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 *d /* 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, 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, st { 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 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, 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, str 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 * Index: valops.c =================================================================== RCS file: /cvs/src/src/gdb/valops.c,v retrieving revision 1.119 diff -u -p -r1.119 valops.c --- valops.c 8 Nov 2003 00:13:03 -0000 1.119 +++ valops.c 14 Jan 2004 16:50:50 -0000 @@ -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_metho 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 *curtyp { 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 *curtyp "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 t 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,32 +2400,45 @@ value_struct_elt_for_reference (struct t 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. Index: testsuite/gdb.cp/namespace.cc =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/namespace.cc,v retrieving revision 1.2 diff -u -p -r1.2 namespace.cc --- testsuite/gdb.cp/namespace.cc 25 Sep 2003 16:39:39 -0000 1.2 +++ testsuite/gdb.cp/namespace.cc 14 Jan 2004 16:50:57 -0000 @@ -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; Index: testsuite/gdb.cp/namespace.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/namespace.exp,v retrieving revision 1.5 diff -u -p -r1.5 namespace.exp --- testsuite/gdb.cp/namespace.exp 7 Jan 2004 08:44:32 -0000 1.5 +++ testsuite/gdb.cp/namespace.exp 14 Jan 2004 16:50:57 -0000 @@ -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,14 +249,34 @@ gdb_test "print cc" "No symbol \"cc\" in 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. Index: testsuite/gdb.cp/namespace1.cc =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/namespace1.cc,v retrieving revision 1.1 diff -u -p -r1.1 namespace1.cc --- testsuite/gdb.cp/namespace1.cc 23 Aug 2003 03:55:59 -0000 1.1 +++ testsuite/gdb.cp/namespace1.cc 14 Jan 2004 16:50:57 -0000 @@ -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; };