55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Keep only non-GC subtype_dealloc's type_needs_decref C89-safe."""
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nstatic void\nsubtype_dealloc\(PyObject \*self\)\n\{(.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert match, "subtype_dealloc definition missing"
|
|
body = match.group(1)
|
|
start = body.index(" if (!_PyType_IS_GC(type)) {")
|
|
end = body.index(" /* We get here only if the type has GC */", start)
|
|
branch = re.sub(r"/\*.*?\*/|//[^\n]*", "", body[start:end], flags=re.S)
|
|
assert re.match(r"\s*if \(!_PyType_IS_GC\(type\)\) \{\s*int type_needs_decref;", branch), (
|
|
"non-GC subtype_dealloc: type_needs_decref must be declared at block entry (C89)"
|
|
)
|
|
expected = """
|
|
if (!_PyType_IS_GC(type)) {
|
|
int type_needs_decref;
|
|
if (type->tp_finalize) {
|
|
if (PyObject_CallFinalizerFromDealloc(self) < 0)
|
|
return;
|
|
}
|
|
if (type->tp_del) {
|
|
type->tp_del(self);
|
|
if (Py_REFCNT(self) > 0) {
|
|
return;
|
|
}
|
|
}
|
|
base = type;
|
|
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
|
|
base = base->tp_base;
|
|
assert(base);
|
|
}
|
|
type = Py_TYPE(self);
|
|
type_needs_decref = (type->tp_flags & Py_TPFLAGS_HEAPTYPE
|
|
&& !(base->tp_flags & Py_TPFLAGS_HEAPTYPE));
|
|
assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
|
|
assert(basedealloc);
|
|
basedealloc(self);
|
|
if (type_needs_decref) {
|
|
Py_DECREF(type);
|
|
}
|
|
return;
|
|
}
|
|
"""
|
|
assert branch.split() == expected.split(), (
|
|
"non-GC subtype_dealloc: preserve assignment evaluation point and all control flow"
|
|
)
|
|
print("non-GC subtype_dealloc type_needs_decref C89 declaration and unchanged control flow: PASS")
|