34 lines
1.6 KiB
Python
34 lines
1.6 KiB
Python
"""Check type_set_bases declares res with opening locals without moving assignments."""
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
|
|
source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nstatic int\ntype_set_bases\(PyTypeObject \*type, PyObject \*new_bases, void \*context\)\n\{(.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert match, "type_set_bases definition missing"
|
|
body = match.group(1)
|
|
assert re.search(
|
|
r"\A\n\s*Py_ssize_t n;\n\s*Py_ssize_t i;\n\s*PyTypeObject \*new_base;\n"
|
|
r"\s*PyObject \*old_bases;\n\s*PyTypeObject \*old_base;\n\s*PyObject \*temp;\n\s*int res;",
|
|
body,
|
|
), "type_set_bases: res must be declared with the opening locals"
|
|
assert body.count("int res;") == 1, "res declaration must occur once"
|
|
assert re.findall(r"\bres\s*=\s*([^;]+);", body) == [
|
|
"0", "add_all_subclasses(type, new_bases)", "0",
|
|
], "type_set_bases: preserve all res assignments and their order"
|
|
without_comments = re.sub(r"/\*.*?\*/|//[^\n]*", "", body, flags=re.S)
|
|
assert re.search(
|
|
r"if \(mro_hierarchy\(type, temp\) < 0\) \{\s*goto undo;\s*\}\s*"
|
|
r"Py_DECREF\(temp\);\s*res = 0;\s*if \(type->tp_bases == new_bases\) \{\s*"
|
|
r"remove_all_subclasses\(type, old_bases\);\s*"
|
|
r"res = add_all_subclasses\(type, new_bases\);\s*update_all_slots\(type\);\s*"
|
|
r"\}\s*else \{\s*res = 0;\s*\}\s*"
|
|
r"Py_DECREF\(old_bases\);\s*Py_DECREF\(old_base\);\s*"
|
|
r"assert\(_PyType_CheckConsistency\(type\)\);\s*return res;",
|
|
without_comments,
|
|
), "type_set_bases: preserve res assignment evaluation and control-flow order"
|