fix: match NumPy 3.15 proxy layout on 32-bit free-threaded builds (#6200)

* fix: match NumPy 3.15 proxy layout on 32-bit free-threaded builds

NumPy 2.5.2+ aligns the first field after PyObject_HEAD to 8 bytes when
built for Python 3.15+. On 32-bit free-threaded builds sizeof(PyObject)
is 20, so the proxy structs read every field 4 bytes too early.

Fixes #6196.

Assisted-by: ClaudeCode:claude-opus-5-5

* Update include/pybind11/numpy.h

Co-authored-by: Ralf W. Grosse-Kunstleve <rwgkio@gmail.com>

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rwgkio@gmail.com>
diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h
index 1c3613c..fdaaecc 100644
--- a/include/pybind11/numpy.h
+++ b/include/pybind11/numpy.h
@@ -71,10 +71,21 @@
 template <typename type, typename SFINAE = void>
 struct npy_format_descriptor;
 
+// NumPy 2.5.2+ aligns the first field after PyObject_HEAD to 8 bytes on Python 3.15+.
+// NumPy 2.5.2, the first release supporting Python 3.15, aligns the first
+// field after PyObject_HEAD to 8 bytes on Python 3.15+.
+// This assumes a supported NumPy/Python pairing: older NumPy builds on
+// 32-bit free-threaded Python 3.15 have an incompatible layout.
+#if PY_VERSION_HEX >= 0x030F0000
+#    define PYBIND11_NPY_FIRST_FIELD alignas(8)
+#else
+#    define PYBIND11_NPY_FIRST_FIELD
+#endif
+
 /* NumPy 1 proxy (always includes legacy fields) */
 struct PyArrayDescr1_Proxy {
     PyObject_HEAD
-    PyObject *typeobj;
+    PYBIND11_NPY_FIRST_FIELD PyObject *typeobj;
     char kind;
     char type;
     char byteorder;
@@ -89,7 +100,7 @@
 
 struct PyArrayDescr_Proxy {
     PyObject_HEAD
-    PyObject *typeobj;
+    PYBIND11_NPY_FIRST_FIELD PyObject *typeobj;
     char kind;
     char type;
     char byteorder;
@@ -101,7 +112,7 @@
 /* NumPy 2 proxy, including legacy fields */
 struct PyArrayDescr2_Proxy {
     PyObject_HEAD
-    PyObject *typeobj;
+    PYBIND11_NPY_FIRST_FIELD PyObject *typeobj;
     char kind;
     char type;
     char byteorder;
@@ -121,7 +132,7 @@
 
 struct PyArray_Proxy {
     PyObject_HEAD
-    char *data;
+    PYBIND11_NPY_FIRST_FIELD char *data;
     int nd;
     ssize_t *dimensions;
     ssize_t *strides;
@@ -130,6 +141,8 @@
     int flags;
 };
 
+#undef PYBIND11_NPY_FIRST_FIELD
+
 struct PyVoidScalarObject_Proxy {
     PyObject_VAR_HEAD char *obval;
     PyArrayDescr_Proxy *descr;