[gdb/exp] Handle recursive namespace import

Consider test.c, compiled to a.out using "g++ -g test.c":
...
     1  namespace mod_a { int xxx = 10; }
     2  namespace mod_b { using namespace mod_a;
     3                    int yyy = 20; }
     4  int main (void) {
     5    using namespace mod_b;
     6    void (xxx + yyy);
     7    return 0;
     8  }
...

When trying to print the value of variable xxx we get:
...
$ gdb -q -batch a.out -ex start -ex "print xxx"
  ...
Temporary breakpoint 1, main () at test.c:7
7           return 0;
No symbol "xxx" in current context.
...

The symbol xxx is defined in namespace mod_a, so it's available as:
...
(gdb) p mod_a::xxx
$1 = 10
...
and namespace mod_b uses namespace mod_a, so it's available as:
...
(gdb) p mod_b::xxx
$2 = 10
...

Then main uses namespace mod_b so xxx should also be available in main, but
it's not.

The problem happens here in cp_lookup_symbol_via_imports:
...
Thread 1 "gdb" hit Breakpoint 1, cp_lookup_symbol_via_imports (scope=0x5f43d0 "",
    name=0xfffffffface0 "xxx", block=0x2fba5a0, domain=..., search_scope_first=0,
    declaration_only=0, search_parents=1, found_symbols=...)
    at /home/vries/gdb/src/gdb/cp-namespace.c:505
505                   cp_lookup_symbol_via_imports (current->import_src, name,
...

We're about to follow the "using namespace mod_b" statement:
...
(gdb) p *current
$1 = {import_src = 0x2ed2140 "mod_b", import_dest = 0x66e910 "", alias = 0x0,
      declaration = 0x0, next = 0x0, decl_line = 5, searched = 1,
      excludes = {0x0}}
...

But it does so using the current block, which is the function block for main:
...
(gdb) p block->function ().m_name
$7 = 0x2f8bc20 "main()"
...
and the block containing the "using namespace mod_a" statement is the static
block.

Fix this by additionally iterating over the static and global blocks instead
of only using the current block.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34034
This commit is contained in:
Tom de Vries 2026-07-14 10:43:14 +02:00
parent 6f6e739987
commit 2e2f760e57
2 changed files with 25 additions and 6 deletions

View file

@ -520,9 +520,13 @@ cp_lookup_symbol_via_imports (const char *scope,
/* If this import statement creates no alias, pass
current->inner as NAMESPACE to direct the search
towards the imported namespace. */
cp_lookup_symbol_via_imports (current->import_src, name,
block, domain, 1, 0, 0,
found_symbols);
for (const struct block *b = block; b != nullptr;
b = ((b->is_static_block () || b->is_global_block ())
? b->superblock ()
: b->static_block ()))
cp_lookup_symbol_via_imports (current->import_src, name,
b, domain, 1, 0, 0,
found_symbols);
}
}

View file

@ -22,6 +22,11 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
return
}
# Xfail for incorrect decl_line on DW_TAG_imported_module,
# GCC PR debug/108716.
set have_gcc108716_xfail \
[expr {[test_compiler_info gcc-*] && [gcc_major_version] < 13}]
with_test_prefix pre-main {
gdb_test "print mod_a::xxx" " = 10"
gdb_test "print mod_b::yyy" " = 20"
@ -45,8 +50,19 @@ with_test_prefix start-of-main {
gdb_test "print mod_b::xxx" " = 10"
# Same command as in end-of-main, but not a regression test for PR34034.
gdb_test "print xxx" \
[string_to_regexp {No symbol "xxx" in current context.}]
set re_pass [string_to_regexp {No symbol "xxx" in current context.}]
set re_xfail "$valnum_re = 10"
gdb_test_multiple "print xxx" "" {
-re -wrap $re_pass {
pass $gdb_test_name
}
-re -wrap $re_xfail {
if {$have_gcc108716_xfail} {
setup_xfail *-*-* gcc/108716
}
fail $gdb_test_name
}
}
# Same test as in end-of-main, but not a regression test for PR34051.
gdb_test "print mod_a::yyy" \
@ -66,7 +82,6 @@ foreach_with_prefix n {1 2 3 4} {
# Function main is using namespace mod_b, and namespace mod_b is using
# namespace mod_a, so mod_a::xxx is available as xxx. Regression test for
# PR34034.
setup_kfail exp/34034 *-*-*
gdb_test "print xxx" " = 10"
# This used to print " $<n> = 20". Regression test for PR34051.