mirror of
https://github.com/python/cpython.git
synced 2025-11-02 22:51:25 +00:00
Allow Py_LIMITED_API for (Py_GIL_DISABLED && _Py_OPAQUE_PYOBJECT)
API that's removed when _Py_OPAQUE_PYOBJECT is defined:
- PyObject_HEAD
- _PyObject_EXTRA_INIT
- PyObject_HEAD_INIT
- PyObject_VAR_HEAD
- struct _object (i.e. PyObject) (opaque)
- struct PyVarObject (opaque)
- Py_SIZE
- Py_SET_TYPE
- Py_SET_SIZE
- PyModuleDef_Base (opaque)
- PyModuleDef_HEAD_INIT
- PyModuleDef (opaque)
- _Py_IsImmortal
- _Py_IsStaticImmortal
Note that the `_Py_IsImmortal` removal (and a few other issues)
means _Py_OPAQUE_PYOBJECT only works with limited
API 3.14+ now.
Co-authored-by: Victor Stinner <vstinner@python.org>
145 lines
3.5 KiB
C
145 lines
3.5 KiB
C
// gh-116869: Basic C test extension to check that the Python C API
|
|
// does not emit C compiler warnings.
|
|
//
|
|
// Test also the internal C API if the TEST_INTERNAL_C_API macro is defined.
|
|
|
|
// Always enable assertions
|
|
#undef NDEBUG
|
|
|
|
#ifdef TEST_INTERNAL_C_API
|
|
# define Py_BUILD_CORE_MODULE 1
|
|
#endif
|
|
|
|
#include "Python.h"
|
|
|
|
#ifdef TEST_INTERNAL_C_API
|
|
// gh-135906: Check for compiler warnings in the internal C API.
|
|
// - Cython uses pycore_frame.h.
|
|
// - greenlet uses pycore_frame.h, pycore_interpframe_structs.h and
|
|
// pycore_interpframe.h.
|
|
# include "internal/pycore_frame.h"
|
|
# include "internal/pycore_gc.h"
|
|
# include "internal/pycore_interp.h"
|
|
# include "internal/pycore_interpframe.h"
|
|
# include "internal/pycore_interpframe_structs.h"
|
|
# include "internal/pycore_object.h"
|
|
# include "internal/pycore_pystate.h"
|
|
#endif
|
|
|
|
#ifndef MODULE_NAME
|
|
# error "MODULE_NAME macro must be defined"
|
|
#endif
|
|
|
|
#define _STR(NAME) #NAME
|
|
#define STR(NAME) _STR(NAME)
|
|
|
|
PyDoc_STRVAR(_testcext_add_doc,
|
|
"add(x, y)\n"
|
|
"\n"
|
|
"Return the sum of two integers: x + y.");
|
|
|
|
static PyObject *
|
|
_testcext_add(PyObject *Py_UNUSED(module), PyObject *args)
|
|
{
|
|
long i, j, res;
|
|
if (!PyArg_ParseTuple(args, "ll:foo", &i, &j)) {
|
|
return NULL;
|
|
}
|
|
res = i + j;
|
|
return PyLong_FromLong(res);
|
|
}
|
|
|
|
|
|
static PyMethodDef _testcext_methods[] = {
|
|
{"add", _testcext_add, METH_VARARGS, _testcext_add_doc},
|
|
{NULL, NULL, 0, NULL} // sentinel
|
|
};
|
|
|
|
|
|
static int
|
|
_testcext_exec(
|
|
#ifdef __STDC_VERSION__
|
|
PyObject *module
|
|
#else
|
|
PyObject *Py_UNUSED(module)
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef __STDC_VERSION__
|
|
if (PyModule_AddIntMacro(module, __STDC_VERSION__) < 0) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
|
|
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
|
|
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define _FUNC_NAME(NAME) PyInit_ ## NAME
|
|
#define FUNC_NAME(NAME) _FUNC_NAME(NAME)
|
|
|
|
// Converting from function pointer to void* has undefined behavior, but
|
|
// works on all known platforms, and CPython's module and type slots currently
|
|
// need it.
|
|
// (GCC doesn't have a narrower category for this than -Wpedantic.)
|
|
_Py_COMP_DIAG_PUSH
|
|
#if defined(__GNUC__)
|
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
|
#elif defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wpedantic"
|
|
#endif
|
|
|
|
static PyModuleDef_Slot _testcext_slots[] = {
|
|
{Py_mod_exec, (void*)_testcext_exec},
|
|
{0, NULL}
|
|
};
|
|
|
|
_Py_COMP_DIAG_POP
|
|
|
|
PyDoc_STRVAR(_testcext_doc, "C test extension.");
|
|
|
|
#ifndef _Py_OPAQUE_PYOBJECT
|
|
|
|
static struct PyModuleDef _testcext_module = {
|
|
PyModuleDef_HEAD_INIT, // m_base
|
|
STR(MODULE_NAME), // m_name
|
|
_testcext_doc, // m_doc
|
|
0, // m_size
|
|
_testcext_methods, // m_methods
|
|
_testcext_slots, // m_slots
|
|
NULL, // m_traverse
|
|
NULL, // m_clear
|
|
NULL, // m_free
|
|
};
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
FUNC_NAME(MODULE_NAME)(void)
|
|
{
|
|
return PyModuleDef_Init(&_testcext_module);
|
|
}
|
|
|
|
#else // _Py_OPAQUE_PYOBJECT
|
|
|
|
// Opaque PyObject means that PyModuleDef is also opaque and cannot be
|
|
// declared statically. See PEP 793.
|
|
// So, this part of module creation is split into a separate source file
|
|
// which uses non-limited API.
|
|
|
|
// (repeated definition to avoid creating a header)
|
|
extern PyObject *testcext_create_moduledef(
|
|
const char *name, const char *doc,
|
|
PyMethodDef *methods, PyModuleDef_Slot *slots);
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
FUNC_NAME(MODULE_NAME)(void)
|
|
{
|
|
return testcext_create_moduledef(
|
|
STR(MODULE_NAME), _testcext_doc, _testcext_methods, _testcext_slots);
|
|
}
|
|
|
|
#endif // _Py_OPAQUE_PYOBJECT
|