From 1fcb515536dbda348515162ccdb82cb102928798 Mon Sep 17 00:00:00 2001 From: David Carlton Date: Tue, 20 May 2003 03:56:29 +0000 Subject: [PATCH] 2003-05-19 David Carlton Partial fix for PR c++/827. * cp-support.h: Include symtab.h. Declare cp_lookup_symbol_nonlocal, cp_lookup_symbol_namespace. * cp-namespace.c: Update contributors. (cp_lookup_symbol_nonlocal): New. (lookup_namespace_scope, cp_lookup_symbol_namespace) (lookup_symbol_file): Ditto. * c-lang.c (cplus_language_defn): Use cp_lookup_symbol_nonlocal. * block.h: Declare block_scope, block_using, block_global_block. * block.c (block_scope): New. (block_using, block_global_block): Ditto. * Makefile.in (cp_support_h): Depend on symtab_h. * config/djgpp/fnchange.lst: Add testsuite/gdb.c++/namespace1.cc. 2003-05-19 David Carlton * gdb.c++/namespace.exp: Add namespace scope and anonymous namespace tests. Bump copyright date. * gdb.c++/namespace.cc: Add anonymous namespace and namespace C. (main): Call C::D::marker2. * gdb.c++/namespace1.cc: New file. --- gdb/ChangeLog | 16 +++ gdb/Makefile.in | 2 +- gdb/block.c | 57 ++++++++- gdb/block.h | 6 + gdb/c-lang.c | 3 +- gdb/config/djgpp/fnchange.lst | 1 + gdb/cp-namespace.c | 191 +++++++++++++++++++++++++++- gdb/cp-support.h | 18 ++- gdb/testsuite/ChangeLog | 9 ++ gdb/testsuite/gdb.c++/namespace.cc | 70 +++++++++- gdb/testsuite/gdb.c++/namespace.exp | 43 ++++++- 11 files changed, 399 insertions(+), 17 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8f1ab3dc21..1425ca7926 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2003-05-19 David Carlton + + Partial fix for PR c++/827. + * cp-support.h: Include symtab.h. + Declare cp_lookup_symbol_nonlocal, cp_lookup_symbol_namespace. + * cp-namespace.c: Update contributors. + (cp_lookup_symbol_nonlocal): New. + (lookup_namespace_scope, cp_lookup_symbol_namespace) + (lookup_symbol_file): Ditto. + * c-lang.c (cplus_language_defn): Use cp_lookup_symbol_nonlocal. + * block.h: Declare block_scope, block_using, block_global_block. + * block.c (block_scope): New. + (block_using, block_global_block): Ditto. + * Makefile.in (cp_support_h): Depend on symtab_h. + * config/djgpp/fnchange.lst: Add testsuite/gdb.c++/namespace1.cc. + 2003-05-19 David Carlton * language.h (struct language_defn): Add 'la_value_of_this' diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 197d17704f..b01642a006 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -626,7 +626,7 @@ complaints_h = complaints.h completer_h = completer.h config_h = config.h cp_abi_h = cp-abi.h -cp_support_h = cp-support.h +cp_support_h = cp-support.h $(symtab_h) dcache_h = dcache.h defs_h = defs.h $(config_h) $(gdb_locale_h) $(gdb_signals_h) $(ansidecl_h) \ $(libiberty_h) $(progress_h) $(bfd_h) $(tui_h) $(ui_file_h) $(xm_h) \ diff --git a/gdb/block.c b/gdb/block.c index 1360a1589d..3396c8aa96 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -155,8 +155,25 @@ block_for_pc (register CORE_ADDR pc) return block_for_pc_sect (pc, find_pc_mapped_section (pc)); } -/* Now come some functions designed to deal with C++ namespace - issues. */ +/* Now come some functions designed to deal with C++ namespace issues. + The accessors are safe to use even in the non-C++ case. */ + +/* This returns the namespace that BLOCK is enclosed in, or "" if it + isn't enclosed in a namespace at all. This travels the chain of + superblocks looking for a scope, if necessary. */ + +const char * +block_scope (const struct block *block) +{ + for (; block != NULL; block = BLOCK_SUPERBLOCK (block)) + { + if (BLOCK_NAMESPACE (block) != NULL + && BLOCK_NAMESPACE (block)->scope != NULL) + return BLOCK_NAMESPACE (block)->scope; + } + + return ""; +} /* Set BLOCK's scope member to SCOPE; if needed, allocate memory via OBSTACK. (It won't make a copy of SCOPE, however, so that already @@ -171,6 +188,27 @@ block_set_scope (struct block *block, const char *scope, BLOCK_NAMESPACE (block)->scope = scope; } +/* This returns the first using directives associated to BLOCK, if + any. */ + +/* FIXME: carlton/2003-04-23: This uses the fact that we currently + only have using directives in static blocks, because we only + generate using directives from anonymous namespaces. Eventually, + when we support using directives everywhere, we'll want to replace + this by some iterator functions. */ + +struct using_direct * +block_using (const struct block *block) +{ + const struct block *static_block = block_static_block (block); + + if (static_block == NULL + || BLOCK_NAMESPACE (static_block) == NULL) + return NULL; + else + return BLOCK_NAMESPACE (static_block)->using; +} + /* Set BLOCK's using member to USING; if needed, allocate memory via OBSTACK. (It won't make a copy of USING, however, so that already has to be allocated correctly.) */ @@ -214,3 +252,18 @@ block_static_block (const struct block *block) return block; } + +/* Return the static block associated to BLOCK. Return NULL if block + is NULL. */ + +const struct block * +block_global_block (const struct block *block) +{ + if (block == NULL) + return NULL; + + while (BLOCK_SUPERBLOCK (block) != NULL) + block = BLOCK_SUPERBLOCK (block); + + return block; +} diff --git a/gdb/block.h b/gdb/block.h index 17c726dc17..442fa4a86e 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -200,13 +200,19 @@ extern struct block *block_for_pc (CORE_ADDR); extern struct block *block_for_pc_sect (CORE_ADDR, asection *); +extern const char *block_scope (const struct block *block); + extern void block_set_scope (struct block *block, const char *scope, struct obstack *obstack); +extern struct using_direct *block_using (const struct block *block); + extern void block_set_using (struct block *block, struct using_direct *using, struct obstack *obstack); extern const struct block *block_static_block (const struct block *block); +extern const struct block *block_global_block (const struct block *block); + #endif /* BLOCK_H */ diff --git a/gdb/c-lang.c b/gdb/c-lang.c index 9f7ba8ef7e..bdbbb54172 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -32,6 +32,7 @@ #include "charset.h" #include "gdb_string.h" #include "demangle.h" +#include "cp-support.h" extern void _initialize_c_language (void); static void c_emit_char (int c, struct ui_file * stream, int quoter); @@ -610,7 +611,7 @@ const struct language_defn cplus_language_defn = c_value_print, /* Print a top-level value */ NULL, /* Language specific skip_trampoline */ value_of_this, /* value_of_this */ - basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ + cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ cplus_demangle, /* Language specific symbol demangler */ {"", "", "", ""}, /* Binary format info */ {"0%lo", "0", "o", ""}, /* Octal format info */ diff --git a/gdb/config/djgpp/fnchange.lst b/gdb/config/djgpp/fnchange.lst index 1b9fd8bf26..10287c9f89 100644 --- a/gdb/config/djgpp/fnchange.lst +++ b/gdb/config/djgpp/fnchange.lst @@ -244,6 +244,7 @@ @V@/gdb/testsuite/gdb.c++/misc.cc @V@/gdb/testsuite/gdb.cxx/misc.cc @V@/gdb/testsuite/gdb.c++/misc.exp @V@/gdb/testsuite/gdb.cxx/misc.exp @V@/gdb/testsuite/gdb.c++/namespace.cc @V@/gdb/testsuite/gdb.cxx/namespace.cc +@V@/gdb/testsuite/gdb.c++/namespace1.cc @V@/gdb/testsuite/gdb.cxx/namesp1.cc @V@/gdb/testsuite/gdb.c++/namespace.exp @V@/gdb/testsuite/gdb.cxx/namespace.exp @V@/gdb/testsuite/gdb.c++/overload.cc @V@/gdb/testsuite/gdb.cxx/overload.cc @V@/gdb/testsuite/gdb.c++/overload.exp @V@/gdb/testsuite/gdb.cxx/overload.exp diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index 7205cf7383..a4c7b8d357 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -1,7 +1,7 @@ /* Helper routines for C++ support in GDB. Copyright 2003 Free Software Foundation, Inc. - Contributed by David Carlton. + Contributed by David Carlton and by Kealia, Inc. This file is part of GDB. @@ -52,6 +52,21 @@ static struct using_direct *cp_add_using (const char *name, static struct using_direct *cp_copy_usings (struct using_direct *using, struct obstack *obstack); +static struct symbol *lookup_namespace_scope (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab, + const char *scope, + int scope_len); + +static struct symbol *lookup_symbol_file (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab, + int anonymous_namespace); + /* Set up support for dealing with C++ namespace info in the current symtab. */ @@ -264,3 +279,177 @@ cp_copy_usings (struct using_direct *using, return retval; } } + +/* The C++-specific version of name lookup for static and global + names. This makes sure that names get looked for in all namespaces + that are in scope. NAME is the natural name of the symbol that + we're looking for, LINKAGE_NAME (which is optional) is its linkage + name, BLOCK is the block that we're searching within, DOMAIN says + what kind of symbols we're looking for, and if SYMTAB is non-NULL, + we should store the symtab where we found the symbol in it. */ + +struct symbol * +cp_lookup_symbol_nonlocal (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab) +{ + return lookup_namespace_scope (name, linkage_name, block, domain, + symtab, block_scope (block), 0); +} + +/* Lookup NAME at namespace scope (or, in C terms, in static and + global variables). SCOPE is the namespace that the current + function is defined within; only consider namespaces whose length + is at least SCOPE_LEN. Other arguments are as in + cp_lookup_symbol_nonlocal. + + For example, if we're within a function A::B::f and looking for a + symbol f, this will get called with NAME = "f", SCOPE = "A::B", and + SCOPE_LEN = 0. It then calls itself with NAME and SCOPE the same, + but with SCOPE_LEN = 1. And then it calls itself with NAME and + SCOPE the same, but with SCOPE_LEN = 4. This third call looks for + "A::B::x"; if it doesn't find it, then the second call looks for + "A::x", and if that call fails, then the first call looks for + "x". */ + +static struct symbol * +lookup_namespace_scope (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab, + const char *scope, + int scope_len) +{ + char *namespace; + + if (scope[scope_len] != '\0') + { + /* Recursively search for names in child namespaces first. */ + + struct symbol *sym; + int new_scope_len = scope_len; + + /* If the current scope is followed by "::", skip past that. */ + if (new_scope_len != 0) + { + gdb_assert (scope[new_scope_len] == ':'); + new_scope_len += 2; + } + new_scope_len += cp_find_first_component (scope + new_scope_len); + sym = lookup_namespace_scope (name, linkage_name, block, + domain, symtab, + scope, new_scope_len); + if (sym != NULL) + return sym; + } + + /* Okay, we didn't find a match in our children, so look for the + name in the current namespace. */ + + namespace = alloca (scope_len + 1); + strncpy (namespace, scope, scope_len); + namespace[scope_len] = '\0'; + return cp_lookup_symbol_namespace (namespace, name, linkage_name, + block, domain, symtab); +} + +/* Look up NAME in the C++ namespace NAMESPACE, applying the using + directives that are active in BLOCK. Other arguments are as in + cp_lookup_symbol_nonlocal. */ + +struct symbol * +cp_lookup_symbol_namespace (const char *namespace, + const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab) +{ + const struct using_direct *current; + struct symbol *sym; + + /* First, go through the using directives. If any of them add new + names to the namespace we're searching in, see if we can find a + match by applying them. */ + + for (current = block_using (block); + current != NULL; + current = current->next) + { + if (strcmp (namespace, current->outer) == 0) + { + sym = cp_lookup_symbol_namespace (current->inner, + name, + linkage_name, + block, + domain, + symtab); + if (sym != NULL) + return sym; + } + } + + /* We didn't find anything by applying any of the using directives + that are still applicable; so let's see if we've got a match + using the current namespace. */ + + if (namespace[0] == '\0') + { + return lookup_symbol_file (name, linkage_name, block, + domain, symtab, 0); + } + else + { + char *concatenated_name + = alloca (strlen (namespace) + 2 + strlen (name) + 1); + strcpy (concatenated_name, namespace); + strcat (concatenated_name, "::"); + strcat (concatenated_name, name); + sym = lookup_symbol_file (concatenated_name, linkage_name, + block, domain, symtab, + cp_is_anonymous (namespace)); + return sym; + } +} + +/* Look up NAME in BLOCK's static block and in global blocks. If + ANONYMOUS_NAMESPACE is nonzero, the symbol in question is located + within an anonymous namespace. Other arguments are as in + cp_lookup_symbol_nonlocal. */ + +static struct symbol * +lookup_symbol_file (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab, + int anonymous_namespace) +{ + struct symbol *sym = NULL; + + sym = lookup_symbol_static (name, linkage_name, block, domain, symtab); + if (sym != NULL) + return sym; + + if (anonymous_namespace) + { + /* Symbols defined in anonymous namespaces have external linkage + but should be treated as local to a single file nonetheless. + So we only search the current file's global block. */ + + 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; + } + else + { + return lookup_symbol_global (name, linkage_name, domain, symtab); + } +} diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 76e842b5d1..952d6a2b17 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -24,11 +24,14 @@ #ifndef CP_SUPPORT_H #define CP_SUPPORT_H +/* We need this for 'domain_enum', alas... */ + +#include "symtab.h" + /* Opaque declarations. */ struct obstack; struct block; -struct symbol; /* This struct is designed to store data from using directives. It says that names from namespace INNER should be visible within @@ -78,4 +81,17 @@ extern void cp_set_block_scope (const struct symbol *symbol, extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol); +extern struct symbol *cp_lookup_symbol_nonlocal (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab); + +extern struct symbol *cp_lookup_symbol_namespace (const char *namespace, + const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + struct symtab **symtab); + #endif /* CP_SUPPORT_H */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 27eae486e2..a2fb2dbec8 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2003-05-19 David Carlton + + * gdb.c++/namespace.exp: Add namespace scope and anonymous + namespace tests. + Bump copyright date. + * gdb.c++/namespace.cc: Add anonymous namespace and namespace C. + (main): Call C::D::marker2. + * gdb.c++/namespace1.cc: New file. + 2003-05-14 Jeff Johnston Roland McGrath diff --git a/gdb/testsuite/gdb.c++/namespace.cc b/gdb/testsuite/gdb.c++/namespace.cc index 7667266c27..7b9a173d81 100644 --- a/gdb/testsuite/gdb.c++/namespace.cc +++ b/gdb/testsuite/gdb.c++/namespace.cc @@ -68,6 +68,70 @@ void marker1(void) return; } +namespace +{ + int X = 9; + + namespace G + { + int Xg = 10; + } +} + +namespace C +{ + int c = 1; + int shadow = 12; + + namespace + { + int cX = 6; + + namespace F + { + int cXf = 7; + } + } + + namespace C + { + int cc = 2; + } + + namespace D + { + int cd = 3; + int shadow = 13; + + namespace E + { + int cde = 5; + } + + void marker2 (void) + { + // NOTE: carlton/2003-04-23: I'm listing the expressions that I + // plan to have GDB try to print out, just to make sure that the + // compiler and I agree which ones should be legal! It's easy + // to screw up when testing the boundaries of namespace stuff. + c; + //cc; + C::cc; + cd; + E::cde; + shadow; + cX; + F::cXf; + X; + G::Xg; + //cXOtherFile; + //XOtherFile; + + return; + } + + } +} int main () { @@ -95,9 +159,5 @@ int main () marker1(); + C::D::marker2 (); } - - - - - diff --git a/gdb/testsuite/gdb.c++/namespace.exp b/gdb/testsuite/gdb.c++/namespace.exp index 3e502c4b50..f4efaf64d2 100644 --- a/gdb/testsuite/gdb.c++/namespace.exp +++ b/gdb/testsuite/gdb.c++/namespace.exp @@ -1,4 +1,4 @@ -# Copyright 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. +# Copyright 1997, 1998, 2000, 2001, 2002, 2003 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 @@ -39,20 +39,26 @@ if { [skip_cplus_tests] } { continue } set testfile "namespace" set srcfile ${testfile}.cc +set objfile ${objdir}/${subdir}/${testfile}.o +set srcfile1 ${testfile}1.cc +set objfile1 ${objdir}/${subdir}/${testfile}1.o set binfile ${objdir}/${subdir}/${testfile} if [get_compiler_info ${binfile}] { return -1; } - - -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { - gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will a -utomatically fail." +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug c++}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." } +if { [gdb_compile "${srcdir}/${subdir}/${srcfile1}" "${objfile1}" object {debug c++}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} +if { [gdb_compile "${objfile} ${objfile1}" "${binfile}" executable {debug c++}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} gdb_exit gdb_start @@ -186,3 +192,28 @@ gdb_expect { timeout { fail "(timeout) break BBB::Class::xyzq" } } +# Test to see if the appropriate namespaces are in scope when trying +# to print out stuff from within a function defined within a +# namespace. + +if ![runto "C::D::marker2"] then { + perror "couldn't run to marker2" + continue +} + +gdb_test "print c" "\\$\[0-9\].* = 1" +gdb_test "print cc" "No symbol \"cc\" in current context." +gdb_test "print 'C::cc'" "\\$\[0-9\].* = 2" +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" + +# Some anonymous namespace tests. + +gdb_test "print cX" "\\$\[0-9\].* = 6" +gdb_test "print 'F::cXf'" "\\$\[0-9\].* = 7" +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." -- 2.34.1