* [PATCH v4 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
2026-04-15 10:07 [PATCH v4 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
@ 2026-04-15 10:07 ` Tom de Vries
2026-04-15 10:07 ` [PATCH v4 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
1 sibling, 0 replies; 3+ messages in thread
From: Tom de Vries @ 2026-04-15 10:07 UTC (permalink / raw)
To: gdb-patches
In cp_lookup_symbol_via_imports, we have a complex assignment:
...
directive_match = (search_parents
? (startswith (scope, current->import_dest)
&& (len == 0
|| scope[len] == ':'
|| scope[len] == '\0'))
: streq (scope, current->import_dest));
...
Writing it like this makes it:
- harder to comment on parts of the expression, and also
- harder to understand and modify it.
Also, len == 0 makes the startswith redundant, so that part of the expression
can be hoisted. Doing so makes it clear that scope is not compared against in
all cases.
Fix this by breaking this up into three separate assignments:
...
if (search_parents)
{
if (len == 0)
directive_match = true;
else
directive_match = (startswith (scope, current->import_dest)
&& (scope[len] == ':'
|| scope[len] == '\0'));
}
else
directive_match = streq (scope, current->import_dest);
...
Approved-By: Tom Tromey <tom@tromey.com>
---
gdb/cp-namespace.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index c8cd5c245aa..1903287770b 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -394,7 +394,6 @@ cp_lookup_symbol_via_imports (const char *scope,
{
struct block_symbol sym = {};
int len;
- int directive_match;
/* All the symbols we found will be kept in this relational map between
the mangled name and the block_symbol found. We do this so that GDB
@@ -425,13 +424,21 @@ cp_lookup_symbol_via_imports (const char *scope,
do not use this directive. */
if (!current->valid_line (boundary_sal.line))
continue;
+
len = strlen (current->import_dest);
- directive_match = (search_parents
- ? (startswith (scope, current->import_dest)
- && (len == 0
- || scope[len] == ':'
- || scope[len] == '\0'))
- : streq (scope, current->import_dest));
+
+ bool directive_match;
+ if (search_parents)
+ {
+ if (len == 0)
+ directive_match = true;
+ else
+ directive_match = (startswith (scope, current->import_dest)
+ && (scope[len] == ':'
+ || scope[len] == '\0'));
+ }
+ else
+ directive_match = streq (scope, current->import_dest);
/* If the import destination is the current scope or one of its
ancestors then it is applicable. */
--
2.51.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v4 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix
2026-04-15 10:07 [PATCH v4 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
2026-04-15 10:07 ` [PATCH v4 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
@ 2026-04-15 10:07 ` Tom de Vries
1 sibling, 0 replies; 3+ messages in thread
From: Tom de Vries @ 2026-04-15 10:07 UTC (permalink / raw)
To: gdb-patches
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 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 = 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.
Fix this by being more strict in the calculation of directive_match:
...
if (len == 0)
- directive_match = true;
+ {
+ const char *current_scope = (block->function_block () != nullptr
+ ? block->scope ()
+ : nullptr /* Don't know. */);
+ directive_match = (current_scope != nullptr
+ ? streq (scope, current_scope)
+ : true /* Assume there's a match. */);
+ }
...
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 cornercase we
haven't run into yet. If so, it's a pre-existing issue.
The new test-case contains regression tests for:
- PR34051, and
- PR34034 for which it contains a kfail.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34051
---
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(-)
create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.cc
create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.exp
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 1903287770b..d7a960127dc 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -431,7 +431,14 @@ cp_lookup_symbol_via_imports (const char *scope,
if (search_parents)
{
if (len == 0)
- directive_match = true;
+ {
+ const char *current_scope = (block->function_block () != nullptr
+ ? block->scope ()
+ : nullptr /* Don't know. */);
+ directive_match = (current_scope != nullptr
+ ? streq (scope, current_scope)
+ : true /* Assume there's a match. */);
+ }
else
directive_match = (startswith (scope, current->import_dest)
&& (scope[len] == ':'
diff --git a/gdb/testsuite/gdb.cp/nsusing-2.cc b/gdb/testsuite/gdb.cp/nsusing-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 = 10;
+}
+
+namespace mod_b {
+ using namespace mod_a;
+ int yyy = 20;
+}
+
+static void foo () {}
+
+int
+main (void)
+{
+ foo (); /* main-entry. */
+
+ { /* Variant 1: using block is stop block, using block is not function block. */
+ 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/nsusing-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 PR34051.
+
+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" " = 10"
+ gdb_test "print mod_b::yyy" " = 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" " = 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.}]
+
+ # 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 variants.
+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" " = 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" " = 10"
+
+ # This used to print " $<n> = 20". Regression test for PR34051.
+ gdb_test "print mod_a::yyy" \
+ [string_to_regexp {No symbol "yyy" in namespace "mod_a".}]
+}
--
2.51.0
^ permalink raw reply [flat|nested] 3+ messages in thread