* [PATCH v6 1/3] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
2026-05-12 10:21 [PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
@ 2026-05-12 10:21 ` Tom de Vries
2026-05-12 10:21 ` [PATCH v6 2/3] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-05-12 10:21 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] 6+ messages in thread* [PATCH v6 2/3] [gdb/exp] Fix ignoring of incorrect namespace prefix
2026-05-12 10:21 [PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
2026-05-12 10:21 ` [PATCH v6 1/3] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
@ 2026-05-12 10:21 ` Tom de Vries
2026-05-12 10:21 ` [PATCH v6 3/3] [gdb/exp] Handle recursive namespace import Tom de Vries
2026-05-26 10:01 ` [PING][PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
3 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-05-12 10:21 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.
More concretely, cp_lookup_symbol_via_imports is called with:
- scope == "mod_a",
- name == "yyy", and
- block.m_function.m_name == "main()",
and when looking at "using namespace mod_b":
...
(gdb) p *current
$12 = {import_src = 0x344018c "mod_b", import_dest = 0x1b477a0 "",
alias = 0x0, declaration = 0x0, next = 0x0, decl_line = 5,
searched = 0, excludes = {0x0}}
...
we hit "directive_match = true" because strlen (current->import_dest) == 0.
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. */);
+ }
...
which gets us:
- current_scope == "", and
- directive_match == false,
because scope == "mod_a", so streq (scope, current_scope) == false.
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] 6+ messages in thread* [PATCH v6 3/3] [gdb/exp] Handle recursive namespace import
2026-05-12 10:21 [PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
2026-05-12 10:21 ` [PATCH v6 1/3] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
2026-05-12 10:21 ` [PATCH v6 2/3] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
@ 2026-05-12 10:21 ` Tom de Vries
2026-05-26 10:01 ` [PING][PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
3 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-05-12 10:21 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 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
---
gdb/cp-namespace.c | 10 +++++++---
gdb/testsuite/gdb.cp/nsusing-2.exp | 1 -
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index d7a960127dc..9e37265b27d 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -502,9 +502,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);
}
}
diff --git a/gdb/testsuite/gdb.cp/nsusing-2.exp b/gdb/testsuite/gdb.cp/nsusing-2.exp
index 65e685d0d32..5a2eac5ce67 100644
--- a/gdb/testsuite/gdb.cp/nsusing-2.exp
+++ b/gdb/testsuite/gdb.cp/nsusing-2.exp
@@ -66,7 +66,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.
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PING][PATCH v6 0/3] [gdb/exp] Fix some namespace issues
2026-05-12 10:21 [PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
` (2 preceding siblings ...)
2026-05-12 10:21 ` [PATCH v6 3/3] [gdb/exp] Handle recursive namespace import Tom de Vries
@ 2026-05-26 10:01 ` Tom de Vries
2026-07-14 8:43 ` Tom de Vries
3 siblings, 1 reply; 6+ messages in thread
From: Tom de Vries @ 2026-05-26 10:01 UTC (permalink / raw)
To: gdb-patches
On 5/12/26 12:21 PM, Tom de Vries wrote:
> Hafiz Abid Qadeer reported PR34034, a problem with namespace handling using a
> Fortran program. I wrote an equivalent program in C++, and reproduced the
> reported problem with both. While investigating the problem, I ran into
> another problem, for which I filed PR34051.
>
> This series contains three patches.
>
> The first patch refactors a complex assignment in
> cp_lookup_symbol_via_imports.
>
> The second patch fixes PR34051, in that same assignment.
>
> The third patch fixes PR34034.
>
Ping.
Thanks,
- Tom
> Tested on aarch64-linux.
>
> Changes in v2 [2]:
> - updated type of directive_match to bool
>
> Changes in v3 [3]:
> - fixed top-level "return -1" in test-case
> - fixed typo in test-case
>
> Changes in v4 [4]:
> - don't use 1 to set bool
> - added approval tag to first patch
> - replaced "block->function () != nullptr" with
> "block->function_block () != nullptr" to handle the case that current block
> is not a function block, but nested in one
> - extended test-case to exercise nested block scenario
>
> Changes in v5:
> - add third patch to fix PR34034
> - update description subject to reflect that we're fixing two PRs
>
> Changes in v6:
> - extend commit message for second patch
> - fix third patch to handle inlined function correctly
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34034
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34051
>
> Versions:
> - v1 https://sourceware.org/pipermail/gdb-patches/2026-April/226370.html
> - v2 https://sourceware.org/pipermail/gdb-patches/2026-April/226375.html
> - v3 https://sourceware.org/pipermail/gdb-patches/2026-April/226433.html
> - v4 https://sourceware.org/pipermail/gdb-patches/2026-April/226488.html
> - v5 https://sourceware.org/pipermail/gdb-patches/2026-April/226628.html
>
> Tom de Vries (3):
> [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
> [gdb/exp] Fix ignoring of incorrect namespace prefix
> [gdb/exp] Handle recursive namespace import
>
> gdb/cp-namespace.c | 38 +++++++++++----
> gdb/testsuite/gdb.cp/nsusing-2.cc | 62 +++++++++++++++++++++++++
> gdb/testsuite/gdb.cp/nsusing-2.exp | 74 ++++++++++++++++++++++++++++++
> 3 files changed, 164 insertions(+), 10 deletions(-)
> create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.cc
> create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.exp
>
>
> base-commit: 2d7f2dbbd4adadf7c388fa0d8b9ce95d9dfde641
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PING][PATCH v6 0/3] [gdb/exp] Fix some namespace issues
2026-05-26 10:01 ` [PING][PATCH v6 0/3] [gdb/exp] Fix some namespace issues Tom de Vries
@ 2026-07-14 8:43 ` Tom de Vries
0 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-07-14 8:43 UTC (permalink / raw)
To: gdb-patches
On 5/26/26 12:01 PM, Tom de Vries wrote:
> On 5/12/26 12:21 PM, Tom de Vries wrote:
>> Hafiz Abid Qadeer reported PR34034, a problem with namespace handling
>> using a
>> Fortran program. I wrote an equivalent program in C++, and reproduced
>> the
>> reported problem with both. While investigating the problem, I ran into
>> another problem, for which I filed PR34051.
>>
>> This series contains three patches.
>>
>> The first patch refactors a complex assignment in
>> cp_lookup_symbol_via_imports.
>>
>> The second patch fixes PR34051, in that same assignment.
>>
>> The third patch fixes PR34034.
>>
>
> Ping.
>
I've pushed this, with a trivial update to the test-case to add an xfail
for GCC PR debug/108716.
Thanks,
- Tom
> Thanks,
> - Tom
>
>> Tested on aarch64-linux.
>>
>> Changes in v2 [2]:
>> - updated type of directive_match to bool
>>
>> Changes in v3 [3]:
>> - fixed top-level "return -1" in test-case
>> - fixed typo in test-case
>>
>> Changes in v4 [4]:
>> - don't use 1 to set bool
>> - added approval tag to first patch
>> - replaced "block->function () != nullptr" with
>> "block->function_block () != nullptr" to handle the case that
>> current block
>> is not a function block, but nested in one
>> - extended test-case to exercise nested block scenario
>>
>> Changes in v5:
>> - add third patch to fix PR34034
>> - update description subject to reflect that we're fixing two PRs
>>
>> Changes in v6:
>> - extend commit message for second patch
>> - fix third patch to handle inlined function correctly
>>
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34034
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34051
>>
>> Versions:
>> - v1 https://sourceware.org/pipermail/gdb-patches/2026-April/226370.html
>> - v2 https://sourceware.org/pipermail/gdb-patches/2026-April/226375.html
>> - v3 https://sourceware.org/pipermail/gdb-patches/2026-April/226433.html
>> - v4 https://sourceware.org/pipermail/gdb-patches/2026-April/226488.html
>> - v5 https://sourceware.org/pipermail/gdb-patches/2026-April/226628.html
>>
>> Tom de Vries (3):
>> [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
>> [gdb/exp] Fix ignoring of incorrect namespace prefix
>> [gdb/exp] Handle recursive namespace import
>>
>> gdb/cp-namespace.c | 38 +++++++++++----
>> gdb/testsuite/gdb.cp/nsusing-2.cc | 62 +++++++++++++++++++++++++
>> gdb/testsuite/gdb.cp/nsusing-2.exp | 74 ++++++++++++++++++++++++++++++
>> 3 files changed, 164 insertions(+), 10 deletions(-)
>> create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.cc
>> create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.exp
>>
>>
>> base-commit: 2d7f2dbbd4adadf7c388fa0d8b9ce95d9dfde641
>
^ permalink raw reply [flat|nested] 6+ messages in thread