Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffi module cleanup #1338

Merged
merged 10 commits into from
Dec 27, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed
- Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334)
- Remove `#[deny(warnings)]` attribute (and instead refuse warnings only in CI). [#1340](https://github.com/PyO3/pyo3/pull/1340)
- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338)

## [0.13.0] - 2020-12-22
### Packaging
Expand Down
23 changes: 17 additions & 6 deletions src/ffi/boolobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ use std::os::raw::{c_int, c_long};
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyBool_Type")]
pub static mut PyBool_Type: PyTypeObject;
#[cfg_attr(PyPy, link_name = "_PyPy_FalseStruct")]
static mut _Py_FalseStruct: PyLongObject;
#[cfg_attr(PyPy, link_name = "_PyPy_TrueStruct")]
static mut _Py_TrueStruct: PyLongObject;
#[cfg_attr(PyPy, link_name = "PyPyBool_FromLong")]
pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject;
}

#[inline]
pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyBool_Type) as c_int
}

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "_PyPy_FalseStruct")]
static mut _Py_FalseStruct: PyLongObject;
#[cfg_attr(PyPy, link_name = "_PyPy_TrueStruct")]
static mut _Py_TrueStruct: PyLongObject;
}

#[inline]
pub unsafe fn Py_False() -> *mut PyObject {
&mut _Py_FalseStruct as *mut PyLongObject as *mut PyObject
Expand All @@ -28,3 +30,12 @@ pub unsafe fn Py_False() -> *mut PyObject {
pub unsafe fn Py_True() -> *mut PyObject {
&mut _Py_TrueStruct as *mut PyLongObject as *mut PyObject
}

// skipped Py_RETURN_TRUE
// skipped Py_RETURN_FALSE

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyBool_FromLong")]
pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject;
}
11 changes: 8 additions & 3 deletions src/ffi/bytesobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ extern "C" {
pub fn PyBytes_FromString(arg1: *const c_char) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyBytes_FromObject")]
pub fn PyBytes_FromObject(arg1: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormatV")]
// skipped PyBytes_FromFormatV
//#[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormatV")]
//pub fn PyBytes_FromFormatV(arg1: *const c_char, arg2: va_list)
// -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormat")]
Expand All @@ -52,6 +53,10 @@ extern "C" {
s: *mut *mut c_char,
len: *mut Py_ssize_t,
) -> c_int;
#[cfg(not(PyPy))]
pub fn _PyBytes_Resize(bytes: *mut *mut PyObject, newsize: Py_ssize_t) -> c_int;
}

// skipped F_LJUST
// skipped F_SIGN
// skipped F_BLANK
// skipped F_ALT
// skipped F_ZERO
39 changes: 25 additions & 14 deletions src/ffi/ceval.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#[cfg(not(Py_LIMITED_API))]
use crate::ffi::code::FreeFunc;
use crate::ffi::object::PyObject;
use crate::ffi::pystate::{PyThreadState, Py_tracefunc};
use crate::ffi::pystate::PyThreadState;
use std::os::raw::{c_char, c_int, c_void};

// TODO: move to cpython
pub type _PyFrameEvalFunction =
extern "C" fn(*mut crate::ffi::PyFrameObject, c_int) -> *mut PyObject;

extern "C" {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't select the exact line, but PyEval_CallObjectWithKeywords is marked deprecated in 3.9. However, if I mark it with #[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))], I can't compile due to deny(warnings) on this crate (it's used by PyEval_CallObject below).

Maybe we could consider being a bit more specific with the crate's deny attribute? https://github.com/rust-unofficial/patterns/blob/master/anti_patterns/deny-warnings.md

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I recently added this and I agree it's now an antipattern.

I've opened #1340 to remove the attribute.

As specifically here, I think we will need to put #[allow(deprecated)] on the call inside PyEval_CallObject so that this passes CI. Mildly annoying, but hey!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, I think. I think the only gotcha is that we need to add the deprecation to PyEval_CallObject as well.

#[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))]
#[cfg_attr(PyPy, link_name = "PyPyEval_CallObjectWithKeywords")]
pub fn PyEval_CallObjectWithKeywords(
func: *mut PyObject,
Expand All @@ -13,14 +16,18 @@ extern "C" {
) -> *mut PyObject;
}

#[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))]
#[inline]
pub unsafe fn PyEval_CallObject(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject {
#[allow(deprecated)]
PyEval_CallObjectWithKeywords(func, arg, ::std::ptr::null_mut())
}

extern "C" {
#[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))]
#[cfg_attr(PyPy, link_name = "PyPyEval_CallFunction")]
pub fn PyEval_CallFunction(obj: *mut PyObject, format: *const c_char, ...) -> *mut PyObject;
#[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))]
#[cfg_attr(PyPy, link_name = "PyPyEval_CallMethod")]
pub fn PyEval_CallMethod(
obj: *mut PyObject,
Expand Down Expand Up @@ -49,28 +56,20 @@ extern "C" {
fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int;
}

// TODO: Py_EnterRecursiveCall etc
pub type _PyFrameEvalFunction =
extern "C" fn(*mut crate::ffi::PyFrameObject, c_int) -> *mut PyObject;
// TODO
// skipped Py_EnterRecursiveCall
// skipped Py_LeaveRecursiveCall

extern "C" {
pub fn PyEval_GetFuncName(arg1: *mut PyObject) -> *const c_char;
pub fn PyEval_GetFuncDesc(arg1: *mut PyObject) -> *const c_char;
pub fn PyEval_GetCallStats(arg1: *mut PyObject) -> *mut PyObject;
pub fn PyEval_EvalFrame(arg1: *mut crate::ffi::PyFrameObject) -> *mut PyObject;
pub fn _PyEval_EvalFrameDefault(
arg1: *mut crate::ffi::PyFrameObject,
exc: c_int,
) -> *mut PyObject;
#[cfg(not(Py_LIMITED_API))]
pub fn _PyEval_RequestCodeExtraIndex(func: FreeFunc) -> c_int;
pub fn PyEval_EvalFrameEx(f: *mut crate::ffi::PyFrameObject, exc: c_int) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")]
pub fn PyEval_SaveThread() -> *mut PyThreadState;
#[cfg_attr(PyPy, link_name = "PyPyEval_RestoreThread")]
pub fn PyEval_RestoreThread(arg1: *mut PyThreadState);
pub fn PyEval_SetProfile(trace_func: Py_tracefunc, arg1: *mut PyObject);
pub fn PyEval_SetTrace(trace_func: Py_tracefunc, arg1: *mut PyObject);
}

#[cfg(py_sys_config = "WITH_THREAD")]
Expand All @@ -88,3 +87,15 @@ extern "C" {
#[cfg(not(Py_3_8))]
pub fn PyEval_ReInitThreads();
}

// skipped Py_BEGIN_ALLOW_THREADS
// skipped Py_BLOCK_THREADS
// skipped Py_UNBLOCK_THREADS
// skipped Py_END_ALLOW_THREADS
// skipped FVC_MASK
// skipped FVC_NONE
// skipped FVC_STR
// skipped FVC_REPR
// skipped FVC_ASCII
// skipped FVS_MASK
// skipped FVS_HAVE_SPEC
158 changes: 2 additions & 156 deletions src/ffi/code.rs
Original file line number Diff line number Diff line change
@@ -1,156 +1,2 @@
use crate::ffi::object::*;
use crate::ffi::pyport::Py_ssize_t;
use std::os::raw::{c_char, c_int, c_uchar, c_void};

#[cfg(Py_3_8)]
opaque_struct!(_PyOpcache);

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyCodeObject {
pub ob_base: PyObject,
pub co_argcount: c_int,
#[cfg(Py_3_8)]
pub co_posonlyargcount: c_int,
pub co_kwonlyargcount: c_int,
pub co_nlocals: c_int,
pub co_stacksize: c_int,
pub co_flags: c_int,
pub co_firstlineno: c_int,
pub co_code: *mut PyObject,
pub co_consts: *mut PyObject,
pub co_names: *mut PyObject,
pub co_varnames: *mut PyObject,
pub co_freevars: *mut PyObject,
pub co_cellvars: *mut PyObject,
pub co_cell2arg: *mut c_uchar,
pub co_filename: *mut PyObject,
pub co_name: *mut PyObject,
pub co_lnotab: *mut PyObject,
pub co_zombieframe: *mut c_void,
pub co_weakreflist: *mut PyObject,
pub co_extra: *mut c_void,
#[cfg(Py_3_8)]
pub co_opcache_map: *mut c_uchar,
#[cfg(Py_3_8)]
pub co_opcache: *mut _PyOpcache,
#[cfg(Py_3_8)]
pub co_opcache_flag: c_int,
#[cfg(Py_3_8)]
pub co_opcache_size: c_uchar,
}

/* Masks for co_flags */
pub const CO_OPTIMIZED: c_int = 0x0001;
pub const CO_NEWLOCALS: c_int = 0x0002;
pub const CO_VARARGS: c_int = 0x0004;
pub const CO_VARKEYWORDS: c_int = 0x0008;
pub const CO_NESTED: c_int = 0x0010;
pub const CO_GENERATOR: c_int = 0x0020;
/* The CO_NOFREE flag is set if there are no free or cell variables.
This information is redundant, but it allows a single flag test
to determine whether there is any extra work to be done when the
call frame it setup.
*/
pub const CO_NOFREE: c_int = 0x0040;
/* The CO_COROUTINE flag is set for coroutine functions (defined with
``async def`` keywords) */
pub const CO_COROUTINE: c_int = 0x0080;
pub const CO_ITERABLE_COROUTINE: c_int = 0x0100;
pub const CO_ASYNC_GENERATOR: c_int = 0x0200;

pub const CO_FUTURE_DIVISION: c_int = 0x2000;
pub const CO_FUTURE_ABSOLUTE_IMPORT: c_int = 0x4000; /* do absolute imports by default */
pub const CO_FUTURE_WITH_STATEMENT: c_int = 0x8000;
pub const CO_FUTURE_PRINT_FUNCTION: c_int = 0x1_0000;
pub const CO_FUTURE_UNICODE_LITERALS: c_int = 0x2_0000;
pub const CO_FUTURE_BARRY_AS_BDFL: c_int = 0x4_0000;
pub const CO_FUTURE_GENERATOR_STOP: c_int = 0x8_0000;

pub const CO_MAXBLOCKS: usize = 20;
pub type FreeFunc = extern "C" fn(*mut c_void) -> c_void;

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
pub static mut PyCode_Type: PyTypeObject;
}

extern "C" {
pub fn _PyCode_GetExtra(
code: *mut PyObject,
index: Py_ssize_t,
extra: *const *mut c_void,
) -> c_int;
pub fn _PyCode_SetExtra(code: *mut PyObject, index: Py_ssize_t, extra: *mut c_void) -> c_int;

#[cfg_attr(PyPy, link_name = "PyPyCode_New")]
pub fn PyCode_New(
argcount: c_int,
kwonlyargcount: c_int,
nlocals: c_int,
stacksize: c_int,
flags: c_int,
code: *mut PyObject,
consts: *mut PyObject,
names: *mut PyObject,
varnames: *mut PyObject,
freevars: *mut PyObject,
cellvars: *mut PyObject,
filename: *mut PyObject,
name: *mut PyObject,
firstlineno: c_int,
lnotab: *mut PyObject,
) -> *mut PyCodeObject;
#[cfg(Py_3_8)]
pub fn PyCode_NewWithPosOnlyArgs(
argcount: c_int,
posonlyargcount: c_int,
kwonlyargcount: c_int,
nlocals: c_int,
stacksize: c_int,
flags: c_int,
code: *mut PyObject,
consts: *mut PyObject,
names: *mut PyObject,
varnames: *mut PyObject,
freevars: *mut PyObject,
cellvars: *mut PyObject,
filename: *mut PyObject,
name: *mut PyObject,
firstlineno: c_int,
lnotab: *mut PyObject,
) -> *mut PyCodeObject;
#[cfg_attr(PyPy, link_name = "PyPyCode_NewEmpty")]
pub fn PyCode_NewEmpty(
filename: *const c_char,
funcname: *const c_char,
firstlineno: c_int,
) -> *mut PyCodeObject;
pub fn PyCode_Addr2Line(arg1: *mut PyCodeObject, arg2: c_int) -> c_int;
pub fn PyCode_Optimize(
code: *mut PyObject,
consts: *mut PyObject,
names: *mut PyObject,
lnotab: *mut PyObject,
) -> *mut PyObject;

#[cfg(PyPy)]
#[link_name = "PyPyCode_Check"]
pub fn PyCode_Check(op: *mut PyObject) -> c_int;

#[cfg(PyPy)]
#[link_name = "PyPyCode_GetNumFree"]
pub fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t;
}

#[inline]
#[cfg(not(PyPy))]
pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCode_Type) as c_int
}

#[inline]
#[cfg(not(PyPy))]
pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t {
crate::ffi::tupleobject::PyTuple_GET_SIZE((*op).co_freevars)
}
#[cfg(Py_LIMITED_API)]
opaque_struct!(PyCodeObject);
10 changes: 10 additions & 0 deletions src/ffi/codecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::os::raw::{c_char, c_int};

extern "C" {
pub fn PyCodec_Register(search_function: *mut PyObject) -> c_int;
// skipped PyCodec_Unregister
// skipped non-limited _PyCodec_Lookup from Include/codecs.h
// skipped non-limited _PyCodec_Forget from Include/codecs.h
pub fn PyCodec_KnownEncoding(encoding: *const c_char) -> c_int;
pub fn PyCodec_Encode(
object: *mut PyObject,
Expand All @@ -14,6 +17,11 @@ extern "C" {
encoding: *const c_char,
errors: *const c_char,
) -> *mut PyObject;
// skipped non-limited _PyCodec_LookupTextEncoding from Include/codecs.h
// skipped non-limited _PyCodec_EncodeText from Include/codecs.h
// skipped non-limited _PyCodec_DecodeText from Include/codecs.h
// skipped non-limited _PyCodecInfo_GetIncrementalDecoder from Include/codecs.h
// skipped non-limited _PyCodecInfo_GetIncrementalEncoder from Include/codecs.h
pub fn PyCodec_Encoder(encoding: *const c_char) -> *mut PyObject;
pub fn PyCodec_Decoder(encoding: *const c_char) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyCodec_IncrementalEncoder")]
Expand Down Expand Up @@ -43,4 +51,6 @@ extern "C" {
pub fn PyCodec_ReplaceErrors(exc: *mut PyObject) -> *mut PyObject;
pub fn PyCodec_XMLCharRefReplaceErrors(exc: *mut PyObject) -> *mut PyObject;
pub fn PyCodec_BackslashReplaceErrors(exc: *mut PyObject) -> *mut PyObject;
// skipped non-limited PyCodec_NameReplaceErrors from Include/codecs.h
// skipped non-limited Py_hexdigits from Include/codecs.h
}
23 changes: 22 additions & 1 deletion src/ffi/compile.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
use crate::ffi::code::*;
use crate::ffi::object::PyObject;
use crate::ffi::pyarena::*;
use crate::ffi::pythonrun::*;
use crate::ffi::PyCodeObject;
use std::os::raw::{c_char, c_int};

// skipped non-limited PyCF_MASK
// skipped non-limited PyCF_MASK_OBSOLETE
// skipped non-limited PyCF_SOURCE_IS_UTF8
// skipped non-limited PyCF_DONT_IMPLY_DEDENT
// skipped non-limited PyCF_ONLY_AST
// skipped non-limited PyCF_IGNORE_COOKIE
// skipped non-limited PyCF_TYPE_COMMENTS
// skipped non-limited PyCF_ALLOW_TOP_LEVEL_AWAIT
// skipped non-limited PyCF_COMPILE_MASK

// skipped non-limited PyCompilerFlags
// skipped non-limited _PyCompilerFlags_INIT

#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(not(Py_LIMITED_API))]
Expand All @@ -30,6 +43,7 @@ pub const FUTURE_UNICODE_LITERALS: &str = "unicode_literals";
pub const FUTURE_BARRY_AS_BDFL: &str = "barry_as_FLUFL";
#[cfg(not(Py_LIMITED_API))]
pub const FUTURE_GENERATOR_STOP: &str = "generator_stop";
// skipped non-limited FUTURE_ANNOTATIONS

#[cfg(not(Py_LIMITED_API))]
extern "C" {
Expand Down Expand Up @@ -58,14 +72,21 @@ extern "C" {
filename: *mut PyObject,
) -> *mut PyFutureFeatures;

// skipped non-limited _Py_Mangle
// skipped non-limited PY_INVALID_STACK_EFFECT

pub fn PyCompile_OpcodeStackEffect(opcode: c_int, oparg: c_int) -> c_int;

#[cfg(Py_3_8)]
pub fn PyCompile_OpcodeStackEffectWithJump(opcode: c_int, oparg: c_int, jump: c_int) -> c_int;

// skipped non-limited _PyASTOptimizeState
// skipped non-limited _PyAST_Optimize
}

pub const Py_single_input: c_int = 256;
pub const Py_file_input: c_int = 257;
pub const Py_eval_input: c_int = 258;
#[cfg(Py_3_8)]
pub const Py_func_type_input: c_int = 345;
// skipped Py_fstring_input
Loading