37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Keep _PyType_GetSubclasses's obj in opening C89 locals."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nPyObject\*\n_PyType_GetSubclasses\(PyTypeObject \*self\)\n\{(.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert match, "_PyType_GetSubclasses definition missing"
|
|
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
|
|
assert re.match(
|
|
r"\s*PyObject \*subclasses;\s*Py_ssize_t i;\s*"
|
|
r"PyObject \*list = PyList_New\(0\);\s*PyObject \*ref;\s*"
|
|
r"PyObject \*obj;",
|
|
body,
|
|
), "_PyType_GetSubclasses: obj must be in the opening declaration block (C89)"
|
|
assert len(re.findall(r"\bPyObject\s*\*\s*obj\b", body)) == 1, (
|
|
"_PyType_GetSubclasses: declare obj exactly once without initialization"
|
|
)
|
|
assert body.count("PyWeakref_GET_OBJECT(ref)") == 1, (
|
|
"_PyType_GetSubclasses: preserve the single weakref object read"
|
|
)
|
|
assert re.search(
|
|
r"while \(PyDict_Next\(subclasses, &i, NULL, &ref\)\) \{\s*"
|
|
r"assert\(PyWeakref_CheckRef\(ref\)\);\s*"
|
|
r"obj = PyWeakref_GET_OBJECT\(ref\);\s*"
|
|
r"if \(obj == Py_None\) \{\s*continue;\s*\}\s*"
|
|
r"assert\(PyType_Check\(obj\)\);\s*"
|
|
r"if \(PyList_Append\(list, obj\) < 0\) \{\s*"
|
|
r"Py_DECREF\(list\);\s*return NULL;\s*\}\s*\}\s*return list;\s*$",
|
|
body,
|
|
), "_PyType_GetSubclasses: preserve obj assignment timing and loop control flow"
|
|
print("_PyType_GetSubclasses obj C89 declaration and preserved assignment timing: PASS")
|