port: record MSVC6 frontier through md5module
This commit is contained in:
@@ -132,6 +132,111 @@ else
|
||||
bad "pymath.h provides a VC6 Py_NAN fallback without C99 NAN"
|
||||
fi
|
||||
|
||||
# Keep the current mathmodule.c VC6 frontier explicit: MSVC6 has no CRT
|
||||
# atanh(), so the guarded fallback must preserve signed zero, NaN, and domain
|
||||
# error behavior while native compilers retain the CRT path.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#else\n# define PY_MATH_ULONG_LONG", start)
|
||||
block = source[start:end]
|
||||
if "m_atanh(double x)" not in block:
|
||||
raise SystemExit("VC6 m_atanh fallback missing")
|
||||
if "if (Py_IS_NAN(x))" not in block:
|
||||
raise SystemExit("m_atanh NaN handling missing")
|
||||
if "if (a >= 1.0)" not in block or "errno = EDOM;" not in block:
|
||||
raise SystemExit("m_atanh domain handling missing")
|
||||
if "return x;" not in block:
|
||||
raise SystemExit("m_atanh signed-zero/small-input preservation missing")
|
||||
if "FUNC1(atanh, m_atanh, 0," not in source:
|
||||
raise SystemExit("atanh is not routed through m_atanh")
|
||||
if "# define m_atanh atanh" not in source:
|
||||
raise SystemExit("native m_atanh mapping missing")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 atanh fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 atanh fallback"
|
||||
fi
|
||||
|
||||
# Keep the current mathmodule.c VC6 frontier explicit: MSVC6 has no CRT
|
||||
# cbrt(), so the guarded fallback must preserve zero/NaN and native mapping.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#else\n# define PY_MATH_ULONG_LONG", start)
|
||||
block = source[start:end]
|
||||
if "m_cbrt(double x)" not in block:
|
||||
raise SystemExit("VC6 m_cbrt fallback missing")
|
||||
if "if (Py_IS_NAN(x))" not in block or "if (x == 0.0)" not in block:
|
||||
raise SystemExit("m_cbrt special-value handling missing")
|
||||
if "FUNC1(cbrt, m_cbrt, 0," not in source:
|
||||
raise SystemExit("cbrt is not routed through m_cbrt")
|
||||
if "# define m_cbrt cbrt" not in source:
|
||||
raise SystemExit("native m_cbrt mapping missing")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 cbrt fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 cbrt fallback"
|
||||
fi
|
||||
|
||||
# Keep the current mathmodule.c VC6 frontier explicit: MSVC6 has no CRT
|
||||
# exp2(), so the guarded fallback must preserve NaN handling and native mapping.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#else\n# define PY_MATH_ULONG_LONG", start)
|
||||
block = source[start:end]
|
||||
if "m_exp2(double x)" not in block:
|
||||
raise SystemExit("VC6 m_exp2 fallback missing")
|
||||
if "if (Py_IS_NAN(x))" not in block:
|
||||
raise SystemExit("m_exp2 NaN handling missing")
|
||||
if "FUNC1(exp2, m_exp2, 1," not in source:
|
||||
raise SystemExit("exp2 is not routed through m_exp2")
|
||||
if "# define m_exp2 exp2" not in source:
|
||||
raise SystemExit("native m_exp2 mapping missing")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 exp2 fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 exp2 fallback"
|
||||
fi
|
||||
|
||||
# Keep the current mathmodule.c VC6 frontier explicit: MSVC6 has no CRT
|
||||
# expm1(), so the guarded fallback must preserve small inputs and native mapping.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#else\n# define PY_MATH_ULONG_LONG", start)
|
||||
block = source[start:end]
|
||||
if "m_expm1(double x)" not in block:
|
||||
raise SystemExit("VC6 m_expm1 fallback missing")
|
||||
if "if (fabs(x) < 1e-5)" not in block:
|
||||
raise SystemExit("m_expm1 small-input handling missing")
|
||||
if "FUNC1(expm1, m_expm1, 1," not in source:
|
||||
raise SystemExit("expm1 is not routed through m_expm1")
|
||||
if "# define m_expm1 expm1" not in source:
|
||||
raise SystemExit("native m_expm1 mapping missing")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 expm1 fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 expm1 fallback"
|
||||
fi
|
||||
|
||||
# Keep the first _pickle.c VC6/C89 slice explicit: batch_list_exact() must
|
||||
# declare its shared error local before executable statements.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/_pickle.c" <<'PY'
|
||||
@@ -2468,6 +2573,233 @@ else
|
||||
bad "_datetimemodule _datetime_exec uses C89-compatible locals"
|
||||
fi
|
||||
|
||||
# The active mathmodule.c VC6 frontier must provide a local asinh fallback for
|
||||
# MSVC6 while leaving newer CRTs on the native implementation.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#endif\n\n/*[clinic input]", start)
|
||||
block = source[start:end]
|
||||
if "static double\nm_asinh(double x)" not in block:
|
||||
raise SystemExit("VC6 m_asinh fallback missing")
|
||||
if "FUNC1(asinh, asinh, 0," in source:
|
||||
raise SystemExit("mathmodule still routes asinh through the unavailable CRT symbol")
|
||||
if "FUNC1(asinh, m_asinh, 0," not in source:
|
||||
raise SystemExit("mathmodule does not route asinh through the fallback")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 asinh fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 asinh fallback"
|
||||
fi
|
||||
|
||||
# The active mathmodule.c VC6 frontier must provide a local acosh fallback for
|
||||
# MSVC6 while leaving newer CRTs on the native implementation.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("#if defined(_MSC_VER) && _MSC_VER < 1300")
|
||||
end = source.index("#endif\n\n/*[clinic input]", start)
|
||||
block = source[start:end]
|
||||
if "static double\nm_acosh(double x)" not in block:
|
||||
raise SystemExit("VC6 m_acosh fallback missing")
|
||||
if "FUNC1(acosh, acosh, 0," in source:
|
||||
raise SystemExit("mathmodule still routes acosh through the unavailable CRT symbol")
|
||||
if "FUNC1(acosh, m_acosh, 0," not in source:
|
||||
raise SystemExit("mathmodule does not route acosh through the fallback")
|
||||
PY
|
||||
then
|
||||
pass "mathmodule provides a guarded VC6 acosh fallback"
|
||||
else
|
||||
bad "mathmodule provides a guarded VC6 acosh fallback"
|
||||
fi
|
||||
|
||||
# The active mathmodule.c VC6/C89 frontier must hoist math_gcd()'s borrowed
|
||||
# singleton local before executable statements while preserving its assignment point.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("math_gcd(PyObject *module")
|
||||
end = source.index("\n}\n\nPyDoc_STRVAR(math_gcd_doc", start) + 2
|
||||
function = source[start:end]
|
||||
opening = function[:function.index(" if (nargs == 0)")]
|
||||
if " PyObject *res, *x, *one;\n" not in opening:
|
||||
raise SystemExit("math_gcd one declaration missing from opening group")
|
||||
if " PyObject *one = _PyLong_GetOne();" in function:
|
||||
raise SystemExit("math_gcd retains mixed one declaration")
|
||||
if function.count(" one = _PyLong_GetOne(); // borrowed ref\n") != 1:
|
||||
raise SystemExit("math_gcd one assignment missing")
|
||||
PY
|
||||
then
|
||||
pass "math_gcd uses C89 declaration-order-safe borrowed singleton local"
|
||||
else
|
||||
bad "math_gcd uses C89 declaration-order-safe borrowed singleton local"
|
||||
fi
|
||||
|
||||
# The active mathmodule.c VC6/C89 frontier must hoist math_lcm()'s borrowed
|
||||
# zero local before executable statements while preserving its assignment point.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("math_lcm(PyObject *module")
|
||||
end = source.index("\n}\n\n\nPyDoc_STRVAR(math_lcm_doc", start) + 2
|
||||
function = source[start:end]
|
||||
opening = function[:function.index(" if (nargs == 0)")]
|
||||
if " PyObject *res, *x, *zero;\n" not in opening:
|
||||
raise SystemExit("math_lcm zero declaration missing from opening group")
|
||||
if " PyObject *zero = _PyLong_GetZero();" in function:
|
||||
raise SystemExit("math_lcm retains mixed zero declaration")
|
||||
if function.count(" zero = _PyLong_GetZero(); // borrowed ref\n") != 1:
|
||||
raise SystemExit("math_lcm zero assignment missing or duplicated")
|
||||
if " Py_INCREF(zero);" in function or " Py_DECREF(zero);" in function:
|
||||
raise SystemExit("math_lcm borrowed zero reference ownership changed")
|
||||
PY
|
||||
then
|
||||
pass "math_lcm uses C89 declaration-order-safe borrowed zero local"
|
||||
else
|
||||
bad "math_lcm uses C89 declaration-order-safe borrowed zero local"
|
||||
fi
|
||||
|
||||
# The active gcmodule.c VC6/C89 frontier must not redeclare clear_unreachable_mask()
|
||||
# locals after the initial declaration group.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/gcmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("clear_unreachable_mask(PyGC_Head *unreachable)")
|
||||
end = source.index("\n}\n\n/* A traversal callback", start) + 2
|
||||
function = source[start:end]
|
||||
if function.count(" PyGC_Head *gc, *next;\n") != 1:
|
||||
raise SystemExit("clear_unreachable_mask duplicate local declaration")
|
||||
PY
|
||||
then
|
||||
pass "gcmodule clear_unreachable_mask uses one C89 declaration group"
|
||||
else
|
||||
bad "gcmodule clear_unreachable_mask uses one C89 declaration group"
|
||||
fi
|
||||
|
||||
# math_ceil() must declare x before statements and convert at the original point.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("math_ceil(PyObject *module, PyObject *number)")
|
||||
end = source.index("\n}\n", start) + 2
|
||||
function = source[start:end]
|
||||
opening = function[:function.index(" if (!PyFloat_CheckExact(number))")]
|
||||
assert (
|
||||
" double x;\n" in opening
|
||||
and "double x =" not in function
|
||||
and function.count(" x = PyFloat_AsDouble(number);\n") == 1
|
||||
and " if (PyErr_Occurred())\n return NULL;\n }\n"
|
||||
" x = PyFloat_AsDouble(number);\n"
|
||||
" if (x == -1.0 && PyErr_Occurred())" in function
|
||||
), "math_ceil needs an opening x declaration and original-point assignment"
|
||||
PY
|
||||
then
|
||||
pass "math_ceil uses an opening C89 declaration and original-point assignment"
|
||||
else
|
||||
bad "math_ceil uses an opening C89 declaration and original-point assignment"
|
||||
fi
|
||||
|
||||
# math_isqrt() must declare its slow-path loop counter in the opening group.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("math_isqrt(PyObject *module, PyObject *n)")
|
||||
end = source.index("\n}\n", start) + 2
|
||||
function = source[start:end]
|
||||
opening = function[:function.index(" n = _PyNumber_Index(n);")]
|
||||
assert (
|
||||
" int s;\n" in opening
|
||||
and "for (int s" not in function
|
||||
and function.count(" for (s = c_bit_length - 6; s >= 0; --s) {\n") == 1
|
||||
), "math_isqrt needs an opening int s declaration and assignment-only loop initializer"
|
||||
PY
|
||||
then
|
||||
pass "math_isqrt uses an opening C89 loop counter declaration"
|
||||
else
|
||||
bad "math_isqrt uses an opening C89 loop counter declaration"
|
||||
fi
|
||||
|
||||
# _check_long_mult_overflow() must declare temporaries before its early return
|
||||
# while evaluating their expressions only at the original point after it.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("_check_long_mult_overflow(long a, long b)")
|
||||
end = source.index("\n}\n", start) + 2
|
||||
function = source[start:end]
|
||||
opening, statements = function.split(" if (doubled_longprod == doubleprod)", 1)
|
||||
for name in ("diff", "absdiff", "absprod"):
|
||||
assert f" double {name};\n" in opening, (
|
||||
f"_check_long_mult_overflow needs an opening {name} declaration"
|
||||
)
|
||||
assert f"double {name}" not in statements, (
|
||||
f"_check_long_mult_overflow retains a mixed {name} declaration"
|
||||
)
|
||||
assert statements == """ {
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff = doubled_longprod - doubleprod;
|
||||
absdiff = diff >= 0.0 ? diff : -diff;
|
||||
absprod = doubleprod >= 0.0 ? doubleprod : -doubleprod;
|
||||
|
||||
if (32.0 * absdiff <= absprod) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}""", "_check_long_mult_overflow must preserve evaluation order and return logic"
|
||||
PY
|
||||
then
|
||||
pass "_check_long_mult_overflow uses opening C89 declarations and original-point assignments"
|
||||
else
|
||||
bad "_check_long_mult_overflow uses opening C89 declarations and original-point assignments"
|
||||
fi
|
||||
|
||||
# fast_comb_limits2 must be declared before perm_comb_small() executes statements.
|
||||
if python3 - "$REPO_ROOT/cpython/Modules/mathmodule.c" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
start = source.index("perm_comb_small(PY_MATH_ULONG_LONG n,")
|
||||
end = source.index("\n}\n", start) + 2
|
||||
function = source[start:end]
|
||||
opening, statements = function.split(" if (k == 0) {", 1)
|
||||
declaration = """ static const PY_MATH_ULONG_LONG fast_comb_limits2[] = {
|
||||
0, PY_MATH_ULLONG_MAX, (PY_MATH_ULONG_LONG)4294967296I64, 3329022, 102570, 13467, 3612, 1449, // 0-7
|
||||
746, 453, 308, 227, 178, 147, // 8-13
|
||||
};"""
|
||||
assert (
|
||||
declaration in opening
|
||||
and function.count("static const PY_MATH_ULONG_LONG fast_comb_limits2[]") == 1
|
||||
and " if (k < Py_ARRAY_LENGTH(fast_comb_limits2) && n <= fast_comb_limits2[k]) {" in statements
|
||||
), "perm_comb_small opening fast_comb_limits2 declaration missing or changed"
|
||||
PY
|
||||
then
|
||||
pass "perm_comb_small uses a C89 declaration-order-safe fast_comb_limits2 array"
|
||||
else
|
||||
bad "perm_comb_small uses a C89 declaration-order-safe fast_comb_limits2 array"
|
||||
fi
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "FAILED"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user