[binutils-gdb] [gdb/exp] Handle recursive namespace import

Tom de Vries via Gdb-cvs <[email protected]> Tue, 14 Jul 2026 08:43:30 +0000 (GMT)
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D2e2f760e5765=
fbc923aac825ea3118c06ff5d827

commit 2e2f760e5765fbc923aac825ea3118c06ff5d827
Author: Tom de Vries <[email protected]>
Date:   Tue Jul 14 10:43:14 2026 +0200

    [gdb/exp] Handle recursive namespace import
   =20
    Consider test.c, compiled to a.out using "g++ -g test.c":
    ...
         1  namespace mod_a { int xxx =3D 10; }
         2  namespace mod_b { using namespace mod_a;
         3                    int yyy =3D 20; }
         4  int main (void) {
         5    using namespace mod_b;
         6    void (xxx + yyy);
         7    return 0;
         8  }
    ...
   =20
    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.
    ...
   =20
    The symbol xxx is defined in namespace mod_a, so it's available as:
    ...
    (gdb) p mod_a::xxx
    $1 =3D 10
    ...
    and namespace mod_b uses namespace mod_a, so it's available as:
    ...
    (gdb) p mod_b::xxx
    $2 =3D 10
    ...
   =20
    Then main uses namespace mod_b so xxx should also be available in main,=
 but
    it's not.
   =20
    The problem happens here in cp_lookup_symbol_via_imports:
    ...
    Thread 1 "gdb" hit Breakpoint 1, cp_lookup_symbol_via_imports (scope=3D=
0x5f43d0 "",
        name=3D0xfffffffface0 "xxx", block=3D0x2fba5a0, domain=3D..., searc=
h_scope_first=3D0,
        declaration_only=3D0, search_parents=3D1, found_symbols=3D...)
        at /home/vries/gdb/src/gdb/cp-namespace.c:505
    505                   cp_lookup_symbol_via_imports (current->import_src=
, name,
    ...
   =20
    We're about to follow the "using namespace mod_b" statement:
    ...
    (gdb) p *current
    $1 =3D {import_src =3D 0x2ed2140 "mod_b", import_dest =3D 0x66e910 "", =
alias =3D 0x0,
          declaration =3D 0x0, next =3D 0x0, decl_line =3D 5, searched =3D =
1,
          excludes =3D {0x0}}
    ...
   =20
    But it does so using the current block, which is the function block for=
 main:
    ...
    (gdb) p block->function ().m_name
    $7 =3D 0x2f8bc20 "main()"
    ...
    and the block containing the "using namespace mod_a" statement is the s=
tatic
    block.
   =20
    Fix this by additionally iterating over the static and global blocks in=
stead
    of only using the current block.
   =20
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34034

Diff:
---
 gdb/cp-namespace.c                 | 10 +++++++---
 gdb/testsuite/gdb.cp/nsusing-2.exp | 21 ++++++++++++++++++---
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 17c4d40e294..ce7cba3d264 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -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 =3D block; b !=3D nullptr;
+		   b =3D ((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);
 	    }
=20
 	}
diff --git a/gdb/testsuite/gdb.cp/nsusing-2.exp b/gdb/testsuite/gdb.cp/nsus=
ing-2.exp
index 65e685d0d32..417b4097989 100644
--- a/gdb/testsuite/gdb.cp/nsusing-2.exp
+++ b/gdb/testsuite/gdb.cp/nsusing-2.exp
@@ -22,6 +22,11 @@ if {[prepare_for_testing "failed to prepare" $testfile $=
srcfile \
     return
 }
=20
+# 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" " =3D 10"
     gdb_test "print mod_b::yyy" " =3D 20"
@@ -45,8 +50,19 @@ with_test_prefix start-of-main {
     gdb_test "print mod_b::xxx" " =3D 10"
=20
     # Same command as in end-of-main, but not a regression test for PR3403=
4.
-    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 =3D 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
+	}
+    }
=20
     # 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" " =3D 10"
=20
     # This used to print " $<n> =3D 20".  Regression test for PR34051.