49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Check custom_mro's C89 declaration and lookup/decref evaluation order."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
start = source.index("type_mro_modified(PyTypeObject *type, PyObject *bases) {")
|
|
end = source.index("\n}", start)
|
|
function = source[start:end]
|
|
start = function.index(" if (custom) {")
|
|
end = function.index("\n n = PyTuple_GET_SIZE(bases);", start)
|
|
block = function[start:end]
|
|
assert re.match(
|
|
r"if \(custom\) \{\s*PyObject \*mro_meth, \*type_mro_meth;\s*"
|
|
r"int custom_mro;\s*mro_meth =",
|
|
block.strip(),
|
|
), "custom_mro must be declared in the opening declaration block"
|
|
assert len(re.findall(r"\bint\s+custom_mro\b", function)) == 1, (
|
|
"declare custom_mro exactly once"
|
|
)
|
|
expected = """
|
|
if (custom) {
|
|
PyObject *mro_meth, *type_mro_meth;
|
|
int custom_mro;
|
|
mro_meth = lookup_maybe_method(
|
|
(PyObject *)type, &_Py_ID(mro), &unbound);
|
|
if (mro_meth == NULL) {
|
|
goto clear;
|
|
}
|
|
type_mro_meth = lookup_maybe_method(
|
|
(PyObject *)&PyType_Type, &_Py_ID(mro), &unbound);
|
|
if (type_mro_meth == NULL) {
|
|
Py_DECREF(mro_meth);
|
|
goto clear;
|
|
}
|
|
custom_mro = (mro_meth != type_mro_meth);
|
|
Py_DECREF(mro_meth);
|
|
Py_DECREF(type_mro_meth);
|
|
if (custom_mro) {
|
|
goto clear;
|
|
}
|
|
}
|
|
"""
|
|
assert block.split() == expected.split(), (
|
|
"preserve both successful lookups before custom_mro assignment, "
|
|
"then decrefs and conditional, including lookup failure handling"
|
|
)
|
|
print("type_mro_modified custom_mro C89 declaration and evaluation order: PASS")
|