From 771c50b4654f2382e14efc103255b189935c17bb Mon Sep 17 00:00:00 2001 From: da-woods Date: Sun, 19 Nov 2023 13:00:25 +0000 Subject: [PATCH] Build Parsing.py in the limited api It isn't actually usable because it cimports other modules but it does build without warning. Changes are mainly to string handling (because that's the nature of parsing). Depends on #5841 and #5798 to actually build, but the PR itself doesn't depend on those --- Cython/Compiler/Code.py | 2 ++ Cython/Compiler/ExprNodes.py | 16 ++++++++----- Cython/Utility/Builtins.c | 36 ++++++++++++++++++++++++++-- Cython/Utility/ObjectHandling.c | 39 ++++++++++++++++++++++++++++-- Cython/Utility/Optimize.c | 42 +++++++++++++++++++++++++++++---- Cython/Utility/StringTools.c | 18 +++++++++++++- Cython/Utility/TypeConversion.c | 9 +++++++ 7 files changed, 147 insertions(+), 15 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 7f5f39cea8b..88e439781e3 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -1842,6 +1842,8 @@ def getvalue(self): return self.buffer.getvalue() def write(self, s): + if "__pyx_t_9 = (PyList_GET_SIZE(__pyx_v_keyword_args) != 0);" in s: + pass #import pdb; pdb.set_trace() if '\n' in s: self._write_lines(s) else: diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 4012ac6422a..2bffbedc40c 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -14155,13 +14155,14 @@ class CoerceToBooleanNode(CoercionNode): type = PyrexTypes.c_bint_type + # Note that all of these need a check if CYTHON_ASSUME_SAFE_MACROS is false _special_builtins = { - Builtin.list_type: 'PyList_GET_SIZE', - Builtin.tuple_type: 'PyTuple_GET_SIZE', - Builtin.set_type: 'PySet_GET_SIZE', - Builtin.frozenset_type: 'PySet_GET_SIZE', - Builtin.bytes_type: 'PyBytes_GET_SIZE', - Builtin.bytearray_type: 'PyByteArray_GET_SIZE', + Builtin.list_type: '__Pyx_PyList_GET_SIZE', + Builtin.tuple_type: '__Pyx_PyTuple_GET_SIZE', + Builtin.set_type: '__Pyx_PySet_GET_SIZE', + Builtin.frozenset_type: '__Pyx_PySet_GET_SIZE', + Builtin.bytes_type: '__Pyx_PyBytes_GET_SIZE', + Builtin.bytearray_type: '__Pyx_PyByteArray_GET_SIZE', Builtin.unicode_type: '__Pyx_PyUnicode_IS_TRUE', } @@ -14193,6 +14194,9 @@ def generate_result_code(self, code): checks = ["(%s != Py_None)" % self.arg.py_result()] if self.arg.may_be_none() else [] checks.append("(%s(%s) != 0)" % (test_func, self.arg.py_result())) code.putln("%s = %s;" % (self.result(), '&&'.join(checks))) + code.putln("#if !CYTHON_ASSUME_SAFE_MACROS") + code.putln(code.error_goto_if_neg(self.result(), self.pos)) + code.putln("#endif") else: code.putln( "%s = __Pyx_PyObject_IsTrue(%s); %s" % ( diff --git a/Cython/Utility/Builtins.c b/Cython/Utility/Builtins.c index d6b67c8909c..7e1a31f0eca 100644 --- a/Cython/Utility/Builtins.c +++ b/Cython/Utility/Builtins.c @@ -331,16 +331,34 @@ static long __Pyx__PyObject_Ord(PyObject* c); /*proto*/ static long __Pyx__PyObject_Ord(PyObject* c) { Py_ssize_t size; if (PyBytes_Check(c)) { + #if CYTHON_ASSUME_SAFE_MACROS size = PyBytes_GET_SIZE(c); if (likely(size == 1)) { return (unsigned char) PyBytes_AS_STRING(c)[0]; } -#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + #else + size = PyBytes_Size(c); + if (unlikely(size) < 0) return -1; + else if (likely(size==1)) { + char *data = PyBytes_AsString(c); + if (unlikely(!data)) return -1; + return (unsigned char) data[0]; + } + #endif } else if (PyByteArray_Check(c)) { +#if CYTHON_ASSUME_SAFE_MACROS size = PyByteArray_GET_SIZE(c); if (likely(size == 1)) { return (unsigned char) PyByteArray_AS_STRING(c)[0]; } +#else + size = PyByteArray_Size(c); + if (unlikely(size<0)) return -1; + else if (likely(size == 1)) { + char *data = PyByteArray_AsString(c); + if (unlikely(!data)) return -1; + return (unsigned char) data[0]; + } #endif } else { // FIXME: support character buffers - but CPython doesn't support them either @@ -475,8 +493,22 @@ static CYTHON_INLINE PyObject* __Pyx_PyFrozenSet_New(PyObject* it) { result = PyFrozenSet_New(it); if (unlikely(!result)) return NULL; - if ((PY_VERSION_HEX >= 0x031000A1) || likely(PySet_GET_SIZE(result))) + if ((__PYX_LIMITED_VERSION_HEX >= 0x031000A1)) return result; + { + Py_ssize_t size; + #if CYTHON_ASSUME_SAFE_MACROS + size = PySet_GET_SIZE(result); + #else + size = PySet_Size(result); + if (size < 0) { + Py_DECREF(result); + return NULL; + } + #endif + if (likely(size)) + return result; + } // empty frozenset is a singleton (on Python <3.10) // seems wasteful, but CPython does the same Py_DECREF(result); diff --git a/Cython/Utility/ObjectHandling.c b/Cython/Utility/ObjectHandling.c index 9bf9744a61f..c71fe43d095 100644 --- a/Cython/Utility/ObjectHandling.c +++ b/Cython/Utility/ObjectHandling.c @@ -52,9 +52,17 @@ static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/ static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) { if (t == Py_None) { __Pyx_RaiseNoneNotIterableError(); - } else if (PyTuple_GET_SIZE(t) < index) { - __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t)); } else { +#if CYTHON_ASSUME_SAFE_MACROS + Py_ssize_t size = PyTuple_GET_SIZE(t); +#else + Py_ssize_t size = PyTuple_Size(t); + if (unlikely(size < 0)) return; +#endif + if (size < index) { + __Pyx_RaiseNeedMoreValuesError(size); + return; + } __Pyx_RaiseTooManyValuesError(index); } } @@ -79,12 +87,17 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { /////////////// UnpackTuple2.proto /////////////// +#if CYTHON_ASSUME_SAFE_MACROS #define __Pyx_unpack_tuple2(tuple, value1, value2, is_tuple, has_known_size, decref_tuple) \ (likely(is_tuple || PyTuple_Check(tuple)) ? \ (likely(has_known_size || PyTuple_GET_SIZE(tuple) == 2) ? \ __Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple) : \ (__Pyx_UnpackTupleError(tuple, 2), -1)) : \ __Pyx_unpack_tuple2_generic(tuple, value1, value2, has_known_size, decref_tuple)) +#else +static CYTHON_INLINE int __Pyx_unpack_tuple2( + PyObject* tuple, PyObject** value1, PyObject** value2, int is_tuple, int has_known_size, int decref_tuple); +#endif static CYTHON_INLINE int __Pyx_unpack_tuple2_exact( PyObject* tuple, PyObject** value1, PyObject** value2, int decref_tuple); @@ -96,6 +109,28 @@ static int __Pyx_unpack_tuple2_generic( //@requires: UnpackTupleError //@requires: RaiseNeedMoreValuesToUnpack +#if !CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_unpack_tuple2( + PyObject* tuple, PyObject** value1, PyObject** value2, int is_tuple, int has_known_size, int decref_tuple) { + if (likely(is_tuple || PyTuple_Check(tuple))) { + Py_ssize_t size; + if (has_known_size) { + return __Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple); + } + size = PyTuple_Size(tuple); + if (unlikely(size < 0)) { + return -1; + } else if (likely(size == 2)) { + return __Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple); + } + __Pyx_UnpackTupleError(tuple, 2); + return -1; + } else { + return __Pyx_unpack_tuple2_generic(tuple, value1, value2, has_known_size, decref_tuple); + } +} +#endif + static CYTHON_INLINE int __Pyx_unpack_tuple2_exact( PyObject* tuple, PyObject** pvalue1, PyObject** pvalue2, int decref_tuple) { PyObject *value1 = NULL, *value2 = NULL; diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c index 1eb97ba9329..7665569ee18 100644 --- a/Cython/Utility/Optimize.c +++ b/Cython/Utility/Optimize.c @@ -361,8 +361,20 @@ static CYTHON_INLINE int __Pyx_dict_iter_next( } Py_INCREF(key); Py_INCREF(value); + #if CYTHON_ASSUME_SAFE_MACROS PyTuple_SET_ITEM(tuple, 0, key); PyTuple_SET_ITEM(tuple, 1, value); + #else + if (unlikely(PyTuple_SetItem(tuple, 0, key) < 0)) { + Py_DECREF(value); // we haven't set this yet + Py_DECREF(tuple); + return -1; + } + if (unlikely(PyTuple_SetItem(tuple, 1, value) < 0)) { + Py_DECREF(tuple); + return -1; + } + #endif *pitem = tuple; } else { if (pkey) { @@ -376,16 +388,38 @@ static CYTHON_INLINE int __Pyx_dict_iter_next( } return 1; } else if (PyTuple_CheckExact(iter_obj)) { - Py_ssize_t pos = *ppos; - if (unlikely(pos >= PyTuple_GET_SIZE(iter_obj))) return 0; + Py_ssize_t pos = *ppos, iter_size; + #if CYTHON_ASSUME_SAFE_MACROS + iter_size = PyTuple_GET_SIZE(iter_obj); + #else + iter_size = PyTuple_Size(iter_obj); + if (unlikely(iter_size < 0)) return -1; + #endif + if (unlikely(pos >= iter_size)) return 0; *ppos = pos + 1; + #if CYTHON_ASSUME_SAFE_MACROS next_item = PyTuple_GET_ITEM(iter_obj, pos); + #else + next_item = PyTuple_GetItem(iter_obj, pos); + if (unlikely(!next_item)) return -1; + #endif Py_INCREF(next_item); } else if (PyList_CheckExact(iter_obj)) { - Py_ssize_t pos = *ppos; - if (unlikely(pos >= PyList_GET_SIZE(iter_obj))) return 0; + Py_ssize_t pos = *ppos, iter_size; + #if CYTHON_ASSUME_SAFE_MACROS + siiter_sizeze = PyList_GET_SIZE(iter_obj); + #else + iter_size = PyList_Size(iter_obj); + if (unlikely(iter_size < 0)) return -1; + #endif + if (unlikely(pos >= iter_size)) return 0; *ppos = pos + 1; + #if CYTHON_ASSUME_SAFE_MACROS next_item = PyList_GET_ITEM(iter_obj, pos); + #else + next_item = PyList_GetItem(iter_obj, pos); + if (unlikely(!next_item)) return -1; + #endif Py_INCREF(next_item); } else #endif diff --git a/Cython/Utility/StringTools.c b/Cython/Utility/StringTools.c index 1597f448330..59f30aa5dc3 100644 --- a/Cython/Utility/StringTools.c +++ b/Cython/Utility/StringTools.c @@ -75,7 +75,7 @@ static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 ch //////////////////// PyUCS4InUnicode //////////////////// -#if PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE)) +#if (PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE)) && !CYTHON_COMPILING_IN_LIMITED_API) #if PY_VERSION_HEX < 0x03090000 #define __Pyx_PyUnicode_AS_UNICODE(op) PyUnicode_AS_UNICODE(op) @@ -113,6 +113,14 @@ static int __Pyx_PyUnicodeBufferContainsUCS4_BMP(Py_UNICODE* buffer, Py_ssize_t #endif static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) { +#if CYTHON_COMPILING_IN_LIMITED_API + // Note that from Python 3.7, the indices of FindChar account for wraparound so no + // need to check the length + Py_ssize_t idx = PyUnicode_FindChar(unicode, character, 0, -1, 1); + if (idx == -1) return 0; // not found + else if (unlikely(idx < 0)) return -1; // error + else return 1; // found +#else const int kind = PyUnicode_KIND(unicode); #ifdef PyUnicode_WCHAR_KIND if (likely(kind != PyUnicode_WCHAR_KIND)) @@ -144,6 +152,7 @@ static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 ch } #endif +#endif } @@ -550,12 +559,18 @@ static CYTHON_INLINE PyObject* __Pyx_decode_bytearray( /////////////// PyUnicode_Substring.proto /////////////// +#if !CYTHON_COMPILING_IN_LIMITED_API static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( PyObject* text, Py_ssize_t start, Py_ssize_t stop); +#else +// In the limited API since 3.7 +#define __Pyx_PyUnicode_Substring(text, start, stop) PyUnicode_Substring(text, start, stop) +#endif /////////////// PyUnicode_Substring /////////////// //@substitute: naming +#if !CYTHON_COMPILING_IN_LIMITED_API static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( PyObject* text, Py_ssize_t start, Py_ssize_t stop) { Py_ssize_t length; @@ -577,6 +592,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( return PyUnicode_FromKindAndData(PyUnicode_KIND(text), PyUnicode_1BYTE_DATA(text) + start*PyUnicode_KIND(text), stop-start); } +#endif /////////////// py_unicode_istitle.proto /////////////// diff --git a/Cython/Utility/TypeConversion.c b/Cython/Utility/TypeConversion.c index 05764a00ec3..0f5c24abbfa 100644 --- a/Cython/Utility/TypeConversion.c +++ b/Cython/Utility/TypeConversion.c @@ -576,9 +576,18 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*); static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) { Py_ssize_t length; + #if CYTHON_ASSUME_SAFE_MACROS length = PyUnicode_GET_LENGTH(x); + #else + length = PyUnicode_GetLength(x); + if (length < 0) return (Py_UCS4)-1; + #endif if (likely(length == 1)) { + #if CYTHON_ASSUME_SAFE_MACROS return PyUnicode_READ_CHAR(x, 0); + #else + return PyUnicode_ReadChar(x, 0); + #endif } PyErr_Format(PyExc_ValueError, "only single character unicode strings can be converted to Py_UCS4, "