Skip to content

Commit caf35f9

Browse files
authored
remove private types from pyo3-ffi (PyO3#5064)
* remove private types from `pyo3-ffi` * newsfragments * make `PyCodeObject` opaque on all versions * fix msrv * fix msrv, try 2 * remove unused constant * sync `cpython/compile.rs` with header at 3.13 * fix size of INT_MAX * remove `PyCode_GetNumFree`
1 parent 7619e62 commit caf35f9

27 files changed

+99
-291
lines changed

newsfragments/5064.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add FFI definition `PY_INVALID_STACK_EFFECT`.

newsfragments/5064.changed.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Reduce visibility of some CPython implementation details:
2+
- The FFI definition `PyCodeObject` is now an opaque struct on all Python versions.
3+
- The FFI definition `PyFutureFeatures` is now only defined up until Python 3.10 (it was present in CPython headers but unused in 3.11 and 3.12).

newsfragments/5064.removed.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove private types from `pyo3-ffi` (i.e. starting with `_Py`) which are not referenced by public APIs: `_PyLocalMonitors`, `_Py_GlobalMonitors`, `_PyCoCached`, `_PyCoLineInstrumentationData`, `_PyCoMonitoringData`, `_PyCompilerSrcLocation`, `_PyErr_StackItem`.
2+
Remove FFI definition `PyCode_GetNumFree` (PyO3 cannot support it due to knowledge of the code object).

pyo3-ffi-check/macro/src/lib.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ const PY_3_12: PythonVersion = PythonVersion {
99
minor: 12,
1010
};
1111

12-
const PY_3_13: PythonVersion = PythonVersion {
13-
major: 3,
14-
minor: 13,
15-
};
16-
1712
/// Macro which expands to multiple macro calls, one per pyo3-ffi struct.
1813
#[proc_macro]
1914
pub fn for_all_structs(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
@@ -55,16 +50,6 @@ pub fn for_all_structs(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
5550
.strip_suffix(".html")
5651
.unwrap();
5752

58-
if struct_name == "_PyCoLineInstrumentationData"
59-
&& pyo3_build_config::get().version == PY_3_13
60-
{
61-
// private type, fields changed name in 3.13.2 -> 3.13.3
62-
//
63-
// PyO3 0.25 will remove this struct, ignoring temporarily just to unblock CI
64-
// changed, the size stayed the same.
65-
continue;
66-
}
67-
6853
let struct_ident = Ident::new(struct_name, Span::call_site());
6954
output.extend(quote!(#macro_name!(#struct_ident);));
7055
}

pyo3-ffi/src/bytearrayobject.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct PyByteArrayObject {
1717
}
1818

1919
#[cfg(any(PyPy, GraalPy, Py_LIMITED_API))]
20-
opaque_struct!(PyByteArrayObject);
20+
opaque_struct!(pub PyByteArrayObject);
2121

2222
#[cfg_attr(windows, link(name = "pythonXY"))]
2323
extern "C" {

pyo3-ffi/src/code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// This header doesn't exist in CPython, but Include/cpython/code.h does. We add
22
// this here so that PyCodeObject has a definition under the limited API.
33

4-
opaque_struct!(PyCodeObject);
4+
opaque_struct!(pub PyCodeObject);

pyo3-ffi/src/cpython/bytesobject.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct PyBytesObject {
1717
}
1818

1919
#[cfg(any(PyPy, GraalPy, Py_LIMITED_API))]
20-
opaque_struct!(PyBytesObject);
20+
opaque_struct!(pub PyBytesObject);
2121

2222
extern "C" {
2323
#[cfg_attr(PyPy, link_name = "_PyPyBytes_Resize")]

pyo3-ffi/src/cpython/code.rs

Lines changed: 27 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -1,209 +1,43 @@
11
use crate::object::*;
22
use crate::pyport::Py_ssize_t;
33

4-
#[allow(unused_imports)]
5-
use std::os::raw::{c_char, c_int, c_short, c_uchar, c_void};
4+
#[cfg(not(GraalPy))]
5+
use std::os::raw::c_char;
6+
use std::os::raw::{c_int, c_void};
67
#[cfg(not(any(PyPy, GraalPy)))]
78
use std::ptr::addr_of_mut;
89

9-
#[cfg(all(Py_3_8, not(any(PyPy, GraalPy)), not(Py_3_11)))]
10-
opaque_struct!(_PyOpcache);
10+
// skipped private _PY_MONITORING_LOCAL_EVENTS
11+
// skipped private _PY_MONITORING_UNGROUPED_EVENTS
12+
// skipped private _PY_MONITORING_EVENTS
1113

12-
#[cfg(Py_3_12)]
13-
pub const _PY_MONITORING_LOCAL_EVENTS: usize = 10;
14-
#[cfg(Py_3_12)]
15-
pub const _PY_MONITORING_UNGROUPED_EVENTS: usize = 15;
16-
#[cfg(Py_3_12)]
17-
pub const _PY_MONITORING_EVENTS: usize = 17;
14+
// skipped private _PyLocalMonitors
15+
// skipped private _Py_GlobalMonitors
1816

19-
#[cfg(Py_3_12)]
20-
#[repr(C)]
21-
#[derive(Clone, Copy)]
22-
pub struct _Py_LocalMonitors {
23-
pub tools: [u8; if cfg!(Py_3_13) {
24-
_PY_MONITORING_LOCAL_EVENTS
25-
} else {
26-
_PY_MONITORING_UNGROUPED_EVENTS
27-
}],
28-
}
29-
30-
#[cfg(Py_3_12)]
31-
#[repr(C)]
32-
#[derive(Clone, Copy)]
33-
pub struct _Py_GlobalMonitors {
34-
pub tools: [u8; _PY_MONITORING_UNGROUPED_EVENTS],
35-
}
36-
37-
// skipped _Py_CODEUNIT
17+
// skipped private _Py_CODEUNIT
3818

39-
// skipped _Py_OPCODE
40-
// skipped _Py_OPARG
19+
// skipped private _Py_OPCODE
20+
// skipped private _Py_OPARG
4121

42-
// skipped _py_make_codeunit
22+
// skipped private _py_make_codeunit
4323

44-
// skipped _py_set_opcode
24+
// skipped private _py_set_opcode
4525

46-
// skipped _Py_MAKE_CODEUNIT
47-
// skipped _Py_SET_OPCODE
48-
49-
#[cfg(Py_3_12)]
50-
#[repr(C)]
51-
#[derive(Copy, Clone)]
52-
pub struct _PyCoCached {
53-
pub _co_code: *mut PyObject,
54-
pub _co_varnames: *mut PyObject,
55-
pub _co_cellvars: *mut PyObject,
56-
pub _co_freevars: *mut PyObject,
57-
}
58-
59-
#[cfg(Py_3_12)]
60-
#[repr(C)]
61-
#[derive(Copy, Clone)]
62-
pub struct _PyCoLineInstrumentationData {
63-
pub original_opcode: u8,
64-
pub line_delta: i8,
65-
}
26+
// skipped private _Py_MAKE_CODEUNIT
27+
// skipped private _Py_SET_OPCODE
6628

67-
#[cfg(Py_3_12)]
68-
#[repr(C)]
69-
#[derive(Copy, Clone)]
70-
pub struct _PyCoMonitoringData {
71-
pub local_monitors: _Py_LocalMonitors,
72-
pub active_monitors: _Py_LocalMonitors,
73-
pub tools: *mut u8,
74-
pub lines: *mut _PyCoLineInstrumentationData,
75-
pub line_tools: *mut u8,
76-
pub per_instruction_opcodes: *mut u8,
77-
pub per_instruction_tools: *mut u8,
78-
}
79-
80-
#[cfg(all(not(any(PyPy, GraalPy)), not(Py_3_7)))]
81-
opaque_struct!(PyCodeObject);
82-
83-
#[cfg(all(not(any(PyPy, GraalPy)), Py_3_7, not(Py_3_8)))]
84-
#[repr(C)]
85-
pub struct PyCodeObject {
86-
pub ob_base: PyObject,
87-
pub co_argcount: c_int,
88-
pub co_kwonlyargcount: c_int,
89-
pub co_nlocals: c_int,
90-
pub co_stacksize: c_int,
91-
pub co_flags: c_int,
92-
pub co_firstlineno: c_int,
93-
pub co_code: *mut PyObject,
94-
pub co_consts: *mut PyObject,
95-
pub co_names: *mut PyObject,
96-
pub co_varnames: *mut PyObject,
97-
pub co_freevars: *mut PyObject,
98-
pub co_cellvars: *mut PyObject,
99-
pub co_cell2arg: *mut Py_ssize_t,
100-
pub co_filename: *mut PyObject,
101-
pub co_name: *mut PyObject,
102-
pub co_lnotab: *mut PyObject,
103-
pub co_zombieframe: *mut c_void,
104-
pub co_weakreflist: *mut PyObject,
105-
pub co_extra: *mut c_void,
106-
}
107-
108-
#[cfg(Py_3_13)]
109-
opaque_struct!(_PyExecutorArray);
110-
111-
#[cfg(all(not(any(PyPy, GraalPy)), Py_3_8, not(Py_3_11)))]
112-
#[repr(C)]
113-
pub struct PyCodeObject {
114-
pub ob_base: PyObject,
115-
pub co_argcount: c_int,
116-
pub co_posonlyargcount: c_int,
117-
pub co_kwonlyargcount: c_int,
118-
pub co_nlocals: c_int,
119-
pub co_stacksize: c_int,
120-
pub co_flags: c_int,
121-
pub co_firstlineno: c_int,
122-
pub co_code: *mut PyObject,
123-
pub co_consts: *mut PyObject,
124-
pub co_names: *mut PyObject,
125-
pub co_varnames: *mut PyObject,
126-
pub co_freevars: *mut PyObject,
127-
pub co_cellvars: *mut PyObject,
128-
pub co_cell2arg: *mut Py_ssize_t,
129-
pub co_filename: *mut PyObject,
130-
pub co_name: *mut PyObject,
131-
#[cfg(not(Py_3_10))]
132-
pub co_lnotab: *mut PyObject,
133-
#[cfg(Py_3_10)]
134-
pub co_linetable: *mut PyObject,
135-
pub co_zombieframe: *mut c_void,
136-
pub co_weakreflist: *mut PyObject,
137-
pub co_extra: *mut c_void,
138-
pub co_opcache_map: *mut c_uchar,
139-
pub co_opcache: *mut _PyOpcache,
140-
pub co_opcache_flag: c_int,
141-
pub co_opcache_size: c_uchar,
142-
}
29+
// skipped private _PyCoCached
30+
// skipped private _PyCoLineInstrumentationData
31+
// skipped private _PyCoMontoringData
14332

144-
#[cfg(all(not(any(PyPy, GraalPy)), Py_3_11))]
145-
#[repr(C)]
146-
pub struct PyCodeObject {
147-
pub ob_base: PyVarObject,
148-
pub co_consts: *mut PyObject,
149-
pub co_names: *mut PyObject,
150-
pub co_exceptiontable: *mut PyObject,
151-
pub co_flags: c_int,
152-
#[cfg(not(Py_3_12))]
153-
pub co_warmup: c_int,
33+
// skipped private _PyExecutorArray
15434

155-
pub co_argcount: c_int,
156-
pub co_posonlyargcount: c_int,
157-
pub co_kwonlyargcount: c_int,
158-
pub co_stacksize: c_int,
159-
pub co_firstlineno: c_int,
160-
161-
pub co_nlocalsplus: c_int,
162-
#[cfg(Py_3_12)]
163-
pub co_framesize: c_int,
164-
pub co_nlocals: c_int,
165-
#[cfg(not(Py_3_12))]
166-
pub co_nplaincellvars: c_int,
167-
pub co_ncellvars: c_int,
168-
pub co_nfreevars: c_int,
169-
#[cfg(Py_3_12)]
170-
pub co_version: u32,
171-
172-
pub co_localsplusnames: *mut PyObject,
173-
pub co_localspluskinds: *mut PyObject,
174-
pub co_filename: *mut PyObject,
175-
pub co_name: *mut PyObject,
176-
pub co_qualname: *mut PyObject,
177-
pub co_linetable: *mut PyObject,
178-
pub co_weakreflist: *mut PyObject,
179-
#[cfg(not(Py_3_12))]
180-
pub _co_code: *mut PyObject,
181-
#[cfg(not(Py_3_12))]
182-
pub _co_linearray: *mut c_char,
183-
#[cfg(Py_3_13)]
184-
pub co_executors: *mut _PyExecutorArray,
185-
#[cfg(Py_3_12)]
186-
pub _co_cached: *mut _PyCoCached,
187-
#[cfg(all(Py_3_12, not(Py_3_13)))]
188-
pub _co_instrumentation_version: u64,
189-
#[cfg(Py_3_13)]
190-
pub _co_instrumentation_version: libc::uintptr_t,
191-
#[cfg(Py_3_12)]
192-
pub _co_monitoring: *mut _PyCoMonitoringData,
193-
pub _co_firsttraceable: c_int,
194-
pub co_extra: *mut c_void,
195-
pub co_code_adaptive: [c_char; 1],
196-
}
197-
198-
#[cfg(PyPy)]
199-
#[repr(C)]
200-
pub struct PyCodeObject {
201-
pub ob_base: PyObject,
202-
pub co_name: *mut PyObject,
203-
pub co_filename: *mut PyObject,
204-
pub co_argcount: c_int,
205-
pub co_flags: c_int,
206-
}
35+
opaque_struct!(
36+
#[doc = "A Python code object.\n"]
37+
#[doc = "\n"]
38+
#[doc = "`pyo3-ffi` does not expose the contents of this struct, as it has no stability guarantees."]
39+
pub PyCodeObject
40+
);
20741

20842
/* Masks for co_flags */
20943
pub const CO_OPTIMIZED: c_int = 0x0001;
@@ -249,28 +83,14 @@ pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int {
24983
(Py_TYPE(op) == addr_of_mut!(PyCode_Type)) as c_int
25084
}
25185

252-
#[inline]
253-
#[cfg(all(not(any(PyPy, GraalPy)), Py_3_10, not(Py_3_11)))]
254-
pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t {
255-
crate::PyTuple_GET_SIZE((*op).co_freevars)
256-
}
257-
258-
#[inline]
259-
#[cfg(all(not(Py_3_10), Py_3_11, not(any(PyPy, GraalPy))))]
260-
pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> c_int {
261-
(*op).co_nfreevars
262-
}
263-
26486
extern "C" {
26587
#[cfg(PyPy)]
26688
#[link_name = "PyPyCode_Check"]
26789
pub fn PyCode_Check(op: *mut PyObject) -> c_int;
268-
269-
#[cfg(PyPy)]
270-
#[link_name = "PyPyCode_GetNumFree"]
271-
pub fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t;
27290
}
27391

92+
// skipped PyCode_GetNumFree (requires knowledge of code object layout)
93+
27494
extern "C" {
27595
#[cfg(not(GraalPy))]
27696
#[cfg_attr(PyPy, link_name = "PyPyCode_New")]

0 commit comments

Comments
 (0)