50 lines
2.3 KiB
Python
50 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify legacy MSVC gets runtime-assigned classobject type fields."""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
if len(sys.argv) != 3:
|
|
raise SystemExit("usage: vc6-classobject-typeinit.test.py classobject.c object.c")
|
|
class_source = Path(sys.argv[1]).read_text()
|
|
object_source = Path(sys.argv[2]).read_text()
|
|
legacy_condition = "!defined(MS_WINDOWS) || !defined(_MSC_VER) || _MSC_VER >= 1300"
|
|
for symbol in ("PyMethod_Type", "PyInstanceMethod_Type"):
|
|
start = class_source.index("PyTypeObject " + symbol + " = {")
|
|
end = class_source.index("\n};", start)
|
|
initializer = class_source[start:end]
|
|
if "#if " + legacy_condition not in initializer:
|
|
raise SystemExit(symbol + " designated initializer must be excluded for VC6 Windows")
|
|
|
|
start = object_source.index("_PyTypes_InitTypes(PyInterpreterState *interp)")
|
|
body_start = object_source.index("\n{\n", start) + 2
|
|
body_end = object_source.index("\n}\n", body_start)
|
|
body = object_source[body_start:body_end]
|
|
ready = body.index("PyType_Ready(type)")
|
|
call = body.index("_PyClassObject_InitTypes();")
|
|
if call > ready:
|
|
raise SystemExit("legacy type fields must be initialized before PyType_Ready")
|
|
|
|
helper = class_source.index("_PyClassObject_InitTypes(void)")
|
|
helper_body_start = class_source.index("\n{\n", helper) + 2
|
|
helper_body_end = class_source.index("\n}\n", helper_body_start)
|
|
helper_body = class_source[helper_body_start:helper_body_end]
|
|
assignments = {
|
|
"PyMethod_Type": (
|
|
"tp_name", "tp_basicsize", "tp_dealloc", "tp_vectorcall_offset", "tp_repr",
|
|
"tp_hash", "tp_call", "tp_getattro", "tp_setattro", "tp_flags", "tp_doc",
|
|
"tp_traverse", "tp_richcompare", "tp_weaklistoffset", "tp_methods", "tp_members",
|
|
"tp_getset", "tp_new",
|
|
),
|
|
"PyInstanceMethod_Type": (
|
|
"tp_name", "tp_basicsize", "tp_dealloc", "tp_repr", "tp_call", "tp_getattro",
|
|
"tp_setattro", "tp_flags", "tp_doc", "tp_traverse", "tp_richcompare",
|
|
"tp_members", "tp_getset", "tp_descr_get", "tp_new",
|
|
),
|
|
}
|
|
for symbol, fields in assignments.items():
|
|
for field in fields:
|
|
assignment = symbol + "." + field + " ="
|
|
if assignment not in helper_body:
|
|
raise SystemExit("missing legacy setup assignment " + assignment)
|
|
print("classobject VC6 type initialization coverage: PASS")
|