Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
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


  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