From: Andrew Burgess <aburgess@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>
Subject: [PATCH 3/3] gdb/testsuite: add a test to check for Python traits static_assert
Date: Fri, 15 May 2026 11:00:48 +0100 [thread overview]
Message-ID: <93b625c0ab2f23cafa636d42e503361b70ee6edf.1778839043.git.aburgess@redhat.com> (raw)
In-Reply-To: <cover.1778839043.git.aburgess@redhat.com>
The previous two commits added a new type trait which can be used
within a static_assert to check the properties of a struct used by GDB
to implement Python objects.
The previous commit fixed a bug in GDB which this trait check exposed.
This commit adds a new test gdb.gdb/python-traits-check.exp which
checks that every struct in the Python/ directory that inherits from
PyObject, has a suitable static_assert in place.
Adding this test should mean that if someone adds a new Python object
type to GDB, and they forget to add the static_assert, then this test
should give a failure, which should remind them to add the required
static_assert. The static_assert will then check that their new
struct is compliant.
---
gdb/testsuite/gdb.gdb/python-traits-check.exp | 156 ++++++++++++++++++
1 file changed, 156 insertions(+)
create mode 100644 gdb/testsuite/gdb.gdb/python-traits-check.exp
diff --git a/gdb/testsuite/gdb.gdb/python-traits-check.exp b/gdb/testsuite/gdb.gdb/python-traits-check.exp
new file mode 100644
index 00000000000..46cb1cabbb0
--- /dev/null
+++ b/gdb/testsuite/gdb.gdb/python-traits-check.exp
@@ -0,0 +1,156 @@
+# 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/>.
+
+# Check that every struct inheriting from PyObject in the gdb/python/
+# directory has a corresponding static_assert for
+# gdb::is_python_allocatable_v immediately after the struct definition.
+# The expected format is:
+#
+# struct some_new_type : public PyObject
+# {
+# ... fields go here ...
+# };
+#
+# static_assert (gdb::is_python_allocatable_v<some_new_type>);
+#
+# It is OK to add comments between the struct and the static_assert if
+# needed, but nothing else, the static_assert must be the next non-empty,
+# non-comment line.
+#
+# If the new type has no fields then this can be written like:
+#
+# struct some_empty_type : public PyObject
+# {};
+#
+# static_assert (gdb::is_python_allocatable_v<some_empty_type>);
+#
+# We do have a few of these in GDB currently. We require that the
+# static_assert still be present because (a) it has zero run-time cost,
+# and (b) it catches issues if fields are added in the future.
+
+set python_dir "$srcdir/$subdir/../../python"
+
+# Gather all .c and .h files in the python directory.
+set files [lsort [concat \
+ [glob -nocomplain -directory $python_dir *.c] \
+ [glob -nocomplain -directory $python_dir *.h]]]
+
+gdb_assert { [llength $files] > 0 } "found python source files"
+
+# Check a single file for PyObject-derived structs and matching
+# static_asserts.
+#
+# Opens FILENAME, reads it line by line looking for struct definitions of
+# the form "struct NAME : public PyObject". For each one found, scans
+# forward past the struct body, then checks that a matching static_assert
+# line follows, allowing only blank lines and GDB-style comments to
+# intervene.
+
+proc check_file { filename } {
+ set fd [open $filename r]
+ set lines [split [read $fd] "\n"]
+ close $fd
+
+ set num_lines [llength $lines]
+ set short_name [file tail $filename]
+
+ for { set i 0 } { $i < $num_lines } { incr i } {
+ set line [lindex $lines $i]
+
+ # Look for struct definitions inheriting from PyObject. These
+ # start in column 0.
+ if { ![regexp {^struct (\w+)\s*:\s*public PyObject} \
+ $line whole struct_name] } {
+ continue
+ }
+
+ set testname "$short_name: $struct_name: static assert check"
+
+ # Found a struct. Now scan forward for the closing brace and
+ # semicolon. Within the struct body, lines are either blank or
+ # start with whitespace. The closing line starts in column 0. For
+ # empty structs the open and close brace may appear together on a
+ # single line.
+ set found_close false
+ for { incr i } { $i < $num_lines } { incr i } {
+ set line [lindex $lines $i]
+ if { [regexp "^(?:\\{\\s*)?\\};" $line] } {
+ set found_close true
+ break
+ }
+ }
+
+ if { !$found_close } {
+ fail "$testname (no closing brace found)"
+ continue
+ }
+
+ # Now scan forward from the line after the struct close, skipping
+ # empty lines and GDB-style /* ... */ comments. The next non-blank,
+ # non-comment line should be the static_assert.
+ set in_comment false
+ set found_assert false
+ set found_other false
+ for { incr i } { $i < $num_lines } { incr i } {
+ set line [lindex $lines $i]
+
+ if { $in_comment } {
+ # Inside a multi-line comment, look for the closing "*/".
+ if { [regexp {\*/} $line] } {
+ set in_comment false
+ }
+ continue
+ }
+
+ # Skip blank lines.
+ if { [regexp {^\s*$} $line] } {
+ continue
+ }
+
+ # Check for the start of a comment.
+ if { [regexp {^\s*/\*} $line] } {
+ # If the comment also ends on this line then we don't need
+ # to enter IN_COMMENT mode, we can just ignore this line.
+ if { ![regexp {\*/} $line] } {
+ set in_comment true
+ }
+ continue
+ }
+
+ # This is a non-blank, non-comment line. Check if it is the
+ # expected static_assert.
+ set expected \
+ "static_assert (gdb::is_python_allocatable_v<$struct_name>);"
+ if { $line eq $expected } {
+ set found_assert true
+ } else {
+ set found_other true
+ }
+ break
+ }
+
+ if { $found_assert } {
+ pass $testname
+ } elseif { $found_other } {
+ fail "$testname (missing static_assert)"
+ } else {
+ fail "$testname (reached end of file)"
+ }
+ }
+}
+
+foreach file $files {
+ check_file $file
+}
--
2.25.4
next prev parent reply other threads:[~2026-05-15 10:02 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-15 10:00 [PATCH 0/3] Use C++ type traits check to catch bugs in Python API Andrew Burgess
2026-05-15 10:00 ` [PATCH 1/3] gdb/python: add type traits check for all PyObject sub-classes Andrew Burgess
2026-05-15 17:10 ` Tom Tromey
2026-05-16 12:27 ` Andrew Burgess
2026-05-15 10:00 ` [PATCH 2/3] gdb/python: fix use of frame_info_ptr within pending_frame_object Andrew Burgess
2026-05-15 17:22 ` Tom Tromey
2026-05-16 12:28 ` Andrew Burgess
2026-05-15 10:00 ` Andrew Burgess [this message]
2026-05-15 17:31 ` [PATCH 3/3] gdb/testsuite: add a test to check for Python traits static_assert Tom Tromey
2026-05-16 12:29 ` Andrew Burgess
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=93b625c0ab2f23cafa636d42e503361b70ee6edf.1778839043.git.aburgess@redhat.com \
--to=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox