50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Keep lookup_maybe_method's descriptor getter C89-safe without reordering."""
|
|
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 PyObject \*\nlookup_maybe_method\(PyObject \*self, PyObject \*attr, int \*unbound\)\n\{(.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert match, "lookup_maybe_method definition missing"
|
|
body = match.group(1)
|
|
assert re.match(
|
|
r"\s*PyObject \*res = _PyType_Lookup\(Py_TYPE\(self\), attr\);\s*descrgetfunc f;",
|
|
body,
|
|
), "lookup_maybe_method: f must be declared in the opening declaration block (C89)"
|
|
assert len(re.findall(r"\bdescrgetfunc\s+f\b", body)) == 1, (
|
|
"lookup_maybe_method: declare the descriptor getter exactly once"
|
|
)
|
|
expected = """
|
|
PyObject *res = _PyType_Lookup(Py_TYPE(self), attr);
|
|
descrgetfunc f;
|
|
if (res == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
|
|
/* Avoid temporary PyMethodObject */
|
|
*unbound = 1;
|
|
Py_INCREF(res);
|
|
}
|
|
else {
|
|
*unbound = 0;
|
|
f = Py_TYPE(res)->tp_descr_get;
|
|
if (f == NULL) {
|
|
Py_INCREF(res);
|
|
}
|
|
else {
|
|
res = f(res, self, (PyObject *)(Py_TYPE(self)));
|
|
}
|
|
}
|
|
return res;
|
|
"""
|
|
assert body.split() == expected.split(), (
|
|
"lookup_maybe_method: preserve getter evaluation after *unbound = 0 and all control flow"
|
|
)
|
|
print("lookup_maybe_method descriptor getter C89 declaration and unchanged evaluation/control flow: PASS")
|