[PATCH] [gdb/symtab] Fix DW_TAG_member regression
Tom de Vries
tdevries@suse.de
Thu Sep 11 13:19:56 GMT 2025
On openSUSE Leap 15.6 x86_64, with gcc 7 and test-case
gdb.base/condbreak-multi-context.exp I run into:
...
(gdb) print aaa^M
$3 = <optimized out>^M
(gdb) FAIL: $exp: start_before=true: scenario_1: print aaa
...
This is a regression since commit 86ac8c54623 ("Convert
lookup_symbol_in_objfile").
Likewise in test-cases gdb.cp/m-static.exp and gdb.cp/namespace.exp.
The failure is specific to using Dwarf v4:
- using target board unix/gdb:debug_flags=-gdwarf-5 fixes it
- using target board unix/gdb:debug_flags=-gdwarf-4 on Tumbleweed (with gcc 15
and Dwarf v5 default) triggers it
The variable we're trying to print, A::aaa is a static const int member:
...
class A : public Base
{
public:
static const int aaa = 10;
...
};
...
With Dwarf v5, we have this DIE:
...
<2><356>: Abbrev Number: 2 (DW_TAG_variable)
<357> DW_AT_name : aaa
<35c> DW_AT_linkage_name: _ZN1A3aaaE
<364> DW_AT_external : 1
<364> DW_AT_accessibility: 1 (public)
<364> DW_AT_declaration : 1
<364> DW_AT_const_value : 10
...
and the cooked index contains these corresponding entries:
...
[45] ((cooked_index_entry *) 0x7facf0004730)
name: _ZN1A3aaaE
canonical: _ZN1A3aaaE
qualified: _ZN1A3aaaE
DWARF tag: DW_TAG_variable
flags: 0x4 [IS_LINKAGE]
DIE offset: 0x356
parent: ((cooked_index_entry *) 0)
[52] ((cooked_index_entry *) 0x7facf0004700)
name: aaa
canonical: aaa
qualified: A::aaa
DWARF tag: DW_TAG_variable
flags: 0x0 []
DIE offset: 0x356
parent: ((cooked_index_entry *) 0x7facf00046d0) [A]
...
With Dwarf v4, we have instead the following DIE:
...
<2><350>: Abbrev Number: 3 (DW_TAG_member)
<351> DW_AT_name : aaa
<35b> DW_AT_external : 1
<35b> DW_AT_accessibility: 1 (public)
<35c> DW_AT_declaration : 1
<35c> DW_AT_const_value : 4 byte block: a 0 0 0
...
and there are no corresponding entries.
Fix this by adding an entry:
...
[47] ((cooked_index_entry *) 0x7f5a24004660)
name: aaa
canonical: aaa
qualified: A::aaa
DWARF tag: DW_TAG_member
flags: 0x0 []
DIE offset: 0x350
parent: ((cooked_index_entry *) 0x7f5a24004630) [A]
...
I tried to keep the changes as minimal as possible, and in the process learned
the following things:
- a change in write_cooked_index to emit GDB_INDEX_SYMBOL_KIND_VARIABLE for
DW_TAG_member was not necessary. Apparently GDB_INDEX_SYMBOL_KIND_OTHER
works fine.
- without the change in abbrev_table::read, the new Dwarf assembly test-case
gdb.dwarf2/static-const-member.exp still passes. So I added an additional
regression test gdb.cp/m-static-v4.exp.
Tested on x86_64-linux.
PR symtab/33415
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33415
---
gdb/dwarf2/abbrev.c | 5 +-
gdb/dwarf2/cooked-indexer.c | 3 +-
gdb/dwarf2/tag.h | 1 +
gdb/testsuite/gdb.cp/m-static-v4.exp | 19 ++
gdb/testsuite/gdb.cp/m-static.exp | 198 +---------------
gdb/testsuite/gdb.cp/m-static.exp.tcl | 212 ++++++++++++++++++
.../gdb.dwarf2/static-const-member.exp | 85 +++++++
7 files changed, 326 insertions(+), 197 deletions(-)
create mode 100644 gdb/testsuite/gdb.cp/m-static-v4.exp
create mode 100644 gdb/testsuite/gdb.cp/m-static.exp.tcl
create mode 100644 gdb/testsuite/gdb.dwarf2/static-const-member.exp
diff --git a/gdb/dwarf2/abbrev.c b/gdb/dwarf2/abbrev.c
index e3c268e7c47..ec173bb00ee 100644
--- a/gdb/dwarf2/abbrev.c
+++ b/gdb/dwarf2/abbrev.c
@@ -62,6 +62,7 @@ tag_interesting_for_index (dwarf_tag tag)
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
case DW_TAG_variable:
+ case DW_TAG_member:
return true;
}
@@ -243,7 +244,9 @@ abbrev_table::read (struct dwarf2_section_info *section,
cur_abbrev->interesting = true;
}
else if (has_hardcoded_declaration
- && (cur_abbrev->tag != DW_TAG_variable || !has_external))
+ && ((cur_abbrev->tag != DW_TAG_variable
+ && cur_abbrev->tag != DW_TAG_member)
+ || !has_external))
{
cur_abbrev->interesting = false;
if (cur_abbrev->tag == DW_TAG_subprogram && has_name
diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c
index 913ff77f890..19361b25517 100644
--- a/gdb/dwarf2/cooked-indexer.c
+++ b/gdb/dwarf2/cooked-indexer.c
@@ -290,7 +290,8 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu,
that is ok. Similarly, we allow an external variable without a
location; those are resolved via minimal symbols. */
if (is_declaration && !for_specification
- && !(abbrev->tag == DW_TAG_variable && (*flags & IS_STATIC) == 0))
+ && !((abbrev->tag == DW_TAG_variable || abbrev->tag == DW_TAG_member)
+ && (*flags & IS_STATIC) == 0))
{
/* We always want to recurse into some types, but we may not
want to treat them as definitions. */
diff --git a/gdb/dwarf2/tag.h b/gdb/dwarf2/tag.h
index 9b5c77554da..40936131938 100644
--- a/gdb/dwarf2/tag.h
+++ b/gdb/dwarf2/tag.h
@@ -76,6 +76,7 @@ tag_matches_domain (dwarf_tag tag, domain_search_flags search, language lang)
switch (tag)
{
case DW_TAG_variable:
+ case DW_TAG_member:
case DW_TAG_enumerator:
case DW_TAG_constant:
flags = SEARCH_VAR_DOMAIN;
diff --git a/gdb/testsuite/gdb.cp/m-static-v4.exp b/gdb/testsuite/gdb.cp/m-static-v4.exp
new file mode 100644
index 00000000000..e5c821f33fd
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/m-static-v4.exp
@@ -0,0 +1,19 @@
+# Copyright 2025 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/>.
+
+set flags {}
+lappend flags additional_flags=-gdwarf-4
+
+source ${srcdir}/gdb.cp/m-static.exp.tcl
diff --git a/gdb/testsuite/gdb.cp/m-static.exp b/gdb/testsuite/gdb.cp/m-static.exp
index 6b108040da5..b5bdee42883 100644
--- a/gdb/testsuite/gdb.cp/m-static.exp
+++ b/gdb/testsuite/gdb.cp/m-static.exp
@@ -1,4 +1,4 @@
-# Copyright 2002-2025 Free Software Foundation, Inc.
+# Copyright 2025 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
@@ -13,198 +13,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# Tests for member static data
-# 2002-05-13 Benjamin Kosnik <bkoz@redhat.com>
-# 2002-08-22 David Carlton <carlton@math.stanford.edu>
+set flags {}
-# This file is part of the gdb testsuite
-
-require allow_cplus_tests
-
-#
-# test running programs
-#
-
-standard_testfile .cc m-static1.cc
-
-include_file m-static.h
-
-set flags [list debug c++]
-if { [test_compiler_info gcc-*] && [gcc_major_version] >= 10 } {
- # Work around PR gcc/101452.
- lappend flags additional_flags=-fno-eliminate-unused-debug-types
-}
-
-if {[prepare_for_testing "failed to prepare" $testfile \
- [list $srcfile $srcfile2] $flags]} {
- return -1
-}
-
-if {![runto_main]} {
- return
-}
-
-get_debug_format
-set non_dwarf [expr ! [test_debug_format "DWARF \[0-9\]"]]
-
-# First, run to after we've constructed all the objects:
-
-gdb_breakpoint [gdb_get_line_number "constructs-done"]
-gdb_continue_to_breakpoint "end of constructors"
-
-
-# One.
-
-# simple object, static const bool
-gdb_test "print test1.test" "\\$\[0-9\]* = true" "simple object, static const bool"
-
-# simple object, static const int
-gdb_test "print test1.key1" "\\$\[0-9\]* = 5" "simple object, static const int"
-
-# simple object, static long
-gdb_test "print test1.key2" "\\$\[0-9\]* = 77" "simple object, static long"
-
-# simple object, static enum
-gdb_test "print test1.value" "\\$\[0-9\]* = oriental" "simple object, static enum"
-
-if { [is_aarch32_target] } {
- gdb_test "print test5.single_constructor" \
- { = {single_constructor \*\(single_constructor \* const\)} 0x[0-9a-f]+ <single_constructor::single_constructor\(\)>} \
- "simple object instance, print constructor"
-
- set re \
- [multi_line_string_to_regexp \
- "type = class single_constructor {" \
- "" \
- " public:" \
- " single_constructor(void);" \
- " ~single_constructor(void);" \
- "} *(single_constructor * const)"]
- gdb_test "ptype test5.single_constructor" $re \
- "simple object instance, ptype constructor"
- gdb_test "ptype single_constructor::single_constructor" $re \
- "simple object class, ptype constructor"
-
- gdb_test "print test1.~gnu_obj_1" \
- { = {void \*\(gnu_obj_1 \* const(, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
- "simple object instance, print destructor"
- gdb_test "ptype test1.~gnu_obj_1" \
- {type = void \*\(gnu_obj_1 \* const(, int)?\)} \
- "simple object instance, ptype destructor"
-
- gdb_test "print test1.'~gnu_obj_1'" \
- { = {void \*\(gnu_obj_1 \*( const)?(, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
- "simple object instance, print quoted destructor"
-
- gdb_test "ptype gnu_obj_1::'~gnu_obj_1'" \
- {type = void \*\(gnu_obj_1 \* const\)} \
- "simple object class, ptype quoted destructor"
-} else {
- gdb_test "print test5.single_constructor" \
- { = {void \(single_constructor \* const\)} 0x[0-9a-f]+ <single_constructor::single_constructor\(\)>} \
- "simple object instance, print constructor"
- gdb_test "ptype test5.single_constructor" \
- {type = void \(single_constructor \* const\)} \
- "simple object instance, ptype constructor"
- gdb_test "ptype single_constructor::single_constructor" \
- {type = void \(single_constructor \* const\)} \
- "simple object class, ptype constructor"
-
- gdb_test "print test1.~gnu_obj_1"\
- { = {void \(gnu_obj_1 \* const(?:, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>}\
- "simple object instance, print destructor"
-
- gdb_test "ptype test1.~gnu_obj_1"\
- {type = void \(gnu_obj_1 \* const(?:, int)?\)}\
- "simple object instance, ptype destructor"
-
- gdb_test "print test1.'~gnu_obj_1'" \
- { = {void \(gnu_obj_1 \*( const)?(?:, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
- "simple object instance, print quoted destructor"
-
- gdb_test "ptype gnu_obj_1::'~gnu_obj_1'" \
- {type = void \(gnu_obj_1 \* const\)} \
- "simple object class, ptype quoted destructor"
-}
-
-# Two.
-
-# derived template object, base static const bool
-gdb_test "print test2.test" "\\$\[0-9\]* = true" "derived template object, base static const bool"
-
-# derived template object, base static const int
-gdb_test "print test2.key1" "\\$\[0-9\]* = 5" "derived template object, base static const int"
-
-# derived template object, base static long
-gdb_test "print test2.key2" "\\$\[0-9\]* = 77" "derived template object, base static long"
-
-# derived template object, base static enum
-gdb_test "print test2.value" "\\$\[0-9\].* = oriental" "derived template object, base static enum"
-
-# derived template object, static enum
-gdb_test "print test2.value_derived" "\\$\[0-9\].* = etruscan" "derived template object, static enum"
-
-# Three.
-
-# template object, static derived template data member's base static const bool
-gdb_test "print test3.data.test" "\\$\[0-9\].* = true" "template object, static const bool"
-
-# template object, static derived template data member's base static const int
-gdb_test "print test3.data.key1" "\\$\[0-9\].* = 5" "template object, static const int"
-
-# template object, static derived template data member's base static long
-gdb_test "print test3.data.key2" "\\$\[0-9\].* = 77" "template object, static long"
-
-# template object, static derived template data member's base static enum
-gdb_test "print test3.data.value" "\\$\[0-9\].* = oriental" "template object, static enum"
-
-# template object, static derived template data member's static enum
-gdb_test "print test3.data.value_derived" "\\$\[0-9\].* = etruscan" "template object, static derived enum"
-
-# 2002-08-16
-# Four.
-
-# static const int initialized in another file.
-gdb_test "print test4.elsewhere" "\\$\[0-9\].* = 221" "static const int initialized elsewhere"
-
-# static const int that nobody initializes. From PR gdb/635.
-if {[test_compiler_info {gcc-[0-3]-*}]
- || [test_compiler_info {gcc-4-[0-4]-*}]} {
- # There was an extra CU-level DW_TAG_variable as DW_AT_declaration
- # with DW_AT_name = nowhere
- # and DW_AT_MIPS_linkage_name = _ZN9gnu_obj_47nowhereE .
- setup_xfail *-*-*
-}
-gdb_test "print test4.nowhere" "<optimized out>" "static const int initialized nowhere, print field"
-gdb_test "ptype test4.nowhere" "type = const int"
-gdb_test "print test4.nowhere.nowhere" "Attempt to extract a component of a value that is not a structure."
-
-# Same, but print the whole struct.
-gdb_test "print test4" "static nowhere = <optimized out>.*" "static const int initialized nowhere, whole struct"
-
-# static const initialized in the class definition, PR gdb/11702.
-if { $non_dwarf } { setup_xfail *-*-* }
-gdb_test "print test4.everywhere" "\\$\[0-9\].* = 317" "static const int initialized in class definition"
-if { $non_dwarf } { setup_xfail *-*-* }
-gdb_test "print test4.somewhere" "\\$\[0-9\].* = 3.14\[0-9\]*" "static const float initialized in class definition"
-
-# Also make sure static const members can be found via "info var".
-if { $non_dwarf } { setup_xfail *-*-* }
-gdb_test "info variable everywhere" \
- [multi_line \
- {All variables matching regular expression "everywhere":} \
- "" \
- "File (.*/)?m-static\[.\]h:" \
- "$decimal:\tconst int gnu_obj_4::everywhere;"]
-
-# Perhaps at some point test4 should also include a test for a static
-# const int that was initialized in the header file. But I'm not sure
-# that GDB's current behavior in such situations is either consistent
-# across platforms or optimal, so I'm not including one now.
-
-# Step into test1.method and examine the method-scoped static.
-# This is a regression test for PR 9708.
-gdb_test "step" "gnu_obj_1::method.*"
-gdb_test "print svar" " = true"
-
-gdb_exit
+source ${srcdir}/gdb.cp/m-static.exp.tcl
diff --git a/gdb/testsuite/gdb.cp/m-static.exp.tcl b/gdb/testsuite/gdb.cp/m-static.exp.tcl
new file mode 100644
index 00000000000..ead39ca325e
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/m-static.exp.tcl
@@ -0,0 +1,212 @@
+# Copyright 2002-2025 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/>.
+
+# Tests for member static data
+# 2002-05-13 Benjamin Kosnik <bkoz@redhat.com>
+# 2002-08-22 David Carlton <carlton@math.stanford.edu>
+
+# This file is part of the gdb testsuite
+
+require allow_cplus_tests
+
+#
+# test running programs
+#
+
+standard_testfile m-static.cc m-static1.cc
+
+include_file m-static.h
+
+lappend flags debug
+lappend flags c++
+
+if { [test_compiler_info gcc-*] && [gcc_major_version] >= 10 } {
+ # Work around PR gcc/101452.
+ lappend flags additional_flags=-fno-eliminate-unused-debug-types
+}
+
+if {[prepare_for_testing "failed to prepare" $testfile \
+ [list $srcfile $srcfile2] $flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return
+}
+
+get_debug_format
+set non_dwarf [expr ! [test_debug_format "DWARF \[0-9\]"]]
+
+# First, run to after we've constructed all the objects:
+
+gdb_breakpoint [gdb_get_line_number "constructs-done"]
+gdb_continue_to_breakpoint "end of constructors"
+
+
+# One.
+
+# simple object, static const bool
+gdb_test "print test1.test" "\\$\[0-9\]* = true" "simple object, static const bool"
+
+# simple object, static const int
+gdb_test "print test1.key1" "\\$\[0-9\]* = 5" "simple object, static const int"
+
+# simple object, static long
+gdb_test "print test1.key2" "\\$\[0-9\]* = 77" "simple object, static long"
+
+# simple object, static enum
+gdb_test "print test1.value" "\\$\[0-9\]* = oriental" "simple object, static enum"
+
+if { [is_aarch32_target] } {
+ gdb_test "print test5.single_constructor" \
+ { = {single_constructor \*\(single_constructor \* const\)} 0x[0-9a-f]+ <single_constructor::single_constructor\(\)>} \
+ "simple object instance, print constructor"
+
+ set re \
+ [multi_line_string_to_regexp \
+ "type = class single_constructor {" \
+ "" \
+ " public:" \
+ " single_constructor(void);" \
+ " ~single_constructor(void);" \
+ "} *(single_constructor * const)"]
+ gdb_test "ptype test5.single_constructor" $re \
+ "simple object instance, ptype constructor"
+ gdb_test "ptype single_constructor::single_constructor" $re \
+ "simple object class, ptype constructor"
+
+ gdb_test "print test1.~gnu_obj_1" \
+ { = {void \*\(gnu_obj_1 \* const(, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
+ "simple object instance, print destructor"
+ gdb_test "ptype test1.~gnu_obj_1" \
+ {type = void \*\(gnu_obj_1 \* const(, int)?\)} \
+ "simple object instance, ptype destructor"
+
+ gdb_test "print test1.'~gnu_obj_1'" \
+ { = {void \*\(gnu_obj_1 \*( const)?(, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
+ "simple object instance, print quoted destructor"
+
+ gdb_test "ptype gnu_obj_1::'~gnu_obj_1'" \
+ {type = void \*\(gnu_obj_1 \* const\)} \
+ "simple object class, ptype quoted destructor"
+} else {
+ gdb_test "print test5.single_constructor" \
+ { = {void \(single_constructor \* const\)} 0x[0-9a-f]+ <single_constructor::single_constructor\(\)>} \
+ "simple object instance, print constructor"
+ gdb_test "ptype test5.single_constructor" \
+ {type = void \(single_constructor \* const\)} \
+ "simple object instance, ptype constructor"
+ gdb_test "ptype single_constructor::single_constructor" \
+ {type = void \(single_constructor \* const\)} \
+ "simple object class, ptype constructor"
+
+ gdb_test "print test1.~gnu_obj_1"\
+ { = {void \(gnu_obj_1 \* const(?:, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>}\
+ "simple object instance, print destructor"
+
+ gdb_test "ptype test1.~gnu_obj_1"\
+ {type = void \(gnu_obj_1 \* const(?:, int)?\)}\
+ "simple object instance, ptype destructor"
+
+ gdb_test "print test1.'~gnu_obj_1'" \
+ { = {void \(gnu_obj_1 \*( const)?(?:, int)?\)} 0x[0-9a-f]+ <gnu_obj_1::~gnu_obj_1\(\)>} \
+ "simple object instance, print quoted destructor"
+
+ gdb_test "ptype gnu_obj_1::'~gnu_obj_1'" \
+ {type = void \(gnu_obj_1 \* const\)} \
+ "simple object class, ptype quoted destructor"
+}
+
+# Two.
+
+# derived template object, base static const bool
+gdb_test "print test2.test" "\\$\[0-9\]* = true" "derived template object, base static const bool"
+
+# derived template object, base static const int
+gdb_test "print test2.key1" "\\$\[0-9\]* = 5" "derived template object, base static const int"
+
+# derived template object, base static long
+gdb_test "print test2.key2" "\\$\[0-9\]* = 77" "derived template object, base static long"
+
+# derived template object, base static enum
+gdb_test "print test2.value" "\\$\[0-9\].* = oriental" "derived template object, base static enum"
+
+# derived template object, static enum
+gdb_test "print test2.value_derived" "\\$\[0-9\].* = etruscan" "derived template object, static enum"
+
+# Three.
+
+# template object, static derived template data member's base static const bool
+gdb_test "print test3.data.test" "\\$\[0-9\].* = true" "template object, static const bool"
+
+# template object, static derived template data member's base static const int
+gdb_test "print test3.data.key1" "\\$\[0-9\].* = 5" "template object, static const int"
+
+# template object, static derived template data member's base static long
+gdb_test "print test3.data.key2" "\\$\[0-9\].* = 77" "template object, static long"
+
+# template object, static derived template data member's base static enum
+gdb_test "print test3.data.value" "\\$\[0-9\].* = oriental" "template object, static enum"
+
+# template object, static derived template data member's static enum
+gdb_test "print test3.data.value_derived" "\\$\[0-9\].* = etruscan" "template object, static derived enum"
+
+# 2002-08-16
+# Four.
+
+# static const int initialized in another file.
+gdb_test "print test4.elsewhere" "\\$\[0-9\].* = 221" "static const int initialized elsewhere"
+
+# static const int that nobody initializes. From PR gdb/635.
+if {[test_compiler_info {gcc-[0-3]-*}]
+ || [test_compiler_info {gcc-4-[0-4]-*}]} {
+ # There was an extra CU-level DW_TAG_variable as DW_AT_declaration
+ # with DW_AT_name = nowhere
+ # and DW_AT_MIPS_linkage_name = _ZN9gnu_obj_47nowhereE .
+ setup_xfail *-*-*
+}
+gdb_test "print test4.nowhere" "<optimized out>" "static const int initialized nowhere, print field"
+gdb_test "ptype test4.nowhere" "type = const int"
+gdb_test "print test4.nowhere.nowhere" "Attempt to extract a component of a value that is not a structure."
+
+# Same, but print the whole struct.
+gdb_test "print test4" "static nowhere = <optimized out>.*" "static const int initialized nowhere, whole struct"
+
+# static const initialized in the class definition, PR gdb/11702.
+if { $non_dwarf } { setup_xfail *-*-* }
+gdb_test "print test4.everywhere" "\\$\[0-9\].* = 317" "static const int initialized in class definition"
+if { $non_dwarf } { setup_xfail *-*-* }
+gdb_test "print test4.somewhere" "\\$\[0-9\].* = 3.14\[0-9\]*" "static const float initialized in class definition"
+
+# Also make sure static const members can be found via "info var".
+if { $non_dwarf } { setup_xfail *-*-* }
+gdb_test "info variable everywhere" \
+ [multi_line \
+ {All variables matching regular expression "everywhere":} \
+ "" \
+ "File (.*/)?m-static\[.\]h:" \
+ "$decimal:\tconst int gnu_obj_4::everywhere;"]
+
+# Perhaps at some point test4 should also include a test for a static
+# const int that was initialized in the header file. But I'm not sure
+# that GDB's current behavior in such situations is either consistent
+# across platforms or optimal, so I'm not including one now.
+
+# Step into test1.method and examine the method-scoped static.
+# This is a regression test for PR 9708.
+gdb_test "step" "gnu_obj_1::method.*"
+gdb_test "print svar" " = true"
+
+gdb_exit
diff --git a/gdb/testsuite/gdb.dwarf2/static-const-member.exp b/gdb/testsuite/gdb.dwarf2/static-const-member.exp
new file mode 100644
index 00000000000..2529c37eb91
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/static-const-member.exp
@@ -0,0 +1,85 @@
+# Copyright 2025 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/>.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+require dwarf2_support
+
+standard_testfile main.c .S
+
+set asm_file [standard_output_file ${srcfile2}]
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+set int_size [get_sizeof "int" -1]
+
+Dwarf::assemble ${asm_file} {
+ cu {} {
+ DW_TAG_compile_unit {
+ {DW_AT_language @DW_LANG_C_plus_plus}
+ } {
+ declare_labels int_label
+
+ int_label: DW_TAG_base_type {
+ {DW_AT_byte_size $::int_size DW_FORM_udata}
+ {DW_AT_encoding @DW_ATE_signed}
+ {DW_AT_name "int"}
+ }
+
+ DW_TAG_class_type {
+ {DW_AT_name "A"}
+ } {
+ DW_TAG_member {
+ {DW_AT_name "aaa"}
+ {DW_AT_type :$int_label}
+ {DW_AT_external 1 DW_FORM_flag}
+ {DW_AT_declaration 1 DW_FORM_flag}
+ {DW_AT_accessibility 1 DW_FORM_data1}
+ {DW_AT_const_value 10 DW_FORM_data1}
+ }
+ }
+
+ DW_TAG_subprogram {
+ {MACRO_AT_func { "main" }}
+ {DW_AT_type :${int_label}}
+ {DW_AT_external 1 DW_FORM_flag}
+ } {
+ }
+ }
+ }
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile \
+ [list $asm_file $srcfile] {nodebug}] } {
+ return
+}
+
+# Regression test for PR symtab/33415. Print the value of A::aaa in:
+#
+# class A
+# {
+# public:
+# static const int aaa = 10;
+# };
+#
+# With DWARF 5, we get a DW_TAG_variable, but with DWARF 4, we get a
+# DW_TAG_member instead.
+
+gdb_test \
+ "print A::aaa" \
+ " = 10"
base-commit: cabae1c1c87d5f4ba28b7fdafe735b7c6207fb78
--
2.51.0
More information about the Gdb-patches
mailing list