55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Check tupledealloc's C89 declaration and exact teardown evaluation order."""
|
|
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"static void\ntupledealloc\(PyTupleObject \*op\)\n\{(.*?)\n\}",
|
|
source.read_text(),
|
|
re.S,
|
|
)
|
|
assert match, "tupledealloc definition not found"
|
|
body = match.group(1)
|
|
assert re.match(r"\s*Py_ssize_t i;", body), (
|
|
"tupledealloc: i must be declared without initializer before the empty "
|
|
"tuple check; declaration after Py_TRASHCAN_BEGIN is not C89 compatible"
|
|
)
|
|
expected = """
|
|
Py_ssize_t i;
|
|
if (Py_SIZE(op) == 0) {
|
|
/* The empty tuple is statically allocated. */
|
|
if (op == &_Py_SINGLETON(tuple_empty)) {
|
|
#ifdef Py_DEBUG
|
|
_Py_FatalRefcountError("deallocating the empty tuple singleton");
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
#ifdef Py_DEBUG
|
|
/* tuple subclasses have their own empty instances. */
|
|
assert(!PyTuple_CheckExact(op));
|
|
#endif
|
|
}
|
|
|
|
PyObject_GC_UnTrack(op);
|
|
Py_TRASHCAN_BEGIN(op, tupledealloc)
|
|
|
|
i = Py_SIZE(op);
|
|
while (--i >= 0) {
|
|
Py_XDECREF(op->ob_item[i]);
|
|
}
|
|
// This will abort on the empty singleton (if there is one).
|
|
if (!maybe_freelist_push(op)) {
|
|
Py_TYPE(op)->tp_free((PyObject *)op);
|
|
}
|
|
|
|
Py_TRASHCAN_END
|
|
"""
|
|
assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), (
|
|
"preserve empty-tuple guards, GC untracking, size assignment immediately "
|
|
"after trashcan entry, reverse item decrefs, freelist/free, and trashcan exit"
|
|
)
|
|
print("tupledealloc C89 declaration and exact teardown evaluation order: PASS")
|