#!/usr/bin/env python3 """Check only _PyTuple_FromArraySteal's allocation-failure and success loop C89 fixes.""" import re import sys from pathlib import Path source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/tupleobject.c") match = re.search( r"PyObject \*\n_PyTuple_FromArraySteal\(PyObject \*const \*src, Py_ssize_t n\)\n\{(.*?)\n\}", source.read_text(), re.S, ) assert match, "_PyTuple_FromArraySteal definition not found" body = match.group(1) assert re.match( r"\s*PyTupleObject \*tuple;\s*Py_ssize_t i;\s*PyObject \*\*dst;\s*if \(n == 0\)", body ), "_PyTuple_FromArraySteal: function-scope Py_ssize_t i must precede statements" assert "for (Py_ssize_t i =" not in body, ( "_PyTuple_FromArraySteal: success loop must reuse function-scope i with assignment" ) expected = """ PyTupleObject *tuple; Py_ssize_t i; PyObject **dst; if (n == 0) { return tuple_get_empty(); } tuple = tuple_alloc(n); if (tuple == NULL) { for (i = 0; i < n; i++) { Py_DECREF(src[i]); } return NULL; } dst = tuple->ob_item; for (i = 0; i < n; i++) { PyObject *item = src[i]; dst[i] = item; } _PyObject_GC_TRACK(tuple); return (PyObject *)tuple; """ assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), ( "preserve empty return/allocation/NULL check, failure loop initialization, " "condition, increment, DECREF and NULL return order; retain later " "dst/item declarations and success-loop initialization/condition/increment/order" ) print("_PyTuple_FromArraySteal failure/success C89 loops and evaluation/DECREF/return order: PASS")