[binutils-gdb] [gdb/exp] Fix ignoring of incorrect namespace prefix
Tom de Vries via Gdb-cvs <[email protected]> Tue, 14 Jul 2026 08:43:25 +0000 (GMT)
| Newsgroups | gmane.comp.gdb.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D6f6e739987d6= f0b904aa8e6d6bc7cc4e3d71d408 commit 6f6e739987d6f0b904aa8e6d6bc7cc4e3d71d408 Author: Tom de Vries <[email protected]> Date: Tue Jul 14 10:43:14 2026 +0200 [gdb/exp] Fix ignoring of incorrect namespace prefix =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 non-existent variable mod_a::yyy, we = get: ... $ gdb -q -batch a.out -ex start -ex "print mod_a::yyy" ... Temporary breakpoint 1, main () at test.c:7 7 return 0; $1 =3D 20 ... =20 The problem is in cp_lookup_symbol_via_imports, where we decide that the "using namespace mod_b" from main is applicable in scope mod_a. =20 More concretely, cp_lookup_symbol_via_imports is called with: - scope =3D=3D "mod_a", - name =3D=3D "yyy", and - block.m_function.m_name =3D=3D "main()", and when looking at "using namespace mod_b": ... (gdb) p *current $12 =3D {import_src =3D 0x344018c "mod_b", import_dest =3D 0x1b477a0 "", alias =3D 0x0, declaration =3D 0x0, next =3D 0x0, decl_line =3D = 5, searched =3D 0, excludes =3D {0x0}} ... we hit "directive_match =3D true" because strlen (current->import_dest)= =3D=3D 0. =20 Fix this by being more strict in the calculation of directive_match: ... if (len =3D=3D 0) - directive_match =3D true; + { + const char *current_scope =3D (block->function_block () != =3D nullptr + ? block->scope () + : nullptr /* Don't know. */= ); + directive_match =3D (current_scope !=3D nullptr + ? streq (scope, current_scope) + : true /* Assume there's a match. */); + } ... which gets us: - current_scope =3D=3D "", and - directive_match =3D=3D false, because scope =3D=3D "mod_a", so streq (scope, current_scope) =3D=3D fa= lse. =20 As is clear from the code, in case we don't know the current scope, we = assume there's a match. This may be harmless, or this may describe a cornerca= se we haven't run into yet. If so, it's a pre-existing issue. =20 The new test-case contains regression tests for: - PR34051, and - PR34034 for which it contains a kfail. =20 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34051 Diff: --- gdb/cp-namespace.c | 9 ++++- gdb/testsuite/gdb.cp/nsusing-2.cc | 62 +++++++++++++++++++++++++++++++ gdb/testsuite/gdb.cp/nsusing-2.exp | 75 ++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 145 insertions(+), 1 deletion(-) diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index 87c491d821b..17c4d40e294 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -449,7 +449,14 @@ cp_lookup_symbol_via_imports (const char *scope, if (search_parents) { if (len =3D=3D 0) - directive_match =3D true; + { + const char *current_scope =3D (block->function_block () !=3D nullptr + ? block->scope () + : nullptr /* Don't know. */); + directive_match =3D (current_scope !=3D nullptr + ? streq (scope, current_scope) + : true /* Assume there's a match. */); + } else directive_match =3D (startswith (scope, current->import_dest) && (scope[len] =3D=3D ':' diff --git a/gdb/testsuite/gdb.cp/nsusing-2.cc b/gdb/testsuite/gdb.cp/nsusi= ng-2.cc new file mode 100644 index 00000000000..226bda3e101 --- /dev/null +++ b/gdb/testsuite/gdb.cp/nsusing-2.cc @@ -0,0 +1,62 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. = */ + +/* C++ variant of the Fortran example from PR34034. */ + +namespace mod_a { + int xxx =3D 10; +} + +namespace mod_b { + using namespace mod_a; + int yyy =3D 20; +} + +static void foo () {} + +int +main (void) +{ + foo (); /* main-entry. */ + + { /* Variant 1: using block is stop block, using block is not function b= lock. */ + using namespace mod_b; + void (xxx + yyy); + foo (); /* main-1. */ + } + + { /* Variant 2: using block is super block of stop block, using block is= not function block. */ + using namespace mod_b; + { + void (xxx + yyy); + foo (); /* main-2. */ + } + } + + using namespace mod_b; + + { /* Variant 3: using block is super block of stop block, using block is= function block. */ + void (xxx + yyy); + foo (); /* main-3. */ + } + + /* Variant 4: using block is stop block, using block is function block. = */ + void (xxx + yyy); + foo (); /* main-4. */ + + return 0; +} diff --git a/gdb/testsuite/gdb.cp/nsusing-2.exp b/gdb/testsuite/gdb.cp/nsus= ing-2.exp new file mode 100644 index 00000000000..65e685d0d32 --- /dev/null +++ b/gdb/testsuite/gdb.cp/nsusing-2.exp @@ -0,0 +1,75 @@ +# Copyright 2026 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 +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test recursive "using namespace". Regression test for PR34034 and PR340= 51. + +standard_testfile .cc + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + {debug c++}]} { + return +} + +with_test_prefix pre-main { + gdb_test "print mod_a::xxx" " =3D 10" + gdb_test "print mod_b::yyy" " =3D 20" + + # Namespace mod_b is using namespace mod_a, so mod_a::xxx is available= as + # mod_b::xxx. This is not available here though, but later, at + # start-of-main. I wonder if this should also be available here. + gdb_test "print mod_b::xxx" \ + [string_to_regexp {No symbol "xxx" in namespace "mod_b".}] +} + +set line_main_entry [gdb_get_line_number main-entry] +if {![runto $srcfile:$line_main_entry]} { + return +} + +# Start of main. Function main is not yet using namespace mod_b. +with_test_prefix start-of-main { + # Namespace mod_b is using namespace mod_a, so mod_a::xxx is available= as + # mod_b::xxx. See also the note at the identical command in pre-main. + gdb_test "print mod_b::xxx" " =3D 10" + + # 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.}] + + # Same test as in end-of-main, but not a regression test for PR34051. + gdb_test "print mod_a::yyy" \ + [string_to_regexp {No symbol "yyy" in namespace "mod_a".}] +} + +# After start of main. Function main is using namespace mod_b. Check 4 v= ariants. +foreach_with_prefix n {1 2 3 4} { + set line_main_n [gdb_get_line_number "main-$n"] + gdb_test "next" \ + [subst_vars {$line_main_n\t[^\r\n]+}] + + # Function main is using namespace mod_b, so mod_b::yyy is available as + # yyy. + gdb_test "print yyy" " =3D 20" + + # 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" + + # This used to print " $<n> =3D 20". Regression test for PR34051. + gdb_test "print mod_a::yyy" \ + [string_to_regexp {No symbol "yyy" in namespace "mod_a".}] +}