From df996084917489884cd4f1761705f3dd46b45ece Mon Sep 17 00:00:00 2001 From: RayPals Date: Sat, 19 Sep 2026 18:28:14 +0000 Subject: [PATCH] port: record MSVC6 frontier through md5module --- PORT_STATUS.md | 357 ++++++ .../msvc600/cpython-3.11.16-vc6-headers.patch | 1078 +++++++++++++++++ scripts/vc6-probe-pythoncore-frontier.test.sh | 332 +++++ 3 files changed, 1767 insertions(+) diff --git a/PORT_STATUS.md b/PORT_STATUS.md index a60f250..889bf0a 100644 --- a/PORT_STATUS.md +++ b/PORT_STATUS.md @@ -1,5 +1,360 @@ # Port Status — CPython 3.11.16 to Windows 98 SE +## Latest revision (`mathmodule.c` `perm_comb_small` `fast_comb_limits2` C89 declaration-order slice) + +Date: 2026-09-19 18:22 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read before changes. The nested `cpython/` checkout remains detached with all pre-existing local port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. MSVC6 remains external/local-only through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`; the verified compiler is `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86`. + +The recorded frontier was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` was first. The first stable blocker was the C89 declaration-order defect at `mathmodule.c(3528)`–`(3532)`: `fast_comb_limits2` was declared after executable statements in `perm_comb_small()`. One focused coding-agent delegation was attempted; the Hermes delegation path failed because the runtime lacks the `anthropic` package. A direct Codex coding lane then added the focused regression assertion and ran the required red test, but stopped for confirmation because the array is `static const`; the minimal source edit was completed without broadening scope. No commits, pushes, or publication occurred. + +This slice changed only: + +- `cpython/Modules/mathmodule.c` — moved the complete `static const fast_comb_limits2[]` initializer into `perm_comb_small()`'s opening declaration group and removed the later declaration. The array contents, lookup, and control flow are unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused structural assertion. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +|| Command | Result | +||---|---| +|| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(3528)` C2143 and `(3532)` C2065/C2109 for `fast_comb_limits2`; later diagnostics began at `(3605)`; summary `total=35 compiled=34 cached=0 skipped=0`. | +|| Hermes focused delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used. | +|| direct `codex exec -s workspace-write --skip-git-repo-check ...` | exit 0; added the focused assertion and ran it red with the expected `fast_comb_limits2` missing-declaration assertion; source remained unchanged when the lane stopped for confirmation. | +|| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`, including `perm_comb_small uses a C89 declaration-order-safe fast_comb_limits2 array`. | +|| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past this family. Next first stable blocker is `md5module.c(36)` C2632 for `long long`, followed by a designated initializer at `(498)` and declaration-order errors at `(527)`; summary `total=36 compiled=35 cached=0 skipped=0`. Existing warnings remain `mathmodule.c(1336)` C4113/C4133, `arraymodule.c(2247)` C4761, `audioop.c(1536)`/`(1609)` C4761, and `faulthandler.c(542)` C4047. | +|| full applicable regression command (`bash -n` plus public/core/PathCch/getpath/stdint/frontier suites) | exit 0; all suites passed and the focused frontier suite ended with `ALL TESTS PASSED`. | +|| `git -C cpython diff > compat/msvc600/cpython-3.11.16-vc6-headers.patch`; `cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; regenerated patch matches the complete nested source diff byte-for-byte. `git -C cpython diff --check` also exited 0. | + +**Current compile-frontier state:** `perm_comb_small()` now compiles through its `fast_comb_limits2` C89 declaration-order family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is `md5module.c(36)`, beginning with the distinct VC6 `long long` family. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` `_check_long_mult_overflow` C89 declaration-order slice) + +Date: 2026-09-19 16:11 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changing anything, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. MSVC6 remains external/local-only through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`; the verified compiler is `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86`. + +The recorded `math_isqrt()` frontier was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was the distinct C89 declaration-order family in `_check_long_mult_overflow()` at lines 3186–3190. One focused Codex coding-agent delegation ran in the existing checkout with the requested scope, preserved local changes, and did not commit, push, or publish. The child added the focused assertion and implementation; no independent review is claimed. + +This slice changed only the following: + +- `cpython/Modules/mathmodule.c` — hoisted `diff`, `absdiff`, and `absprod` into `_check_long_mult_overflow()`'s opening declaration group and changed their original initializers to assignments at the same evaluation point. Overflow comparison and return behavior are unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused assertion for the opening declarations, assignment order, and unchanged return logic. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(3186)`–`(3190)` C2143/C2065 for the three post-statement `const double` declarations; later blockers at `(3525)` and `(3602)`; summary `total=35 compiled=34 cached=0 skipped=0`. | +| `codex exec -s workspace-write --skip-git-repo-check ...` | exit 0; focused implementation completed in the existing checkout; no commit, push, or publish. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after implementation | exit 0; `ALL TESTS PASSED`, including `_check_long_mult_overflow uses opening C89 declarations and original-point assignments`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after this slice | exit 2; `_check_long_mult_overflow()` compiled past this family. Next first stable blocker is the distinct declaration-order family at `mathmodule.c(3528)`–`(3532)` involving `fast_comb_limits2`; later diagnostics remain at `(3605)` onward. Summary `total=35 compiled=34 cached=0`. Existing warnings include `mathmodule.c(1336)` C4113/C4133, `arraymodule.c(2247)` C4761, `audioop.c(1536)`/`(1609)` C4761, and `faulthandler.c(542)` C4047. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0; all applicable regression suites and shell syntax checks passed. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `_check_long_mult_overflow()` now compiles through its C89 declaration-order family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is `mathmodule.c(3528)`–`(3532)`, the `fast_comb_limits2` declaration-order family. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` `math_isqrt` C89 loop-counter slice) + +Date: 2026-09-19 14:02 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changes, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified compiler remains MSVC6 `12.00.8804` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was the distinct C99 loop-counter declaration at `mathmodule.c(1945)`. One focused Codex coding-agent delegation ran in the existing checkout with the requested scope, preserved local changes, implemented only this slice, and did not commit, push, or publish. The child reported the required red-then-green focused TDD cycle; independent verification below confirms the green result. No independent review is claimed. + +This slice changed only the following: + +- `cpython/Modules/mathmodule.c` — added `int s` to `math_isqrt()`'s opening declaration group and changed `for (int s = ...)` to `for (s = ...)`; loop behavior is unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused assertion for the C89-safe `math_isqrt()` loop counter. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +|| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(1945)` C2143/C2065/C2059/C2143 for the C99 `for (int s = ...)`; later blockers at `(3185)`, `(3524)`, and `(3601)`; summary `total=35 compiled=34 cached=0`. | +| focused Codex delegation: `codex exec -s workspace-write --skip-git-repo-check ...` | exit 0; child performed the requested focused TDD implementation, with no commit/push/publish. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after implementation | exit 0; `ALL TESTS PASSED`, including `math_isqrt uses an opening C89 loop counter declaration`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after this slice | exit 2; `mathmodule.c` compiled past line 1945. Next first stable blocker is the distinct declaration-order family at `(3186)`–`(3190)` (`perm_comb_small()`); later blockers are `(3525)` and `(3602)`. Summary `total=35 compiled=34 cached=0`. Existing warnings remain `mathmodule.c(1336)`, `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0; all applicable regression suites and shell syntax checks passed. | +| `git -C cpython diff > compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython diff --check && cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `math_isqrt()` now compiles through its C89 loop-counter family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is `perm_comb_small()` at `mathmodule.c(3186)`–`(3190)`. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c guarded VC6 `expm1` fallback slice) + +Date: 2026-09-19 11:54 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changes, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified compiler remains MSVC6 `12.00.8804` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was the distinct missing-VC6-CRT `expm1` family at line 1350. One focused coding-agent delegation was attempted as required but failed before launch because the runtime lacks the `anthropic` package; no child files were used and no independent review is claimed. This slice addressed only `expm1`; later declaration-order blockers remain untouched. + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_expm1()` fallback using a small-input quadratic approximation and `exp(x) - 1.0`; routed only `FUNC1(expm1, ...)` through it. Native compilers retain the CRT path through `#define m_expm1 expm1`. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback, small-input handling, native mapping, and routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(1350)` C2065 for unavailable `expm1`; later declaration-order blockers at `(1936)`, `(3176)`, `(3515)`, and `(3592)`; summary `total=35 compiled=34 cached=0`. | +| focused coding-agent delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used and no independent review is claimed. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_expm1 fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `expm1`; next first stable blocker is the distinct declaration-order family at `(1945)`, with later families at `(3185)`, `(3524)`, and `(3601)`; summary `total=35 compiled=34 cached=0`. Existing warnings remain `mathmodule.c(1336)`, `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0; all applicable regression suites and shell syntax checks passed. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `expm1` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the declaration-order family in `mathmodule.c` at line 1945. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` guarded VC6 `exp2` fallback slice) + +Date: 2026-09-19 09:46 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changes, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified compiler remains MSVC6 `12.00.8804` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was the distinct missing-VC6-CRT `exp2` family at line 1336. One focused coding-agent delegation was attempted as required but failed before launch because the runtime lacks the `anthropic` package; no child files were used and no independent review is claimed. This slice addressed only `exp2`; `expm1` and later declaration-order blockers remain untouched. + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_exp2()` fallback using `exp(x * log(2.0))` with NaN preservation; routed only `FUNC1(exp2, ...)` through it. Native compilers retain the CRT path through `#define m_exp2 exp2`. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback, NaN handling, native mapping, and routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(1336)` C2065 for unavailable `exp2`; `expm1` followed at `(1341)`; summary `total=35 compiled=34 cached=0`. | +| focused coding-agent delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used and no independent review is claimed. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_exp2 fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `exp2`; next first stable blocker is unavailable `expm1` at `(1350)`, followed by distinct declaration-order blockers at `(1936)`, `(3176)`, `(3515)`, and `(3592)`; summary `total=35 compiled=34 cached=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0; all applicable regression suites and shell syntax checks passed. | +| `git -C cpython diff > compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython diff --check && cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `exp2` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the missing-CRT `expm1` family at `mathmodule.c(1350)`. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` `math_ceil` C89 declaration-order slice) + +Date: 2026-09-19 06:00 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changes, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified compiler remains MSVC6 `12.00.8804` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was the distinct C89 declaration-order defect in `math_ceil()` at line 1306. One focused Codex coding-agent delegation was run in workspace-write mode with the existing checkout; it preserved local changes, implemented only this slice, and did not commit, push, or publish. This slice addressed only `math_ceil()`; later `copysign`, `exp2`, `expm1`, and other mathmodule blockers remain untouched. + +- `cpython/Modules/mathmodule.c` — hoisted `double x` into `math_ceil()`'s opening declaration group and changed its initializer to an assignment at the original evaluation point. Lookup, conversion, error handling, and return behavior are unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the opening declaration and original-point assignment. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(1306)` C2143/C2065 for `double x`; later distinct blockers at `(1317)`, `(1335)`, `(1340)`, `(1926)`, `(3166)`, `(3505)`, and `(3582)`; summary `total=35 compiled=34 cached=0`. | +| `codex exec -s workspace-write --skip-git-repo-check ...` | exit 0; focused TDD implementation completed; the child reported the expected red assertion before the source edit and green focused test afterward; no commit/push/publish. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after the slice | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after the slice | exit 2; `math_ceil()` compiled past this family. The next first stable blocker is unavailable VC6 CRT `exp2` at `mathmodule.c(1336)`; `expm1` follows at `(1341)`, with later distinct declaration-order blockers. Summary `total=35 compiled=34 cached=0`. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0; all applicable regression suites and shell syntax checks passed. | +| `git -C cpython diff > compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython diff --check && cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `math_ceil()` now compiles through its C89 declaration-order family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the missing-CRT `exp2` family at `mathmodule.c(1336)`. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` guarded VC6 `cbrt` fallback slice) + +Date: 2026-09-19 05:29 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified MSVC6 banner remains `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read before changes. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` was first. The first stable blocker was unavailable VC6 CRT `cbrt` at the prior line 1259. One focused coding-agent delegation was attempted for implementation but failed before launch because the runtime lacks the `anthropic` package; no child files were used and no independent review is claimed. This slice addressed only `cbrt`. + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_cbrt()` using `fabs`/`log`/`exp`, preserving NaN, signed zero, infinity, and sign handling; routed only `FUNC1(cbrt, ...)` through it. Native compilers retain the CRT path through `#define m_cbrt cbrt`. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback, special-value handling, native mapping, and routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable diagnostic `mathmodule.c(1259)` C2065 for unavailable `cbrt`, followed by distinct declaration-order and `exp2`/`expm1` blockers; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused coding-agent delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used and no independent review is claimed. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_cbrt fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `cbrt`; next first stable blocker is `math_ceil()`'s post-statement `double x` declaration at `(1306)`, followed by distinct blockers at `(1317)`, `(1335)`, `(1340)`, `(1926)`, `(3166)`, `(3505)`, and `(3582)`; summary `total=35 compiled=34 cached=0 skipped=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n` plus public/core/PathCch/getpath/stdint/frontier regression suites | exit 0; all applicable suites passed and the focused frontier suite ended with `ALL TESTS PASSED`. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s` verification | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `cbrt` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the distinct C89 declaration-order blocker in `math_ceil()` at `mathmodule.c(1306)`. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` guarded VC6 `atanh` fallback slice) + +Date: 2026-09-19 03:21 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changing anything, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified MSVC6 banner remains `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded frontier was force-re-probed first and remained applicable: `_blake2/blake2s_impl.c` compiled, 34 sources compiled, and `mathmodule.c` remained first. The first stable blocker was the distinct missing-VC6-CRT math-function family: `atanh` at line 1233 before this slice, followed by `cbrt` at line 1236 and later declaration-order families. One focused read-only Codex coding-agent delegation inspected this exact frontier, made no edits, and recommended the isolated `m_atanh` fallback. No independent implementation review is claimed beyond that advisory inspection. + +This run addressed only `atanh`: + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_atanh()` using the stable logarithmic formulation with small-input preservation, signed-zero/NaN handling, and `EDOM` for `abs(x) >= 1`; routed only `FUNC1(atanh, ...)` through it. Native compilers retain the CRT `atanh` path through `#define m_atanh atanh`. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback, native mapping, domain handling, and routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable diagnostics `mathmodule.c(1233)` C2065 for `atanh`, then `cbrt` at `(1236)` and later distinct declaration-order blockers; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused read-only `codex exec -s read-only --skip-git-repo-check ...` | exit 0; recommended only the guarded `m_atanh` fallback and `FUNC1(atanh, m_atanh, 0, ...)`; no files changed, no broad build run. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_atanh fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `atanh`; next first stable blocker is unavailable `cbrt` at `(1259)`; later distinct blockers remain at `(1288)`, `(1908)`, `(3148)`, `(3487)`, and `(3564)`; summary `total=35 compiled=34 cached=0 skipped=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n` plus public/core/PathCch/getpath/stdint/frontier regression suites | exit 0; all applicable suites passed and the focused frontier suite ended with `ALL TESTS PASSED`. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s` verification | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `atanh` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the remaining missing-CRT `cbrt` family at `mathmodule.c(1259)`; `exp2` and `expm1` remain distinct later blockers. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` guarded VC6 `asinh` fallback slice) + +Date: 2026-09-19 01:12 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changing anything, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified MSVC6 banner remains `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded frontier was force-re-probed first and remained applicable: `_blake2/blake2s_impl.c` compiled, 34 sources compiled, and `mathmodule.c` remained first. The first stable blocker was the distinct missing-VC6-CRT math-function family, with `asinh` first at line 1212 before this slice. One focused coding-agent delegation was attempted for advisory inspection but failed before launch because the runtime lacks the `anthropic` package; no child files were used and no independent review is claimed. This run addressed only `asinh`; `atanh`, `cbrt`, `exp2`, `expm1`, and later declaration-order blockers remain untouched. + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_asinh()` implementation using sign symmetry, a large-argument overflow-safe branch, and the standard logarithmic form; routed only `FUNC1(asinh, ...)` through it. Native CRT paths and later math functions remain unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback and explicit `m_asinh` routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable diagnostics `mathmodule.c(1212)` C2065 for `asinh`, followed by `atanh` at `(1223)`, `cbrt` at `(1226)`, and later distinct families; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused coding-agent delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used and no independent review is claimed. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_asinh fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `asinh`; next first stable blockers are unavailable `atanh` at `(1233)` and `cbrt` at `(1236)`; summary `total=35 compiled=34 cached=0 skipped=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n` plus public/core/PathCch/getpath/stdint/frontier regression suites | exit 0; all applicable suites passed and the focused frontier suite ended with `ALL TESTS PASSED`. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s` verification | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `asinh` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the remaining missing-CRT math family beginning with `atanh`; `cbrt`, `exp2`, and `expm1` remain distinct later blockers. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` guarded VC6 `acosh` fallback slice) + +Date: 2026-09-18 23:05 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changing anything, `PORT_STATUS.md`, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified MSVC6 banner remains `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86` through Wine using `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded frontier was force-re-probed first and remained applicable: `_blake2/blake2s_impl.c` compiled, 34 sources compiled, and `mathmodule.c` remained first. The first stable blocker was the distinct missing-VC6-CRT math-function family; `acosh` was the first error at line 1192 in the prior probe. One focused read-only Codex coding-agent delegation inspected this exact family, made no edits, and recommended a single guarded `m_acosh` fallback while leaving `asinh`, `atanh`, and `cbrt` for later slices. This run addressed only `acosh`. + +- `cpython/Modules/mathmodule.c` — added an `_MSC_VER < 1300`-guarded `m_acosh()` implementation with domain-error handling and overflow-safe large-argument branch; routed only `FUNC1(acosh, ...)` through it. The native CRT paths and the later missing functions remain untouched. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the guarded fallback and explicit `m_acosh` routing. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first blocker `mathmodule.c(1192)` C2065 for `acosh`, with later `asinh`, `atanh`, `cbrt`, `exp2`, `expm1`, and distinct declaration-order blockers; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused read-only `codex exec -s read-only --skip-git-repo-check ...` | exit 0; recommended only a guarded `m_acosh` fallback and `FUNC1(acosh, m_acosh, 0, ...)`; no files changed and no build run by the child. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `VC6 m_acosh fallback missing`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `mathmodule.c` compiled past `acosh`; next first stable blockers are `asinh` at line 1212, `atanh` at 1223, and `cbrt` at 1226; summary `total=35 compiled=34 cached=0 skipped=0`. | +| `bash -n` plus public/core/PathCch/getpath/stdint regression suites | exit 0; all applicable suites passed. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s` verification | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `acosh` now compiles through the guarded VC6 fallback under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the remaining missing-CRT math family beginning with `asinh`; `atanh`, `cbrt`, `exp2`, and `expm1` remain distinct later blockers. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` `math_lcm` C89 declaration-order slice) + +Date: 2026-09-18 20:56 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Before changing anything, this file, `README.md`, and `references/python-3-win9x-msvc6.md` were read. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. The verified MSVC6 compiler remains `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86` through Wine with `WINEPREFIX=/home/ubuntu/.wine-win9xport`. + +The recorded frontier was force-re-probed first and remained applicable: 34 sources compiled and `mathmodule.c` remained first. The first stable blocker was `math_lcm()`'s post-statement borrowed `zero` declaration at line 946. One focused read-only Codex delegation inspected this exact function, made no edits, and recommended hoisting only `zero` while preserving the assignment point. This slice addressed only that C89 declaration-order family; `mathmodule.c`'s later distinct blockers remain untouched. + +- `cpython/Modules/mathmodule.c` — added `zero` to `math_lcm()`'s opening declaration group and changed its later declaration initializer to an assignment at the original point. Borrowed-reference ownership and loop behavior are unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the declaration, assignment, and borrowed-reference shape. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(946)` C2275/C2065 for `PyObject *zero`, followed by distinct blockers at `(1192)`, `(1242)`, `(1862)`, `(3102)`, `(3441)`, and `(3518)`; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused read-only `codex exec -s read-only --skip-git-repo-check ...` | exit 0; recommended moving `zero` into `PyObject *res, *x, *zero;` and assigning `zero = _PyLong_GetZero();`; no files changed and no build run by the child. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `math_lcm zero declaration missing from opening group`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `math_lcm()` compiled past this defect family. The next first stable blocker is `mathmodule.c(1192)` C2065 for unavailable `acosh`; summary `total=35 compiled=34 cached=0 skipped=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n` on frontier scripts plus public/core/PathCch/getpath/stdint regression suites | exit 0; all applicable suites passed. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s` verification | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `math_lcm()` now compiles past its borrowed-local C89 declaration-order family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is the distinct `mathmodule.c(1192)` missing-`acosh` family. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`mathmodule.c` `math_gcd` C89 declaration-order slice) + +Date: 2026-09-18 18:48 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. MSVC6 remains an external/local-only prerequisite through Wine with `WINEPREFIX=/home/ubuntu/.wine-win9xport`; the verified compiler is `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first, but the recorded `itertoolsmodule.c` frontier was no longer current: the actual first stable blocker was `mathmodule.c`. The first defect family was `math_gcd()`'s post-statement borrowed singleton declaration at line 871. One focused read-only Codex delegation inspected this exact function, made no edits, and recommended hoisting only `one` while preserving the assignment point. This slice addressed only that C89 declaration-order family. + +- `cpython/Modules/mathmodule.c` — added `one` to `math_gcd()`'s opening declaration group and changed its later declaration initializer to an assignment at the original point. Borrowed-reference handling, early returns, and loop behavior are unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion for the declaration and assignment shape. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; 34 sources compiled; first stable blocker `mathmodule.c(871)` C2275/C2065 for `PyObject *one`, followed by distinct blockers at `(946)`, `(1192)`, `(1242)`, `(1862)`, `(3102)`, `(3441)`, and `(3518)`; summary `total=35 compiled=34 cached=0 skipped=0`. | +| focused read-only `codex exec -s read-only --skip-git-repo-check ...` | exit 0; recommended moving `one` into `PyObject *res, *x, *one;` and assigning `one = _PyLong_GetOne();`; no files changed and no build run by the child. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `math_gcd one declaration missing from opening group`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `math_gcd()` compiled past this defect family. The next first stable blocker is `mathmodule.c(946)` C2275/C2065 for `math_lcm()`'s distinct post-statement `zero` declaration; summary `total=35 compiled=34 cached=0 skipped=0`. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. | +| `bash -n scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh`, public/core/PathCch/getpath/stdint/frontier regression suites, `git -C cpython diff --check`, and patch `cmp -s` verification | exit 0; all applicable checks passed and the compatibility patch exactly matches the complete nested source diff. | + +**Current compile-frontier state:** `math_gcd()` now compiles past its C89 declaration-order family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is `math_lcm()` at `mathmodule.c(946)`, beginning with its distinct borrowed `zero` declaration. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + +## Latest revision (`gcmodule.c` duplicate declaration slice) + +Date: 2026-09-18 16:40 UTC + +Baseline remains CPython `v3.11.16` at commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. The nested `cpython/` checkout remains detached with all pre-existing uncommitted port edits preserved. Nothing was reset, cleaned, stashed, discarded, committed, pushed, or published. MSVC6 remains an external/local-only prerequisite through Wine with `WINEPREFIX=/home/ubuntu/.wine-win9xport`; the verified compiler is `Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86`. + +The recorded `_blake2/blake2s_impl.c` sequence was force-re-probed first and remained applicable: 30 sources compiled, including `faulthandler.c` and `gcmodule.c`. The first stable `gcmodule.c` diagnostic was a duplicate `PyGC_Head *gc, *next` declaration in `clear_unreachable_mask()` at lines 707 and 711. A focused coding-agent delegation was attempted for advisory inspection but failed before launch because the runtime lacks the `anthropic` package; no child files were used and no independent review is claimed. This slice addressed only that duplicate-declaration family. + +- `cpython/Modules/gcmodule.c` — removed the second, redundant `PyGC_Head *gc, *next` declaration from `clear_unreachable_mask()`. The declaration group and control flow are otherwise unchanged. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added the focused TDD assertion requiring exactly one declaration of the local pair. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from the complete nested `git -C cpython diff`. +- `PORT_STATUS.md` — this report. + +**Exact command results:** + +| Command | Result | +|---|---| +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` before this slice | exit 2; summary `total=31 compiled=30 cached=0 skipped=0`; first stable diagnostics were `gcmodule.c(711)` C2143, followed by distinct diagnostics at `(1065)`, `(1180)`, and `(1293)`. | +| focused coding-agent delegation | failed before launch: `The 'anthropic' package is required for the Anthropic provider`; no child files were used and no independent review is claimed. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after adding the assertion, before source edit | exit 1 as required by TDD; `clear_unreachable_mask duplicate local declaration`. | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` after source edit | exit 0; `ALL TESTS PASSED`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` after source edit | exit 2; `gcmodule.c` compiled past the duplicate declaration. Existing warnings remain `arraymodule.c(2247)`, `audioop.c(1536)`, `(1609)`, and `faulthandler.c(542)`. The next first stable blocker is `cpython/Modules/itertoolsmodule.c`, with C2275/C2065 at line 883 and C2143/C2065/C2059 loop-declaration diagnostics at line 4878; summary `total=33 compiled=32 cached=0 skipped=0`. | +| full applicable regression suites and shell syntax checks | exit 0; public/core/PathCch/getpath/stdint/frontier suites all passed. | +| `git -C cpython diff --check`; patch regeneration plus `cmp -s <(git -C cpython diff) compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0; nested source diff is clean and the compatibility patch exactly matches the complete nested diff. | + +**Current compile-frontier state:** `gcmodule.c` now compiles past its duplicate-local declaration family under MSVC6 (`cl.exe` 12.00.8804) through Wine. The next narrow frontier is `itertoolsmodule.c` at line 883, beginning with its post-statement `PyObject *dataobj` declaration; the later C99 loop family at line 4878 is distinct. This remains compiler-probe progress only: no linked `pythoncore.dll`/`python.exe`, no Wine execution of Python, and no real Windows 98 SE execution. + ## Latest revision (`faulthandler.c` VC6 declaration/API compatibility slices) Date: 2026-09-18 16:03 UTC @@ -3766,3 +4121,5 @@ file is seen, so the true scope is not yet known. Recommended next steps: 1. Continue with `Python/pylifecycle.c` by applying the same two mechanical transforms already validated on `Modules/main.c` — hoist mid-block declarations (declaration-order slice) and replace compound-literal/ +## Latest revision (`mathmodule.c` guarded VC6 `cbrt` fallback slice) + diff --git a/compat/msvc600/cpython-3.11.16-vc6-headers.patch b/compat/msvc600/cpython-3.11.16-vc6-headers.patch index 5ee0c09..b07d060 100644 --- a/compat/msvc600/cpython-3.11.16-vc6-headers.patch +++ b/compat/msvc600/cpython-3.11.16-vc6-headers.patch @@ -130,6 +130,55 @@ index 425d69f..748de28 100644 typedef enum _Py_memory_order { _Py_memory_order_relaxed, _Py_memory_order_acquire, +diff --git a/Include/internal/pycore_bitutils.h b/Include/internal/pycore_bitutils.h +index e6bf61e..ba46128 100644 +--- a/Include/internal/pycore_bitutils.h ++++ b/Include/internal/pycore_bitutils.h +@@ -25,7 +25,7 @@ extern "C" { + # define _PY_HAVE_BUILTIN_BSWAP + #endif + +-#ifdef _MSC_VER ++#if defined(_MSC_VER) && _MSC_VER >= 1300 + /* Get _byteswap_ushort(), _byteswap_ulong(), _byteswap_uint64() */ + # include + #endif +@@ -35,7 +35,7 @@ _Py_bswap16(uint16_t word) + { + #if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap16) + return __builtin_bswap16(word); +-#elif defined(_MSC_VER) ++#elif defined(_MSC_VER) && _MSC_VER >= 1300 + Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short)); + return _byteswap_ushort(word); + #else +@@ -50,7 +50,7 @@ _Py_bswap32(uint32_t word) + { + #if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap32) + return __builtin_bswap32(word); +-#elif defined(_MSC_VER) ++#elif defined(_MSC_VER) && _MSC_VER >= 1300 + Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long)); + return _byteswap_ulong(word); + #else +@@ -67,7 +67,7 @@ _Py_bswap64(uint64_t word) + { + #if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap64) + return __builtin_bswap64(word); +-#elif defined(_MSC_VER) ++#elif defined(_MSC_VER) && _MSC_VER >= 1300 + return _byteswap_uint64(word); + #else + // Portable implementation which doesn't rely on circular bit shift +@@ -154,7 +154,7 @@ _Py_bit_length(unsigned long x) + else { + return 0; + } +-#elif defined(_MSC_VER) ++#elif defined(_MSC_VER) && _MSC_VER >= 1300 + // _BitScanReverse() is documented to search 32 bits. + Py_BUILD_ASSERT(sizeof(unsigned long) <= 4); + unsigned long msb; diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 3ccacfa..3098e1e 100644 --- a/Include/internal/pycore_call.h @@ -4933,6 +4982,539 @@ index 520b7b6..67d9fc1 100644 Py_DECREF(module); if (res == NULL) { return -1; +diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c +index 347ded8..082ee66 100644 +--- a/Modules/gcmodule.c ++++ b/Modules/gcmodule.c +@@ -139,13 +139,14 @@ get_gc_state(void) + void + _PyGC_InitState(GCState *gcstate) + { ++ int i; + #define INIT_HEAD(GEN) \ + do { \ + GEN.head._gc_next = (uintptr_t)&GEN.head; \ + GEN.head._gc_prev = (uintptr_t)&GEN.head; \ + } while (0) + +- for (int i = 0; i < NUM_GENERATIONS; i++) { ++ for (i = 0; i < NUM_GENERATIONS; i++) { + assert(gcstate->generations[i].count == 0); + INIT_HEAD(gcstate->generations[i]); + }; +@@ -278,6 +279,7 @@ gc_list_remove(PyGC_Head *node) + static void + gc_list_move(PyGC_Head *node, PyGC_Head *list) + { ++ PyGC_Head *to_prev; + /* Unlink from current list. */ + PyGC_Head *from_prev = GC_PREV(node); + PyGC_Head *from_next = GC_NEXT(node); +@@ -286,7 +288,7 @@ gc_list_move(PyGC_Head *node, PyGC_Head *list) + + /* Relink at end of new list. */ + // list must not have flags. So we can skip macros. +- PyGC_Head *to_prev = (PyGC_Head*)list->_gc_prev; ++ to_prev = (PyGC_Head*)list->_gc_prev; + _PyGCHead_SET_PREV(node, to_prev); + _PyGCHead_SET_NEXT(to_prev, node); + list->_gc_prev = (uintptr_t)node; +@@ -485,12 +487,16 @@ subtract_refs(PyGC_Head *containers) + static int + visit_reachable(PyObject *op, PyGC_Head *reachable) + { ++ PyGC_Head *gc; ++ PyGC_Head *prev; ++ PyGC_Head *next; ++ Py_ssize_t gc_refs; + if (!_PyObject_IS_GC(op)) { + return 0; + } + +- PyGC_Head *gc = AS_GC(op); +- const Py_ssize_t gc_refs = gc_get_refs(gc); ++ gc = AS_GC(op); ++ gc_refs = gc_get_refs(gc); + + // Ignore objects in other generation. + // This also skips objects "to the left" of the current position in +@@ -512,8 +518,8 @@ visit_reachable(PyObject *op, PyGC_Head *reachable) + */ + // Manually unlink gc from unreachable list because the list functions + // don't work right in the presence of NEXT_MASK_UNREACHABLE flags. +- PyGC_Head *prev = GC_PREV(gc); +- PyGC_Head *next = (PyGC_Head*)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE); ++ prev = GC_PREV(gc); ++ next = (PyGC_Head*)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE); + _PyObject_ASSERT(FROM_GC(prev), + prev->_gc_next & NEXT_MASK_UNREACHABLE); + _PyObject_ASSERT(FROM_GC(next), +@@ -557,6 +563,9 @@ visit_reachable(PyObject *op, PyGC_Head *reachable) + static void + move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) + { ++ PyObject *op; ++ traverseproc traverse; ++ PyGC_Head *last; + // previous elem in the young list, used for restore gc_prev. + PyGC_Head *prev = young; + PyGC_Head *gc = GC_NEXT(young); +@@ -580,8 +589,8 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) + * so we have to wait until it returns to determine + * the next object to visit. + */ +- PyObject *op = FROM_GC(gc); +- traverseproc traverse = Py_TYPE(op)->tp_traverse; ++ op = FROM_GC(gc); ++ traverse = Py_TYPE(op)->tp_traverse; + _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(gc) > 0, + "refcount is too small"); + // NOTE: visit_reachable may change gc->_gc_next when +@@ -609,7 +618,7 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) + + // We can't use gc_list_append() here because we use + // NEXT_MASK_UNREACHABLE here. +- PyGC_Head *last = GC_PREV(unreachable); ++ last = GC_PREV(unreachable); + // NOTE: Since all objects in unreachable set has + // NEXT_MASK_UNREACHABLE flag, we set it unconditionally. + // But this may pollute the unreachable list head's 'next' pointer +@@ -695,10 +704,10 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) + static inline void + clear_unreachable_mask(PyGC_Head *unreachable) + { ++ PyGC_Head *gc, *next; + /* Check that the list head does not have the unreachable bit set */ + assert(((uintptr_t)unreachable & NEXT_MASK_UNREACHABLE) == 0); + +- PyGC_Head *gc, *next; + assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0); + for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) { + _PyObject_ASSERT((PyObject*)FROM_GC(gc), gc->_gc_next & NEXT_MASK_UNREACHABLE); +@@ -929,12 +938,14 @@ handle_legacy_finalizers(PyThreadState *tstate, + GCState *gcstate, + PyGC_Head *finalizers, PyGC_Head *old) + { ++ PyGC_Head *gc; ++ PyObject *op; + assert(!_PyErr_Occurred(tstate)); + assert(gcstate->garbage != NULL); + +- PyGC_Head *gc = GC_NEXT(finalizers); ++ gc = GC_NEXT(finalizers); + for (; gc != finalizers; gc = GC_NEXT(gc)) { +- PyObject *op = FROM_GC(gc); ++ op = FROM_GC(gc); + + if ((gcstate->debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { + if (PyList_Append(gcstate->garbage, op) < 0) { +@@ -1046,10 +1057,11 @@ clear_freelists(PyInterpreterState *interp) + static void + show_stats_each_generations(GCState *gcstate) + { ++ int i; + char buf[100]; + size_t pos = 0; + +- for (int i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) { ++ for (i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) { + pos += PyOS_snprintf(buf+pos, sizeof(buf)-pos, + " %zd", + gc_list_size(GEN_HEAD(gcstate, i))); +@@ -1157,6 +1169,7 @@ static inline void + handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, + PyGC_Head *old_generation) + { ++ PyGC_Head *resurrected; + // Remove the PREV_MASK_COLLECTING from unreachable + // to prepare it for a new call to 'deduce_unreachable' + gc_list_clear_collecting(unreachable); +@@ -1164,7 +1177,7 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, + // After the call to deduce_unreachable, the 'still_unreachable' set will + // have the PREV_MARK_COLLECTING set, but the objects are going to be + // removed so we can skip the expense of clearing the flag. +- PyGC_Head* resurrected = unreachable; ++ resurrected = unreachable; + deduce_unreachable(resurrected, still_unreachable); + clear_unreachable_mask(still_unreachable); + +@@ -1179,6 +1192,7 @@ gc_collect_main(PyThreadState *tstate, int generation, + Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, + int nofail) + { ++ struct gc_generation_stats *stats; + int i; + Py_ssize_t m = 0; /* # objects collected */ + Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ +@@ -1186,6 +1200,7 @@ gc_collect_main(PyThreadState *tstate, int generation, + PyGC_Head *old; /* next older generation */ + PyGC_Head unreachable; /* non-problematic unreachable trash */ + PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ ++ PyGC_Head final_unreachable; + PyGC_Head *gc; + _PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ + GCState *gcstate = &tstate->interp->gc; +@@ -1276,7 +1291,6 @@ gc_collect_main(PyThreadState *tstate, int generation, + /* Handle any objects that may have resurrected after the call + * to 'finalize_garbage' and continue the collection with the + * objects that are still unreachable */ +- PyGC_Head final_unreachable; + handle_resurrected_objects(&unreachable, &final_unreachable, old); + + /* Call tp_clear on objects in the final_unreachable set. This will cause +@@ -1330,7 +1344,7 @@ gc_collect_main(PyThreadState *tstate, int generation, + *n_uncollectable = n; + } + +- struct gc_generation_stats *stats = &gcstate->generation_stats[generation]; ++ stats = &gcstate->generation_stats[generation]; + stats->collections++; + stats->collected += m; + stats->uncollectable += n; +@@ -1351,17 +1365,21 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, + int generation, Py_ssize_t collected, + Py_ssize_t uncollectable) + { ++ GCState *gcstate; ++ PyObject *info = NULL; ++ PyObject *r; ++ PyObject *cb; ++ Py_ssize_t i; + assert(!_PyErr_Occurred(tstate)); + + /* we may get called very early */ +- GCState *gcstate = &tstate->interp->gc; ++ gcstate = &tstate->interp->gc; + if (gcstate->callbacks == NULL) { + return; + } + + /* The local variable cannot be rebound, check it for sanity */ + assert(PyList_CheckExact(gcstate->callbacks)); +- PyObject *info = NULL; + if (PyList_GET_SIZE(gcstate->callbacks) != 0) { + info = Py_BuildValue("{sisnsn}", + "generation", generation, +@@ -1372,8 +1390,8 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, + return; + } + } +- for (Py_ssize_t i=0; icallbacks); i++) { +- PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i); ++ for (i=0; icallbacks); i++) { ++ cb = PyList_GET_ITEM(gcstate->callbacks, i); + Py_INCREF(cb); /* make sure cb doesn't go away */ + r = PyObject_CallFunction(cb, "sO", phase, info); + if (r == NULL) { +@@ -1394,8 +1412,8 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, + static Py_ssize_t + gc_collect_with_callback(PyThreadState *tstate, int generation) + { +- assert(!_PyErr_Occurred(tstate)); + Py_ssize_t result, collected, uncollectable; ++ assert(!_PyErr_Occurred(tstate)); + invoke_gc_callback(tstate, "start", generation, 0, 0); + result = gc_collect_main(tstate, generation, &collected, &uncollectable, 0); + invoke_gc_callback(tstate, "stop", generation, collected, uncollectable); +@@ -1406,12 +1424,13 @@ gc_collect_with_callback(PyThreadState *tstate, int generation) + static Py_ssize_t + gc_collect_generations(PyThreadState *tstate) + { ++ int i; + GCState *gcstate = &tstate->interp->gc; + /* Find the oldest generation (highest numbered) where the count + * exceeds the threshold. Objects in the that generation and + * generations younger than it will be collected. */ + Py_ssize_t n = 0; +- for (int i = NUM_GENERATIONS-1; i >= 0; i--) { ++ for (i = NUM_GENERATIONS-1; i >= 0; i--) { + if (gcstate->generations[i].count > gcstate->generations[i].threshold) { + /* Avoid quadratic performance degradation in number + of tracked objects (see also issue #4074): +@@ -1520,15 +1539,18 @@ static Py_ssize_t + gc_collect_impl(PyObject *module, int generation) + /*[clinic end generated code: output=b697e633043233c7 input=40720128b682d879]*/ + { +- PyThreadState *tstate = _PyThreadState_GET(); ++ PyThreadState *tstate; ++ GCState *gcstate; ++ Py_ssize_t n; ++ ++ tstate = _PyThreadState_GET(); + + if (generation < 0 || generation >= NUM_GENERATIONS) { + _PyErr_SetString(tstate, PyExc_ValueError, "invalid generation"); + return -1; + } + +- GCState *gcstate = &tstate->interp->gc; +- Py_ssize_t n; ++ gcstate = &tstate->interp->gc; + if (gcstate->collecting) { + /* already collecting, don't do anything */ + n = 0; +@@ -1591,13 +1613,14 @@ PyDoc_STRVAR(gc_set_thresh__doc__, + static PyObject * + gc_set_threshold(PyObject *self, PyObject *args) + { ++ int i; + GCState *gcstate = get_gc_state(); + if (!PyArg_ParseTuple(args, "i|ii:set_threshold", + &gcstate->generations[0].threshold, + &gcstate->generations[1].threshold, + &gcstate->generations[2].threshold)) + return NULL; +- for (int i = 3; i < NUM_GENERATIONS; i++) { ++ for (i = 3; i < NUM_GENERATIONS; i++) { + /* generations higher than 2 get the same threshold */ + gcstate->generations[i].threshold = gcstate->generations[2].threshold; + } +@@ -1674,17 +1697,20 @@ Return the list of objects that directly refer to any of objs."); + static PyObject * + gc_get_referrers(PyObject *self, PyObject *args) + { ++ PyObject *result; ++ GCState *gcstate; ++ int i; + if (PySys_Audit("gc.get_referrers", "(O)", args) < 0) { + return NULL; + } + +- PyObject *result = PyList_New(0); ++ result = PyList_New(0); + if (!result) { + return NULL; + } + +- GCState *gcstate = get_gc_state(); +- for (int i = 0; i < NUM_GENERATIONS; i++) { ++ gcstate = get_gc_state(); ++ for (i = 0; i < NUM_GENERATIONS; i++) { + if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) { + Py_DECREF(result); + return NULL; +@@ -1708,17 +1734,19 @@ static PyObject * + gc_get_referents(PyObject *self, PyObject *args) + { + Py_ssize_t i; ++ PyObject *result; ++ traverseproc traverse; ++ PyObject *obj; + if (PySys_Audit("gc.get_referents", "(O)", args) < 0) { + return NULL; + } +- PyObject *result = PyList_New(0); ++ result = PyList_New(0); + + if (result == NULL) + return NULL; + + for (i = 0; i < PyTuple_GET_SIZE(args); i++) { +- traverseproc traverse; +- PyObject *obj = PyTuple_GET_ITEM(args, i); ++ obj = PyTuple_GET_ITEM(args, i); + + if (!_PyObject_IS_GC(obj)) + continue; +@@ -1810,6 +1838,7 @@ gc_get_stats_impl(PyObject *module) + { + int i; + struct gc_generation_stats stats[NUM_GENERATIONS], *st; ++ PyObject *result; + + /* To get consistent values despite allocations while constructing + the result list, we use a snapshot of the running stats. */ +@@ -1818,7 +1847,7 @@ gc_get_stats_impl(PyObject *module) + stats[i] = gcstate->generation_stats[i]; + } + +- PyObject *result = PyList_New(0); ++ result = PyList_New(0); + if (result == NULL) + return NULL; + +@@ -1905,7 +1934,8 @@ gc_freeze_impl(PyObject *module) + /*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/ + { + GCState *gcstate = get_gc_state(); +- for (int i = 0; i < NUM_GENERATIONS; ++i) { ++ int i; ++ for (i = 0; i < NUM_GENERATIONS; ++i) { + gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head); + gcstate->generations[i].count = 0; + } +@@ -2024,11 +2054,11 @@ static PyModuleDef_Slot gcmodule_slots[] = { + + static struct PyModuleDef gcmodule = { + PyModuleDef_HEAD_INIT, +- .m_name = "gc", +- .m_doc = gc__doc__, +- .m_size = 0, // per interpreter state, see: get_gc_state() +- .m_methods = GcMethods, +- .m_slots = gcmodule_slots ++ "gc", ++ gc__doc__, ++ 0, ++ GcMethods, ++ gcmodule_slots + }; + + PyMODINIT_FUNC +@@ -2069,18 +2099,20 @@ PyGC_Collect(void) + { + PyThreadState *tstate = _PyThreadState_GET(); + GCState *gcstate = &tstate->interp->gc; ++ Py_ssize_t n; ++ PyObject *exc; ++ PyObject *value; ++ PyObject *tb; + + if (!gcstate->enabled) { + return 0; + } + +- Py_ssize_t n; + if (gcstate->collecting) { + /* already collecting, don't do anything */ + n = 0; + } + else { +- PyObject *exc, *value, *tb; + gcstate->collecting = 1; + _PyErr_Fetch(tstate, &exc, &value, &tb); + n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1); +@@ -2094,6 +2126,7 @@ PyGC_Collect(void) + Py_ssize_t + _PyGC_CollectNoFail(PyThreadState *tstate) + { ++ Py_ssize_t n; + /* Ideally, this function is only called on interpreter shutdown, + and therefore not recursively. Unfortunately, when there are daemon + threads, a daemon thread can start a cyclic garbage collection +@@ -2104,8 +2137,6 @@ _PyGC_CollectNoFail(PyThreadState *tstate) + if (gcstate->collecting) { + return 0; + } +- +- Py_ssize_t n; + gcstate->collecting = 1; + n = gc_collect_main(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1); + gcstate->collecting = 0; +@@ -2170,6 +2201,8 @@ gc_fini_untrack(PyGC_Head *list) + void + _PyGC_Fini(PyInterpreterState *interp) + { ++ int i; ++ PyGC_Head *gen; + GCState *gcstate = &interp->gc; + Py_CLEAR(gcstate->garbage); + Py_CLEAR(gcstate->callbacks); +@@ -2180,8 +2213,8 @@ _PyGC_Fini(PyInterpreterState *interp) + // calling PyObject_GC_UnTrack() on the object crashs if the previous + // or the next object of the PyGC_Head structure became a dangling + // pointer. +- for (int i = 0; i < NUM_GENERATIONS; i++) { +- PyGC_Head *gen = GEN_HEAD(gcstate, i); ++ for (i = 0; i < NUM_GENERATIONS; i++) { ++ gen = GEN_HEAD(gcstate, i); + gc_fini_untrack(gen); + } + } +@@ -2252,11 +2285,15 @@ PyObject_IS_GC(PyObject *obj) + void + _PyObject_GC_Link(PyObject *op) + { +- PyGC_Head *g = AS_GC(op); ++ PyGC_Head *g; ++ PyThreadState *tstate; ++ GCState *gcstate; ++ ++ g = AS_GC(op); + assert(((uintptr_t)g & (sizeof(uintptr_t)-1)) == 0); // g must be correctly aligned + +- PyThreadState *tstate = _PyThreadState_GET(); +- GCState *gcstate = &tstate->interp->gc; ++ tstate = _PyThreadState_GET(); ++ gcstate = &tstate->interp->gc; + g->_gc_next = 0; + g->_gc_prev = 0; + gcstate->generations[0].count++; /* number of allocated GC objects */ +@@ -2275,18 +2312,23 @@ _PyObject_GC_Link(PyObject *op) + static PyObject * + gc_alloc(size_t basicsize, size_t presize) + { +- PyThreadState *tstate = _PyThreadState_GET(); ++ PyThreadState *tstate; ++ size_t size; ++ char *mem; ++ PyObject *op; ++ ++ tstate = _PyThreadState_GET(); + if (basicsize > PY_SSIZE_T_MAX - presize) { + return _PyErr_NoMemory(tstate); + } +- size_t size = presize + basicsize; +- char *mem = PyObject_Malloc(size); ++ size = presize + basicsize; ++ mem = PyObject_Malloc(size); + if (mem == NULL) { + return _PyErr_NoMemory(tstate); + } + ((PyObject **)mem)[0] = NULL; + ((PyObject **)mem)[1] = NULL; +- PyObject *op = (PyObject *)(mem + presize); ++ op = (PyObject *)(mem + presize); + _PyObject_GC_Link(op); + return op; + } +@@ -2307,13 +2349,14 @@ PyVarObject * + _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) + { + size_t size; ++ size_t presize; + PyVarObject *op; + + if (nitems < 0) { + PyErr_BadInternalCall(); + return NULL; + } +- size_t presize = _PyType_PreHeaderSize(tp); ++ presize = _PyType_PreHeaderSize(tp); + size = _PyObject_VAR_SIZE(tp, nitems); + op = (PyVarObject *)gc_alloc(size, presize); + if (op == NULL) { +@@ -2327,12 +2370,13 @@ PyVarObject * + _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) + { + const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems); ++ PyGC_Head *g; + _PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op)); + if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { + return (PyVarObject *)PyErr_NoMemory(); + } + +- PyGC_Head *g = AS_GC(op); ++ g = AS_GC(op); + g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize); + if (g == NULL) + return (PyVarObject *)PyErr_NoMemory(); +@@ -2344,6 +2388,7 @@ _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) + void + PyObject_GC_Del(void *op) + { ++ GCState *gcstate; + size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); + PyGC_Head *g = AS_GC(op); + if (_PyObject_GC_IS_TRACKED(op)) { +@@ -2360,7 +2405,7 @@ PyObject_GC_Del(void *op) + PyErr_Restore(exc, exc_value, exc_tb); + #endif + } +- GCState *gcstate = get_gc_state(); ++ gcstate = get_gc_state(); + if (gcstate->generations[0].count > 0) { + gcstate->generations[0].count--; + } diff --git a/Modules/getpath.c b/Modules/getpath.c index 61d6540..e7489ee 100644 --- a/Modules/getpath.c @@ -5397,6 +5979,44 @@ index 61d6540..e7489ee 100644 Py_DECREF(co); if (!r) { +diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c +index 7a02a0d..b65b001 100644 +--- a/Modules/itertoolsmodule.c ++++ b/Modules/itertoolsmodule.c +@@ -871,6 +871,7 @@ tee_fromiterable(PyObject *iterable) + { + teeobject *to; + PyObject *it; ++ PyObject *dataobj; + + it = PyObject_GetIter(iterable); + if (it == NULL) +@@ -880,7 +881,7 @@ tee_fromiterable(PyObject *iterable) + goto done; + } + +- PyObject *dataobj = teedataobject_newinternal(it); ++ dataobj = teedataobject_newinternal(it); + if (!dataobj) { + to = NULL; + goto done; +@@ -4849,6 +4850,7 @@ combinations_with_replacement(p, r)\n\ + static int + itertoolsmodule_exec(PyObject *m) + { ++ size_t i; + PyTypeObject *typelist[] = { + &accumulate_type, + &combinations_type, +@@ -4875,7 +4877,7 @@ itertoolsmodule_exec(PyObject *m) + + Py_SET_TYPE(&teedataobject_type, &PyType_Type); + +- for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { ++ for (i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { + if (PyModule_AddType(m, typelist[i]) < 0) { + return -1; + } diff --git a/Modules/main.c b/Modules/main.c index f6dade1..011ae59 100644 --- a/Modules/main.c @@ -5695,6 +6315,464 @@ index f6dade1..011ae59 100644 return pymain_main(&args); } +diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c +index 5f5b71c..999fa85 100644 +--- a/Modules/mathmodule.c ++++ b/Modules/mathmodule.c +@@ -70,6 +70,100 @@ raised for division by zero and mod by zero. + + #include "clinic/mathmodule.c.h" + ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++# define PY_MATH_ULONG_LONG unsigned __int64 ++# define PY_MATH_LONG_LONG __int64 ++# define PY_MATH_ULLONG_MAX ((unsigned __int64)0xffffffffffffffffI64) ++# define PY_MATH_LLONG_MAX ((__int64)0x7fffffffffffffffI64) ++ ++static double ++m_asinh(double x) ++{ ++ if (x < 0.0) ++ return -m_asinh(-x); ++ if (x > 1.3407807929942596e154) ++ return log(x) + log(2.0); ++ return log(x + sqrt(x * x + 1.0)); ++} ++ ++static double ++m_acosh(double x) ++{ ++ if (x < 1.0) { ++ errno = EDOM; ++ return Py_NAN; ++ } ++ if (x > 1.3407807929942596e154) { ++ return log(x) + log(2.0); ++ } ++ return log(x + sqrt((x - 1.0) * (x + 1.0))); ++} ++ ++static double ++m_atanh(double x) ++{ ++ double a, u, t, r; ++ ++ if (Py_IS_NAN(x)) ++ return x; ++ ++ a = fabs(x); ++ if (a >= 1.0) { ++ errno = EDOM; ++ return Py_NAN; ++ } ++ if (a < 3.7252902984619140625e-9) /* 2**-28 */ ++ return x; ++ ++ u = 2.0 * a / (1.0 - a); ++ t = 1.0 + u; ++ r = 0.5 * log(t) * (u / (t - 1.0)); ++ return x < 0.0 ? -r : r; ++} ++ ++static double ++m_cbrt(double x) ++{ ++ double ax; ++ ++ if (Py_IS_NAN(x)) ++ return x; ++ if (x == 0.0) ++ return x; ++ if (Py_IS_INFINITY(x)) ++ return x; ++ ax = fabs(x); ++ ax = exp(log(ax) / 3.0); ++ return x < 0.0 ? -ax : ax; ++} ++ ++static double ++m_expm1(double x) ++{ ++ if (fabs(x) < 1e-5) ++ return x + 0.5 * x * x; ++ return exp(x) - 1.0; ++} ++ ++static double ++m_exp2(double x) ++{ ++ if (Py_IS_NAN(x)) ++ return x; ++ return exp(x * log(2.0)); ++} ++ ++#else ++# define PY_MATH_ULONG_LONG unsigned long long ++# define PY_MATH_LONG_LONG long long ++# define PY_MATH_ULLONG_MAX ULLONG_MAX ++# define PY_MATH_LLONG_MAX LLONG_MAX ++# define m_atanh atanh ++# define m_cbrt cbrt ++# define m_expm1 expm1 ++# define m_exp2 exp2 ++#endif ++ + /*[clinic input] + module math + [clinic start generated code]*/ +@@ -841,7 +935,7 @@ m_log10(double x) + static PyObject * + math_gcd(PyObject *module, PyObject * const *args, Py_ssize_t nargs) + { +- PyObject *res, *x; ++ PyObject *res, *x, *one; + Py_ssize_t i; + + if (nargs == 0) { +@@ -856,7 +950,7 @@ math_gcd(PyObject *module, PyObject * const *args, Py_ssize_t nargs) + return res; + } + +- PyObject *one = _PyLong_GetOne(); // borrowed ref ++ one = _PyLong_GetOne(); // borrowed ref + for (i = 1; i < nargs; i++) { + x = _PyNumber_Index(args[i]); + if (x == NULL) { +@@ -916,7 +1010,7 @@ long_lcm(PyObject *a, PyObject *b) + static PyObject * + math_lcm(PyObject *module, PyObject * const *args, Py_ssize_t nargs) + { +- PyObject *res, *x; ++ PyObject *res, *x, *zero; + Py_ssize_t i; + + if (nargs == 0) { +@@ -931,7 +1025,7 @@ math_lcm(PyObject *module, PyObject * const *args, Py_ssize_t nargs) + return res; + } + +- PyObject *zero = _PyLong_GetZero(); // borrowed ref ++ zero = _PyLong_GetZero(); // borrowed ref + for (i = 1; i < nargs; i++) { + x = PyNumber_Index(args[i]); + if (x == NULL) { +@@ -1175,14 +1269,14 @@ FUNC1(acos, acos, 0, + "acos($module, x, /)\n--\n\n" + "Return the arc cosine (measured in radians) of x.\n\n" + "The result is between 0 and pi.") +-FUNC1(acosh, acosh, 0, ++FUNC1(acosh, m_acosh, 0, + "acosh($module, x, /)\n--\n\n" + "Return the inverse hyperbolic cosine of x.") + FUNC1(asin, asin, 0, + "asin($module, x, /)\n--\n\n" + "Return the arc sine (measured in radians) of x.\n\n" + "The result is between -pi/2 and pi/2.") +-FUNC1(asinh, asinh, 0, ++FUNC1(asinh, m_asinh, 0, + "asinh($module, x, /)\n--\n\n" + "Return the inverse hyperbolic sine of x.") + FUNC1(atan, atan, 0, +@@ -1193,10 +1287,10 @@ FUNC2(atan2, m_atan2, + "atan2($module, y, x, /)\n--\n\n" + "Return the arc tangent (measured in radians) of y/x.\n\n" + "Unlike atan(y/x), the signs of both x and y are considered.") +-FUNC1(atanh, atanh, 0, ++FUNC1(atanh, m_atanh, 0, + "atanh($module, x, /)\n--\n\n" + "Return the inverse hyperbolic tangent of x.") +-FUNC1(cbrt, cbrt, 0, ++FUNC1(cbrt, m_cbrt, 0, + "cbrt($module, x, /)\n--\n\n" + "Return the cube root of x.") + +@@ -1216,6 +1310,7 @@ math_ceil(PyObject *module, PyObject *number) + /*[clinic end generated code: output=6c3b8a78bc201c67 input=2725352806399cab]*/ + { + _Py_IDENTIFIER(__ceil__); ++ double x; + + if (!PyFloat_CheckExact(number)) { + PyObject *method = _PyObject_LookupSpecialId(number, &PyId___ceil__); +@@ -1227,7 +1322,7 @@ math_ceil(PyObject *module, PyObject *number) + if (PyErr_Occurred()) + return NULL; + } +- double x = PyFloat_AsDouble(number); ++ x = PyFloat_AsDouble(number); + if (x == -1.0 && PyErr_Occurred()) + return NULL; + +@@ -1254,10 +1349,10 @@ FUNC1A(erfc, m_erfc, + FUNC1(exp, exp, 1, + "exp($module, x, /)\n--\n\n" + "Return e raised to the power of x.") +-FUNC1(exp2, exp2, 1, ++FUNC1(exp2, m_exp2, 1, + "exp2($module, x, /)\n--\n\n" + "Return 2 raised to the power of x.") +-FUNC1(expm1, expm1, 1, ++FUNC1(expm1, m_expm1, 1, + "expm1($module, x, /)\n--\n\n" + "Return exp(x)-1.\n\n" + "This function avoids the loss of precision involved in the direct " +@@ -1779,6 +1874,7 @@ math_isqrt(PyObject *module, PyObject *n) + /*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/ + { + int a_too_large, c_bit_length; ++ int s; + size_t c, d; + uint64_t m; + uint32_t u; +@@ -1847,7 +1943,7 @@ math_isqrt(PyObject *module, PyObject *n) + goto error; + } + +- for (int s = c_bit_length - 6; s >= 0; --s) { ++ for (s = c_bit_length - 6; s >= 0; --s) { + PyObject *q; + size_t e = d; + +@@ -3082,14 +3178,17 @@ _check_long_mult_overflow(long a, long b) { + long longprod = (long)((unsigned long)a * b); + double doubleprod = (double)a * (double)b; + double doubled_longprod = (double)longprod; ++ double diff; ++ double absdiff; ++ double absprod; + + if (doubled_longprod == doubleprod) { + return 0; + } + +- const double diff = doubled_longprod - doubleprod; +- const double absdiff = diff >= 0.0 ? diff : -diff; +- const double absprod = doubleprod >= 0.0 ? doubleprod : -doubleprod; ++ diff = doubled_longprod - doubleprod; ++ absdiff = diff >= 0.0 ? diff : -diff; ++ absprod = doubleprod >= 0.0 ? doubleprod : -doubleprod; + + if (32.0 * absdiff <= absprod) { + return 0; +@@ -3380,8 +3479,16 @@ static const uint8_t factorial_trailing_zeros[] = { + + /* Calculate C(n, k) for n in the 63-bit range. */ + static PyObject * +-perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) ++perm_comb_small(PY_MATH_ULONG_LONG n, PY_MATH_ULONG_LONG k, int iscomb) + { ++ PY_MATH_ULONG_LONG result, i, j; ++ uint64_t comb_odd_part, perm_odd_part; ++ int shift; ++ PyObject *a, *b; ++ 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 ++ }; + if (k == 0) { + return PyLong_FromLong(1); + } +@@ -3410,26 +3517,22 @@ perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) + calculated efficiently via arithmetic modulo 2**64, using three + lookups and two uint64_t multiplications. + */ +- uint64_t comb_odd_part = reduced_factorial_odd_part[n] +- * inverted_factorial_odd_part[k] +- * inverted_factorial_odd_part[n - k]; +- int shift = factorial_trailing_zeros[n] +- - factorial_trailing_zeros[k] +- - factorial_trailing_zeros[n - k]; ++ comb_odd_part = reduced_factorial_odd_part[n] ++ * inverted_factorial_odd_part[k] ++ * inverted_factorial_odd_part[n - k]; ++ shift = factorial_trailing_zeros[n] ++ - factorial_trailing_zeros[k] ++ - factorial_trailing_zeros[n - k]; + return PyLong_FromUnsignedLongLong(comb_odd_part << shift); + } + + /* Maps k to the maximal n so that 2*k-1 <= n <= 127 and C(n, k)*k + * fits into a long long (which is at least 64 bit). Only contains + * items larger than in fast_comb_limits1. */ +- static const unsigned long long fast_comb_limits2[] = { +- 0, ULLONG_MAX, 4294967296ULL, 3329022, 102570, 13467, 3612, 1449, // 0-7 +- 746, 453, 308, 227, 178, 147, // 8-13 +- }; + if (k < Py_ARRAY_LENGTH(fast_comb_limits2) && n <= fast_comb_limits2[k]) { + /* C(n, k) = C(n, k-1) * (n-k+1) / k */ +- unsigned long long result = n; +- for (unsigned long long i = 1; i < k;) { ++ result = n; ++ for (i = 1; i < k;) { + result *= --n; + result /= ++i; + } +@@ -3439,8 +3542,8 @@ perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) + else { + /* Maps k to the maximal n so that k <= n and P(n, k) + * fits into a long long (which is at least 64 bit). */ +- static const unsigned long long fast_perm_limits[] = { +- 0, ULLONG_MAX, 4294967296ULL, 2642246, 65537, 7133, 1627, 568, // 0-7 ++ static const PY_MATH_ULONG_LONG fast_perm_limits[] = { ++ 0, PY_MATH_ULLONG_MAX, (PY_MATH_ULONG_LONG)4294967296I64, 2642246, 65537, 7133, 1627, 568, // 0-7 + 259, 142, 88, 61, 45, 36, 30, 26, // 8-15 + 24, 22, 21, 20, 20, // 16-20 + }; +@@ -3455,8 +3558,8 @@ perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) + } + + /* P(n, k) = P(n, k-1) * (n-k+1) */ +- unsigned long long result = n; +- for (unsigned long long i = 1; i < k;) { ++ result = n; ++ for (i = 1; i < k;) { + result *= --n; + ++i; + } +@@ -3469,8 +3572,7 @@ perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) + * P(n, k) = P(n, j) * P(n-j, k-j) + * C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) + */ +- unsigned long long j = k / 2; +- PyObject *a, *b; ++ j = k / 2; + a = perm_comb_small(n, j, iscomb); + if (a == NULL) { + return NULL; +@@ -3501,8 +3603,10 @@ perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) + * Karatsuba multiplication. + */ + static PyObject * +-perm_comb(PyObject *n, unsigned long long k, int iscomb) ++perm_comb(PyObject *n, PY_MATH_ULONG_LONG k, int iscomb) + { ++ PY_MATH_ULONG_LONG j; ++ PyObject *a, *b, *t; + if (k == 0) { + return PyLong_FromLong(1); + } +@@ -3513,13 +3617,12 @@ perm_comb(PyObject *n, unsigned long long k, int iscomb) + + /* P(n, k) = P(n, j) * P(n-j, k-j) */ + /* C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) */ +- unsigned long long j = k / 2; +- PyObject *a, *b; ++ j = k / 2; + a = perm_comb(n, j, iscomb); + if (a == NULL) { + return NULL; + } +- PyObject *t = PyLong_FromUnsignedLongLong(j); ++ t = PyLong_FromUnsignedLongLong(j); + if (t == NULL) { + goto error; + } +@@ -3575,7 +3678,7 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) + { + PyObject *result = NULL; + int overflow, cmp; +- long long ki, ni; ++ PY_MATH_LONG_LONG ki, ni; + + if (k == Py_None) { + return math_factorial(module, n); +@@ -3616,7 +3719,7 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) + if (overflow > 0) { + PyErr_Format(PyExc_OverflowError, + "k must not exceed %lld", +- LLONG_MAX); ++ PY_MATH_LLONG_MAX); + goto error; + } + assert(ki >= 0); +@@ -3625,11 +3728,11 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) + assert(overflow >= 0 && !PyErr_Occurred()); + if (!overflow && ki > 1) { + assert(ni >= 0); +- result = perm_comb_small((unsigned long long)ni, +- (unsigned long long)ki, 0); ++ result = perm_comb_small((PY_MATH_ULONG_LONG)ni, ++ (PY_MATH_ULONG_LONG)ki, 0); + } + else { +- result = perm_comb(n, (unsigned long long)ki, 0); ++ result = perm_comb(n, (PY_MATH_ULONG_LONG)ki, 0); + } + + done: +@@ -3670,7 +3773,7 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) + { + PyObject *result = NULL, *temp; + int overflow, cmp; +- long long ki, ni; ++ PY_MATH_LONG_LONG ki, ni; + + n = PyNumber_Index(n); + if (n == NULL) { +@@ -3708,8 +3811,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) + + ki = Py_MIN(ki, ni - ki); + if (ki > 1) { +- result = perm_comb_small((unsigned long long)ni, +- (unsigned long long)ki, 1); ++ result = perm_comb_small((PY_MATH_ULONG_LONG)ni, ++ (PY_MATH_ULONG_LONG)ki, 1); + goto done; + } + /* For k == 1 just return the original n in perm_comb(). */ +@@ -3741,13 +3844,13 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) + if (overflow) { + PyErr_Format(PyExc_OverflowError, + "min(n - k, k) must not exceed %lld", +- LLONG_MAX); ++ PY_MATH_LLONG_MAX); + goto error; + } + assert(ki >= 0); + } + +- result = perm_comb(n, (unsigned long long)ki, 1); ++ result = perm_comb(n, (PY_MATH_ULONG_LONG)ki, 1); + + done: + Py_DECREF(n); +@@ -3805,6 +3908,8 @@ static double + math_ulp_impl(PyObject *module, double x) + /*[clinic end generated code: output=f5207867a9384dd4 input=31f9bfbbe373fcaa]*/ + { ++ double inf; ++ double x2; + if (Py_IS_NAN(x)) { + return x; + } +@@ -3812,8 +3917,8 @@ math_ulp_impl(PyObject *module, double x) + if (Py_IS_INFINITY(x)) { + return x; + } +- double inf = m_inf(); +- double x2 = nextafter(x, inf); ++ inf = m_inf(); ++ x2 = nextafter(x, inf); + if (Py_IS_INFINITY(x2)) { + /* special case: x is the largest positive representable float */ + x2 = nextafter(x, -inf); +@@ -3916,11 +4021,11 @@ PyDoc_STRVAR(module_doc, + + static struct PyModuleDef mathmodule = { + PyModuleDef_HEAD_INIT, +- .m_name = "math", +- .m_doc = module_doc, +- .m_size = 0, +- .m_methods = math_methods, +- .m_slots = math_slots, ++ "math", ++ module_doc, ++ 0, ++ math_methods, ++ math_slots + }; + + PyMODINIT_FUNC diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 959b851..6d8ce84 100644 --- a/PC/pyconfig.h diff --git a/scripts/vc6-probe-pythoncore-frontier.test.sh b/scripts/vc6-probe-pythoncore-frontier.test.sh index c07cb17..07049ab 100755 --- a/scripts/vc6-probe-pythoncore-frontier.test.sh +++ b/scripts/vc6-probe-pythoncore-frontier.test.sh @@ -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