diff --git a/PORT_STATUS.md b/PORT_STATUS.md index 0aceaaa..f5a9b42 100644 --- a/PORT_STATUS.md +++ b/PORT_STATUS.md @@ -1,10 +1,866 @@ # Port Status — CPython 3.11.16 to Windows 98 SE -Date: 2026-08-17 +Date: 2026-08-22 Baseline: CPython `v3.11.16` Compiler: MSVC 6.0 (`cl.exe` 12.00.8804), from external `MSVC600` Host test environment: Linux + Wine +## Files changed in this revision (`_blake2/blake2b_impl.c` ULL-literal + declaration-order + `long long`/designated-initializer slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Modules/_blake2/impl/blake2b-ref.c` — two separate slices, each re-probed individually before moving to the next: + - **ULL/LL literal-suffix root blocker.** Inventoried every C99 `ULL`/`LL`-suffixed integer literal in the file by grep (`grep -n "ULL\|[0-9]LL\b"`): the 8 `blake2b_IV[8]` initializer constants (lines 23-26) and 4 occurrences of `~0ULL`/`0ULL` in `blake2b_set_lastnode()`/`blake2b_clear_lastnode()`/`blake2b_set_lastblock()`/`blake2b_clear_lastblock()` (lines 48, 54, 63, 71) — 12 literals total, and no others (`blake2b_impl.c` itself has one more at line 163, but it sits inside a dead `#ifdef HAVE_BLAKE2S` branch that is never defined in this port, so the C preprocessor only needs to recognize it as a pp-number token to skip it, not evaluate its suffix, and it was left alone). VC6's C89 front end rejects the C99 `ULL`/`LL` suffix spelling outright (`error C2059: syntax error : 'bad suffix on number'`) but does accept the Microsoft-specific `i64`/`ui64` 64-bit literal suffixes. Rather than rewriting the literals to bare `ui64` (a new, unreviewed spelling choice), every literal was routed through the existing `PY_LL`/`PY_ULL` macro pair already defined in `PC/pyconfig.h` for exactly this compiler (`#define PY_ULL(x) x##ui64` when `_MSC_VER < 1300`, else `x##ULL`) — the same macro pair `Include/pyport.h` already anticipates via its own `#ifndef PY_LL` guard and accompanying comment ("see PC/pyconfig.h for the compilers that need something other than the C99 LL/ULL suffixes"), and the same defect family/fix shape as the earlier `PY_LONG_LONG` routing for `_abc.c`. `blake2b-ref.c` is `#include`d from `blake2b_impl.c` *after* `#include "Python.h"`, so `PY_ULL` is already visible by the time it is preprocessed; no new include was added. Every literal's digit value is unchanged — `0x6a09e667f3bcc908ULL` became `PY_ULL(0x6a09e667f3bcc908)`, `~0ULL` became `~PY_ULL(0)`, etc. — this is a suffix-spelling change only, and it round-trips to the identical `x##ULL` expansion on every non-VC6 compiler, so no behavior change on any other target. + - **C89 declaration-order fallout in the same file**, the next diagnostic once the literal-suffix errors cleared: `blake2b_init0()` declared its `for` loop counter as a C99 `for( int i = 0; ...)` init-declaration, and `blake2b_init_param()` declared `uint8_t *p` after the `blake2b_init0( S )` statement and used a second C99 `for( size_t i = 0; ...)` init-declaration. Both were hoisted to each function's opening declaration group (`int i;` / `uint8_t *p; size_t i;`), with every assignment left at its original execution point (`p = (uint8_t *)(P);` still runs right after `blake2b_init0(S)`, in the same order) — the same hoist-and-reprobe pattern already used throughout this port (`_abc.c`, `getpath.c`, `pystate.c`). No control flow or arithmetic changed. +- `cpython/Modules/_blake2/blake2b_impl.c` — two more of the previously-characterized-but-unfixed defect families, each re-probed individually: + - Changed `unsigned long long node_offset` (the `py_blake2b_new_impl()` parameter, line 94) to `unsigned PY_LONG_LONG node_offset`. VC6 has no `long long` keyword (`error C2632: 'long' followed by 'long' is illegal`); this is not a new port-local convention — CPython's own public headers already spell 64-bit unsigned parameters exactly this way for the same reason (e.g. `Include/longobject.h`'s `PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG)` and `PyLong_AsUnsignedLongLong`). `_PyLong_UnsignedLongLong_Converter()` (the Argument Clinic-generated converter call site for this parameter) takes a `void *` out-parameter, so the declared-type change has no call-site ABI/type-mismatch implications. + - `py_blake2b_dealloc()`: hoisted `PyTypeObject *type` into the function's opening declaration group (previously declared, C89-illegally, after the lock-free and secure-zero statements); the assignment `type = Py_TYPE(self);` stays at its original point, immediately before `PyObject_Free(self)`/`Py_DECREF(type)`, unchanged. + - `blake2b_type_spec`: converted from C99 designated initializers (`.name = ...`, `.basicsize = ...`, `.flags = ...`, `.slots = ...`) to plain positional initializers in `PyType_Spec`'s declared field order from `Include/object.h` (`name`, `basicsize`, `itemsize`, `flags`, `slots`); the struct's initializer omitted `itemsize`, so the positional form spells that slot `0` explicitly, matching the implicit C99 zero-fill it already had. Same defect family and fix approach as `_abc_data_type_spec`/`_abcmodule`/`_bisectmodule`'s `PyModuleDef` literals earlier in this port. Field values and order are unchanged. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` (4800 lines) so the project-local compatibility patch includes this `_blake2/blake2b_impl.c` slice plus all prior uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` worktree exited 0; the temporary worktree was removed afterward. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, stdint shim suite, and pythoncore frontier regression suite all passed with no regressions after this slice. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (before this revision's first edit) | exit 2 — confirmed the recorded first blocker reproduces exactly: bare `ULL` literal-suffix errors in `impl/blake2b-ref.c` (`error C2059: syntax error : 'bad suffix on number'`) as the first diagnostic for `Modules/_blake2/blake2b_impl.c`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the `PY_ULL`/`PY_LL` literal-suffix slice only) | exit 2 — every `ULL`-suffix diagnostic is gone. New first blocker: `cpython\Modules\_blake2\impl/blake2b-ref.c(143) : error C2143: syntax error : missing ';' before 'type'` (the `for( int i = ...)` C99 init-declaration in `blake2b_init0()`), with follow-on errors at lines 165/168-169 in `blake2b_init_param()`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the `blake2b-ref.c` declaration-order slice) | exit 2 — `impl/blake2b-ref.c` is now fully clean (no diagnostics reference it anymore). New first blockers, all in `Modules/_blake2/blake2b_impl.c`/its clinic header: `error C2632: 'long' followed by 'long' is illegal` at `clinic/blake2b_impl.c.h(18)`, `clinic/blake2b_impl.c.h(39)`, and `blake2b_impl.c(94)`; `error C2275: 'PyTypeObject' : illegal use of this type as an expression` at `blake2b_impl.c(397)`; and `error C2059: syntax error : '.'` at `blake2b_impl.c(412)`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the `unsigned PY_LONG_LONG` slice only) | exit 2 — all three `long long` diagnostics are gone; the `PyTypeObject`/designated-initializer diagnostics at lines 397/412 remain, confirming they are independent defects rather than parser-desync fallout. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the `py_blake2b_dealloc()`/`blake2b_type_spec` slice — final state this revision) | exit 2 — `Modules/_blake2/blake2b_impl.c` now compiles with **zero** errors and **zero** warnings; `total=6 compiled=5 cached=0 skipped=0`. The frontier advances to the next source in `pythoncore.vcxproj` order, `Modules/_blake2/blake2s_impl.c` (autogenerated from `blake2b_impl.c` per its own header comment), whose first blockers are the identical defect families mirrored into the `s`-variant files: C99 `for`-init-declarations in `impl/blake2s-ref.c` (lines 231, 275), `unsigned long long` in `clinic/blake2s_impl.c.h`(18,39)/`blake2s_impl.c`(94), a bare `ULL`-suffix literal at `blake2s_impl.c(163)` (`if (node_offset > 0xFFFFFFFFFFFFULL)`, guarded by `#ifdef HAVE_BLAKE2S` in `blake2b_impl.c` but **not** guarded in `blake2s_impl.c`, so it is live code there), and the same `PyTypeObject *type = Py_TYPE(self);`/designated-initializer pair at `blake2s_impl.c`(397)/(412). None of this has been fixed yet. | +| `bash scripts/vc6-probe-core.sh cpython/Modules/main.c` | exit 0 — still compiles cleanly after this slice. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after this slice. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree; temporary worktree removed. | + +**Current pythoncore compile-frontier status:** `Modules/_blake2/blake2b_impl.c` (and its `#include`d `impl/blake2b-ref.c`) is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past `_abc.c`, `_bisectmodule.c`, `blake2module.c`, and now `blake2b_impl.c`. The frontier has moved on to `Modules/_blake2/blake2s_impl.c`, whose first blocker set is the same defect families just fixed here, mirrored into the autogenerated `s`-variant sources — plus one new wrinkle: the `0xFFFFFFFFFFFFULL` node-offset overflow check that sits inside a dead `#ifdef HAVE_BLAKE2S` branch in `blake2b_impl.c` (and so never needed fixing there) is **not** dead code in `blake2s_impl.c`, so its `ULL` suffix will need the same `PY_ULL()` treatment as a live diagnostic this time. Recommended next slice: mirror this revision's three sub-slices onto the `s`-variant files in the same order (literal suffixes in `impl/blake2s-ref.c` plus the live `blake2s_impl.c(163)` literal first, then `blake2s-ref.c`'s C89 declaration-order fallout, then `unsigned PY_LONG_LONG`/`PyTypeObject`/designated-initializer in `blake2s_impl.c`/its clinic header), re-probing after each sub-slice as done here. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`compat/msvc600/stdint.h` shim + `_blake2/blake2module.c` slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `compat/msvc600/stdint.h` — new VC6-scoped project-local compatibility header providing the missing C99 `` that `cpython/Modules/_blake2/impl/blake2.h` and `blake2-impl.h` `#include`. **Evidence before adding it:** grepped every fixed-width-integer identifier (`u?int(8|16|32|64)_t`, `u?intptr_t`, `u?int_least*_t`, `u?int_fast*_t`, `size_t`) across the entire `Modules/_blake2/` tree (both impl headers/sources and the `blake2b_impl.c`/`blake2s_impl.c`/clinic wrappers). The only fixed-width types actually used anywhere in that tree are `uint8_t`, `uint32_t`, and `uint64_t` (in `load32/64/48`, `store32/64/48`, `rotl32/64`, `rotr32/64`, and the reference block-compression loops); no `int8_t`/`int16_t`/`int32_t`/`int64_t` or `intptr_t`/`uintptr_t` appear at all. `size_t` is also used but is unaffected — it already comes from ``, which VC6 has natively. **Design:** rather than re-declaring these three typedefs a second time under a second include guard, `stdint.h` forwards to the already-existing, already-verified `compat/msvc600/inttypes.h` (added in an earlier revision so CPython's own `Include/pyport.h`, which does `#include `, would compile) via `#include "inttypes.h"`. `inttypes.h`'s own include guard makes this forwarding idempotent regardless of which of the two headers a given translation unit reaches first, so a TU that ends up pulling in both `Python.h` (→ `pyport.h` → ``) and `blake2.h` (→ ``) cannot hit a duplicate-typedef error. Width assumptions (unchanged, already relied on by `inttypes.h`): `uint8_t` = `unsigned char` (1 byte), `uint32_t` = `unsigned long` (4 bytes on Win32/ILP32), `uint64_t` = `unsigned __int64` (VC6's non-standard 64-bit extension, 8 bytes) — verified sufficient by a compile-time fixture (below) using `typedef char check[(sizeof(uint32_t)==4) ? 1 : -1];`-style width assertions, since VC6 has no `static_assert`. +- `scripts/fixtures/vc6_stdint_smoke.c` — new focused compile fixture: includes both `` and `` in the same translation unit (reproducing the Python.h + blake2.h coexistence case), asserts `sizeof(uint8_t)==1`/`sizeof(uint32_t)==4`/`sizeof(uint64_t)==8` at compile time, and exercises `load32`/`load64`/`rotl32`/`rotl64` in the same shape `blake2-impl.h` uses. +- `scripts/vc6-probe-stdint.test.sh` — new regression test for the shim and fixture under the VC6 probe, modeled directly on the existing `scripts/vc6-probe-pathcch.test.sh` (skips, not fails, when Wine/MSVC600 are unavailable). +- `cpython/Modules/_blake2/blake2module.c` — with the `` blocker gone, the file advanced to two blockers from defect families already fixed elsewhere in this port: (1) `blake2_exec()` declared `PyObject *d = st->blake2b_type->tp_dict;` after preceding statements (C89 mixed-declaration; VC6 requires declarations before statements) — hoisted `PyObject *d;` into the function's opening declaration group and changed the first assignment to plain `d = ...`, leaving the second assignment (`d = st->blake2s_type->tp_dict;`) unchanged since `d` was already in scope there; (2) the `blake2_module` `PyModuleDef` struct literal mixed a positional `PyModuleDef_HEAD_INIT`/`"_blake2"` prefix with C99 designated initializers (`.m_doc = ...` etc.) for the rest — converted to plain positional initializers in `Include/moduleobject.h`'s declared field order (`m_base`, `m_name`, `m_doc`, `m_size`, `m_methods`, `m_slots`, `m_traverse`, `m_clear`, `m_free`), the same defect family and fix already used in `_abc.c` and `_bisectmodule.c`. Field values and order are unchanged — this is a spelling change only, not a behavior change. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` (4651 lines) so the project-local compatibility patch includes this `stdint.h`/`blake2module.c` slice plus all prior uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` worktree exited 0; the temporary worktree was removed afterward. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, new stdint shim suite, and pythoncore frontier regression suite all passed with no regressions after this slice. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (before this slice) | exit 2 — confirmed the recorded first blocker reproduces exactly: `cpython\Modules\_blake2\impl/blake2.h(18) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory`. Summary: `total=4 compiled=3 cached=0 skipped=0`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after adding `compat/msvc600/stdint.h` only, before the `blake2module.c` source edits) | exit 2 — the missing-`stdint.h` fatal error is gone; new first blocker is `cpython\Modules\_blake2\blake2module.c(98) : error C2275: 'PyObject' : illegal use of this type as an expression` (C89 mixed-declaration) immediately followed by the `.m_doc = ...` designated-initializer `error C2059: syntax error : '.'` at line 145. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the `blake2module.c` slice) | exit 2 — `Modules/_blake2/blake2module.c` now compiles with **zero** errors and **zero** warnings. The frontier advances to the next source in `pythoncore.vcxproj` order, `Modules/_blake2/blake2b_impl.c`, whose new first blockers are a different defect family: bare `0ULL`/`64ULL`-style integer-literal suffixes in `Modules/_blake2/impl/blake2b-ref.c` (`error C2059: syntax error : 'bad suffix on number'` — VC6's C89 front end does not accept the C99 `ULL`/`LL` integer-constant suffixes at all, only `UL`/`L`/`U`), C99 mixed-declaration/`for`-init-declaration fallout in the same file, `unsigned long long` in `clinic/blake2b_impl.c.h` and `blake2b_impl.c` itself (the same `long long`-keyword gap already routed through `PY_LONG_LONG` elsewhere in this port), and a `PyTypeObject *type = ...` C89 mixed-declaration plus a `.` designated-initializer in `blake2b_impl.c`. None of this has been fixed yet. Summary: `total=5 compiled=4 cached=0 skipped=0`. | +| `bash scripts/vc6-probe-core.sh cpython/Modules/main.c` | exit 0 — still compiles cleanly after this slice. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after this slice. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree; temporary worktree removed. | + +**Current pythoncore compile-frontier status:** `Modules/_blake2/blake2module.c` is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past `_abc.c`, `_bisectmodule.c`, and now `blake2module.c`. The frontier has moved on to `Modules/_blake2/blake2b_impl.c` (via its `#include`d `impl/blake2b-ref.c`), whose first blocker is a new defect family for this port: VC6's C89 front end rejects the C99 `ULL`/`LL` unsigned-long-long integer-literal suffixes used throughout the BLAKE2 reference constants and IV tables. This is distinct from the already-solved `long long` *keyword* gap (`PY_LONG_LONG`) — it is about literal-suffix spelling, and will need either rewriting the affected literals (e.g. `0x6A09E667F3BCC908ULL` → a `PY_LONG_LONG`-safe spelling, likely via a cast or an `_LL`/`ui64`-suffix substitution valid under VC6) or a targeted macro, plus the follow-on C89 declaration-order, `long long`-keyword, and designated-initializer fixes already characterized above in `blake2b_impl.c` and its clinic header. Recommended next slice: `Modules/_blake2/impl/blake2b-ref.c`'s integer-literal suffixes first (it is the root blocker `blake2b_impl.c` `#include`s), then re-probe before touching `blake2b_impl.c` itself. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`_bisectmodule.c` designated-initializer slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Modules/_bisectmodule.c` — converted the `_bisectmodule` `PyModuleDef` struct literal from C99 designated initializers (`.m_name = ...`, `.m_size = ...`, etc.) to plain positional initializers in the struct's declared field order (`m_base`, `m_name`, `m_doc`, `m_size`, `m_methods`, `m_slots`, `m_traverse`, `m_clear`, `m_free`, per `Include/moduleobject.h`). This is the same defect family and same fix approach already used twice in `_abc.c` (`error C2059: syntax error : '.'`; VC6 has no C99 designated-initializer support). The struct had no `m_traverse` initializer in the original, so the corresponding positional slot is `NULL`. Field values and order are otherwise unchanged — this is a spelling change only, not a behavior change. No declaration-order (C89 mixed-declaration) errors followed this fix; the file compiles clean end-to-end on the first re-probe. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` (4609 lines) so the project-local compatibility patch includes this `_bisectmodule.c` slice plus all prior uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` worktree exited 0; the temporary worktree was removed afterward. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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-pythoncore-frontier.test.sh` | exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (before this slice) | exit 2 — confirmed the recorded first blocker reproduces exactly: `cpython\Modules\_bisectmodule.c(329) : error C2059: syntax error : '.'` at `.m_name = "_bisect",` in the `_bisectmodule` `PyModuleDef` initializer. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after this slice) | exit 2 — `Modules/_bisectmodule.c` now compiles with **zero** errors and **zero** warnings (only the source-filename echo from `cl.exe`, same as a clean compile). The frontier advances to the next source in `pythoncore.vcxproj` order, `Modules/_blake2/blake2module.c`, whose new first blocker is `cpython\Modules\_blake2\impl/blake2.h(18) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory` — a missing modern-C/SDK standard header, a different defect family from designated initializers or C89 declaration ordering, and not yet addressed here. Summary: `total=4 compiled=3 cached=0 skipped=0`. | +| `bash scripts/vc6-probe-core.sh cpython/Modules/main.c` | exit 0 — still compiles cleanly after this slice. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after this slice. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree; temporary worktree removed. | + +**Current pythoncore compile-frontier status:** `Modules/_bisectmodule.c` is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past both `_abc.c` and `_bisectmodule.c`. The frontier has moved on to `Modules/_blake2/blake2module.c`, whose first blocker is a missing `` (needed by `Modules/_blake2/impl/blake2.h` for fixed-width integer types like `uint32_t`/`uint64_t`). This is a new defect family — a missing standard/SDK header, not a source-level C89/C99 compatibility issue — and will likely need either a project-local `stdint.h` compatibility shim (similar in spirit to the existing `compat/msvc600/pathcch.h` shim) or a decision to exclude/stub the `_blake2` module for this port, rather than a source-hoist slice. The recommended next step is to characterize the actual `uint32_t`/`uint64_t`/etc. usage in `Modules/_blake2/impl/*.h` before choosing between those two approaches. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`_abc.c` C89 declaration-hoist + designated-initializer slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Modules/_abc.c` — advanced the `_abc.c` frontier past its full body with a sequence of small, individually re-probed slices: + - `abc_data_dealloc()`: hoisted `PyTypeObject *tp` before the `PyObject_GC_UnTrack(self)` statement (the exact line-67 blocker recorded at the start of this revision). + - `_abc_data_type_spec` and the `_abcmodule` `PyModuleDef`: converted from C99 designated initializers (`.name = ...`, `.m_name = ...`, etc.) to plain positional initializers in declared field order. VC6 has no C99 designated-initializer support at all (`error C2059: syntax error : '.'`); this is a different defect family from declaration-hoisting, so it is called out separately here. Field values and order are unchanged — this is a spelling change only, not a behavior change. + - `_in_weak_set()`, `_add_to_weak_set()`, `_abc__get_dump()`, `compute_abstract_methods()` (both `for` loops, including replacing their C99 `for (Py_ssize_t pos = 0; ...)` init-declarations with a function-scoped `pos` and hoisting per-iteration locals to the top of each loop body), `set_collection_flag_recursive()`, `_abc__abc_register_impl()`, `_abc__abc_instancecheck_impl()`, `_abc__abc_subclasscheck_impl()` (including its inner `for` loop over `subclasses`), and `subclasscheck_check_registry()` (including its inner `for` loop over the registry snapshot): hoisted all locals into each function's or block's opening declaration group, preserving every assignment at its original execution point (after argument validation, inside the same `if`/`for`/`while` branch, etc.). No control flow, lock/refcount ordering, or error-path behavior was changed anywhere in this slice. + - The previously reported "generated `clinic/_abc.c.h` struct-redefinition conflict around line 583" was characterized while fixing `_abc__abc_instancecheck_impl()` (whose opening declaration group sat at old line 583): it was parser-desync fallout from the preceding unfixed declaration-hoist errors, not a real redefinition. `clinic/_abc.c.h` itself is unmodified and is only 163 lines long; there is no struct redefinition in it. This matches the caveat already recorded about that hypothesis. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` (4583 lines) so the project-local compatibility patch includes this `_abc.c` slice plus all prior uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` worktree exited 0; the temporary worktree was removed afterward. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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-pythoncore-frontier.test.sh` | exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (before this slice) | exit 2 — confirmed the recorded first blocker reproduces exactly: `cpython\Modules\_abc.c(67) : error C2275: 'PyTypeObject' : illegal use of this type as an expression` at `PyTypeObject *tp = Py_TYPE(self);` in `abc_data_dealloc()`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after each incremental slice, ~10 live re-probes) | exit 2 each time until the final one — the first diagnostic advanced monotonically through `_abc.c`: line 67 (`abc_data_dealloc`) → line 109 designated-initializer `error C2059` (`_abc_data_type_spec`) → line 138 (`_in_weak_set`) → line 203 (`_add_to_weak_set`) → line 291 (`_abc__get_dump`) → line 311 (`compute_abstract_methods`) → line 507/512 (`set_collection_flag_recursive`) → line 537 (`_abc__abc_register_impl`) → line 612 (`_abc__abc_instancecheck_impl`) → line 695 (`_abc__abc_subclasscheck_impl`) → line 849 (`subclasscheck_check_registry`). Each slice was verified against the live VC6 frontier before moving to the next. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after the final `_abc.c` slice) | exit 2 — `Modules/_abc.c` now compiles with **zero** errors and **zero** warnings; `total=3 compiled=2 cached=0 skipped=0`. The frontier advances to the next source in `pythoncore.vcxproj` order, `Modules/_bisectmodule.c`, whose new first blocker is `cpython\Modules\_bisectmodule.c(329) : error C2059: syntax error : '.'` — the same C99 designated-initializer defect family just fixed twice in `_abc.c`, not yet fixed here. | +| `bash scripts/vc6-probe-core.sh cpython/Modules/main.c` | exit 0 — still compiles cleanly after this slice. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after this slice. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree; temporary worktree removed. | + +**Current pythoncore compile-frontier status:** `Modules/_abc.c` is fully clean under the VC6 frontier probe (0 errors, 0 warnings). The frontier has moved on to `Modules/_bisectmodule.c`, whose first blocker is a C99 designated-initializer struct literal (`error C2059: syntax error : '.'` at line 329), the same defect family already fixed twice above (`_abc_data_type_spec`, `_abcmodule`). The recommended next slice is `_bisectmodule.c`'s designated initializer(s), followed by whatever C89 declaration-order issues follow in that file, using the same per-function hoist-and-reprobe approach used throughout this revision. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`_abc.c` frontier: `pycore_moduleobject.h` declaration-hoist + `long long` spelling) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Include/internal/pycore_moduleobject.h` — hoisted `_PyModule_GetDict()`'s `PyObject *dict` declaration into the function's opening declaration group (C89/VC6 requires declarations before statements; the prior form declared `dict` after the `assert(PyModule_Check(mod));` statement). The assignment stays at the original point, and the following `assert(dict != NULL);`/return are unchanged. +- `cpython/Modules/_abc.c` — changed the two `unsigned long long` struct field declarations (`_abcmodule_state.abc_invalidation_counter`, `_abc_data._abc_negative_cache_version`) to `unsigned PY_LONG_LONG`. VC6 has no `long long` keyword at all (`error C2632: 'long' followed by 'long' is illegal`); CPython's own `PC/pyconfig.h` already defines `PY_LONG_LONG` to fall back to `__int64` for `_MSC_VER < 1300` (VC6) for exactly this reason. This routes through that existing, already-correct CPython compatibility macro instead of adding a new shim; no other files in the current frontier use the bare `long long` spelling. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` so the project-local compatibility patch includes this slice plus all prior uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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-pythoncore-frontier.test.sh` | exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (before this slice) | exit 2 — first blocker `cpython\Include\internal\pycore_moduleobject.h(33) : error C2143: syntax error : missing ';' before 'type'` at `PyObject *dict = ((PyModuleObject *)mod) -> md_dict;`, cascading into spurious `dict`-undeclared fallout plus `pycore_gc.h(15) : error C2061: syntax error : identifier 'uintptr_t'` and further undefined-struct fallout through `pycore_interp.h`, `pycore_global_objects.h`, `pycore_runtime.h`, and `pycore_object.h`, then `_abc.c` fallout until `fatal error C1003: error count exceeds 100`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after `pycore_moduleobject.h` hoist only) | exit 2 — confirms the hoist was the true root cause: every `pycore_gc.h`/`pycore_interp.h`/`pycore_global_objects.h`/`pycore_runtime.h`/`pycore_object.h` diagnostic is gone (those headers were never actually broken; VC6's error recovery from the single C89 syntax error had desynced parsing for the rest of the translation unit). New first blocker is `cpython\Modules\_abc.c(22) : error C2632: 'long' followed by 'long' is illegal` at `unsigned long long abc_invalidation_counter;`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` (after both fixes) | exit 2 — `_abc.c`'s `long long` blocker is gone. New first blocker is `cpython\Modules\_abc.c(67) : error C2275: 'PyTypeObject' : illegal use of this type as an expression` (a C89 mixed-declaration pattern, same family as already fixed repeatedly in `pystate.c`/`pylifecycle.c`/`getpath.c`), followed by many more declaration-order and declaration-after-statement errors throughout the rest of `_abc.c`'s ~35 functions until `fatal error C1003: error count exceeds 100` at line 784. Summary: `total=2 compiled=1 cached=0 skipped=0`. | +| `bash scripts/vc6-probe-core.sh cpython/Modules/main.c` | exit 0 — still compiles cleanly after this slice. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after this slice. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree. | + +**Current pythoncore compile-frontier status:** the frontier has advanced past the `pycore_moduleobject.h`/GC-header cascade and past `_abc.c`'s `long long` blocker. `Modules/_abc.c` is now the active frontier file; the next blocker is a large set of C89 declaration-order violations spread across most of its functions (starting at line 67), plus at least one apparent struct-redefinition conflict with the Argument Clinic-generated `clinic/_abc.c.h` at line 583 that has not yet been individually characterized. This will need a multi-slice declaration-hoist pass through `_abc.c`, similar in shape to the `pystate.c` slices recorded below, rather than a single edit. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (VC6 frontier `/D` string define transport) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `scripts/vc6-probe-pythoncore-frontier.sh` — moved live VC6 compile arguments into per-object response files so quoted `/D` string literals no longer traverse `wine cmd /c` as inline command text. `quote_define_for_cmd()` now doubles define-owned backslashes before protecting literal quotes, so `VPATH="..\\.."` reaches CL preprocessing as the C string literal `"..\\.."`; empty-string defines such as `PYDEBUGEXT=""` are preserved. Added `render_compile_command_for_test()` as a safe no-Wine regression helper for define rendering. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — added a list-only/no-toolchain assertion that checks rendered per-file string defines for `VPATH`, `PYDEBUGEXT`, and `PLATLIBDIR` before the optional live Wine/VC6 run. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash -n scripts/vc6-probe.test.sh scripts/vc6-probe-core.test.sh scripts/vc6-probe-pathcch.test.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/generate-getpath-frozen.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh scripts/vc6-probe.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-pythoncore-frontier.test.sh` | exit 0 — shell syntax plus public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — `Modules/getpath.c` now compiles cleanly under the forced frontier. The frontier advances to `Modules/_abc.c`; first exact blocker is `cpython\\Include\\internal\\pycore_moduleobject.h(33) : error C2143: syntax error : missing ';' before 'type'`, followed by `dict` undeclared fallout, missing/undefined GC internals beginning with `pycore_gc.h(15) : error C2061: syntax error : identifier 'uintptr_t'`, and then `_abc.c` VC6/C89/modern-C fallout until `fatal error C1003: error count exceeds 100`. Summary: `total=2 compiled=1 cached=0 skipped=0`. | + +**Current pythoncore compile-frontier status:** the quoted macro transport blocker is resolved in the harness, and the frontier has advanced past `Modules/getpath.c`. The next actionable blocker is now in shared internal headers reached while compiling `Modules/_abc.c`, starting with C89 declaration ordering in `pycore_moduleobject.h` and missing/unsupported GC typedef structure (`uintptr_t` / `PyGC_Head`) fallout. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`getpath.c` _PyConfig_InitPathConfig C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Modules/getpath.c` — advanced `_PyConfig_InitPathConfig()` past the first main-body VC6/C89 declaration-order blocker by hoisting active locals (`configDict`, `dict`, `co`, Windows-only `winreg`, and `r`) into the function opening declaration group. Assignments remain at their original execution points after `_PyPathConfig_ReadGlobal()`, early status/`compute_path_config` return, and GIL check; refcount cleanup, `winreg` fallback handling, code evaluation, `_PyConfig_FromDict()`, and return statuses are unchanged. Disabled `#if 0` debug locals were left untouched. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` so the compatibility patch includes this `_PyConfig_InitPathConfig()` declaration-hoist slice plus prior uncommitted compatibility edits. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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-pythoncore-frontier.test.sh` | exit 0 — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — `_PyConfig_InitPathConfig()` now gets past the prior line-887 `PyObject *configDict = _PyConfig_AsDict(config);` blocker, plus the follow-on `dict`, `co`, Windows `winreg`, and `r` declaration-order blockers. New exact first blocker is `build\generated\cpython\Modules\getpath.c(956) : error C2001: newline in constant` at `!decode_to_dict(dict, "VPATH", VPATH)`, followed by adjacent newline-in-constant diagnostics for `PLATLIBDIR`, `PYDEBUGEXT`, and `PYWINVER`, then parse fallout. Summary: `total=1 compiled=0 cached=0 skipped=0`. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree. | + +**Current pythoncore compile-frontier status:** the requested `_PyConfig_InitPathConfig()` declaration-order slice is complete and verified. The frontier still starts at `Modules/getpath.c`, but the next blocker has advanced from C89 declarations to quoted macro/value handling in the initial-value dictionary expression. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in this revision (`getpath.c` first VC6/C89 helper slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Modules/getpath.c` — advanced the first `Modules/getpath.c` pythoncore frontier slice by moving early helper declarations to C89/VC6-safe declaration groups while preserving assignment timing after argument parsing and other checks. Covered `getpath_abspath()`, `getpath_basename()`, `getpath_dirname()`, `getpath_hassuffix()`, Windows file-attribute helpers (`isdir`/`isfile`/`isxfile`), `getpath_joinpath()`, `getpath_readlines()`, `funcs_to_dict()`, `decode_to_dict()`, `env_to_dict()`, and `winmodule_to_dict()`. +- `cpython/Modules/getpath.c` — added a narrow VC6/old-SDK fallback for missing `INVALID_FILE_ATTRIBUTES`, guarded as `defined(_MSC_VER) && _MSC_VER < 1300 && !defined(INVALID_FILE_ATTRIBUTES)` under `MS_WINDOWS` after including ``. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` so the project-local compatibility patch includes this `getpath.c` slice plus prior uncommitted compatibility edits. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `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-pythoncore-frontier.test.sh` | exit 0 — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — `Modules/getpath.c` gets past the prior line-66 `Py_ssize_t len` blocker, the immediate helper declaration-order blockers, and the old-SDK `INVALID_FILE_ATTRIBUTES` blocker. New exact first blocker is `build\\generated\\cpython\\Modules\\getpath.c(887) : error C2275: 'PyObject' : illegal use of this type as an expression` at `PyObject *configDict = _PyConfig_AsDict(config);` in `_PyConfig_InitPathConfig()`, followed by the same function's later C89 declaration-order fallout. Summary: `total=1 compiled=0 cached=0 skipped=0`. | +| `git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch` | exit 0 — regenerated compatibility patch applies cleanly to a pristine detached `v3.11.16` worktree. | + +**Current pythoncore compile-frontier status:** the first bounded `getpath.c` helper declaration-order/old-SDK slice is complete and verified. The frontier still starts at `Modules/getpath.c`, but the next blocker has advanced into `_PyConfig_InitPathConfig()`'s main path-calculation body. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in this revision (generated `getpath.h` provisioning) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `scripts/generate-getpath-frozen.sh` — new reproducible project-local generation step for `Python/frozen_modules/getpath.h`. It invokes CPython's documented `Programs/_freeze_module.py getpath Modules/getpath.py ...` path with host `python3` and writes only to ignored `build/generated/cpython/Python/frozen_modules/getpath.h`. +- `scripts/generate-getpath-frozen.test.sh` — new regression coverage for the generated path and header format: verifies the `_freeze_module.py` banner, `_Py_M__getpath` symbol, 16-byte line formatting, unmarshaled `` code object, and byte-for-byte equality with a direct `Programs/_freeze_module.py` invocation. +- `scripts/vc6-probe-pythoncore-frontier.sh` — now provisions the generated getpath header before live VC6 compilation and compiles `Modules/getpath.c` from an ignored generated cpython-shaped source copy so its relative `../Python/frozen_modules/getpath.h` include resolves without tracking generated output. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — live integration check now rejects a stale missing-`getpath.h` blocker and verifies the frontier harness created the ignored generated header. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `chmod +x scripts/generate-getpath-frozen.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.sh && bash -n scripts/generate-getpath-frozen.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0 — generator format/path regression passed and frontier regression passed, including live provisioning of `build/generated/cpython/Python/frozen_modules/getpath.h`. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — `Modules/getpath.c` now gets past both `` and the generated `../Python/frozen_modules/getpath.h` include. It stops at the next honest VC6/C89 compile blocker: mixed declarations in `getpath.c`, first diagnostic `build\\generated\\cpython\\Modules\\getpath.c(66) : error C2275: 'Py_ssize_t' : illegal use of this type as an expression`, followed by more declaration-order errors and `INVALID_FILE_ATTRIBUTES` not being declared before the compiler reaches its 100-error cap. Summary: `total=1 compiled=0 cached=0 skipped=0`. | + +**Current pythoncore compile-frontier status:** generated frozen `getpath.h` is now reproducibly provisioned from CPython source into ignored build output and integrated into the frontier harness. The current first blocker remains `Modules/getpath.c`, now at VC6/C89 declaration-order and old-SDK constant compatibility work rather than missing generated input. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (VC6 `PathCchFindExtension` shim) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `compat/msvc600/pathcch.h` — new VC6-scoped project-local compatibility header that implements only `PathCchFindExtension(PCWSTR, size_t, PCWSTR *)` for the existing `Modules/getpath.c` use. It scans a null-terminated wide path within `cchPath`, returns the last `.` after the last `\\`, `/`, or `:` separator, returns the terminating NUL when no extension is present, and returns `E_INVALIDARG` for null arguments, zero `cchPath`, or a too-small count with no NUL. +- `scripts/fixtures/vc6_pathcch_smoke.c` — focused compile fixture covering `.exe`, no extension, a dot in a directory name, dotfiles, trailing directory separators, multiple suffixes, and invalid/too-small arguments. +- `scripts/vc6-probe-pathcch.test.sh` — new regression test for the shim and fixture under the VC6 probe when Wine/MSVC600 are available. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `chmod +x scripts/vc6-probe-pathcch.test.sh && bash -n scripts/vc6-probe-pathcch.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh scripts/vc6-probe.sh` | exit 0 | +| `bash scripts/vc6-probe-pathcch.test.sh` | exit 0, `ALL TESTS PASSED` — 4/4 checks `ok`; the smoke fixture compiles under VC6 and no longer hits missing `pathcch.h`. | +| `bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0 — public probe suite, core probe suite, pathcch smoke suite, and frontier regression suite all passed. | +| `VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — `Modules/getpath.c` now gets past `` and stops at the next honest blocker: `cpython\\Modules\\getpath.c(22) : fatal error C1083: Cannot open include file: '../Python/frozen_modules/getpath.h': No such file or directory`. Summary: `total=1 compiled=0 cached=0 skipped=0`. | + +**Current pythoncore compile-frontier status:** the narrow `PathCchFindExtension` compatibility needed by `Modules/getpath.c` is implemented and verified under VC6 compile probes. The next blocker in full project order is the missing generated/frozen header `Python/frozen_modules/getpath.h` required by `Modules/getpath.c`; this is separate from the PathCch API gap. No `CompareStringOrdinal` blocker has been reached yet. + +**Caveat:** this is still compile-probe work only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (source-list-driven pythoncore compile frontier) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `scripts/vc6-probe-pythoncore-frontier.sh` — new project-local pythoncore compile-frontier harness. It parses `cpython/PCbuild/pythoncore.vcxproj`'s 198 `` entries, normalizes Windows-style paths to project-local `cpython/...` paths, compiles supported sources incrementally, preserves common/per-file defines, reports external/generated sources, and stops on the first VC6 front-end blocker with `cl.exe`'s real status. +- `scripts/vc6-probe-pythoncore-frontier.test.sh` — new regression test covering source-list parsing, path normalization, per-file define preservation, unsupported/generated/external reporting, and a bounded live first-source VC6 run when Wine/MSVC600 are present. +- `PORT_STATUS.md` — that revision. + +**Command results (previous revision):** + +| Command | Result | +|---|---| +| `for f in scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh; do bash -n "$f" || exit $?; done` | exit 0 | +| `bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0, `ALL TESTS PASSED` — 12/12 checks `ok` | +| `bash scripts/vc6-probe-pythoncore-frontier.sh` | exit 2 — generated the source list, began with `cpython/Modules/getpath.c`, preserved its per-file defines, invoked VC6 `cl.exe`, and stopped truthfully at the first blocker: missing `pathcch.h` at `Modules/getpath.c(14)`. | +| `bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh` | exit 0 — public probe suite, core probe suite, and new frontier suite all passed. | +| `bash scripts/vc6-probe-minlink.sh` | exit 96 — unchanged minimal link-frontier behavior: all four selected translation units compile, then `LINK.EXE` fails with `fatal error LNK1120: 267 unresolved externals`. | + +**Previous pythoncore compile-frontier status:** source-list-driven frontier infrastructure was implemented and verified. The first actionable VC6 compile blocker in full project order was `Modules/getpath.c` requiring `pathcch.h`, a modern Windows SDK header not present in the VC6/MSVC600 include set. + +**Caveat:** this was a compile-frontier harness only. No full `pythoncore.dll`/`python.exe` build, no successful link, no Wine launch, and no Windows 98 runtime execution was claimed. + +## Files changed in previous revision (minimal VC6 link-frontier probe) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `scripts/vc6-probe-minlink.sh` — new project-local link-frontier harness. It reuses the existing Wine/MSVC600 helpers, compiles `Programs/python.c` plus the three currently clean core translation units (`Modules/main.c`, `Python/pylifecycle.c`, and `Python/pystate.c`) with pythoncore-style core/shared defines, then invokes VC6 `LINK.EXE` for a minimal `python-min.exe` attempt. This is intentionally not a full `pythoncore.vcxproj` build; `pythoncore.vcxproj` lists 198 C sources (without externals disabled: plus zlib-conditioned entries), while `python.vcxproj` only contributes `Programs/python.c` and references the core project. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe-minlink.sh` | exit 96 — all four frontier translation units compile under VC6, then `LINK.EXE` runs and fails truthfully with `fatal error LNK1120: 267 unresolved externals`. First unresolved symbols include `__PyPathConfig_ComputeSysPath0` / `__PyPathConfig_UpdateGlobal` (`Python/pathconfig.c`), `__Py_Dealloc` (`Objects/object.c`), `_PyErr_Print` (`Python/pythonrun.c`), and `PyStatus_Ok` (`Python/initconfig.c`). | +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — existing core compile-probe regression checks still pass after adding the link-frontier script | + +**Current minimal-link status:** the first post-core-probe link milestone is now implemented as a reproducible harness that reaches the VC6 linker. A successful link is not feasible from only the already-clean TUs: the exact blocker is the expected unresolved-symbol frontier caused by not yet compiling the rest of `pythoncore.vcxproj`'s source graph. Recommended next artifact is a source-list-driven VC6 `pythoncore` compile frontier (generate/consume the `pythoncore.vcxproj` `` list, with per-file defines such as `getpath.c` and `sysmodule.c` handled explicitly) that compiles additional core objects one at a time before attempting a real `pythoncore`/`python.exe` link. + +**Caveat:** this is a link-frontier probe only. No `pythoncore.dll`/full `python.exe` build, no Wine launch, and no Windows 98 runtime execution is claimed. + +## Files changed in previous revision (`pystate.c` final tail helper C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — `_Py_GetConfig()` now declares `PyThreadState *tstate` in the function opening declaration group while preserving the `assert(PyGILState_Check())` before assigning `tstate = _PyThreadState_GET()`. `push_chunk()` now declares `_PyStackChunk *new` and `PyObject **res` in its opening declaration group while preserving the allocation-size loop, `allocate_chunk(...)` assignment point, chunk linking/top/limit updates, root-chunk offset, and returned stack pointer. `_PyThreadState_PopFrame()` now declares `PyObject **base` in the function opening declaration group while preserving the datastack assertion before assigning `base = (PyObject **)frame`, plus the chunk-pop and top-reset paths. `_PyThreadState_BumpFramePointerSlow()`'s inner block declaration was not changed. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff` (3703 lines); includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` compiles cleanly end-to-end (compile-only) | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the final tail-helper declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 0 — gets past the prior line 3405 (`PyThreadState *tstate = _PyThreadState_GET();`) blocker in `_Py_GetConfig()`, the `push_chunk()` declaration-order blockers at line 3418 (`_PyStackChunk *new = allocate_chunk(...)`) and line 3431 (`PyObject **res = &new->data[...]`), and the follow-on line 3460 (`PyObject **base = (PyObject **)frame;`) blocker in `_PyThreadState_PopFrame()`. No next C89 declaration blocker is currently exposed by the `pystate.c` compile probe; the only diagnostic left in this probe output is the pre-existing line 3361 warning (`warning C4550: expression evaluates to a function which is missing an argument list`). | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + + +## Files changed in previous revision (`pystate.c` PyGILState_Check/Ensure C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `PyGILState_Check()`'s `PyThreadState *tstate` into the function opening declaration group while preserving the early `check_enabled` and TSS-created returns before assigning `tstate = _PyRuntimeGILState_GetThreadState(gilstate)`. `PyGILState_Ensure()` now declares `PyThreadState *tcur` and `int current` in the opening declaration group, keeps `tcur = PyThread_tss_get(...)` after the initialization assertions, and leaves the new/current thread-state branches, restore/save ordering, counter update, and return value unchanged. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `PyGILState_Check()`/`PyGILState_Ensure()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior line 2886 (`error C2275: 'PyThreadState' : illegal use of this type as an expression`) blocker at `PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate);` in `PyGILState_Check()` and the adjacent `PyGILState_Ensure()` declaration-order fallout. New exact first blocker is line 3052 (`error C2059: syntax error : '{'`) at `*data = (_PyCrossInterpreterData){0};` in `_PyObject_GetCrossInterpreterData()`, followed by line 3057 `crossinterpdatafunc getdata = _lookup_getdata(obj);`, line 3062 `int res = getdata(obj, data);`, and later cross-interpreter-data helper declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` frame access and async-exception C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `PyThreadState_GetFrame()`'s `_PyInterpreterFrame *f` and `PyFrameObject *frame` declarations into the function's opening declaration group while preserving the `f = tstate->cframe->current_frame` assignment immediately after the assert and the `frame = _PyFrame_GetFrameObject(f)` assignment after the NULL check. `PyThreadState_SetAsyncExc()` now declares `PyThreadState *tstate` in the function opening group and uses `for (tstate = ...; ...)`; its loop body declares `PyObject *old_exc` before the skip check and assigns it at the original point before the async exception replacement, preserving head-lock traversal, skip behavior, unlock-before-decref, signal, and return paths. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 32/32 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the frame access and async-exception declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `PyThreadState_GetFrame()` blockers at line 2457 (`_PyInterpreterFrame *f = tstate->cframe->current_frame;`) and line 2464 (`PyFrameObject *frame = _PyFrame_GetFrameObject(f);`), plus `PyThreadState_SetAsyncExc()`'s C99 `for (PyThreadState *tstate = ...)` initializer and post-`if` `PyObject *old_exc` loop-body declaration. New exact first blocker is line 2576 (`error C2275: 'PyObject' : illegal use of this type as an expression`) at `PyObject *result = PyDict_New();` in `_PyThread_CurrentFrames()`, followed by line 2582 (`int gc_was_enabled = PyGC_Disable();`) and later declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` thread-state deletion helpers C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists the thread-state deletion helper locals needed by VC6/C89: `tstate_delete_common()` now declares `PyInterpreterState *interp`, `_PyRuntimeState *runtime`, and `_PyStackChunk *chunk` in the opening declaration group while assigning them at their original post-ensure/post-TSS points; `_PyThreadState_DeleteCurrent()` declares `struct _gilstate_runtime_state *gilstate` before `_Py_EnsureTstateNotNULL()` and assigns it immediately after; `_PyThreadState_DeleteExcept()` declares `PyThreadState *list`, `p`, and `next` before `HEAD_LOCK(runtime)` while preserving the locked list capture/unlinking and post-unlock clear/free loop. The stack-chunk loop's block-local `prev` remains at the start of its `while` block. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 32/32 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the thread-state deletion helper declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `tstate_delete_common()` blockers at line 2245 (`PyInterpreterState *interp = tstate->interp;`), line 2249 (`_PyRuntimeState *runtime = interp->runtime;`), and line 2268 (`_PyStackChunk *chunk = tstate->datastack_chunk;`), plus `_PyThreadState_DeleteCurrent()`'s post-ensure `gilstate` declaration and `_PyThreadState_DeleteExcept()`'s post-lock `list` declaration. New exact first blocker is line 2457 (`error C2143: syntax error : missing ';' before 'type'`) at `_PyInterpreterFrame *f = tstate->cframe->current_frame;` in `PyThreadState_GetFrame()`, followed by line 2464 (`PyFrameObject *frame = _PyFrame_GetFrameObject(f);`) and later declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` new_threadstate C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `new_threadstate()`'s `PyThreadState *new_tstate`, `uint64_t id`, and `PyThreadState *old_head` declarations into the function's opening declaration group. `new_tstate = alloc_threadstate()` remains before the lock, `id = interp->threads.next_unique_id` remains after the locked increment, and `old_head = interp->threads.head` remains immediately before the `old_head == NULL` branch, preserving allocation-before-lock, `used_newtstate` behavior, initialization branches, and lock/unlock order. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 32/32 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `new_threadstate()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `new_threadstate()` blockers at line 1970 (`uint64_t id = interp->threads.next_unique_id;`) and line 1973 (`PyThreadState *old_head = interp->threads.head;`). New exact first blocker is line 2080 (`error C2275: 'PyInterpreterState' : illegal use of this type as an expression`) at `PyInterpreterState *interp = tstate->interp;` in `_PyState_AddModule()`, followed by declaration-order fallout for `interp` and later locals. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` _PyInterpreterState_IDDecref C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `_PyInterpreterState_IDDecref()`'s `struct _gilstate_runtime_state *gilstate`, `int64_t refcount`, `PyThreadState *tstate`, and `PyThreadState *save_tstate` declarations to the function's opening declaration group. `gilstate = &_PyRuntime.gilstate` remains immediately after the `id_mutex` assert; `refcount = interp->id_refcount` remains after the decrement while the mutex is still held; `tstate` and `save_tstate` assignments remain inside the `refcount == 0 && interp->requires_idref` block, preserving lock acquisition/release plus `_PyThreadState_Swap()`/`Py_EndInterpreter()` ordering. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `_PyInterpreterState_IDDecref()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `_PyInterpreterState_IDDecref()` blockers at line 1812 (`struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;`), line 1816 (`int64_t refcount = interp->id_refcount;`), and the block-local `tstate`/`save_tstate` declarations. New exact first blocker is line 1876 (`error C2143: syntax error : missing ';' before 'type'`) at `_PyStackChunk *res = _PyObject_VirtualAlloc(size_in_bytes);` in `allocate_chunk()`, followed by declaration-order fallout for `res`. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` PyInterpreterState_Get C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `PyInterpreterState_Get()`'s `PyInterpreterState *interp` declaration beside the existing `PyThreadState *tstate` local. `tstate = _PyThreadState_GET()` remains immediately before `_Py_EnsureTstateNotNULL(tstate)`, and `interp = tstate->interp` remains at the original post-ensure point, preserving the fatal-error check and return behavior. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `PyInterpreterState_Get()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `PyInterpreterState_Get()` blocker at line 1719 (`PyInterpreterState *interp = tstate->interp;`). New exact first blocker is line 1812 (`error C2143: syntax error : missing ';' before 'type'`) at `struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;` in `_PyInterpreterState_IDDecref()`, followed by line 1816 `int64_t refcount = interp->id_refcount;` and later declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` PyInterpreterState_Delete C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `PyInterpreterState_Delete()`'s `PyInterpreterState **p` declaration beside the existing `runtime` and `interpreters` locals. The `for (p = &interpreters->head; ...)` initializer remains under `HEAD_LOCK(runtime)`, preserving the unlink search, remaining-thread checks, main-interpreter checks, assignment to `*p`, and lock/unlock ordering. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `PyInterpreterState_Delete()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `PyInterpreterState_Delete()` blocker at line 1638 (`PyInterpreterState **p;`). New exact first blocker is line 1719 (`error C2275: 'PyInterpreterState' : illegal use of this type as an expression`) at `PyInterpreterState *interp = tstate->interp;` in `PyInterpreterState_Get()`, followed by declaration-order fallout in the same and later functions. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` interpreter_clear C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `interpreter_clear()`'s `PyThreadState *p` declaration beside the existing `_PyRuntimeState *runtime` local. The `p = interp->threads.head;` assignment remains at the same point under `HEAD_LOCK(runtime)`, preserving the lock/unlock ordering and the thread-clear loop behavior. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `interpreter_clear()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `interpreter_clear()` blocker at line 1537 (`PyThreadState *p = interp->threads.head;`). New exact first blocker is line 1638 (`error C2275: 'PyInterpreterState' : illegal use of this type as an expression`) at `PyInterpreterState **p;` in `PyInterpreterState_Delete()`, followed by declaration-order fallout in the same and later functions. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` PyInterpreterState_New C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `PyInterpreterState_New()`'s `PyThreadState *tstate`, `PyThread_type_lock pending_lock`, `_PyRuntimeState *runtime`, `struct pyinterpreters *interpreters`, `int64_t id`, and `PyInterpreterState *old_head` declarations into the function's opening declaration group. `tstate = _PyThreadState_GET()` remains immediately before the audit, and the `pending_lock`, `runtime`, `interpreters`, `id`, and `old_head` assignments stay at the original execution points after the audit, after lock allocation succeeds, after `HEAD_LOCK(runtime)`, and before the `old_head == NULL` test respectively. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `PyInterpreterState_New()` declaration-hoist slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `PyInterpreterState_New()` blockers at line 1438 (`PyThread_type_lock pending_lock = PyThread_allocate_lock();`) and its `runtime`, `interpreters`, `id`, and `old_head` declaration-order fallout. New exact first blocker is line 1537 (`error C2275: 'PyThreadState' : illegal use of this type as an expression`) at `PyThreadState *p = interp->threads.head;` in `interpreter_clear()`, followed by later declaration-order fallout in the same translation unit. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pystate.c` alloc_for_runtime lock C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pystate.c` — hoists `alloc_for_runtime()`'s `PyThread_type_lock lock1`, `lock2`, and `lock3` declarations beside `PyMemAllocatorEx old_alloc`. The three `PyThread_allocate_lock()` calls remain at their original execution points as assignments; the existing NULL checks, `lock1`/`lock2` cleanup order, allocator restoration, output assignments, and return paths are unchanged. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the `pystate.c` lock declaration slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `alloc_for_runtime()` blockers at lines 1185/1190/1196 (`PyThread_type_lock lock1/lock2/lock3 = PyThread_allocate_lock();`). New exact first blocker is line 1438 (`error C2275: 'PyThread_type_lock' : illegal use of this type as an expression`) at `PyThread_type_lock pending_lock = PyThread_allocate_lock();` in `PyInterpreterState_New()`, followed by that function's `runtime`, `interpreters`, `id`, and `old_head` declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pycore_frame.h` frame inline C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Include/internal/pycore_frame.h` — hoists the first VC6/C89 mixed-declaration blockers exposed while compiling `Python/pystate.c`: `_PyFrame_GetFrameObject()` now declares `PyFrameObject *res` before the `assert()` and assigns `frame->frame_obj` at the original point; `_PyThreadState_BumpFramePointer()` keeps `_PyInterpreterFrame *res` scoped inside the stack-space `if` block but declares it before the assignment; `_PyFrame_GetGenerator()` declares `size_t offset_in_gen` before the `assert()` and assigns `offsetof(PyGenObject, gi_iframe)` at the original point. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `v3.11.16` `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — still compiles cleanly after the header slice | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — gets past the prior `pycore_frame.h` blockers at `_PyFrame_GetFrameObject()`, `_PyThreadState_BumpFramePointer()`, and `_PyFrame_GetGenerator()`. New exact first blocker is line 1185 (`error C2275: 'PyThread_type_lock' : illegal use of this type as an expression`) at `PyThread_type_lock lock1 = PyThread_allocate_lock();` in `threadstate_update_waiting_for_thread_shutdown()`, followed by the same function's `lock2` and `lock3` declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` call_ll_exitfuncs C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `call_ll_exitfuncs()`'s `void (*exitfunc)(void)` declaration before the loop and assigns it at the original post-decrement point, preserving the decrement, slot clearing, LIFO invocation order, and final `stdout`/`stderr` flushes. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 0 — gets past the prior line 3045 `void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs];` blocker in `call_ll_exitfuncs()`; no next `pylifecycle.c` blocker was found because the translation unit now compiles cleanly in the VC6 core compile probe. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` fatal_error/_Py_FatalErrorFormat C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `fatal_error()` locals (`runtime`, `tstate`, `interp`, `tss_tstate`, and `has_tstate_and_gil`) into the function declaration area while preserving the original assignment/evaluation points, including `runtime = &_PyRuntime`, `interp = NULL`, `tss_tstate = PyGILState_GetThisThreadState()`, and the `has_tstate_and_gil` boolean assignment. `_Py_FatalErrorFormat()` now declares `stream`, `fd`, and `vargs` before its reentrancy check, then assigns `stream = stderr` and `fd = fileno(stream)` at the original post-reentrancy point before output begins. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 2866 `_PyRuntimeState *runtime = &_PyRuntime;` blocker in `fatal_error()` plus the immediately adjacent `tstate`/`interp`/`tss_tstate`/`has_tstate_and_gil` declaration-order fallout and `_Py_FatalErrorFormat()`'s `FILE *stream`, `fd`, and `va_list vargs` mixed declarations. New exact first blocker is line 3045 (`error C2143: syntax error : missing ';' before 'type'`) at `void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs];` in `call_ll_exitfuncs()`. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` fatal-error dump C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `fatal_error_dump_runtime()`'s `PyThreadState *finalizing` to the function declaration area and assigns it at the original point after the `PUTS()` call. `_Py_DumpExtensionModules()` now declares its function-scope locals (`modules`, `pos`, `key`, `value`, `stdlib_module_names`, `header`, and `count`) before the `interp == NULL` early return; the `modules`, `stdlib_module_names`, `header`, and `count` initializers are preserved as assignments at their original execution points. The inner `is_stdlib_ext`, `i`, `item`, and `hash` block declarations are unchanged. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` tree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 2698 `PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);` blocker in `fatal_error_dump_runtime()` and the adjacent `_Py_DumpExtensionModules()` function-scope declaration-order blockers. New exact first blocker is line 2866 (`error C2275: '_PyRuntimeState' : illegal use of this type as an expression`) at `_PyRuntimeState *runtime = &_PyRuntime;` in `fatal_error()`, followed by additional `fatal_error()` declaration-order fallout. | +| `git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch` against pristine `v3.11.16` tree | exit 0 | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` is_valid_fd platform-branch C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `is_valid_fd()`'s platform-branch locals into the function declaration area under the same preprocessor ladder: `int fd2` for the Linux `dup()` branch, `HANDLE hfile` for `MS_WINDOWS`, and `struct stat st` for the fallback branch. The existing `fd < 0` early return, platform conditions, and branch behavior are unchanged; the original declaration sites now only assign/use (`fd2 = dup(fd)`, `_get_osfhandle()`, and `fstat(fd, &st)`). +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 2296 `HANDLE hfile;` blocker in `is_valid_fd()`. New exact first blocker is line 2403 (`error C2275: 'PyObject' : illegal use of this type as an expression`) at `PyObject *encoding_str = PyUnicode_FromWideChar(encoding, -1);` in `create_stdio()`, followed by line 2409 `PyObject *errors_str = PyUnicode_FromWideChar(errors, -1);` and later declaration-order blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` add_main_module shadowed-loader C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `PyObject *bimod` and a distinct `PyObject *loader_obj` into `add_main_module()`'s existing declaration group. The `builtins` import and `BuiltinImporter` lookup remain at their original execution points; the outer borrowed `loader` variable and its NULL/`Py_None` test are unchanged, while `loader_obj` carries only the formerly shadowed strong reference through its NULL check, `__loader__` dict set, and decref. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 2212 `PyObject *bimod = PyImport_ImportModule("builtins");` blocker and the same function's formerly shadowed line 2233 `PyObject *loader = PyObject_GetAttrString(...)` declaration-order blocker in `add_main_module()`. New exact first blocker is line 2296 (`error C2275: 'HANDLE' : illegal use of this type as an expression`) at `HANDLE hfile;` in `is_valid_fd()`, followed by later declaration-order blockers in `create_stdio()` and finalization diagnostics. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` finalize_modules C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `int verbose` and `PyObject *weaklist` to the top declaration group in `finalize_modules()`. `verbose` is assigned after the existing `modules == NULL` early return, and `weaklist` is assigned at the original `finalize_remove_modules(modules, verbose)` call site, preserving early-return behavior and call order. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1606 `int verbose = _PyInterpreterState_GetConfig(interp)->verbose;` blocker and line 1624 `PyObject *weaklist = finalize_remove_modules(modules, verbose);` in `finalize_modules()`. New exact first blocker is line 1838 (`error C2275: 'PyThreadState' : illegal use of this type as an expression`) at `PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);` in `Py_FinalizeEx()`, followed by line 1868 `int malloc_stats = tstate->interp->config.malloc_stats;` and later finalization declaration-order blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` finalize_modules_clear_weaklist C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `Py_ssize_t i` plus `PyObject *tup`, `name`, `mod`, and `dict` to the top declaration group in `finalize_modules_clear_weaklist()`. The reverse loop now assigns `i = PyList_GET_SIZE(weaklist) - 1` at the original loop point, and each former loop-local declaration is now an assignment at the same position, preserving evaluation order and the two existing `continue` paths. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1551 `for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--)` blocker and the same loop's `PyObject *tup`, `name`, `mod`, and `dict` mixed declarations. New exact first blocker is line 1606 (`error C2143: syntax error : missing ';' before 'type'`) at `int verbose = _PyInterpreterState_GetConfig(interp)->verbose;` in `finalize_modules()`, followed by line 1624 `PyObject *weaklist = finalize_remove_modules(modules, verbose);` and later finalization declaration-order blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` finalize_modules_delete_special C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `const char * const *p` and `PyObject *value` to the top declaration group in `finalize_modules_delete_special()`. The first loop now assigns `p = sys_deletes` at the original declaration point, and the second loop assigns `value = _PyDict_GetItemStringWithError(...)` where the mixed declaration used to be. `name` and `orig_name` remain loop-local, preserving their evaluation/order. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1411 `const char * const *p;` blocker and the line 1426 `PyObject *value` blocker in `finalize_modules_delete_special()`. New exact first blocker is line 1551 (`error C2143: syntax error : missing ';' before 'type'`) at `for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--)` in `finalize_modules_clear_weaklist()`, followed by `PyObject *tup`, `PyObject *name`, `PyObject *mod`, and `PyObject *dict` mixed declarations in the same loop/function plus later finalization blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` pyinit_main/public initialization API C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists declaration-order blockers in `pyinit_main()`, `Py_InitializeFromConfig()`, `Py_InitializeEx()`, and `_Py_InitializeMain()`. Locals are declared at function top, while assignments/calls (`tstate->interp`, `_PyRuntime_Initialize()`, `&_PyRuntime`, `tstate = NULL`, `_PyConfig_InitCompatConfig()`, and `_PyRuntimeState_GetThreadState(runtime)`) remain at their original execution points to preserve behavior. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1285 `PyStatus status = init_interp_main(tstate);` blocker in `pyinit_main()` and the declaration-order fallout in `Py_InitializeFromConfig()`, `Py_InitializeEx()`, and `_Py_InitializeMain()`. New exact first blocker is line 1411 (`error C2143: syntax error : missing ';' before 'const'`) at `const char * const *p;` in `finalize_modules_delete_special()`, followed by `PyObject *value` in the same function and later finalization mixed-declaration blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` pyinit_core/init_interp_main C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists `PyConfig config` to the top of `pyinit_core()` while leaving `PyConfig_InitPythonConfig(&config)` at its original execution point. `init_interp_main()` now declares `PyStatus status`, then initialized `is_main_interp`, `interp`, and `config` at function top before the existing `assert`, preserving the declaration initializer order requested for this narrow VC6 declaration-order slice. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1104 `PyConfig config;` blocker in `pyinit_core()` and the immediately exposed `init_interp_main()` mixed declarations. New exact first blocker is line 1285 (`error C2275: 'PyStatus' : illegal use of this type as an expression`) at the mixed declaration `PyStatus status = init_interp_main(tstate);` in `pyinit_main()`, followed by additional declaration-order fallout in `Py_InitializeFromConfig()` and later functions. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` pre-initialization C89/C99 slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — removes the two pre-initialization `_PyArgv` designated initializers in `Py_PreInitializeFromBytesArgs()` and `Py_PreInitializeFromArgs()` by declaring `args` first and assigning `use_bytes_argv`, `argc`, and the active argv pointer field explicitly before the existing `_Py_PreInitializeFromPyArgv()` call. `_Py_PreInitializeFromConfig()` now declares `PyStatus status`, `_PyRuntimeState *runtime`, `PyPreConfig preconfig`, and `_PyArgv config_args` at function top, assigns `status`/`runtime` at their original execution points, and replaces the `args == NULL` branch's designated `config_args` initializer with field-by-field assignments immediately before the existing call. Evaluation and call order are unchanged. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 1008 and 1016 `_PyArgv args = { .use_bytes_argv = ... }` designated initializers, plus the mixed declarations and designated `config_args` initializer inside `_Py_PreInitializeFromConfig()`. New exact first blocker is line 1104 (`error C2275: 'PyConfig' : illegal use of this type as an expression`) at the mixed declaration `PyConfig config;` in `pyinit_core()`, followed by nearby `pyinit_main()` declaration-order blockers and later C89/C99 fallout. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` builtins C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists the remaining VC6-rejected `PyObject *` declarations in `pycore_init_builtins()` (`bimod`, `builtins_dict`, `isinstance`, `len`, `list_append`, and `import_func`) to the function top, then assigns each at its original execution site. Evaluation order and existing error paths are unchanged; each local is still assigned before use. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past all mixed declarations in `pycore_init_builtins()`. New exact first blocker is line 912 (`error C2143: syntax error : missing ';' before 'const'`) at the mixed declaration `const PyConfig *config = _PyInterpreterState_GetConfig(interp);` in `pycore_interp_init()`, followed by the undeclared `config` fallout and later C89/C99 blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` create-interpreter C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists only the two next VC6-rejected declarations in `pycore_create_interpreter()`: `PyInterpreterState *interp` and `PyThreadState *tstate` are now declared at function top, while `_PyGILState_Init(runtime)`, `PyInterpreterState_New()`, and `PyThreadState_New(interp)` still execute at their original call sites and in the same order. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 682 `pycore_create_interpreter()` `PyInterpreterState *interp` mixed declaration and line 693 `PyThreadState *tstate` mixed declaration. New exact first blocker is line 812 (`error C2275: 'PyObject' : illegal use of this type as an expression`) at the mixed declaration `PyObject *builtins_dict = PyEval_GetBuiltins();` in `pycore_init_builtins()`, followed by the same function's line 819 `PyObject *isinstance = PyDict_GetItem(...)` and additional C89 mixed-declaration blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`pylifecycle.c` interpreter-config C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists only the interpreter-configuration `PyStatus` locals that VC6 rejected as mixed declarations: `interpreter_update_config()` now declares one `PyStatus status` at function top and assigns it at the two original call sites, and `_PyInterpreterState_SetConfig()` declares `PyConfig config` / `PyStatus status` before calling `PyConfig_InitPythonConfig()`. Assignment/evaluation order is unchanged and the former inner `status` shadowing is removed. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 528 `_PyInterpreterState_SetConfig()` mixed-declaration blocker and the nearby line 505 `interpreter_update_config()` `PyStatus` shadow declaration. New exact first blocker is line 580 (`error C2275: 'PyInterpreterState' : illegal use of this type as an expression`) at the mixed declaration `PyInterpreterState *interp = tstate->interp;` in `pyinit_core_reconfigure()`, followed by additional C89 mixed-declaration blockers including line 614 `PyStatus status = _PyConfig_Write(config, runtime);` in `pycore_init_runtime()`. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`_PyStatus_OK()` recursion fix and `_PyStatus_ERR()` VC6 helper slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Include/internal/pycore_initconfig.h` — replaces the VC6-only `_PyStatus_OK()` mapping to `PyStatus_Ok()` with a local static C89 helper that assigns all `PyStatus` fields explicitly, avoiding the `PyStatus_Ok() -> _PyStatus_OK() -> PyStatus_Ok()` recursion. Adds a VC6-only `_PyStatus_ERR()` helper that assigns `_type = _PyStatus_TYPE_ERROR`, `func = NULL` (matching public `PyStatus_Error()` semantics because VC6 has neither `__func__` nor `__FUNCTION__`), `err_msg`, and `exitcode = 0`. Non-VC6 compound-literal macros are unchanged. +- `scripts/fixtures/vc6_compound_literal_smoke.c` — now exercises both `_PyStatus_OK()` and `_PyStatus_ERR()` through the real internal header. +- `scripts/vc6-probe-core.test.sh` — adds a focused regression check that `_PyStatus_OK()` no longer maps to `PyStatus_Ok()`, and updates the compound-literal smoke-test description. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_compound_literal_smoke.c` | exit 0 — focused smoke fixture compiles while calling both `_PyStatus_OK()` and `_PyStatus_ERR()` directly under VC6. | +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 28/28 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 259 `_PyStatus_ERR("external importer setup failed")` compound-literal blocker. New exact first blocker is line 528 (`error C2275: 'PyStatus' : illegal use of this type as an expression`) at the mixed declaration `PyStatus status = _PyConfig_Copy(&config, src_config);` in `_PyInterpreterState_SetConfig()`, followed by additional C89 mixed-declaration blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`init_importlib()` C89 declaration-hoist slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Python/pylifecycle.c` — hoists only the existing `init_importlib()` local declarations (`interp`, `verbose`, `importlib`, `imp_mod`, `value`) to the top of the function, then preserves the prior assignment/evaluation order after the existing assertion and at each original use site. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` worktree exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 27/27 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 202 `init_importlib()` mixed-declaration blocker. New exact first blocker is line 259 (`error C2059: syntax error : '{'`) at `_PyStatus_ERR("external importer setup failed")` in `init_importlib_external()`, followed by further `PyStatus` compound-literal/designated-initializer and C89 mixed-declaration blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`_PyStatus_OK()` VC6 macro fallback slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Include/internal/pycore_initconfig.h` — keeps the existing C99 compound-literal `_PyStatus_OK()` macro for non-VC6 compilers, but maps `_PyStatus_OK()` to the existing public `PyStatus_Ok()` API only for `_MSC_VER < 1300` so VC6 no longer has to parse `(PyStatus){._type = ...}` at `_PyRuntime_Initialize()`. +- `scripts/fixtures/vc6_compound_literal_smoke.c` — now exercises `_PyStatus_OK()` itself, verifying the VC6-only macro fallback rather than bypassing it by calling `PyStatus_Ok()` directly. +- `scripts/vc6-probe-core.test.sh` — updates the focused compound-literal smoke-test description for the shared macro fallback. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: `git apply --check` against a pristine temporary `cpython/` copy exited 0. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_compound_literal_smoke.c` | exit 0 — focused smoke fixture now compiles while calling `_PyStatus_OK()` directly under VC6. | +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 27/27 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — gets past the prior line 143 `_PyStatus_OK()` compound-literal blocker. New exact first blocker is line 202 (`error C2143: syntax error : missing ';' before 'type'`), the existing C89 mixed-declaration wall in `init_importlib()`, followed by further declaration-order and remaining non-OK compound-literal/designated-initializer blockers. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + +## Files changed in previous revision (`_PyRuntimeState_INIT` VC6 replacement slice) + +All still uncommitted; nothing in this list has been pushed anywhere. + +- `cpython/Include/internal/pycore_runtime_init.h` — keeps the existing C99 designated initializer path for non-VC6 compilers, but exposes `_PyRuntimeState_InitStaticDefaults()` for VC6 instead of making VC6 parse `_PyRuntimeState_INIT`. +- `cpython/Python/pylifecycle.c` — leaves `_PyRuntime` zero-initialized only for VC6, then calls the shared explicit defaults routine once before `_PyRuntimeState_Init()`. Non-VC6 still uses `= _PyRuntimeState_INIT`. +- `cpython/Python/pystate.c` — adds the VC6 field-by-field default routine used by both the process-global runtime and later runtime/interpreter/thread resets. It explicitly preserves the required defaults: `gilstate.check_enabled = 1`, zeroed `Py_tss_NEEDS_INIT` storage, `interpreters.next_id = -1`, global small ints/bytes/strings/empty tuple, `_main_interpreter` (`_static`, `id_refcount`, recursion/gc thresholds), and `_initial_thread` (`_static`, recursion limit, `context_ver = 1`). Non-VC6 still uses the upstream `static const initial = _PyRuntimeState_INIT`/`memcpy` path. +- `compat/msvc600/cpython-3.11.16-vc6-headers.patch` — regenerated from `git -C cpython diff`; includes this slice plus earlier uncommitted compatibility edits. +- `PORT_STATUS.md` — this revision. + +**Command results (all reproduced in this revision):** + +| Command | Result | +|---|---| +| `bash scripts/vc6-probe.test.sh` | exit 0, `ALL TESTS PASSED` — 6/6 checks `ok` | +| `bash scripts/vc6-probe-core.test.sh` | exit 0, `ALL TESTS PASSED` — 27/27 checks `ok`; `Modules/main.c` still compiles cleanly | +| `bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c` | exit 2 — the `_PyRuntime` definition no longer fails at `_PyRuntimeState_INIT` line 112. New first error is line 143 (`_PyStatus_OK()` compound literal), followed by existing C89 declaration-order and C99 initializer blockers in the rest of the file. | +| `bash scripts/vc6-probe-core.sh cpython/Python/pystate.c` | exit 2 — the former `static const _PyRuntimeState initial = _PyRuntimeState_INIT` C2059 errors are gone and later `initial._main_interpreter` reset users are covered by the same VC6 defaults helpers. Current first errors are pre-existing C89 declaration-order issues in `pycore_frame.h` and then in `pystate.c`; no remaining `_PyRuntimeState_INIT` parse error is reported before the 100-error cap. | + +**Caveat:** this is still compile-probe work only. No link, no `pythoncore`/`python.exe` build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed. + ## Files changed in this revision (`pylifecycle.c` VC6 PyRuntime section slice) All still uncommitted; nothing in this list has been pushed anywhere. @@ -899,28 +1755,3 @@ 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/ - designated-initializer assignments with field-by-field assignment or, - where a public API function already exists (as `PyStatus_Ok()` did for - `_PyStatus_OK()`), a function call (compound-literal slice) — fixing - what the compiler surfaces in batches of roughly 100 (its per-run error - cap) and re-probing between batches, since the full error count for - this file is not yet known. -2. Re-evaluate the header-level-macro-vs-per-call-site tradeoff noted in - "Larger blockers to plan for" above once `_PyStatus_OK()`/ - `_PyCompilerFlags_INIT`-style macros have been rewritten by hand in two - files (`main.c` and `pylifecycle.c`): if the same macros keep recurring - across many more `.c` files beyond these two, a header-level VC6 branch - (mirroring `_Py_ATOMIC_VC6_X86` in "Atomics slice" above) becomes more - attractive than continuing per-call-site rewrites file by file. -3. Only after enough core translation units compile, and a minimal - `pythoncore`/`Programs/python.c` link is attempted, should work move to - the Win9x API surface one subsystem at a time. - -Validate incrementally with `scripts/vc6-probe-core.sh` against each file -being worked on, the same way this and prior slices did. - -## Scope boundary - -This project does not vendor the 223 MB MSVC600 bundle into a distributable -repository. It records the external tool as a local build prerequisite. No -Microsoft compiler binaries or runtime files should be committed or published. diff --git a/compat/msvc600/cpython-3.11.16-vc6-headers.patch b/compat/msvc600/cpython-3.11.16-vc6-headers.patch index 42b7501..0082edc 100644 --- a/compat/msvc600/cpython-3.11.16-vc6-headers.patch +++ b/compat/msvc600/cpython-3.11.16-vc6-headers.patch @@ -202,6 +202,109 @@ index dc308fe..16feaf3 100644 assert(size+2 < ((uint8_t *)values)[-1]); size++; size_ptr[-size] = (uint8_t)ix; +diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h +index 4866ea2..17ca4f8 100644 +--- a/Include/internal/pycore_frame.h ++++ b/Include/internal/pycore_frame.h +@@ -162,9 +162,10 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame); + static inline PyFrameObject * + _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) + { ++ PyFrameObject *res; + + assert(!_PyFrame_IsIncomplete(frame)); +- PyFrameObject *res = frame->frame_obj; ++ res = frame->frame_obj; + if (res != NULL) { + return res; + } +@@ -211,7 +212,9 @@ static inline _PyInterpreterFrame * + _PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size) + { + if (_PyThreadState_HasStackSpace(tstate, size)) { +- _PyInterpreterFrame *res = (_PyInterpreterFrame *)tstate->datastack_top; ++ _PyInterpreterFrame *res; ++ ++ res = (_PyInterpreterFrame *)tstate->datastack_top; + tstate->datastack_top += size; + return res; + } +@@ -229,8 +232,10 @@ int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame); + static inline + PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) + { ++ size_t offset_in_gen; ++ + assert(frame->owner == FRAME_OWNED_BY_GENERATOR); +- size_t offset_in_gen = offsetof(PyGenObject, gi_iframe); ++ offset_in_gen = offsetof(PyGenObject, gi_iframe); + return (PyGenObject *)(((char *)frame) - offset_in_gen); + } + +diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h +index d765600..dcdd359 100644 +--- a/Include/internal/pycore_initconfig.h ++++ b/Include/internal/pycore_initconfig.h +@@ -14,22 +14,56 @@ struct pyruntimestate; + /* --- PyStatus ----------------------------------------------- */ + + /* Almost all errors causing Python initialization to fail */ +-#ifdef _MSC_VER ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++ /* VC6 has neither C99 __func__ nor later MSVC __FUNCTION__. */ ++# define _PyStatus_GET_FUNC() NULL ++#elif defined(_MSC_VER) + /* Visual Studio 2015 doesn't implement C99 __func__ in C */ + # define _PyStatus_GET_FUNC() __FUNCTION__ + #else + # define _PyStatus_GET_FUNC() __func__ + #endif + +-#define _PyStatus_OK() \ ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++/* VC6 cannot parse the C99 compound literals/designated initializers below. ++ Keep the helpers local to this internal header and construct the status ++ objects field-by-field so PyStatus_Ok() can safely return _PyStatus_OK() ++ without recursing back into itself. */ ++static PyStatus ++_PyStatus_OK_VC6(void) ++{ ++ PyStatus status; ++ status._type = _PyStatus_TYPE_OK; ++ status.func = NULL; ++ status.err_msg = NULL; ++ status.exitcode = 0; ++ return status; ++} ++ ++static PyStatus ++_PyStatus_ERR_VC6(const char *err_msg) ++{ ++ PyStatus status; ++ status._type = _PyStatus_TYPE_ERROR; ++ status.func = _PyStatus_GET_FUNC(); ++ status.err_msg = err_msg; ++ status.exitcode = 0; ++ return status; ++} ++ ++# define _PyStatus_OK() _PyStatus_OK_VC6() ++# define _PyStatus_ERR(ERR_MSG) _PyStatus_ERR_VC6(ERR_MSG) ++#else ++# define _PyStatus_OK() \ + (PyStatus){._type = _PyStatus_TYPE_OK,} + /* other fields are set to 0 */ +-#define _PyStatus_ERR(ERR_MSG) \ ++# define _PyStatus_ERR(ERR_MSG) \ + (PyStatus){ \ + ._type = _PyStatus_TYPE_ERROR, \ + .func = _PyStatus_GET_FUNC(), \ + .err_msg = (ERR_MSG)} + /* other fields are set to 0 */ ++#endif + #define _PyStatus_NO_MEMORY() _PyStatus_ERR("memory allocation failed") + #define _PyStatus_EXIT(EXITCODE) \ + (PyStatus){ \ diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 860dce1..da38ee6 100644 --- a/Include/internal/pycore_list.h @@ -221,6 +324,22 @@ index 860dce1..da38ee6 100644 assert((size_t)len + 1 < PY_SSIZE_T_MAX); if (allocated > len) { PyList_SET_ITEM(self, len, newitem); +diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h +index 76361b8..2b9861b 100644 +--- a/Include/internal/pycore_moduleobject.h ++++ b/Include/internal/pycore_moduleobject.h +@@ -29,8 +29,10 @@ static inline void* _PyModule_GetState(PyObject* mod) { + } + + static inline PyObject* _PyModule_GetDict(PyObject *mod) { ++ PyObject *dict; ++ + assert(PyModule_Check(mod)); +- PyObject *dict = ((PyModuleObject *)mod) -> md_dict; ++ dict = ((PyModuleObject *)mod) -> md_dict; + // _PyModule_GetDict(mod) must not be used after calling module_clear(mod) + assert(dict != NULL); + return dict; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index f022f82..d1c55ae 100644 --- a/Include/internal/pycore_object.h @@ -290,6 +409,31 @@ index f022f82..d1c55ae 100644 _PyGCHead_SET_NEXT(prev, next); _PyGCHead_SET_PREV(next, prev); gc->_gc_next = 0; +diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h +index 13eae1e..91faff4 100644 +--- a/Include/internal/pycore_runtime_init.h ++++ b/Include/internal/pycore_runtime_init.h +@@ -14,6 +14,11 @@ extern "C" { + /* The static initializers defined here should only be used + in the runtime init code (in pystate.c and pylifecycle.c). */ + ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++/* VC6 does not support the nested C99 designated initializers below. ++ pystate.c provides a field-by-field initializer for the same defaults. */ ++extern void _PyRuntimeState_InitStaticDefaults(_PyRuntimeState *runtime); ++#else + + #define _PyRuntimeState_INIT \ + { \ +@@ -72,6 +77,8 @@ extern "C" { + .context_ver = 1, \ + } + ++#endif /* !(defined(_MSC_VER) && _MSC_VER < 1300) */ ++ + + // global objects + diff --git a/Include/longobject.h b/Include/longobject.h index 778cb62..d25edf7 100644 --- a/Include/longobject.h @@ -414,6 +558,1087 @@ index a483290..defdaf1 100644 #endif +diff --git a/Modules/_abc.c b/Modules/_abc.c +index b22daa8..69cfd5c 100644 +--- a/Modules/_abc.c ++++ b/Modules/_abc.c +@@ -19,7 +19,7 @@ PyDoc_STRVAR(_abc__doc__, + + typedef struct { + PyTypeObject *_abc_data_type; +- unsigned long long abc_invalidation_counter; ++ unsigned PY_LONG_LONG abc_invalidation_counter; + } _abcmodule_state; + + static inline _abcmodule_state* +@@ -38,7 +38,7 @@ typedef struct { + PyObject *_abc_registry; + PyObject *_abc_cache; /* Normal set of weak references. */ + PyObject *_abc_negative_cache; /* Normal set of weak references. */ +- unsigned long long _abc_negative_cache_version; ++ unsigned PY_LONG_LONG _abc_negative_cache_version; + } _abc_data; + + static int +@@ -63,8 +63,9 @@ abc_data_clear(_abc_data *self) + static void + abc_data_dealloc(_abc_data *self) + { ++ PyTypeObject *tp; + PyObject_GC_UnTrack(self); +- PyTypeObject *tp = Py_TYPE(self); ++ tp = Py_TYPE(self); + (void)abc_data_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +@@ -105,10 +106,11 @@ static PyType_Slot _abc_data_type_spec_slots[] = { + }; + + static PyType_Spec _abc_data_type_spec = { +- .name = "_abc._abc_data", +- .basicsize = sizeof(_abc_data), +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .slots = _abc_data_type_spec_slots, ++ "_abc._abc_data", ++ sizeof(_abc_data), ++ 0, ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, ++ _abc_data_type_spec_slots, + }; + + static _abc_data * +@@ -130,10 +132,12 @@ _get_impl(PyObject *module, PyObject *self) + static int + _in_weak_set(PyObject *set, PyObject *obj) + { ++ PyObject *ref; ++ int res; + if (set == NULL || PySet_GET_SIZE(set) == 0) { + return 0; + } +- PyObject *ref = PyWeakref_NewRef(obj, NULL); ++ ref = PyWeakref_NewRef(obj, NULL); + if (ref == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); +@@ -141,7 +145,7 @@ _in_weak_set(PyObject *set, PyObject *obj) + } + return -1; + } +- int res = PySet_Contains(set, ref); ++ res = PySet_Contains(set, ref); + Py_DECREF(ref); + return res; + } +@@ -170,6 +174,10 @@ static PyMethodDef _destroy_def = { + static int + _add_to_weak_set(PyObject **pset, PyObject *obj) + { ++ PyObject *set; ++ PyObject *ref, *wr; ++ PyObject *destroy_cb; ++ int ret; + if (*pset == NULL) { + *pset = PySet_New(NULL); + if (*pset == NULL) { +@@ -177,9 +185,7 @@ _add_to_weak_set(PyObject **pset, PyObject *obj) + } + } + +- PyObject *set = *pset; +- PyObject *ref, *wr; +- PyObject *destroy_cb; ++ set = *pset; + wr = PyWeakref_NewRef(set, NULL); + if (wr == NULL) { + return -1; +@@ -195,7 +201,7 @@ _add_to_weak_set(PyObject **pset, PyObject *obj) + Py_DECREF(wr); + return -1; + } +- int ret = PySet_Add(set, ref); ++ ret = PySet_Add(set, ref); + Py_DECREF(wr); + Py_DECREF(ref); + return ret; +@@ -279,14 +285,15 @@ _abc__get_dump(PyObject *module, PyObject *self) + /*[clinic end generated code: output=9d9569a8e2c1c443 input=2c5deb1bfe9e3c79]*/ + { + _abc_data *impl = _get_impl(module, self); ++ PyObject *res; + if (impl == NULL) { + return NULL; + } +- PyObject *res = Py_BuildValue("NNNK", +- PySet_New(impl->_abc_registry), +- PySet_New(impl->_abc_cache), +- PySet_New(impl->_abc_negative_cache), +- impl->_abc_negative_cache_version); ++ res = Py_BuildValue("NNNK", ++ PySet_New(impl->_abc_registry), ++ PySet_New(impl->_abc_cache), ++ PySet_New(impl->_abc_negative_cache), ++ impl->_abc_negative_cache_version); + Py_DECREF(impl); + return res; + } +@@ -297,12 +304,12 @@ compute_abstract_methods(PyObject *self) + { + int ret = -1; + PyObject *abstracts = PyFrozenSet_New(NULL); ++ PyObject *ns = NULL, *items = NULL, *bases = NULL; // Py_XDECREF()ed on error. ++ Py_ssize_t pos; + if (abstracts == NULL) { + return -1; + } + +- PyObject *ns = NULL, *items = NULL, *bases = NULL; // Py_XDECREF()ed on error. +- + /* Stage 1: direct abstract methods. */ + ns = PyObject_GetAttr(self, &_Py_ID(__dict__)); + if (!ns) { +@@ -316,8 +323,11 @@ compute_abstract_methods(PyObject *self) + goto error; + } + assert(PyList_Check(items)); +- for (Py_ssize_t pos = 0; pos < PyList_GET_SIZE(items); pos++) { +- PyObject *it = PySequence_Fast( ++ for (pos = 0; pos < PyList_GET_SIZE(items); pos++) { ++ PyObject *it; ++ PyObject *key, *value; ++ int is_abstract; ++ it = PySequence_Fast( + PyList_GET_ITEM(items, pos), + "items() returned non-iterable"); + if (!it) { +@@ -331,12 +341,12 @@ compute_abstract_methods(PyObject *self) + } + + // borrowed +- PyObject *key = PySequence_Fast_GET_ITEM(it, 0); +- PyObject *value = PySequence_Fast_GET_ITEM(it, 1); ++ key = PySequence_Fast_GET_ITEM(it, 0); ++ value = PySequence_Fast_GET_ITEM(it, 1); + // items or it may be cleared while accessing __abstractmethod__ + // So we need to keep strong reference for key + Py_INCREF(key); +- int is_abstract = _PyObject_IsAbstract(value); ++ is_abstract = _PyObject_IsAbstract(value); + if (is_abstract < 0 || + (is_abstract && PySet_Add(abstracts, key) < 0)) { + Py_DECREF(it); +@@ -357,10 +367,12 @@ compute_abstract_methods(PyObject *self) + goto error; + } + +- for (Py_ssize_t pos = 0; pos < PyTuple_GET_SIZE(bases); pos++) { +- PyObject *item = PyTuple_GET_ITEM(bases, pos); // borrowed ++ for (pos = 0; pos < PyTuple_GET_SIZE(bases); pos++) { ++ PyObject *item; + PyObject *base_abstracts, *iter; ++ PyObject *key, *value; + ++ item = PyTuple_GET_ITEM(bases, pos); // borrowed + if (_PyObject_LookupAttr(item, &_Py_ID(__abstractmethods__), + &base_abstracts) < 0) { + goto error; +@@ -373,8 +385,8 @@ compute_abstract_methods(PyObject *self) + goto error; + } + Py_DECREF(base_abstracts); +- PyObject *key, *value; + while ((key = PyIter_Next(iter))) { ++ int is_abstract; + if (_PyObject_LookupAttr(self, key, &value) < 0) { + Py_DECREF(key); + Py_DECREF(iter); +@@ -385,7 +397,7 @@ compute_abstract_methods(PyObject *self) + continue; + } + +- int is_abstract = _PyObject_IsAbstract(value); ++ is_abstract = _PyObject_IsAbstract(value); + Py_DECREF(value); + if (is_abstract < 0 || + (is_abstract && PySet_Add(abstracts, key) < 0)) +@@ -482,6 +494,8 @@ _abc__abc_init(PyObject *module, PyObject *self) + static void + set_collection_flag_recursive(PyTypeObject *child, unsigned long flag) + { ++ PyObject *grandchildren; ++ Py_ssize_t i; + assert(flag == Py_TPFLAGS_MAPPING || flag == Py_TPFLAGS_SEQUENCE); + if (PyType_HasFeature(child, Py_TPFLAGS_IMMUTABLETYPE) || + (child->tp_flags & COLLECTION_FLAGS) == flag) +@@ -492,12 +506,12 @@ set_collection_flag_recursive(PyTypeObject *child, unsigned long flag) + child->tp_flags &= ~COLLECTION_FLAGS; + child->tp_flags |= flag; + +- PyObject *grandchildren = _PyType_GetSubclasses(child); ++ grandchildren = _PyType_GetSubclasses(child); + if (grandchildren == NULL) { + return; + } + +- for (Py_ssize_t i = 0; i < PyList_GET_SIZE(grandchildren); i++) { ++ for (i = 0; i < PyList_GET_SIZE(grandchildren); i++) { + PyObject *grandchild = PyList_GET_ITEM(grandchildren, i); + set_collection_flag_recursive((PyTypeObject *)grandchild, flag); + } +@@ -518,11 +532,13 @@ static PyObject * + _abc__abc_register_impl(PyObject *module, PyObject *self, PyObject *subclass) + /*[clinic end generated code: output=7851e7668c963524 input=ca589f8c3080e67f]*/ + { ++ int result; ++ _abc_data *impl; + if (!PyType_Check(subclass)) { + PyErr_SetString(PyExc_TypeError, "Can only register classes"); + return NULL; + } +- int result = PyObject_IsSubclass(subclass, self); ++ result = PyObject_IsSubclass(subclass, self); + if (result > 0) { + Py_INCREF(subclass); + return subclass; /* Already a subclass. */ +@@ -541,7 +557,7 @@ _abc__abc_register_impl(PyObject *module, PyObject *self, PyObject *subclass) + if (result < 0) { + return NULL; + } +- _abc_data *impl = _get_impl(module, self); ++ impl = _get_impl(module, self); + if (impl == NULL) { + return NULL; + } +@@ -583,6 +599,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self, + { + PyObject *subtype, *result = NULL, *subclass = NULL; + _abc_data *impl = _get_impl(module, self); ++ int incache; + if (impl == NULL) { + return NULL; + } +@@ -593,7 +610,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self, + return NULL; + } + /* Inline the cache checking. */ +- int incache = _in_weak_set(impl->_abc_cache, subclass); ++ incache = _in_weak_set(impl->_abc_cache, subclass); + if (incache < 0) { + goto end; + } +@@ -670,16 +687,18 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, + PyObject *subclass) + /*[clinic end generated code: output=b56c9e4a530e3894 input=1d947243409d10b8]*/ + { ++ PyObject *ok, *subclasses = NULL, *result = NULL; ++ _abcmodule_state *state = NULL; ++ Py_ssize_t pos; ++ int incache; ++ _abc_data *impl; ++ PyObject *mro; + if (!PyType_Check(subclass)) { + PyErr_SetString(PyExc_TypeError, "issubclass() arg 1 must be a class"); + return NULL; + } + +- PyObject *ok, *subclasses = NULL, *result = NULL; +- _abcmodule_state *state = NULL; +- Py_ssize_t pos; +- int incache; +- _abc_data *impl = _get_impl(module, self); ++ impl = _get_impl(module, self); + if (impl == NULL) { + return NULL; + } +@@ -747,7 +766,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, + Py_DECREF(ok); + + /* 4. Check if it's a direct subclass. */ +- PyObject *mro = ((PyTypeObject *)subclass)->tp_mro; ++ mro = ((PyTypeObject *)subclass)->tp_mro; + assert(PyTuple_Check(mro)); + for (pos = 0; pos < PyTuple_GET_SIZE(mro); pos++) { + PyObject *mro_item = PyTuple_GET_ITEM(mro, pos); +@@ -777,9 +796,11 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, + goto end; + } + for (pos = 0; pos < PyList_GET_SIZE(subclasses); pos++) { +- PyObject *scls = PyList_GET_ITEM(subclasses, pos); ++ PyObject *scls; ++ int r; ++ scls = PyList_GET_ITEM(subclasses, pos); + Py_INCREF(scls); +- int r = PyObject_IsSubclass(subclass, scls); ++ r = PyObject_IsSubclass(subclass, scls); + Py_DECREF(scls); + if (r > 0) { + if (_add_to_weak_set(&impl->_abc_cache, subclass) < 0) { +@@ -811,8 +832,16 @@ static int + subclasscheck_check_registry(_abc_data *impl, PyObject *subclass, + PyObject **result) + { ++ int ret; ++ Py_ssize_t registry_size; ++ PyObject **copy; ++ PyObject *key; ++ Py_ssize_t pos = 0; ++ Py_hash_t hash; ++ Py_ssize_t i = 0; ++ + // Fast path: check subclass is in weakref directly. +- int ret = _in_weak_set(impl->_abc_registry, subclass); ++ ret = _in_weak_set(impl->_abc_registry, subclass); + if (ret < 0) { + *result = NULL; + return -1; +@@ -825,21 +854,17 @@ subclasscheck_check_registry(_abc_data *impl, PyObject *subclass, + if (impl->_abc_registry == NULL) { + return 0; + } +- Py_ssize_t registry_size = PySet_Size(impl->_abc_registry); ++ registry_size = PySet_Size(impl->_abc_registry); + if (registry_size == 0) { + return 0; + } + // Weakref callback may remove entry from set. + // So we take snapshot of registry first. +- PyObject **copy = PyMem_Malloc(sizeof(PyObject*) * registry_size); ++ copy = PyMem_Malloc(sizeof(PyObject*) * registry_size); + if (copy == NULL) { + PyErr_NoMemory(); + return -1; + } +- PyObject *key; +- Py_ssize_t pos = 0; +- Py_hash_t hash; +- Py_ssize_t i = 0; + + while (_PySet_NextEntry(impl->_abc_registry, &pos, &key, &hash)) { + Py_INCREF(key); +@@ -848,7 +873,9 @@ subclasscheck_check_registry(_abc_data *impl, PyObject *subclass, + assert(i == registry_size); + + for (i = 0; i < registry_size; i++) { +- PyObject *rkey = PyWeakref_GetObject(copy[i]); ++ PyObject *rkey; ++ int r; ++ rkey = PyWeakref_GetObject(copy[i]); + if (rkey == NULL) { + // Someone inject non-weakref type in the registry. + ret = -1; +@@ -858,7 +885,7 @@ subclasscheck_check_registry(_abc_data *impl, PyObject *subclass, + continue; + } + Py_INCREF(rkey); +- int r = PyObject_IsSubclass(subclass, rkey); ++ r = PyObject_IsSubclass(subclass, rkey); + Py_DECREF(rkey); + if (r < 0) { + ret = -1; +@@ -954,14 +981,14 @@ static PyModuleDef_Slot _abcmodule_slots[] = { + + static struct PyModuleDef _abcmodule = { + PyModuleDef_HEAD_INIT, +- .m_name = "_abc", +- .m_doc = _abc__doc__, +- .m_size = sizeof(_abcmodule_state), +- .m_methods = _abcmodule_methods, +- .m_slots = _abcmodule_slots, +- .m_traverse = _abcmodule_traverse, +- .m_clear = _abcmodule_clear, +- .m_free = _abcmodule_free, ++ "_abc", ++ _abc__doc__, ++ sizeof(_abcmodule_state), ++ _abcmodule_methods, ++ _abcmodule_slots, ++ _abcmodule_traverse, ++ _abcmodule_clear, ++ _abcmodule_free, + }; + + PyMODINIT_FUNC +diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c +index 0caa92b..1bfd7d3 100644 +--- a/Modules/_bisectmodule.c ++++ b/Modules/_bisectmodule.c +@@ -326,13 +326,14 @@ static PyModuleDef_Slot bisect_slots[] = { + + static struct PyModuleDef _bisectmodule = { + PyModuleDef_HEAD_INIT, +- .m_name = "_bisect", +- .m_size = sizeof(bisect_state), +- .m_doc = module_doc, +- .m_methods = bisect_methods, +- .m_slots = bisect_slots, +- .m_clear = bisect_clear, +- .m_free = bisect_free, ++ "_bisect", ++ module_doc, ++ sizeof(bisect_state), ++ bisect_methods, ++ bisect_slots, ++ NULL, ++ bisect_clear, ++ bisect_free, + }; + + PyMODINIT_FUNC +diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c +index c2cac98..c9c5d88 100644 +--- a/Modules/_blake2/blake2b_impl.c ++++ b/Modules/_blake2/blake2b_impl.c +@@ -91,7 +91,7 @@ static PyObject * + py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, +- unsigned long long node_offset, int node_depth, ++ unsigned PY_LONG_LONG node_offset, int node_depth, + int inner_size, int last_node, int usedforsecurity) + /*[clinic end generated code: output=32bfd8f043c6896f input=b947312abff46977]*/ + { +@@ -385,6 +385,7 @@ static void + py_blake2b_dealloc(PyObject *self) + { + BLAKE2bObject *obj = (BLAKE2bObject *)self; ++ PyTypeObject *type; + + /* Try not to leave state in memory. */ + secure_zero_memory(&obj->param, sizeof(obj->param)); +@@ -394,7 +395,7 @@ py_blake2b_dealloc(PyObject *self) + obj->lock = NULL; + } + +- PyTypeObject *type = Py_TYPE(self); ++ type = Py_TYPE(self); + PyObject_Free(self); + Py_DECREF(type); + } +@@ -409,8 +410,9 @@ static PyType_Slot blake2b_type_slots[] = { + }; + + PyType_Spec blake2b_type_spec = { +- .name = "_blake2.blake2b", +- .basicsize = sizeof(BLAKE2bObject), +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, +- .slots = blake2b_type_slots ++ "_blake2.blake2b", ++ sizeof(BLAKE2bObject), ++ 0, ++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, ++ blake2b_type_slots + }; +diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c +index 93478f5..afd2e33 100644 +--- a/Modules/_blake2/blake2module.c ++++ b/Modules/_blake2/blake2module.c +@@ -84,6 +84,7 @@ static int + blake2_exec(PyObject *m) + { + Blake2State* st = blake2_get_state(m); ++ PyObject *d; + + st->blake2b_type = (PyTypeObject *)PyType_FromModuleAndSpec( + m, &blake2b_type_spec, NULL); +@@ -95,7 +96,7 @@ blake2_exec(PyObject *m) + return -1; + } + +- PyObject *d = st->blake2b_type->tp_dict; ++ d = st->blake2b_type->tp_dict; + ADD_INT(d, "SALT_SIZE", BLAKE2B_SALTBYTES); + ADD_INT(d, "PERSON_SIZE", BLAKE2B_PERSONALBYTES); + ADD_INT(d, "MAX_KEY_SIZE", BLAKE2B_KEYBYTES); +@@ -142,13 +143,13 @@ static PyModuleDef_Slot _blake2_slots[] = { + static struct PyModuleDef blake2_module = { + PyModuleDef_HEAD_INIT, + "_blake2", +- .m_doc = blake2mod__doc__, +- .m_size = sizeof(Blake2State), +- .m_methods = blake2mod_functions, +- .m_slots = _blake2_slots, +- .m_traverse = _blake2_traverse, +- .m_clear = _blake2_clear, +- .m_free = _blake2_free, ++ blake2mod__doc__, ++ sizeof(Blake2State), ++ blake2mod_functions, ++ _blake2_slots, ++ _blake2_traverse, ++ _blake2_clear, ++ _blake2_free, + }; + + PyMODINIT_FUNC +diff --git a/Modules/_blake2/clinic/blake2b_impl.c.h b/Modules/_blake2/clinic/blake2b_impl.c.h +index 4e74e08..4b079b3 100644 +--- a/Modules/_blake2/clinic/blake2b_impl.c.h ++++ b/Modules/_blake2/clinic/blake2b_impl.c.h +@@ -15,7 +15,7 @@ static PyObject * + py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, +- unsigned long long node_offset, int node_depth, ++ unsigned PY_LONG_LONG node_offset, int node_depth, + int inner_size, int last_node, int usedforsecurity); + + static PyObject * +@@ -36,7 +36,7 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + int fanout = 1; + int depth = 1; + unsigned long leaf_size = 0; +- unsigned long long node_offset = 0; ++ unsigned PY_LONG_LONG node_offset = 0; + int node_depth = 0; + int inner_size = 0; + int last_node = 0; +diff --git a/Modules/_blake2/impl/blake2b-ref.c b/Modules/_blake2/impl/blake2b-ref.c +index e58c436..b386ac5 100644 +--- a/Modules/_blake2/impl/blake2b-ref.c ++++ b/Modules/_blake2/impl/blake2b-ref.c +@@ -20,10 +20,10 @@ + + static const uint64_t blake2b_IV[8] = + { +- 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, +- 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, +- 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, +- 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL ++ PY_ULL(0x6a09e667f3bcc908), PY_ULL(0xbb67ae8584caa73b), ++ PY_ULL(0x3c6ef372fe94f82b), PY_ULL(0xa54ff53a5f1d36f1), ++ PY_ULL(0x510e527fade682d1), PY_ULL(0x9b05688c2b3e6c1f), ++ PY_ULL(0x1f83d9abfb41bd6b), PY_ULL(0x5be0cd19137e2179) + }; + + static const uint8_t blake2b_sigma[12][16] = +@@ -45,13 +45,13 @@ static const uint8_t blake2b_sigma[12][16] = + + static inline int blake2b_set_lastnode( blake2b_state *S ) + { +- S->f[1] = ~0ULL; ++ S->f[1] = ~PY_ULL(0); + return 0; + } + + static inline int blake2b_clear_lastnode( blake2b_state *S ) + { +- S->f[1] = 0ULL; ++ S->f[1] = PY_ULL(0); + return 0; + } + +@@ -60,7 +60,7 @@ static inline int blake2b_set_lastblock( blake2b_state *S ) + { + if( S->last_node ) blake2b_set_lastnode( S ); + +- S->f[0] = ~0ULL; ++ S->f[0] = ~PY_ULL(0); + return 0; + } + +@@ -68,7 +68,7 @@ static inline int blake2b_clear_lastblock( blake2b_state *S ) + { + if( S->last_node ) blake2b_clear_lastnode( S ); + +- S->f[0] = 0ULL; ++ S->f[0] = PY_ULL(0); + return 0; + } + +@@ -138,9 +138,11 @@ static inline int blake2b_param_set_personal( blake2b_param *P, const uint8_t pe + + static inline int blake2b_init0( blake2b_state *S ) + { ++ int i; ++ + memset( S, 0, sizeof( blake2b_state ) ); + +- for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; ++ for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; + + return 0; + } +@@ -161,11 +163,14 @@ extern "C" { + /* init xors IV with input parameter block */ + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) + { ++ uint8_t *p; ++ size_t i; ++ + blake2b_init0( S ); +- uint8_t *p = ( uint8_t * )( P ); ++ p = ( uint8_t * )( P ); + + /* IV XOR ParamBlock */ +- for( size_t i = 0; i < 8; ++i ) ++ for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; +diff --git a/Modules/getpath.c b/Modules/getpath.c +index 61d6540..e7489ee 100644 +--- a/Modules/getpath.c ++++ b/Modules/getpath.c +@@ -12,6 +12,9 @@ + #ifdef MS_WINDOWS + # include // GetFullPathNameW(), MAX_PATH + # include ++# if defined(_MSC_VER) && _MSC_VER < 1300 && !defined(INVALID_FILE_ATTRIBUTES) ++# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) ++# endif + #endif + + #ifdef __APPLE__ +@@ -60,10 +63,10 @@ getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *r = NULL; + PyObject *pathobj; + wchar_t *path; ++ Py_ssize_t len; + if (!PyArg_ParseTuple(args, "U", &pathobj)) { + return NULL; + } +- Py_ssize_t len; + path = PyUnicode_AsWideCharString(pathobj, &len); + if (path) { + wchar_t *abs; +@@ -83,11 +86,13 @@ static PyObject * + getpath_basename(PyObject *Py_UNUSED(self), PyObject *args) + { + PyObject *path; ++ Py_ssize_t end; ++ Py_ssize_t pos; + if (!PyArg_ParseTuple(args, "U", &path)) { + return NULL; + } +- Py_ssize_t end = PyUnicode_GET_LENGTH(path); +- Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1); ++ end = PyUnicode_GET_LENGTH(path); ++ pos = PyUnicode_FindChar(path, SEP, 0, end, -1); + if (pos < 0) { + return Py_NewRef(path); + } +@@ -99,11 +104,13 @@ static PyObject * + getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) + { + PyObject *path; ++ Py_ssize_t end; ++ Py_ssize_t pos; + if (!PyArg_ParseTuple(args, "U", &path)) { + return NULL; + } +- Py_ssize_t end = PyUnicode_GET_LENGTH(path); +- Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1); ++ end = PyUnicode_GET_LENGTH(path); ++ pos = PyUnicode_FindChar(path, SEP, 0, end, -1); + if (pos < 0) { + return PyUnicode_FromStringAndSize(NULL, 0); + } +@@ -138,10 +145,10 @@ getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *suffixobj; + const wchar_t *path; + const wchar_t *suffix; ++ Py_ssize_t len, suffixLen; + if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) { + return NULL; + } +- Py_ssize_t len, suffixLen; + path = PyUnicode_AsWideCharString(pathobj, &len); + if (path) { + suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen); +@@ -172,17 +179,21 @@ getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *r = NULL; + PyObject *pathobj; + const wchar_t *path; ++#ifdef MS_WINDOWS ++ DWORD attr; ++#else ++ struct stat st; ++#endif + if (!PyArg_ParseTuple(args, "U", &pathobj)) { + return NULL; + } + path = PyUnicode_AsWideCharString(pathobj, NULL); + if (path) { + #ifdef MS_WINDOWS +- DWORD attr = GetFileAttributesW(path); ++ attr = GetFileAttributesW(path); + r = (attr != INVALID_FILE_ATTRIBUTES) && + (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False; + #else +- struct stat st; + r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False; + #endif + PyMem_Free((void *)path); +@@ -198,17 +209,21 @@ getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *r = NULL; + PyObject *pathobj; + const wchar_t *path; ++#ifdef MS_WINDOWS ++ DWORD attr; ++#else ++ struct stat st; ++#endif + if (!PyArg_ParseTuple(args, "U", &pathobj)) { + return NULL; + } + path = PyUnicode_AsWideCharString(pathobj, NULL); + if (path) { + #ifdef MS_WINDOWS +- DWORD attr = GetFileAttributesW(path); ++ attr = GetFileAttributesW(path); + r = (attr != INVALID_FILE_ATTRIBUTES) && + !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False; + #else +- struct stat st; + r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False; + #endif + PyMem_Free((void *)path); +@@ -225,21 +240,25 @@ getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *pathobj; + const wchar_t *path; + Py_ssize_t cchPath; ++#ifdef MS_WINDOWS ++ const wchar_t *ext; ++ DWORD attr; ++#else ++ struct stat st; ++#endif + if (!PyArg_ParseTuple(args, "U", &pathobj)) { + return NULL; + } + path = PyUnicode_AsWideCharString(pathobj, &cchPath); + if (path) { + #ifdef MS_WINDOWS +- const wchar_t *ext; +- DWORD attr = GetFileAttributesW(path); ++ attr = GetFileAttributesW(path); + r = (attr != INVALID_FILE_ATTRIBUTES) && + !(attr & FILE_ATTRIBUTE_DIRECTORY) && + SUCCEEDED(PathCchFindExtension(path, cchPath + 1, &ext)) && + (CompareStringOrdinal(ext, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL) + ? Py_True : Py_False; + #else +- struct stat st; + r = (_Py_wstat(path, &st) == 0) && + S_ISREG(st.st_mode) && + (st.st_mode & 0111) +@@ -255,27 +274,35 @@ getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args) + static PyObject * + getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) + { ++ Py_ssize_t n; ++ wchar_t **parts; ++ Py_ssize_t cchFinal; ++ Py_ssize_t first; ++ Py_ssize_t i; ++ PyObject *s; ++ Py_ssize_t cch; ++ wchar_t *final; ++ PyObject *r; + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, "requires tuple of arguments"); + return NULL; + } +- Py_ssize_t n = PyTuple_GET_SIZE(args); ++ n = PyTuple_GET_SIZE(args); + if (n == 0) { + return PyUnicode_FromStringAndSize(NULL, 0); + } + /* Convert all parts to wchar and accumulate max final length */ +- wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *)); ++ parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *)); + if (parts == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(parts, 0, n * sizeof(wchar_t *)); +- Py_ssize_t cchFinal = 0; +- Py_ssize_t first = 0; ++ cchFinal = 0; ++ first = 0; + +- for (Py_ssize_t i = 0; i < n; ++i) { +- PyObject *s = PyTuple_GET_ITEM(args, i); +- Py_ssize_t cch; ++ for (i = 0; i < n; ++i) { ++ s = PyTuple_GET_ITEM(args, i); + if (s == Py_None) { + cch = 0; + } else if (PyUnicode_Check(s)) { +@@ -295,9 +322,9 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) + cchFinal += cch + 1; + } + +- wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL; ++ final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL; + if (!final) { +- for (Py_ssize_t i = 0; i < n; ++i) { ++ for (i = 0; i < n; ++i) { + PyMem_Free(parts[i]); + } + PyMem_Free(parts); +@@ -310,7 +337,7 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) + + final[0] = '\0'; + /* Now join all the paths. The final result should be shorter than the buffer */ +- for (Py_ssize_t i = 0; i < n; ++i) { ++ for (i = 0; i < n; ++i) { + if (!parts[i]) { + continue; + } +@@ -331,7 +358,7 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) + PyErr_SetString(PyExc_SystemError, "failed to join paths"); + return NULL; + } +- PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1); ++ r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1); + PyMem_Free(final); + return r; + } +@@ -343,6 +370,16 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + PyObject *r = NULL; + PyObject *pathobj; + const wchar_t *path; ++ FILE *fp; ++ const size_t MAX_FILE = 32 * 1024; ++ char *buffer; ++ size_t cb; ++ size_t len; ++ wchar_t *wbuffer; ++ wchar_t *p1; ++ wchar_t *p2; ++ Py_ssize_t line_len; ++ PyObject *u; + if (!PyArg_ParseTuple(args, "U", &pathobj)) { + return NULL; + } +@@ -350,7 +387,7 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + if (!path) { + return NULL; + } +- FILE *fp = _Py_wfopen(path, L"rb"); ++ fp = _Py_wfopen(path, L"rb"); + if (!fp) { + PyErr_SetFromErrno(PyExc_OSError); + PyMem_Free((void *)path); +@@ -363,15 +400,14 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + fclose(fp); + return NULL; + } +- const size_t MAX_FILE = 32 * 1024; +- char *buffer = (char *)PyMem_Malloc(MAX_FILE); ++ buffer = (char *)PyMem_Malloc(MAX_FILE); + if (!buffer) { + Py_DECREF(r); + fclose(fp); + return NULL; + } + +- size_t cb = fread(buffer, 1, MAX_FILE, fp); ++ cb = fread(buffer, 1, MAX_FILE, fp); + fclose(fp); + if (!cb) { + return r; +@@ -384,8 +420,7 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + } + buffer[cb] = '\0'; + +- size_t len; +- wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len); ++ wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len); + PyMem_Free((void *)buffer); + if (!wbuffer) { + Py_DECREF(r); +@@ -393,14 +428,14 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + return NULL; + } + +- wchar_t *p1 = wbuffer; +- wchar_t *p2 = p1; ++ p1 = wbuffer; ++ p2 = p1; + while ((p2 = wcschr(p1, L'\n')) != NULL) { +- Py_ssize_t cb = p2 - p1; +- while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) { +- --cb; ++ line_len = p2 - p1; ++ while (line_len >= 0 && (p1[line_len] == L'\n' || p1[line_len] == L'\r')) { ++ --line_len; + } +- PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0); ++ u = PyUnicode_FromWideChar(p1, line_len >= 0 ? line_len + 1 : 0); + if (!u || PyList_Append(r, u) < 0) { + Py_XDECREF(u); + Py_CLEAR(r); +@@ -410,7 +445,7 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) + p1 = p2 + 1; + } + if (r && p1 && *p1) { +- PyObject *u = PyUnicode_FromWideChar(p1, -1); ++ u = PyUnicode_FromWideChar(p1, -1); + if (!u || PyList_Append(r, u) < 0) { + Py_CLEAR(r); + } +@@ -562,8 +597,11 @@ static PyMethodDef getpath_nowarn_method = {"warn", getpath_nowarn, METH_VARARGS + static int + funcs_to_dict(PyObject *dict, int warnings) + { +- for (PyMethodDef *m = getpath_methods; m->ml_name; ++m) { +- PyObject *f = PyCFunction_NewEx(m, NULL, NULL); ++ PyMethodDef *m; ++ PyMethodDef *m2; ++ PyObject *f; ++ for (m = getpath_methods; m->ml_name; ++m) { ++ f = PyCFunction_NewEx(m, NULL, NULL); + if (!f) { + return 0; + } +@@ -573,8 +611,8 @@ funcs_to_dict(PyObject *dict, int warnings) + } + Py_DECREF(f); + } +- PyMethodDef *m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method; +- PyObject *f = PyCFunction_NewEx(m2, NULL, NULL); ++ m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method; ++ f = PyCFunction_NewEx(m2, NULL, NULL); + if (!f) { + return 0; + } +@@ -614,9 +652,10 @@ decode_to_dict(PyObject *dict, const char *key, const char *s) + { + PyObject *u = NULL; + int r; ++ size_t len; ++ const wchar_t *w; + if (s && s[0]) { +- size_t len; +- const wchar_t *w = Py_DecodeLocale(s, &len); ++ w = Py_DecodeLocale(s, &len); + if (w) { + u = PyUnicode_FromWideChar(w, len); + PyMem_RawFree((void *)w); +@@ -639,18 +678,27 @@ env_to_dict(PyObject *dict, const char *key, int and_clear) + { + PyObject *u = NULL; + int r = 0; ++#ifdef MS_WINDOWS ++ wchar_t wkey[64]; ++ wchar_t *wp; ++ const char *p; ++ const wchar_t *v; ++#else ++ const char *v; ++ size_t len; ++ const wchar_t *w; ++#endif + assert(strncmp(key, "ENV_", 4) == 0); + assert(strlen(key) < 64); + #ifdef MS_WINDOWS +- wchar_t wkey[64]; + // Quick convert to wchar_t, since we know key is ASCII +- wchar_t *wp = wkey; +- for (const char *p = &key[4]; *p; ++p) { ++ wp = wkey; ++ for (p = &key[4]; *p; ++p) { + assert(*p < 128); + *wp++ = *p; + } + *wp = L'\0'; +- const wchar_t *v = _wgetenv(wkey); ++ v = _wgetenv(wkey); + if (v) { + u = PyUnicode_FromWideChar(v, -1); + if (!u) { +@@ -658,10 +706,9 @@ env_to_dict(PyObject *dict, const char *key, int and_clear) + } + } + #else +- const char *v = getenv(&key[4]); ++ v = getenv(&key[4]); + if (v) { +- size_t len; +- const wchar_t *w = Py_DecodeLocale(v, &len); ++ w = Py_DecodeLocale(v, &len); + if (w) { + u = PyUnicode_FromWideChar(w, len); + if (!u) { +@@ -709,7 +756,9 @@ static int + winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod) + { + wchar_t *buffer = NULL; +- for (DWORD cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) { ++ DWORD cch; ++ int r; ++ for (cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) { + buffer = (wchar_t*)PyMem_RawMalloc(cch * sizeof(wchar_t)); + if (buffer) { + if (GetModuleFileNameW(mod, buffer, cch) == cch) { +@@ -718,7 +767,7 @@ winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod) + } + } + } +- int r = wchar_to_dict(dict, key, buffer); ++ r = wchar_to_dict(dict, key, buffer); + PyMem_RawFree(buffer); + return r; + } +@@ -826,6 +875,13 @@ PyStatus + _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) + { + PyStatus status = _PyPathConfig_ReadGlobal(config); ++ PyObject *configDict; ++ PyObject *dict; ++ PyObject *co; ++#ifdef MS_WINDOWS ++ PyObject *winreg; ++#endif ++ PyObject *r; + + if (_PyStatus_EXCEPTION(status) || !compute_path_config) { + return status; +@@ -835,13 +891,13 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) + return PyStatus_Error("cannot calculate path configuration without GIL"); + } + +- PyObject *configDict = _PyConfig_AsDict(config); ++ configDict = _PyConfig_AsDict(config); + if (!configDict) { + PyErr_Clear(); + return PyStatus_NoMemory(); + } + +- PyObject *dict = PyDict_New(); ++ dict = PyDict_New(); + if (!dict) { + PyErr_Clear(); + Py_DECREF(configDict); +@@ -857,7 +913,7 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) + /* reference now held by dict */ + Py_DECREF(configDict); + +- PyObject *co = _Py_Get_Getpath_CodeObject(); ++ co = _Py_Get_Getpath_CodeObject(); + if (!co || !PyCode_Check(co)) { + PyErr_Clear(); + Py_XDECREF(co); +@@ -866,7 +922,7 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) + } + + #ifdef MS_WINDOWS +- PyObject *winreg = PyImport_ImportModule("winreg"); ++ winreg = PyImport_ImportModule("winreg"); + if (!winreg || PyDict_SetItemString(dict, "winreg", winreg) < 0) { + PyErr_Clear(); + Py_XDECREF(winreg); +@@ -924,7 +980,7 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) + return PyStatus_Error("error evaluating initial values"); + } + +- PyObject *r = PyEval_EvalCode(co, dict, dict); ++ r = PyEval_EvalCode(co, dict, dict); + Py_DECREF(co); + + if (!r) { diff --git a/Modules/main.c b/Modules/main.c index f6dade1..011ae59 100644 --- a/Modules/main.c @@ -737,7 +1962,7 @@ index 959b851..6d8ce84 100644 Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ #if !defined(MS_NO_COREDLL) && !defined(Py_NO_ENABLE_SHARED) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c -index 9248e97..a2220e9 100644 +index 9248e97..4abd5d4 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -88,8 +88,14 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS @@ -755,13 +1980,2821 @@ index 9248e97..a2220e9 100644 #elif defined(__APPLE__) -@@ -104,6 +110,9 @@ _PyRuntimeState _PyRuntime +@@ -103,10 +109,20 @@ _PyRuntimeState _PyRuntime + #if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) __attribute__ ((section (".PyRuntime"))) #endif ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++; ++#else = _PyRuntimeState_INIT; ++#endif +#if defined(MS_WINDOWS) && defined(_MSC_VER) && _MSC_VER < 1300 +# pragma data_seg() +#endif _Py_COMP_DIAG_POP static int runtime_initialized = 0; ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++static int runtime_static_initialized = 0; ++#endif + + PyStatus + _PyRuntime_Initialize(void) +@@ -117,6 +133,12 @@ _PyRuntime_Initialize(void) + every Py_Initialize() call, but doing so breaks the runtime. + This is because the runtime state is not properly finalized + currently. */ ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++ if (!runtime_static_initialized) { ++ _PyRuntimeState_InitStaticDefaults(&_PyRuntime); ++ runtime_static_initialized = 1; ++ } ++#endif + if (runtime_initialized) { + return _PyStatus_OK(); + } +@@ -175,10 +197,16 @@ Py_IsInitialized(void) + static int + init_importlib(PyThreadState *tstate, PyObject *sysmod) + { ++ PyInterpreterState *interp; ++ int verbose; ++ PyObject *importlib; ++ PyObject *imp_mod; ++ PyObject *value; ++ + assert(!_PyErr_Occurred(tstate)); + +- PyInterpreterState *interp = tstate->interp; +- int verbose = _PyInterpreterState_GetConfig(interp)->verbose; ++ interp = tstate->interp; ++ verbose = _PyInterpreterState_GetConfig(interp)->verbose; + + // Import _importlib through its frozen version, _frozen_importlib. + if (verbose) { +@@ -187,7 +215,7 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod) + if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { + return -1; + } +- PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed ++ importlib = PyImport_AddModule("_frozen_importlib"); // borrowed + if (importlib == NULL) { + return -1; + } +@@ -197,7 +225,7 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod) + if (verbose) { + PySys_FormatStderr("import _imp # builtin\n"); + } +- PyObject *imp_mod = _PyImport_BootstrapImp(tstate); ++ imp_mod = _PyImport_BootstrapImp(tstate); + if (imp_mod == NULL) { + return -1; + } +@@ -207,8 +235,8 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod) + } + + // Install importlib as the implementation of import +- PyObject *value = PyObject_CallMethod(importlib, "_install", +- "OO", sysmod, imp_mod); ++ value = PyObject_CallMethod(importlib, "_install", ++ "OO", sysmod, imp_mod); + Py_DECREF(imp_mod); + if (value == NULL) { + return -1; +@@ -464,9 +492,10 @@ static int + interpreter_update_config(PyThreadState *tstate, int only_update_path_config) + { + const PyConfig *config = &tstate->interp->config; ++ PyStatus status; + + if (!only_update_path_config) { +- PyStatus status = _PyConfig_Write(config, tstate->interp->runtime); ++ status = _PyConfig_Write(config, tstate->interp->runtime); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + return -1; +@@ -474,7 +503,7 @@ interpreter_update_config(PyThreadState *tstate, int only_update_path_config) + } + + if (_Py_IsMainInterpreter(tstate->interp)) { +- PyStatus status = _PyPathConfig_UpdateGlobal(config); ++ status = _PyPathConfig_UpdateGlobal(config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + return -1; +@@ -494,10 +523,11 @@ _PyInterpreterState_SetConfig(const PyConfig *src_config) + { + PyThreadState *tstate = _PyThreadState_GET(); + int res = -1; +- + PyConfig config; ++ PyStatus status; ++ + PyConfig_InitPythonConfig(&config); +- PyStatus status = _PyConfig_Copy(&config, src_config); ++ status = _PyConfig_Copy(&config, src_config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + goto done; +@@ -542,12 +572,13 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime, + { + PyStatus status; + PyThreadState *tstate = _PyThreadState_GET(); ++ PyInterpreterState *interp; + if (!tstate) { + return _PyStatus_ERR("failed to read thread state"); + } + *tstate_p = tstate; + +- PyInterpreterState *interp = tstate->interp; ++ interp = tstate->interp; + if (interp == NULL) { + return _PyStatus_ERR("can't make main interpreter"); + } +@@ -577,11 +608,13 @@ static PyStatus + pycore_init_runtime(_PyRuntimeState *runtime, + const PyConfig *config) + { ++ PyStatus status; ++ + if (runtime->initialized) { + return _PyStatus_ERR("main interpreter already initialized"); + } + +- PyStatus status = _PyConfig_Write(config, runtime); ++ status = _PyConfig_Write(config, runtime); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +@@ -640,13 +673,17 @@ pycore_create_interpreter(_PyRuntimeState *runtime, + const PyConfig *config, + PyThreadState **tstate_p) + { ++ PyStatus status; ++ PyInterpreterState *interp; ++ PyThreadState *tstate; ++ + /* Auto-thread-state API */ +- PyStatus status = _PyGILState_Init(runtime); ++ status = _PyGILState_Init(runtime); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + +- PyInterpreterState *interp = PyInterpreterState_New(); ++ interp = PyInterpreterState_New(); + if (interp == NULL) { + return _PyStatus_ERR("can't make main interpreter"); + } +@@ -657,7 +694,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, + return status; + } + +- PyThreadState *tstate = PyThreadState_New(interp); ++ tstate = PyThreadState_New(interp); + if (tstate == NULL) { + return _PyStatus_ERR("can't make first thread"); + } +@@ -762,8 +799,14 @@ static PyStatus + pycore_init_builtins(PyThreadState *tstate) + { + PyInterpreterState *interp = tstate->interp; +- +- PyObject *bimod = _PyBuiltin_Init(interp); ++ PyObject *bimod; ++ PyObject *builtins_dict; ++ PyObject *isinstance; ++ PyObject *len; ++ PyObject *list_append; ++ PyObject *import_func; ++ ++ bimod = _PyBuiltin_Init(interp); + if (bimod == NULL) { + goto error; + } +@@ -772,20 +815,20 @@ pycore_init_builtins(PyThreadState *tstate) + goto error; + } + +- PyObject *builtins_dict = PyModule_GetDict(bimod); ++ builtins_dict = PyModule_GetDict(bimod); + if (builtins_dict == NULL) { + goto error; + } + Py_INCREF(builtins_dict); + interp->builtins = builtins_dict; + +- PyObject *isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance)); ++ isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance)); + assert(isinstance); + interp->callable_cache.isinstance = isinstance; +- PyObject *len = PyDict_GetItem(builtins_dict, &_Py_ID(len)); ++ len = PyDict_GetItem(builtins_dict, &_Py_ID(len)); + assert(len); + interp->callable_cache.len = len; +- PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append)); ++ list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append)); + assert(list_append); + interp->callable_cache.list_append = list_append; + +@@ -800,8 +843,8 @@ pycore_init_builtins(PyThreadState *tstate) + Py_DECREF(bimod); + + // Get the __import__ function +- PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins, +- "__import__"); ++ import_func = _PyDict_GetItemStringWithError(interp->builtins, ++ "__import__"); + if (import_func == NULL) { + goto error; + } +@@ -822,6 +865,7 @@ pycore_interp_init(PyThreadState *tstate) + PyInterpreterState *interp = tstate->interp; + PyStatus status; + PyObject *sysmod = NULL; ++ const PyConfig *config; + + // Create singletons before the first PyType_Ready() call, since + // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) +@@ -866,7 +910,7 @@ pycore_interp_init(PyThreadState *tstate) + goto done; + } + +- const PyConfig *config = _PyInterpreterState_GetConfig(interp); ++ config = _PyInterpreterState_GetConfig(interp); + if (config->_install_importlib) { + /* This call sets up builtin and frozen import support */ + if (init_importlib(tstate, sysmod) < 0) { +@@ -886,12 +930,14 @@ pyinit_config(_PyRuntimeState *runtime, + PyThreadState **tstate_p, + const PyConfig *config) + { +- PyStatus status = pycore_init_runtime(runtime, config); ++ PyStatus status; ++ PyThreadState *tstate; ++ ++ status = pycore_init_runtime(runtime, config); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + +- PyThreadState *tstate; + status = pycore_create_interpreter(runtime, config, &tstate); + if (_PyStatus_EXCEPTION(status)) { + return status; +@@ -913,6 +959,8 @@ PyStatus + _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) + { + PyStatus status; ++ _PyRuntimeState *runtime; ++ PyPreConfig config; + + if (src_config == NULL) { + return _PyStatus_ERR("preinitialization config is NULL"); +@@ -922,7 +970,7 @@ _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) + if (_PyStatus_EXCEPTION(status)) { + return status; + } +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + + if (runtime->preinitialized) { + /* If it's already configured: ignored the new configuration */ +@@ -933,8 +981,6 @@ _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) + at exit on success. */ + runtime->preinitializing = 1; + +- PyPreConfig config; +- + status = _PyPreConfig_InitFromPreConfig(&config, src_config); + if (_PyStatus_EXCEPTION(status)) { + return status; +@@ -959,7 +1005,11 @@ _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) + PyStatus + Py_PreInitializeFromBytesArgs(const PyPreConfig *src_config, Py_ssize_t argc, char **argv) + { +- _PyArgv args = {.use_bytes_argv = 1, .argc = argc, .bytes_argv = argv}; ++ _PyArgv args; ++ ++ args.use_bytes_argv = 1; ++ args.argc = argc; ++ args.bytes_argv = argv; + return _Py_PreInitializeFromPyArgv(src_config, &args); + } + +@@ -967,7 +1017,11 @@ Py_PreInitializeFromBytesArgs(const PyPreConfig *src_config, Py_ssize_t argc, ch + PyStatus + Py_PreInitializeFromArgs(const PyPreConfig *src_config, Py_ssize_t argc, wchar_t **argv) + { +- _PyArgv args = {.use_bytes_argv = 0, .argc = argc, .wchar_argv = argv}; ++ _PyArgv args; ++ ++ args.use_bytes_argv = 0; ++ args.argc = argc; ++ args.wchar_argv = argv; + return _Py_PreInitializeFromPyArgv(src_config, &args); + } + +@@ -983,31 +1037,33 @@ PyStatus + _Py_PreInitializeFromConfig(const PyConfig *config, + const _PyArgv *args) + { ++ PyStatus status; ++ _PyRuntimeState *runtime; ++ PyPreConfig preconfig; ++ _PyArgv config_args; ++ + assert(config != NULL); + +- PyStatus status = _PyRuntime_Initialize(); ++ status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + + if (runtime->preinitialized) { + /* Already initialized: do nothing */ + return _PyStatus_OK(); + } + +- PyPreConfig preconfig; +- + _PyPreConfig_InitFromConfig(&preconfig, config); + + if (!config->parse_argv) { + return Py_PreInitialize(&preconfig); + } + else if (args == NULL) { +- _PyArgv config_args = { +- .use_bytes_argv = 0, +- .argc = config->argv.length, +- .wchar_argv = config->argv.items}; ++ config_args.use_bytes_argv = 0; ++ config_args.argc = config->argv.length; ++ config_args.wchar_argv = config->argv.items; + return _Py_PreInitializeFromPyArgv(&preconfig, &config_args); + } + else { +@@ -1039,13 +1095,13 @@ pyinit_core(_PyRuntimeState *runtime, + PyThreadState **tstate_p) + { + PyStatus status; ++ PyConfig config; + + status = _Py_PreInitializeFromConfig(src_config, NULL); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + +- PyConfig config; + PyConfig_InitPythonConfig(&config); + + status = _PyConfig_Copy(&config, src_config); +@@ -1093,14 +1149,13 @@ static PyStatus + init_interp_main(PyThreadState *tstate) + { + extern void _PyThread_debug_deprecation(void); +- +- assert(!_PyErr_Occurred(tstate)); +- + PyStatus status; + int is_main_interp = _Py_IsMainInterpreter(tstate->interp); + PyInterpreterState *interp = tstate->interp; + const PyConfig *config = _PyInterpreterState_GetConfig(interp); + ++ assert(!_PyErr_Occurred(tstate)); ++ + if (!config->_install_importlib) { + /* Special mode for freeze_importlib: run with no import system + * +@@ -1218,7 +1273,10 @@ init_interp_main(PyThreadState *tstate) + static PyStatus + pyinit_main(PyThreadState *tstate) + { +- PyInterpreterState *interp = tstate->interp; ++ PyInterpreterState *interp; ++ PyStatus status; ++ ++ interp = tstate->interp; + if (!interp->runtime->core_initialized) { + return _PyStatus_ERR("runtime core not initialized"); + } +@@ -1227,7 +1285,7 @@ pyinit_main(PyThreadState *tstate) + return pyinit_main_reconfigure(tstate); + } + +- PyStatus status = init_interp_main(tstate); ++ status = init_interp_main(tstate); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +@@ -1238,19 +1296,21 @@ pyinit_main(PyThreadState *tstate) + PyStatus + Py_InitializeFromConfig(const PyConfig *config) + { ++ PyStatus status; ++ _PyRuntimeState *runtime; ++ PyThreadState *tstate; ++ + if (config == NULL) { + return _PyStatus_ERR("initialization config is NULL"); + } + +- PyStatus status; +- + status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + +- PyThreadState *tstate = NULL; ++ tstate = NULL; + status = pyinit_core(runtime, config, &tstate); + if (_PyStatus_EXCEPTION(status)) { + return status; +@@ -1272,19 +1332,20 @@ void + Py_InitializeEx(int install_sigs) + { + PyStatus status; ++ _PyRuntimeState *runtime; ++ PyConfig config; + + status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + Py_ExitStatusException(status); + } +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + + if (runtime->initialized) { + /* bpo-33932: Calling Py_Initialize() twice does nothing. */ + return; + } + +- PyConfig config; + _PyConfig_InitCompatConfig(&config); + + config.install_signal_handlers = install_sigs; +@@ -1302,20 +1363,24 @@ Py_Initialize(void) + Py_InitializeEx(1); + } + +- + PyStatus + _Py_InitializeMain(void) + { +- PyStatus status = _PyRuntime_Initialize(); ++ PyStatus status; ++ _PyRuntimeState *runtime; ++ PyThreadState *tstate; ++ ++ status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +- _PyRuntimeState *runtime = &_PyRuntime; +- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); ++ runtime = &_PyRuntime; ++ tstate = _PyRuntimeState_GetThreadState(runtime); + return pyinit_main(tstate); + } + + ++ + static void + finalize_modules_delete_special(PyThreadState *tstate, int verbose) + { +@@ -1336,6 +1401,9 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) + }; + + PyInterpreterState *interp = tstate->interp; ++ const char * const *p; ++ PyObject *value; ++ + if (verbose) { + PySys_WriteStderr("# clear builtins._\n"); + } +@@ -1343,8 +1411,8 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) + PyErr_WriteUnraisable(NULL); + } + +- const char * const *p; +- for (p = sys_deletes; *p != NULL; p++) { ++ p = sys_deletes; ++ for (; *p != NULL; p++) { + if (verbose) { + PySys_WriteStderr("# clear sys.%s\n", *p); + } +@@ -1358,8 +1426,8 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) + if (verbose) { + PySys_WriteStderr("# restore sys.%s\n", name); + } +- PyObject *value = _PyDict_GetItemStringWithError(interp->sysdict, +- orig_name); ++ value = _PyDict_GetItemStringWithError(interp->sysdict, ++ orig_name); + if (value == NULL) { + if (_PyErr_Occurred(tstate)) { + PyErr_WriteUnraisable(NULL); +@@ -1479,16 +1547,22 @@ static void + finalize_modules_clear_weaklist(PyInterpreterState *interp, + PyObject *weaklist, int verbose) + { ++ Py_ssize_t i; ++ PyObject *tup; ++ PyObject *name; ++ PyObject *mod; ++ PyObject *dict; ++ + // First clear modules imported later +- for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { +- PyObject *tup = PyList_GET_ITEM(weaklist, i); +- PyObject *name = PyTuple_GET_ITEM(tup, 0); +- PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); ++ for (i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { ++ tup = PyList_GET_ITEM(weaklist, i); ++ name = PyTuple_GET_ITEM(tup, 0); ++ mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); + if (mod == Py_None) { + continue; + } + assert(PyModule_Check(mod)); +- PyObject *dict = PyModule_GetDict(mod); ++ dict = PyModule_GetDict(mod); + if (dict == interp->builtins || dict == interp->sysdict) { + continue; + } +@@ -1525,11 +1599,14 @@ finalize_modules(PyThreadState *tstate) + { + PyInterpreterState *interp = tstate->interp; + PyObject *modules = interp->modules; ++ int verbose; ++ PyObject *weaklist; ++ + if (modules == NULL) { + // Already done + return; + } +- int verbose = _PyInterpreterState_GetConfig(interp)->verbose; ++ verbose = _PyInterpreterState_GetConfig(interp)->verbose; + + // Delete some special builtins._ and sys attributes first. These are + // common places where user values hide and people complain when their +@@ -1547,7 +1624,7 @@ finalize_modules(PyThreadState *tstate) + // modules when they are removed from sys.modules. The name is used + // for diagnosis messages (in verbose mode), while the weakref helps + // detect those modules which have been held alive. +- PyObject *weaklist = finalize_remove_modules(modules, verbose); ++ weaklist = finalize_remove_modules(modules, verbose); + + // Clear the modules dict + finalize_clear_modules_dict(modules); +@@ -1751,14 +1828,26 @@ int + Py_FinalizeEx(void) + { + int status = 0; +- + _PyRuntimeState *runtime = &_PyRuntime; ++ PyThreadState *tstate; ++#ifdef Py_REF_DEBUG ++ int show_ref_count; ++#endif ++#ifdef Py_TRACE_REFS ++ int dump_refs; ++ wchar_t *dump_refs_file; ++ FILE *dump_refs_fp; ++#endif ++#ifdef WITH_PYMALLOC ++ int malloc_stats; ++#endif ++ + if (!runtime->initialized) { + return status; + } + + /* Get current thread state and interpreter pointer */ +- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); ++ tstate = _PyRuntimeState_GetThreadState(runtime); + + // Wrap up existing "threading"-module-created, non-daemon threads. + wait_for_thread_shutdown(tstate); +@@ -1781,14 +1870,14 @@ Py_FinalizeEx(void) + /* Copy the core config, PyInterpreterState_Delete() free + the core config memory */ + #ifdef Py_REF_DEBUG +- int show_ref_count = tstate->interp->config.show_ref_count; ++ show_ref_count = tstate->interp->config.show_ref_count; + #endif + #ifdef Py_TRACE_REFS +- int dump_refs = tstate->interp->config.dump_refs; +- wchar_t *dump_refs_file = tstate->interp->config.dump_refs_file; ++ dump_refs = tstate->interp->config.dump_refs; ++ dump_refs_file = tstate->interp->config.dump_refs_file; + #endif + #ifdef WITH_PYMALLOC +- int malloc_stats = tstate->interp->config.malloc_stats; ++ malloc_stats = tstate->interp->config.malloc_stats; + #endif + + /* Remaining daemon threads will automatically exit +@@ -1879,7 +1968,7 @@ Py_FinalizeEx(void) + * up later. + */ + +- FILE *dump_refs_fp = NULL; ++ dump_refs_fp = NULL; + if (dump_refs_file != NULL) { + dump_refs_fp = _Py_wfopen(dump_refs_file, L"w"); + if (dump_refs_fp == NULL) { +@@ -1956,12 +2045,17 @@ static PyStatus + new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) + { + PyStatus status; ++ _PyRuntimeState *runtime; ++ PyInterpreterState *interp; ++ PyThreadState *tstate; ++ PyThreadState *save_tstate; ++ const PyConfig *config; + + status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + + if (!runtime->initialized) { + return _PyStatus_ERR("Py_Initialize must be called first"); +@@ -1971,23 +2065,22 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) + interpreters: disable PyGILState_Check(). */ + runtime->gilstate.check_enabled = 0; + +- PyInterpreterState *interp = PyInterpreterState_New(); ++ interp = PyInterpreterState_New(); + if (interp == NULL) { + *tstate_p = NULL; + return _PyStatus_OK(); + } + +- PyThreadState *tstate = PyThreadState_New(interp); ++ tstate = PyThreadState_New(interp); + if (tstate == NULL) { + PyInterpreterState_Delete(interp); + *tstate_p = NULL; + return _PyStatus_OK(); + } + +- PyThreadState *save_tstate = PyThreadState_Swap(tstate); ++ save_tstate = PyThreadState_Swap(tstate); + + /* Copy the current interpreter config into the new interpreter */ +- const PyConfig *config; + if (save_tstate != NULL) { + config = _PyInterpreterState_GetConfig(save_tstate->interp); + } +@@ -2099,7 +2192,7 @@ Py_EndInterpreter(PyThreadState *tstate) + static PyStatus + add_main_module(PyInterpreterState *interp) + { +- PyObject *m, *d, *loader, *ann_dict; ++ PyObject *m, *d, *loader, *ann_dict, *bimod, *loader_obj; + m = PyImport_AddModule("__main__"); + if (m == NULL) + return _PyStatus_ERR("can't create __main__ module"); +@@ -2116,7 +2209,7 @@ add_main_module(PyInterpreterState *interp) + if (PyErr_Occurred()) { + return _PyStatus_ERR("Failed to test __main__.__builtins__"); + } +- PyObject *bimod = PyImport_ImportModule("builtins"); ++ bimod = PyImport_ImportModule("builtins"); + if (bimod == NULL) { + return _PyStatus_ERR("Failed to retrieve builtins module"); + } +@@ -2137,15 +2230,15 @@ add_main_module(PyInterpreterState *interp) + if (PyErr_Occurred()) { + return _PyStatus_ERR("Failed to test __main__.__loader__"); + } +- PyObject *loader = PyObject_GetAttrString(interp->importlib, +- "BuiltinImporter"); +- if (loader == NULL) { ++ loader_obj = PyObject_GetAttrString(interp->importlib, ++ "BuiltinImporter"); ++ if (loader_obj == NULL) { + return _PyStatus_ERR("Failed to retrieve BuiltinImporter"); + } +- if (PyDict_SetItemString(d, "__loader__", loader) < 0) { ++ if (PyDict_SetItemString(d, "__loader__", loader_obj) < 0) { + return _PyStatus_ERR("Failed to initialize __main__.__loader__"); + } +- Py_DECREF(loader); ++ Py_DECREF(loader_obj); + } + return _PyStatus_OK(); + } +@@ -2185,6 +2278,18 @@ is_valid_fd(int fd) + Only use dup() on Linux where dup() is enough to detect invalid FD + (bpo-32849). + */ ++#if defined(F_GETFD) && ( \ ++ defined(__linux__) || \ ++ defined(__APPLE__) || \ ++ defined(__wasm__)) ++#elif defined(__linux__) ++ int fd2; ++#elif defined(MS_WINDOWS) ++ HANDLE hfile; ++#else ++ struct stat st; ++#endif ++ + if (fd < 0) { + return 0; + } +@@ -2194,20 +2299,18 @@ is_valid_fd(int fd) + defined(__wasm__)) + return fcntl(fd, F_GETFD) >= 0; + #elif defined(__linux__) +- int fd2 = dup(fd); ++ fd2 = dup(fd); + if (fd2 >= 0) { + close(fd2); + } + return (fd2 >= 0); + #elif defined(MS_WINDOWS) +- HANDLE hfile; + _Py_BEGIN_SUPPRESS_IPH + hfile = (HANDLE)_get_osfhandle(fd); + _Py_END_SUPPRESS_IPH + return (hfile != INVALID_HANDLE_VALUE + && GetFileType(hfile) != FILE_TYPE_UNKNOWN); + #else +- struct stat st; + return (fstat(fd, &st) == 0); + #endif + } +@@ -2219,6 +2322,7 @@ create_stdio(const PyConfig *config, PyObject* io, + const wchar_t* encoding, const wchar_t* errors) + { + PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; ++ PyObject *encoding_str, *errors_str; + const char* mode; + const char* newline; + PyObject *line_buffering, *write_through; +@@ -2297,13 +2401,13 @@ create_stdio(const PyConfig *config, PyObject* io, + newline = "\n"; + #endif + +- PyObject *encoding_str = PyUnicode_FromWideChar(encoding, -1); ++ encoding_str = PyUnicode_FromWideChar(encoding, -1); + if (encoding_str == NULL) { + Py_CLEAR(buf); + goto error; + } + +- PyObject *errors_str = PyUnicode_FromWideChar(errors, -1); ++ errors_str = PyUnicode_FromWideChar(errors, -1); + if (errors_str == NULL) { + Py_CLEAR(buf); + Py_CLEAR(encoding_str); +@@ -2590,8 +2694,10 @@ fatal_output_debug(const char *msg) + static void + fatal_error_dump_runtime(int fd, _PyRuntimeState *runtime) + { ++ PyThreadState *finalizing; ++ + PUTS(fd, "Python runtime state: "); +- PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); ++ finalizing = _PyRuntimeState_GetFinalizing(runtime); + if (finalizing) { + PUTS(fd, "finalizing (tstate=0x"); + _Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2); +@@ -2640,21 +2746,25 @@ fatal_error_exit(int status) + void + _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) + { ++ PyObject *modules; ++ Py_ssize_t pos; ++ PyObject *key, *value; ++ PyObject *stdlib_module_names; ++ int header; ++ Py_ssize_t count; ++ + if (interp == NULL) { + return; + } +- PyObject *modules = interp->modules; ++ modules = interp->modules; + if (modules == NULL || !PyDict_Check(modules)) { + return; + } + +- Py_ssize_t pos; +- PyObject *key, *value; +- + // Avoid PyDict_GetItemString() which calls PyUnicode_FromString(), + // memory cannot be allocated on the heap in a signal handler. + // Iterate on the dict instead. +- PyObject *stdlib_module_names = NULL; ++ stdlib_module_names = NULL; + if (interp->sysdict != NULL) { + pos = 0; + while (PyDict_Next(interp->sysdict, &pos, &key, &value)) { +@@ -2672,8 +2782,8 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) + } + + // List extensions +- int header = 1; +- Py_ssize_t count = 0; ++ header = 1; ++ count = 0; + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (!PyUnicode_Check(key)) { +@@ -2730,6 +2840,11 @@ fatal_error(int fd, int header, const char *prefix, const char *msg, + int status) + { + static int reentrant = 0; ++ _PyRuntimeState *runtime; ++ PyThreadState *tstate; ++ PyInterpreterState *interp; ++ PyThreadState *tss_tstate; ++ int has_tstate_and_gil; + + if (reentrant) { + /* Py_FatalError() caused a second fatal error. +@@ -2753,7 +2868,7 @@ fatal_error(int fd, int header, const char *prefix, const char *msg, + PUTS(fd, "\n"); + } + +- _PyRuntimeState *runtime = &_PyRuntime; ++ runtime = &_PyRuntime; + fatal_error_dump_runtime(fd, runtime); + + /* Check if the current thread has a Python thread state +@@ -2764,16 +2879,16 @@ fatal_error(int fd, int header, const char *prefix, const char *msg, + + tss_tstate != tstate if the current Python thread does not hold the GIL. + */ +- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); +- PyInterpreterState *interp = NULL; +- PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); ++ tstate = _PyRuntimeState_GetThreadState(runtime); ++ interp = NULL; ++ tss_tstate = PyGILState_GetThisThreadState(); + if (tstate != NULL) { + interp = tstate->interp; + } + else if (tss_tstate != NULL) { + interp = tss_tstate->interp; + } +- int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); ++ has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); + + if (has_tstate_and_gil) { + /* If an exception is set, print the exception with its traceback */ +@@ -2828,21 +2943,24 @@ void _Py_NO_RETURN + _Py_FatalErrorFormat(const char *func, const char *format, ...) + { + static int reentrant = 0; ++ FILE *stream; ++ int fd; ++ va_list vargs; ++ + if (reentrant) { + /* _Py_FatalErrorFormat() caused a second fatal error */ + fatal_error_exit(-1); + } + reentrant = 1; + +- FILE *stream = stderr; +- const int fd = fileno(stream); ++ stream = stderr; ++ fd = fileno(stream); + PUTS(fd, "Fatal Python error: "); + if (func) { + PUTS(fd, func); + PUTS(fd, ": "); + } + +- va_list vargs; + #ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); + #else +@@ -2921,10 +3039,12 @@ int Py_AtExit(void (*func)(void)) + static void + call_ll_exitfuncs(_PyRuntimeState *runtime) + { ++ void (*exitfunc)(void); ++ + while (runtime->nexitfuncs > 0) { + /* pop last function from the list */ + runtime->nexitfuncs--; +- void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs]; ++ exitfunc = runtime->exitfuncs[runtime->nexitfuncs]; + runtime->exitfuncs[runtime->nexitfuncs] = NULL; + + exitfunc(); +diff --git a/Python/pystate.c b/Python/pystate.c +index a451166..f26d2c2 100644 +--- a/Python/pystate.c ++++ b/Python/pystate.c +@@ -50,9 +50,1127 @@ static void _PyThreadState_Delete(PyThreadState *tstate, int check_current); + /* Suppress deprecation warning for PyBytesObject.ob_shash */ + _Py_COMP_DIAG_PUSH + _Py_COMP_DIAG_IGNORE_DEPR_DECLS ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++/* We use an explicit field-by-field initializer on VC6, which cannot parse ++ the C99 designated initializer used by _PyRuntimeState_INIT. */ ++ ++static void ++init_immortal_object(PyObject *op, PyTypeObject *type) ++{ ++#ifdef Py_TRACE_REFS ++ op->_ob_next = NULL; ++ op->_ob_prev = NULL; ++#endif ++ op->ob_refcnt = 999999999; ++ op->ob_type = type; ++} ++ ++static void ++init_immortal_varobject(PyVarObject *op, PyTypeObject *type, Py_ssize_t size) ++{ ++ init_immortal_object(&op->ob_base, type); ++ op->ob_size = size; ++} ++ ++static void ++init_ascii_object(PyASCIIObject *ascii, uint8_t *data, ++ const char *literal, int is_ascii) ++{ ++ size_t len = strlen(literal); ++ init_immortal_object(&ascii->ob_base, &PyUnicode_Type); ++ ascii->length = (Py_ssize_t)len; ++ ascii->hash = -1; ++ ascii->state.interned = 0; ++ ascii->state.kind = 1; ++ ascii->state.compact = 1; ++ ascii->state.ascii = is_ascii; ++ ascii->state.ready = 1; ++ ascii->wstr = NULL; ++ memcpy(data, literal, len + 1); ++} ++ ++static void ++init_latin1_object(PyCompactUnicodeObject *latin1, uint8_t *data, ++ unsigned char ch) ++{ ++ char literal[2]; ++ literal[0] = (char)ch; ++ literal[1] = '\0'; ++ init_ascii_object(&latin1->_base, data, literal, 0); ++ latin1->utf8_length = 0; ++ latin1->utf8 = NULL; ++ latin1->wstr_length = 0; ++} ++ ++static void ++init_static_threadstate(PyThreadState *tstate) ++{ ++ tstate->_static = 1; ++ tstate->recursion_limit = Py_DEFAULT_RECURSION_LIMIT; ++ tstate->context_ver = 1; ++} ++ ++static void ++init_static_interpreter(PyInterpreterState *interp) ++{ ++ interp->_static = 1; ++ interp->id_refcount = -1; ++#ifdef HAVE_DLOPEN ++ interp->dlopenflags = _Py_DLOPEN_FLAGS; ++#endif ++ interp->ceval.recursion_limit = Py_DEFAULT_RECURSION_LIMIT; ++ interp->gc.enabled = 1; ++ interp->gc.generations[0].threshold = 700; ++ interp->gc.generations[1].threshold = 10; ++ interp->gc.generations[2].threshold = 10; ++ init_static_threadstate(&interp->_initial_thread); ++} ++ ++static void ++init_small_int(PyLongObject *op, int value) ++{ ++ int size = 0; ++ int digit_value = value; ++ if (value < 0) { ++ size = -1; ++ digit_value = -value; ++ } ++ else if (value > 0) { ++ size = 1; ++ } ++ init_immortal_varobject(&op->ob_base, &PyLong_Type, size); ++ op->ob_digit[0] = (digit)digit_value; ++} ++ ++static void ++init_static_global_objects(struct _Py_global_objects *objects) ++{ ++ int i; ++ ++ for (i = 0; i < _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS; i++) { ++ init_small_int(&objects->singletons.small_ints[i], ++ i - _PY_NSMALLNEGINTS); ++ } ++ ++ init_immortal_varobject(&objects->singletons.bytes_empty.ob_base, ++ &PyBytes_Type, 0); ++ objects->singletons.bytes_empty.ob_shash = -1; ++ objects->singletons.bytes_empty.ob_sval[0] = '\0'; ++ ++ for (i = 0; i < 256; i++) { ++ init_immortal_varobject(&objects->singletons.bytes_characters[i].ob.ob_base, ++ &PyBytes_Type, 1); ++ objects->singletons.bytes_characters[i].ob.ob_shash = -1; ++ objects->singletons.bytes_characters[i].ob.ob_sval[0] = (char)i; ++ objects->singletons.bytes_characters[i].eos = '\0'; ++ } ++ init_ascii_object(&objects->singletons.strings.literals._anon_dictcomp._ascii, ++ objects->singletons.strings.literals._anon_dictcomp._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_genexpr._ascii, ++ objects->singletons.strings.literals._anon_genexpr._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_lambda._ascii, ++ objects->singletons.strings.literals._anon_lambda._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_listcomp._ascii, ++ objects->singletons.strings.literals._anon_listcomp._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_module._ascii, ++ objects->singletons.strings.literals._anon_module._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_setcomp._ascii, ++ objects->singletons.strings.literals._anon_setcomp._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_string._ascii, ++ objects->singletons.strings.literals._anon_string._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._anon_unknown._ascii, ++ objects->singletons.strings.literals._anon_unknown._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._close_br._ascii, ++ objects->singletons.strings.literals._close_br._data, ++ "}", 1); ++ init_ascii_object(&objects->singletons.strings.literals._comma_sep._ascii, ++ objects->singletons.strings.literals._comma_sep._data, ++ ", ", 1); ++ init_ascii_object(&objects->singletons.strings.literals._dbl_close_br._ascii, ++ objects->singletons.strings.literals._dbl_close_br._data, ++ "}}", 1); ++ init_ascii_object(&objects->singletons.strings.literals._dbl_open_br._ascii, ++ objects->singletons.strings.literals._dbl_open_br._data, ++ "{{", 1); ++ init_ascii_object(&objects->singletons.strings.literals._dbl_percent._ascii, ++ objects->singletons.strings.literals._dbl_percent._data, ++ "%%", 1); ++ init_ascii_object(&objects->singletons.strings.literals._dot._ascii, ++ objects->singletons.strings.literals._dot._data, ++ ".", 1); ++ init_ascii_object(&objects->singletons.strings.literals._dot_locals._ascii, ++ objects->singletons.strings.literals._dot_locals._data, ++ ".", 1); ++ init_ascii_object(&objects->singletons.strings.literals._empty._ascii, ++ objects->singletons.strings.literals._empty._data, ++ "", 1); ++ init_ascii_object(&objects->singletons.strings.literals._list_err._ascii, ++ objects->singletons.strings.literals._list_err._data, ++ "list index out of range", 1); ++ init_ascii_object(&objects->singletons.strings.literals._newline._ascii, ++ objects->singletons.strings.literals._newline._data, ++ "\n", 1); ++ init_ascii_object(&objects->singletons.strings.literals._open_br._ascii, ++ objects->singletons.strings.literals._open_br._data, ++ "{", 1); ++ init_ascii_object(&objects->singletons.strings.literals._percent._ascii, ++ objects->singletons.strings.literals._percent._data, ++ "%", 1); ++ init_ascii_object(&objects->singletons.strings.literals._utf_8._ascii, ++ objects->singletons.strings.literals._utf_8._data, ++ "utf-8", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._False._ascii, ++ objects->singletons.strings.identifiers._False._data, ++ "False", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._Py_Repr._ascii, ++ objects->singletons.strings.identifiers._Py_Repr._data, ++ "Py_Repr", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._TextIOWrapper._ascii, ++ objects->singletons.strings.identifiers._TextIOWrapper._data, ++ "TextIOWrapper", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._True._ascii, ++ objects->singletons.strings.identifiers._True._data, ++ "True", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._WarningMessage._ascii, ++ objects->singletons.strings.identifiers._WarningMessage._data, ++ "WarningMessage", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__._ascii, ++ objects->singletons.strings.identifiers.__._data, ++ "_", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___IOBase_closed._ascii, ++ objects->singletons.strings.identifiers.___IOBase_closed._data, ++ "__IOBase_closed", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___abc_tpflags__._ascii, ++ objects->singletons.strings.identifiers.___abc_tpflags__._data, ++ "__abc_tpflags__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___abs__._ascii, ++ objects->singletons.strings.identifiers.___abs__._data, ++ "__abs__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___abstractmethods__._ascii, ++ objects->singletons.strings.identifiers.___abstractmethods__._data, ++ "__abstractmethods__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___add__._ascii, ++ objects->singletons.strings.identifiers.___add__._data, ++ "__add__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___aenter__._ascii, ++ objects->singletons.strings.identifiers.___aenter__._data, ++ "__aenter__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___aexit__._ascii, ++ objects->singletons.strings.identifiers.___aexit__._data, ++ "__aexit__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___aiter__._ascii, ++ objects->singletons.strings.identifiers.___aiter__._data, ++ "__aiter__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___all__._ascii, ++ objects->singletons.strings.identifiers.___all__._data, ++ "__all__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___and__._ascii, ++ objects->singletons.strings.identifiers.___and__._data, ++ "__and__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___anext__._ascii, ++ objects->singletons.strings.identifiers.___anext__._data, ++ "__anext__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___annotations__._ascii, ++ objects->singletons.strings.identifiers.___annotations__._data, ++ "__annotations__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___args__._ascii, ++ objects->singletons.strings.identifiers.___args__._data, ++ "__args__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___await__._ascii, ++ objects->singletons.strings.identifiers.___await__._data, ++ "__await__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___bases__._ascii, ++ objects->singletons.strings.identifiers.___bases__._data, ++ "__bases__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___bool__._ascii, ++ objects->singletons.strings.identifiers.___bool__._data, ++ "__bool__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___build_class__._ascii, ++ objects->singletons.strings.identifiers.___build_class__._data, ++ "__build_class__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___builtins__._ascii, ++ objects->singletons.strings.identifiers.___builtins__._data, ++ "__builtins__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___bytes__._ascii, ++ objects->singletons.strings.identifiers.___bytes__._data, ++ "__bytes__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___call__._ascii, ++ objects->singletons.strings.identifiers.___call__._data, ++ "__call__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___cantrace__._ascii, ++ objects->singletons.strings.identifiers.___cantrace__._data, ++ "__cantrace__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___class__._ascii, ++ objects->singletons.strings.identifiers.___class__._data, ++ "__class__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___class_getitem__._ascii, ++ objects->singletons.strings.identifiers.___class_getitem__._data, ++ "__class_getitem__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___classcell__._ascii, ++ objects->singletons.strings.identifiers.___classcell__._data, ++ "__classcell__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___complex__._ascii, ++ objects->singletons.strings.identifiers.___complex__._data, ++ "__complex__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___contains__._ascii, ++ objects->singletons.strings.identifiers.___contains__._data, ++ "__contains__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___copy__._ascii, ++ objects->singletons.strings.identifiers.___copy__._data, ++ "__copy__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___del__._ascii, ++ objects->singletons.strings.identifiers.___del__._data, ++ "__del__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___delattr__._ascii, ++ objects->singletons.strings.identifiers.___delattr__._data, ++ "__delattr__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___delete__._ascii, ++ objects->singletons.strings.identifiers.___delete__._data, ++ "__delete__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___delitem__._ascii, ++ objects->singletons.strings.identifiers.___delitem__._data, ++ "__delitem__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___dict__._ascii, ++ objects->singletons.strings.identifiers.___dict__._data, ++ "__dict__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___dir__._ascii, ++ objects->singletons.strings.identifiers.___dir__._data, ++ "__dir__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___divmod__._ascii, ++ objects->singletons.strings.identifiers.___divmod__._data, ++ "__divmod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___doc__._ascii, ++ objects->singletons.strings.identifiers.___doc__._data, ++ "__doc__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___enter__._ascii, ++ objects->singletons.strings.identifiers.___enter__._data, ++ "__enter__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___eq__._ascii, ++ objects->singletons.strings.identifiers.___eq__._data, ++ "__eq__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___exit__._ascii, ++ objects->singletons.strings.identifiers.___exit__._data, ++ "__exit__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___file__._ascii, ++ objects->singletons.strings.identifiers.___file__._data, ++ "__file__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___float__._ascii, ++ objects->singletons.strings.identifiers.___float__._data, ++ "__float__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___floordiv__._ascii, ++ objects->singletons.strings.identifiers.___floordiv__._data, ++ "__floordiv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___format__._ascii, ++ objects->singletons.strings.identifiers.___format__._data, ++ "__format__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___fspath__._ascii, ++ objects->singletons.strings.identifiers.___fspath__._data, ++ "__fspath__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ge__._ascii, ++ objects->singletons.strings.identifiers.___ge__._data, ++ "__ge__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___get__._ascii, ++ objects->singletons.strings.identifiers.___get__._data, ++ "__get__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getattr__._ascii, ++ objects->singletons.strings.identifiers.___getattr__._data, ++ "__getattr__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getattribute__._ascii, ++ objects->singletons.strings.identifiers.___getattribute__._data, ++ "__getattribute__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getinitargs__._ascii, ++ objects->singletons.strings.identifiers.___getinitargs__._data, ++ "__getinitargs__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getitem__._ascii, ++ objects->singletons.strings.identifiers.___getitem__._data, ++ "__getitem__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getnewargs__._ascii, ++ objects->singletons.strings.identifiers.___getnewargs__._data, ++ "__getnewargs__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getnewargs_ex__._ascii, ++ objects->singletons.strings.identifiers.___getnewargs_ex__._data, ++ "__getnewargs_ex__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___getstate__._ascii, ++ objects->singletons.strings.identifiers.___getstate__._data, ++ "__getstate__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___gt__._ascii, ++ objects->singletons.strings.identifiers.___gt__._data, ++ "__gt__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___hash__._ascii, ++ objects->singletons.strings.identifiers.___hash__._data, ++ "__hash__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___iadd__._ascii, ++ objects->singletons.strings.identifiers.___iadd__._data, ++ "__iadd__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___iand__._ascii, ++ objects->singletons.strings.identifiers.___iand__._data, ++ "__iand__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ifloordiv__._ascii, ++ objects->singletons.strings.identifiers.___ifloordiv__._data, ++ "__ifloordiv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ilshift__._ascii, ++ objects->singletons.strings.identifiers.___ilshift__._data, ++ "__ilshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___imatmul__._ascii, ++ objects->singletons.strings.identifiers.___imatmul__._data, ++ "__imatmul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___imod__._ascii, ++ objects->singletons.strings.identifiers.___imod__._data, ++ "__imod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___import__._ascii, ++ objects->singletons.strings.identifiers.___import__._data, ++ "__import__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___imul__._ascii, ++ objects->singletons.strings.identifiers.___imul__._data, ++ "__imul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___index__._ascii, ++ objects->singletons.strings.identifiers.___index__._data, ++ "__index__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___init__._ascii, ++ objects->singletons.strings.identifiers.___init__._data, ++ "__init__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___init_subclass__._ascii, ++ objects->singletons.strings.identifiers.___init_subclass__._data, ++ "__init_subclass__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___instancecheck__._ascii, ++ objects->singletons.strings.identifiers.___instancecheck__._data, ++ "__instancecheck__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___int__._ascii, ++ objects->singletons.strings.identifiers.___int__._data, ++ "__int__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___invert__._ascii, ++ objects->singletons.strings.identifiers.___invert__._data, ++ "__invert__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ior__._ascii, ++ objects->singletons.strings.identifiers.___ior__._data, ++ "__ior__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ipow__._ascii, ++ objects->singletons.strings.identifiers.___ipow__._data, ++ "__ipow__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___irshift__._ascii, ++ objects->singletons.strings.identifiers.___irshift__._data, ++ "__irshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___isabstractmethod__._ascii, ++ objects->singletons.strings.identifiers.___isabstractmethod__._data, ++ "__isabstractmethod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___isub__._ascii, ++ objects->singletons.strings.identifiers.___isub__._data, ++ "__isub__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___iter__._ascii, ++ objects->singletons.strings.identifiers.___iter__._data, ++ "__iter__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___itruediv__._ascii, ++ objects->singletons.strings.identifiers.___itruediv__._data, ++ "__itruediv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ixor__._ascii, ++ objects->singletons.strings.identifiers.___ixor__._data, ++ "__ixor__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___le__._ascii, ++ objects->singletons.strings.identifiers.___le__._data, ++ "__le__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___len__._ascii, ++ objects->singletons.strings.identifiers.___len__._data, ++ "__len__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___length_hint__._ascii, ++ objects->singletons.strings.identifiers.___length_hint__._data, ++ "__length_hint__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___lltrace__._ascii, ++ objects->singletons.strings.identifiers.___lltrace__._data, ++ "__lltrace__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___loader__._ascii, ++ objects->singletons.strings.identifiers.___loader__._data, ++ "__loader__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___lshift__._ascii, ++ objects->singletons.strings.identifiers.___lshift__._data, ++ "__lshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___lt__._ascii, ++ objects->singletons.strings.identifiers.___lt__._data, ++ "__lt__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___main__._ascii, ++ objects->singletons.strings.identifiers.___main__._data, ++ "__main__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___matmul__._ascii, ++ objects->singletons.strings.identifiers.___matmul__._data, ++ "__matmul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___missing__._ascii, ++ objects->singletons.strings.identifiers.___missing__._data, ++ "__missing__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___mod__._ascii, ++ objects->singletons.strings.identifiers.___mod__._data, ++ "__mod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___module__._ascii, ++ objects->singletons.strings.identifiers.___module__._data, ++ "__module__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___mro_entries__._ascii, ++ objects->singletons.strings.identifiers.___mro_entries__._data, ++ "__mro_entries__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___mul__._ascii, ++ objects->singletons.strings.identifiers.___mul__._data, ++ "__mul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___name__._ascii, ++ objects->singletons.strings.identifiers.___name__._data, ++ "__name__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ne__._ascii, ++ objects->singletons.strings.identifiers.___ne__._data, ++ "__ne__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___neg__._ascii, ++ objects->singletons.strings.identifiers.___neg__._data, ++ "__neg__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___new__._ascii, ++ objects->singletons.strings.identifiers.___new__._data, ++ "__new__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___newobj__._ascii, ++ objects->singletons.strings.identifiers.___newobj__._data, ++ "__newobj__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___newobj_ex__._ascii, ++ objects->singletons.strings.identifiers.___newobj_ex__._data, ++ "__newobj_ex__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___next__._ascii, ++ objects->singletons.strings.identifiers.___next__._data, ++ "__next__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___notes__._ascii, ++ objects->singletons.strings.identifiers.___notes__._data, ++ "__notes__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___or__._ascii, ++ objects->singletons.strings.identifiers.___or__._data, ++ "__or__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___orig_class__._ascii, ++ objects->singletons.strings.identifiers.___orig_class__._data, ++ "__orig_class__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___origin__._ascii, ++ objects->singletons.strings.identifiers.___origin__._data, ++ "__origin__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___package__._ascii, ++ objects->singletons.strings.identifiers.___package__._data, ++ "__package__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___parameters__._ascii, ++ objects->singletons.strings.identifiers.___parameters__._data, ++ "__parameters__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___path__._ascii, ++ objects->singletons.strings.identifiers.___path__._data, ++ "__path__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___pos__._ascii, ++ objects->singletons.strings.identifiers.___pos__._data, ++ "__pos__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___pow__._ascii, ++ objects->singletons.strings.identifiers.___pow__._data, ++ "__pow__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___prepare__._ascii, ++ objects->singletons.strings.identifiers.___prepare__._data, ++ "__prepare__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___qualname__._ascii, ++ objects->singletons.strings.identifiers.___qualname__._data, ++ "__qualname__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___radd__._ascii, ++ objects->singletons.strings.identifiers.___radd__._data, ++ "__radd__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rand__._ascii, ++ objects->singletons.strings.identifiers.___rand__._data, ++ "__rand__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rdivmod__._ascii, ++ objects->singletons.strings.identifiers.___rdivmod__._data, ++ "__rdivmod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___reduce__._ascii, ++ objects->singletons.strings.identifiers.___reduce__._data, ++ "__reduce__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___reduce_ex__._ascii, ++ objects->singletons.strings.identifiers.___reduce_ex__._data, ++ "__reduce_ex__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___repr__._ascii, ++ objects->singletons.strings.identifiers.___repr__._data, ++ "__repr__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___reversed__._ascii, ++ objects->singletons.strings.identifiers.___reversed__._data, ++ "__reversed__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rfloordiv__._ascii, ++ objects->singletons.strings.identifiers.___rfloordiv__._data, ++ "__rfloordiv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rlshift__._ascii, ++ objects->singletons.strings.identifiers.___rlshift__._data, ++ "__rlshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rmatmul__._ascii, ++ objects->singletons.strings.identifiers.___rmatmul__._data, ++ "__rmatmul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rmod__._ascii, ++ objects->singletons.strings.identifiers.___rmod__._data, ++ "__rmod__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rmul__._ascii, ++ objects->singletons.strings.identifiers.___rmul__._data, ++ "__rmul__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___ror__._ascii, ++ objects->singletons.strings.identifiers.___ror__._data, ++ "__ror__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___round__._ascii, ++ objects->singletons.strings.identifiers.___round__._data, ++ "__round__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rpow__._ascii, ++ objects->singletons.strings.identifiers.___rpow__._data, ++ "__rpow__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rrshift__._ascii, ++ objects->singletons.strings.identifiers.___rrshift__._data, ++ "__rrshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rshift__._ascii, ++ objects->singletons.strings.identifiers.___rshift__._data, ++ "__rshift__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rsub__._ascii, ++ objects->singletons.strings.identifiers.___rsub__._data, ++ "__rsub__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rtruediv__._ascii, ++ objects->singletons.strings.identifiers.___rtruediv__._data, ++ "__rtruediv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___rxor__._ascii, ++ objects->singletons.strings.identifiers.___rxor__._data, ++ "__rxor__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___set__._ascii, ++ objects->singletons.strings.identifiers.___set__._data, ++ "__set__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___set_name__._ascii, ++ objects->singletons.strings.identifiers.___set_name__._data, ++ "__set_name__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___setattr__._ascii, ++ objects->singletons.strings.identifiers.___setattr__._data, ++ "__setattr__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___setitem__._ascii, ++ objects->singletons.strings.identifiers.___setitem__._data, ++ "__setitem__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___setstate__._ascii, ++ objects->singletons.strings.identifiers.___setstate__._data, ++ "__setstate__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___sizeof__._ascii, ++ objects->singletons.strings.identifiers.___sizeof__._data, ++ "__sizeof__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___slotnames__._ascii, ++ objects->singletons.strings.identifiers.___slotnames__._data, ++ "__slotnames__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___slots__._ascii, ++ objects->singletons.strings.identifiers.___slots__._data, ++ "__slots__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___spec__._ascii, ++ objects->singletons.strings.identifiers.___spec__._data, ++ "__spec__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___str__._ascii, ++ objects->singletons.strings.identifiers.___str__._data, ++ "__str__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___sub__._ascii, ++ objects->singletons.strings.identifiers.___sub__._data, ++ "__sub__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___subclasscheck__._ascii, ++ objects->singletons.strings.identifiers.___subclasscheck__._data, ++ "__subclasscheck__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___subclasshook__._ascii, ++ objects->singletons.strings.identifiers.___subclasshook__._data, ++ "__subclasshook__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___truediv__._ascii, ++ objects->singletons.strings.identifiers.___truediv__._data, ++ "__truediv__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___trunc__._ascii, ++ objects->singletons.strings.identifiers.___trunc__._data, ++ "__trunc__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___typing_is_unpacked_typevartuple__._ascii, ++ objects->singletons.strings.identifiers.___typing_is_unpacked_typevartuple__._data, ++ "__typing_is_unpacked_typevartuple__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___typing_prepare_subst__._ascii, ++ objects->singletons.strings.identifiers.___typing_prepare_subst__._data, ++ "__typing_prepare_subst__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___typing_subst__._ascii, ++ objects->singletons.strings.identifiers.___typing_subst__._data, ++ "__typing_subst__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___typing_unpacked_tuple_args__._ascii, ++ objects->singletons.strings.identifiers.___typing_unpacked_tuple_args__._data, ++ "__typing_unpacked_tuple_args__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___warningregistry__._ascii, ++ objects->singletons.strings.identifiers.___warningregistry__._data, ++ "__warningregistry__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___weakref__._ascii, ++ objects->singletons.strings.identifiers.___weakref__._data, ++ "__weakref__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.___xor__._ascii, ++ objects->singletons.strings.identifiers.___xor__._data, ++ "__xor__", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__abc_impl._ascii, ++ objects->singletons.strings.identifiers.__abc_impl._data, ++ "_abc_impl", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__annotation._ascii, ++ objects->singletons.strings.identifiers.__annotation._data, ++ "_annotation", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__blksize._ascii, ++ objects->singletons.strings.identifiers.__blksize._data, ++ "_blksize", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__bootstrap._ascii, ++ objects->singletons.strings.identifiers.__bootstrap._data, ++ "_bootstrap", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__dealloc_warn._ascii, ++ objects->singletons.strings.identifiers.__dealloc_warn._data, ++ "_dealloc_warn", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__finalizing._ascii, ++ objects->singletons.strings.identifiers.__finalizing._data, ++ "_finalizing", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__find_and_load._ascii, ++ objects->singletons.strings.identifiers.__find_and_load._data, ++ "_find_and_load", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__fix_up_module._ascii, ++ objects->singletons.strings.identifiers.__fix_up_module._data, ++ "_fix_up_module", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__get_sourcefile._ascii, ++ objects->singletons.strings.identifiers.__get_sourcefile._data, ++ "_get_sourcefile", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__handle_fromlist._ascii, ++ objects->singletons.strings.identifiers.__handle_fromlist._data, ++ "_handle_fromlist", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__initializing._ascii, ++ objects->singletons.strings.identifiers.__initializing._data, ++ "_initializing", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__is_text_encoding._ascii, ++ objects->singletons.strings.identifiers.__is_text_encoding._data, ++ "_is_text_encoding", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__lock_unlock_module._ascii, ++ objects->singletons.strings.identifiers.__lock_unlock_module._data, ++ "_lock_unlock_module", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__showwarnmsg._ascii, ++ objects->singletons.strings.identifiers.__showwarnmsg._data, ++ "_showwarnmsg", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__shutdown._ascii, ++ objects->singletons.strings.identifiers.__shutdown._data, ++ "_shutdown", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__slotnames._ascii, ++ objects->singletons.strings.identifiers.__slotnames._data, ++ "_slotnames", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__strptime_time._ascii, ++ objects->singletons.strings.identifiers.__strptime_time._data, ++ "_strptime_time", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__uninitialized_submodules._ascii, ++ objects->singletons.strings.identifiers.__uninitialized_submodules._data, ++ "_uninitialized_submodules", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__warn_unawaited_coroutine._ascii, ++ objects->singletons.strings.identifiers.__warn_unawaited_coroutine._data, ++ "_warn_unawaited_coroutine", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers.__xoptions._ascii, ++ objects->singletons.strings.identifiers.__xoptions._data, ++ "_xoptions", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._add._ascii, ++ objects->singletons.strings.identifiers._add._data, ++ "add", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._append._ascii, ++ objects->singletons.strings.identifiers._append._data, ++ "append", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._big._ascii, ++ objects->singletons.strings.identifiers._big._data, ++ "big", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._buffer._ascii, ++ objects->singletons.strings.identifiers._buffer._data, ++ "buffer", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._builtins._ascii, ++ objects->singletons.strings.identifiers._builtins._data, ++ "builtins", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._c_call._ascii, ++ objects->singletons.strings.identifiers._c_call._data, ++ "c_call", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._c_exception._ascii, ++ objects->singletons.strings.identifiers._c_exception._data, ++ "c_exception", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._c_return._ascii, ++ objects->singletons.strings.identifiers._c_return._data, ++ "c_return", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._call._ascii, ++ objects->singletons.strings.identifiers._call._data, ++ "call", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._clear._ascii, ++ objects->singletons.strings.identifiers._clear._data, ++ "clear", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._close._ascii, ++ objects->singletons.strings.identifiers._close._data, ++ "close", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._closed._ascii, ++ objects->singletons.strings.identifiers._closed._data, ++ "closed", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._code._ascii, ++ objects->singletons.strings.identifiers._code._data, ++ "code", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._copy._ascii, ++ objects->singletons.strings.identifiers._copy._data, ++ "copy", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._copyreg._ascii, ++ objects->singletons.strings.identifiers._copyreg._data, ++ "copyreg", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._decode._ascii, ++ objects->singletons.strings.identifiers._decode._data, ++ "decode", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._default._ascii, ++ objects->singletons.strings.identifiers._default._data, ++ "default", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._defaultaction._ascii, ++ objects->singletons.strings.identifiers._defaultaction._data, ++ "defaultaction", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._dictcomp._ascii, ++ objects->singletons.strings.identifiers._dictcomp._data, ++ "dictcomp", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._difference_update._ascii, ++ objects->singletons.strings.identifiers._difference_update._data, ++ "difference_update", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._dispatch_table._ascii, ++ objects->singletons.strings.identifiers._dispatch_table._data, ++ "dispatch_table", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._displayhook._ascii, ++ objects->singletons.strings.identifiers._displayhook._data, ++ "displayhook", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._enable._ascii, ++ objects->singletons.strings.identifiers._enable._data, ++ "enable", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._encode._ascii, ++ objects->singletons.strings.identifiers._encode._data, ++ "encode", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._encoding._ascii, ++ objects->singletons.strings.identifiers._encoding._data, ++ "encoding", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._end_lineno._ascii, ++ objects->singletons.strings.identifiers._end_lineno._data, ++ "end_lineno", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._end_offset._ascii, ++ objects->singletons.strings.identifiers._end_offset._data, ++ "end_offset", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._errors._ascii, ++ objects->singletons.strings.identifiers._errors._data, ++ "errors", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._excepthook._ascii, ++ objects->singletons.strings.identifiers._excepthook._data, ++ "excepthook", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._exception._ascii, ++ objects->singletons.strings.identifiers._exception._data, ++ "exception", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._extend._ascii, ++ objects->singletons.strings.identifiers._extend._data, ++ "extend", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._filename._ascii, ++ objects->singletons.strings.identifiers._filename._data, ++ "filename", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._fileno._ascii, ++ objects->singletons.strings.identifiers._fileno._data, ++ "fileno", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._fillvalue._ascii, ++ objects->singletons.strings.identifiers._fillvalue._data, ++ "fillvalue", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._filters._ascii, ++ objects->singletons.strings.identifiers._filters._data, ++ "filters", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._find_class._ascii, ++ objects->singletons.strings.identifiers._find_class._data, ++ "find_class", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._flush._ascii, ++ objects->singletons.strings.identifiers._flush._data, ++ "flush", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._genexpr._ascii, ++ objects->singletons.strings.identifiers._genexpr._data, ++ "genexpr", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._get._ascii, ++ objects->singletons.strings.identifiers._get._data, ++ "get", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._get_source._ascii, ++ objects->singletons.strings.identifiers._get_source._data, ++ "get_source", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._getattr._ascii, ++ objects->singletons.strings.identifiers._getattr._data, ++ "getattr", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._getstate._ascii, ++ objects->singletons.strings.identifiers._getstate._data, ++ "getstate", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._ignore._ascii, ++ objects->singletons.strings.identifiers._ignore._data, ++ "ignore", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._importlib._ascii, ++ objects->singletons.strings.identifiers._importlib._data, ++ "importlib", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._inf._ascii, ++ objects->singletons.strings.identifiers._inf._data, ++ "inf", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._intersection._ascii, ++ objects->singletons.strings.identifiers._intersection._data, ++ "intersection", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._isatty._ascii, ++ objects->singletons.strings.identifiers._isatty._data, ++ "isatty", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._isinstance._ascii, ++ objects->singletons.strings.identifiers._isinstance._data, ++ "isinstance", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._items._ascii, ++ objects->singletons.strings.identifiers._items._data, ++ "items", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._iter._ascii, ++ objects->singletons.strings.identifiers._iter._data, ++ "iter", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._join._ascii, ++ objects->singletons.strings.identifiers._join._data, ++ "join", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._keys._ascii, ++ objects->singletons.strings.identifiers._keys._data, ++ "keys", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._lambda._ascii, ++ objects->singletons.strings.identifiers._lambda._data, ++ "lambda", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._last_traceback._ascii, ++ objects->singletons.strings.identifiers._last_traceback._data, ++ "last_traceback", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._last_type._ascii, ++ objects->singletons.strings.identifiers._last_type._data, ++ "last_type", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._last_value._ascii, ++ objects->singletons.strings.identifiers._last_value._data, ++ "last_value", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._latin1._ascii, ++ objects->singletons.strings.identifiers._latin1._data, ++ "latin1", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._len._ascii, ++ objects->singletons.strings.identifiers._len._data, ++ "len", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._line._ascii, ++ objects->singletons.strings.identifiers._line._data, ++ "line", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._lineno._ascii, ++ objects->singletons.strings.identifiers._lineno._data, ++ "lineno", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._listcomp._ascii, ++ objects->singletons.strings.identifiers._listcomp._data, ++ "listcomp", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._little._ascii, ++ objects->singletons.strings.identifiers._little._data, ++ "little", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._locale._ascii, ++ objects->singletons.strings.identifiers._locale._data, ++ "locale", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._match._ascii, ++ objects->singletons.strings.identifiers._match._data, ++ "match", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._metaclass._ascii, ++ objects->singletons.strings.identifiers._metaclass._data, ++ "metaclass", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._mode._ascii, ++ objects->singletons.strings.identifiers._mode._data, ++ "mode", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._modules._ascii, ++ objects->singletons.strings.identifiers._modules._data, ++ "modules", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._mro._ascii, ++ objects->singletons.strings.identifiers._mro._data, ++ "mro", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._msg._ascii, ++ objects->singletons.strings.identifiers._msg._data, ++ "msg", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._n_fields._ascii, ++ objects->singletons.strings.identifiers._n_fields._data, ++ "n_fields", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._n_sequence_fields._ascii, ++ objects->singletons.strings.identifiers._n_sequence_fields._data, ++ "n_sequence_fields", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._n_unnamed_fields._ascii, ++ objects->singletons.strings.identifiers._n_unnamed_fields._data, ++ "n_unnamed_fields", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._name._ascii, ++ objects->singletons.strings.identifiers._name._data, ++ "name", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._newlines._ascii, ++ objects->singletons.strings.identifiers._newlines._data, ++ "newlines", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._next._ascii, ++ objects->singletons.strings.identifiers._next._data, ++ "next", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._obj._ascii, ++ objects->singletons.strings.identifiers._obj._data, ++ "obj", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._offset._ascii, ++ objects->singletons.strings.identifiers._offset._data, ++ "offset", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._onceregistry._ascii, ++ objects->singletons.strings.identifiers._onceregistry._data, ++ "onceregistry", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._opcode._ascii, ++ objects->singletons.strings.identifiers._opcode._data, ++ "opcode", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._open._ascii, ++ objects->singletons.strings.identifiers._open._data, ++ "open", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._parent._ascii, ++ objects->singletons.strings.identifiers._parent._data, ++ "parent", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._partial._ascii, ++ objects->singletons.strings.identifiers._partial._data, ++ "partial", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._path._ascii, ++ objects->singletons.strings.identifiers._path._data, ++ "path", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._peek._ascii, ++ objects->singletons.strings.identifiers._peek._data, ++ "peek", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._persistent_id._ascii, ++ objects->singletons.strings.identifiers._persistent_id._data, ++ "persistent_id", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._persistent_load._ascii, ++ objects->singletons.strings.identifiers._persistent_load._data, ++ "persistent_load", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._print_file_and_line._ascii, ++ objects->singletons.strings.identifiers._print_file_and_line._data, ++ "print_file_and_line", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._ps1._ascii, ++ objects->singletons.strings.identifiers._ps1._data, ++ "ps1", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._ps2._ascii, ++ objects->singletons.strings.identifiers._ps2._data, ++ "ps2", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._raw._ascii, ++ objects->singletons.strings.identifiers._raw._data, ++ "raw", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._read._ascii, ++ objects->singletons.strings.identifiers._read._data, ++ "read", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._read1._ascii, ++ objects->singletons.strings.identifiers._read1._data, ++ "read1", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._readable._ascii, ++ objects->singletons.strings.identifiers._readable._data, ++ "readable", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._readall._ascii, ++ objects->singletons.strings.identifiers._readall._data, ++ "readall", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._readinto._ascii, ++ objects->singletons.strings.identifiers._readinto._data, ++ "readinto", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._readinto1._ascii, ++ objects->singletons.strings.identifiers._readinto1._data, ++ "readinto1", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._readline._ascii, ++ objects->singletons.strings.identifiers._readline._data, ++ "readline", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._reducer_override._ascii, ++ objects->singletons.strings.identifiers._reducer_override._data, ++ "reducer_override", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._reload._ascii, ++ objects->singletons.strings.identifiers._reload._data, ++ "reload", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._replace._ascii, ++ objects->singletons.strings.identifiers._replace._data, ++ "replace", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._reset._ascii, ++ objects->singletons.strings.identifiers._reset._data, ++ "reset", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._return._ascii, ++ objects->singletons.strings.identifiers._return._data, ++ "return", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._reversed._ascii, ++ objects->singletons.strings.identifiers._reversed._data, ++ "reversed", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._seek._ascii, ++ objects->singletons.strings.identifiers._seek._data, ++ "seek", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._seekable._ascii, ++ objects->singletons.strings.identifiers._seekable._data, ++ "seekable", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._send._ascii, ++ objects->singletons.strings.identifiers._send._data, ++ "send", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._setcomp._ascii, ++ objects->singletons.strings.identifiers._setcomp._data, ++ "setcomp", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._setstate._ascii, ++ objects->singletons.strings.identifiers._setstate._data, ++ "setstate", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._sort._ascii, ++ objects->singletons.strings.identifiers._sort._data, ++ "sort", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._stderr._ascii, ++ objects->singletons.strings.identifiers._stderr._data, ++ "stderr", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._stdin._ascii, ++ objects->singletons.strings.identifiers._stdin._data, ++ "stdin", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._stdout._ascii, ++ objects->singletons.strings.identifiers._stdout._data, ++ "stdout", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._strict._ascii, ++ objects->singletons.strings.identifiers._strict._data, ++ "strict", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._symmetric_difference_update._ascii, ++ objects->singletons.strings.identifiers._symmetric_difference_update._data, ++ "symmetric_difference_update", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._tell._ascii, ++ objects->singletons.strings.identifiers._tell._data, ++ "tell", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._text._ascii, ++ objects->singletons.strings.identifiers._text._data, ++ "text", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._threading._ascii, ++ objects->singletons.strings.identifiers._threading._data, ++ "threading", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._throw._ascii, ++ objects->singletons.strings.identifiers._throw._data, ++ "throw", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._top._ascii, ++ objects->singletons.strings.identifiers._top._data, ++ "top", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._truncate._ascii, ++ objects->singletons.strings.identifiers._truncate._data, ++ "truncate", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._unraisablehook._ascii, ++ objects->singletons.strings.identifiers._unraisablehook._data, ++ "unraisablehook", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._values._ascii, ++ objects->singletons.strings.identifiers._values._data, ++ "values", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._version._ascii, ++ objects->singletons.strings.identifiers._version._data, ++ "version", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._warnings._ascii, ++ objects->singletons.strings.identifiers._warnings._data, ++ "warnings", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._warnoptions._ascii, ++ objects->singletons.strings.identifiers._warnoptions._data, ++ "warnoptions", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._writable._ascii, ++ objects->singletons.strings.identifiers._writable._data, ++ "writable", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._write._ascii, ++ objects->singletons.strings.identifiers._write._data, ++ "write", 1); ++ init_ascii_object(&objects->singletons.strings.identifiers._zipimporter._ascii, ++ objects->singletons.strings.identifiers._zipimporter._data, ++ "zipimporter", 1); ++ ++ for (i = 0; i < 128; i++) { ++ char literal[2]; ++ literal[0] = (char)i; ++ literal[1] = '\0'; ++ init_ascii_object(&objects->singletons.strings.ascii[i]._ascii, ++ objects->singletons.strings.ascii[i]._data, ++ literal, 1); ++ init_latin1_object(&objects->singletons.strings.latin1[i]._latin1, ++ objects->singletons.strings.latin1[i]._data, ++ (unsigned char)(i + 128)); ++ } ++ ++ init_immortal_varobject(&objects->singletons.tuple_empty.ob_base, ++ &PyTuple_Type, 0); ++} ++ ++void ++_PyRuntimeState_InitStaticDefaults(_PyRuntimeState *runtime) ++{ ++ memset(runtime, 0, sizeof(*runtime)); ++ runtime->gilstate.check_enabled = 1; ++ runtime->interpreters.next_id = -1; ++ init_static_global_objects(&runtime->global_objects); ++ init_static_interpreter(&runtime->_main_interpreter); ++} ++ ++#else + /* We use "initial" if the runtime gets re-used + (e.g. Py_Finalize() followed by Py_Initialize(). */ + static const _PyRuntimeState initial = _PyRuntimeState_INIT; ++#endif + _Py_COMP_DIAG_POP + + static int +@@ -62,20 +1180,23 @@ alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2, + /* Force default allocator, since _PyRuntimeState_Fini() must + use the same allocator than this function. */ + PyMemAllocatorEx old_alloc; ++ PyThread_type_lock lock1; ++ PyThread_type_lock lock2; ++ PyThread_type_lock lock3; + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + +- PyThread_type_lock lock1 = PyThread_allocate_lock(); ++ lock1 = PyThread_allocate_lock(); + if (lock1 == NULL) { + return -1; + } + +- PyThread_type_lock lock2 = PyThread_allocate_lock(); ++ lock2 = PyThread_allocate_lock(); + if (lock2 == NULL) { + PyThread_free_lock(lock1); + return -1; + } + +- PyThread_type_lock lock3 = PyThread_allocate_lock(); ++ lock3 = PyThread_allocate_lock(); + if (lock3 == NULL) { + PyThread_free_lock(lock1); + PyThread_free_lock(lock2); +@@ -149,7 +1270,11 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) + if (runtime->_initialized) { + // Py_Initialize() must be running again. + // Reset to _PyRuntimeState_INIT. ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++ _PyRuntimeState_InitStaticDefaults(runtime); ++#else + memcpy(runtime, &initial, sizeof(*runtime)); ++#endif + } + init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head, + unicode_next_index, lock1, lock2, lock3); +@@ -302,15 +1427,21 @@ PyInterpreterState * + PyInterpreterState_New(void) + { + PyInterpreterState *interp; +- PyThreadState *tstate = _PyThreadState_GET(); ++ PyThreadState *tstate; ++ PyThread_type_lock pending_lock; ++ _PyRuntimeState *runtime; ++ struct pyinterpreters *interpreters; ++ int64_t id; ++ PyInterpreterState *old_head; + + /* tstate is NULL when Py_InitializeFromConfig() calls + PyInterpreterState_New() to create the main interpreter. */ ++ tstate = _PyThreadState_GET(); + if (_PySys_Audit(tstate, "cpython.PyInterpreterState_New", NULL) < 0) { + return NULL; + } + +- PyThread_type_lock pending_lock = PyThread_allocate_lock(); ++ pending_lock = PyThread_allocate_lock(); + if (pending_lock == NULL) { + if (tstate != NULL) { + _PyErr_NoMemory(tstate); +@@ -319,8 +1450,8 @@ PyInterpreterState_New(void) + } + + /* Don't get runtime from tstate since tstate can be NULL. */ +- _PyRuntimeState *runtime = &_PyRuntime; +- struct pyinterpreters *interpreters = &runtime->interpreters; ++ runtime = &_PyRuntime; ++ interpreters = &runtime->interpreters; + + /* We completely serialize creation of multiple interpreters, since + it simplifies things here and blocking concurrent calls isn't a problem. +@@ -328,11 +1459,11 @@ PyInterpreterState_New(void) + after the main interpreter is created. */ + HEAD_LOCK(runtime); + +- int64_t id = interpreters->next_id; ++ id = interpreters->next_id; + interpreters->next_id += 1; + + // Allocate the interpreter and add it to the runtime state. +- PyInterpreterState *old_head = interpreters->head; ++ old_head = interpreters->head; + if (old_head == NULL) { + // We are creating the main interpreter. + assert(interpreters->main == NULL); +@@ -354,8 +1485,13 @@ PyInterpreterState_New(void) + goto error; + } + // Set to _PyInterpreterState_INIT. ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++ memset(interp, 0, sizeof(*interp)); ++ init_static_interpreter(interp); ++#else + memcpy(interp, &initial._main_interpreter, + sizeof(*interp)); ++#endif + // We need to adjust any fields that are different from the initial + // interpreter (as defined in _PyInterpreterState_INIT): + interp->_static = false; +@@ -391,6 +1527,7 @@ static void + interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) + { + _PyRuntimeState *runtime = interp->runtime; ++ PyThreadState *p; + + if (_PySys_Audit(tstate, "cpython.PyInterpreterState_Clear", NULL) < 0) { + _PyErr_Clear(tstate); +@@ -398,7 +1535,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) + + // Clear the current/main thread state last. + HEAD_LOCK(runtime); +- PyThreadState *p = interp->threads.head; ++ p = interp->threads.head; + HEAD_UNLOCK(runtime); + while (p != NULL) { + // See https://github.com/python/cpython/issues/102126 +@@ -490,6 +1627,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp) + { + _PyRuntimeState *runtime = interp->runtime; + struct pyinterpreters *interpreters = &runtime->interpreters; ++ PyInterpreterState **p; + zapthreads(interp, 0); + + _PyEval_FiniState(&interp->ceval); +@@ -498,7 +1636,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp) + _PyThreadState_Swap(&runtime->gilstate, NULL); + + HEAD_LOCK(runtime); +- PyInterpreterState **p; + for (p = &interpreters->head; ; p = &(*p)->next) { + if (*p == NULL) { + Py_FatalError("NULL interpreter"); +@@ -577,9 +1714,12 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) + PyInterpreterState * + PyInterpreterState_Get(void) + { +- PyThreadState *tstate = _PyThreadState_GET(); ++ PyThreadState *tstate; ++ PyInterpreterState *interp; ++ ++ tstate = _PyThreadState_GET(); + _Py_EnsureTstateNotNULL(tstate); +- PyInterpreterState *interp = tstate->interp; ++ interp = tstate->interp; + if (interp == NULL) { + Py_FatalError("no current interpreter"); + } +@@ -667,20 +1807,25 @@ _PyInterpreterState_IDIncref(PyInterpreterState *interp) + void + _PyInterpreterState_IDDecref(PyInterpreterState *interp) + { ++ struct _gilstate_runtime_state *gilstate; ++ int64_t refcount; ++ PyThreadState *tstate; ++ PyThreadState *save_tstate; ++ + assert(interp->id_mutex != NULL); + +- struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; ++ gilstate = &_PyRuntime.gilstate; + PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); + assert(interp->id_refcount != 0); + interp->id_refcount -= 1; +- int64_t refcount = interp->id_refcount; ++ refcount = interp->id_refcount; + PyThread_release_lock(interp->id_mutex); + + if (refcount == 0 && interp->requires_idref) { + // XXX Using the "head" thread isn't strictly correct. +- PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); ++ tstate = PyInterpreterState_ThreadHead(interp); + // XXX Possible GILState issues? +- PyThreadState *save_tstate = _PyThreadState_Swap(gilstate, tstate); ++ save_tstate = _PyThreadState_Swap(gilstate, tstate); + Py_EndInterpreter(tstate); + _PyThreadState_Swap(gilstate, save_tstate); + } +@@ -727,8 +1872,10 @@ PyInterpreterState_GetDict(PyInterpreterState *interp) + static _PyStackChunk* + allocate_chunk(int size_in_bytes, _PyStackChunk* previous) + { ++ _PyStackChunk *res; ++ + assert(size_in_bytes % sizeof(PyObject **) == 0); +- _PyStackChunk *res = _PyObject_VirtualAlloc(size_in_bytes); ++ res = _PyObject_VirtualAlloc(size_in_bytes); + if (res == NULL) { + return NULL; + } +@@ -807,12 +1954,15 @@ new_threadstate(PyInterpreterState *interp) + { + PyThreadState *tstate; + _PyRuntimeState *runtime = interp->runtime; ++ PyThreadState *new_tstate; ++ int used_newtstate; ++ uint64_t id; ++ PyThreadState *old_head; + // We don't need to allocate a thread state for the main interpreter + // (the common case), but doing it later for the other case revealed a + // reentrancy problem (deadlock). So for now we always allocate before + // taking the interpreters lock. See GH-96071. +- PyThreadState *new_tstate = alloc_threadstate(); +- int used_newtstate; ++ new_tstate = alloc_threadstate(); + if (new_tstate == NULL) { + return NULL; + } +@@ -820,10 +1970,10 @@ new_threadstate(PyInterpreterState *interp) + HEAD_LOCK(runtime); + + interp->threads.next_unique_id += 1; +- uint64_t id = interp->threads.next_unique_id; ++ id = interp->threads.next_unique_id; + + // Allocate the thread state and add it to the interpreter. +- PyThreadState *old_head = interp->threads.head; ++ old_head = interp->threads.head; + if (old_head == NULL) { + // It's the interpreter's initial thread state. + assert(id == 1); +@@ -838,9 +1988,14 @@ new_threadstate(PyInterpreterState *interp) + used_newtstate = 1; + tstate = new_tstate; + // Set to _PyThreadState_INIT. ++#if defined(_MSC_VER) && _MSC_VER < 1300 ++ memset(tstate, 0, sizeof(*tstate)); ++ init_static_threadstate(tstate); ++#else + memcpy(tstate, + &initial._main_interpreter._initial_thread, + sizeof(*tstate)); ++#endif + // We need to adjust any fields that are different from the initial + // thread (as defined in _PyThreadState_INIT): + tstate->_static = false; +@@ -911,6 +2066,8 @@ PyState_FindModule(PyModuleDef* module) + int + _PyState_AddModule(PyThreadState *tstate, PyObject* module, PyModuleDef* def) + { ++ PyInterpreterState *interp; ++ + if (!def) { + assert(_PyErr_Occurred(tstate)); + return -1; +@@ -922,7 +2079,7 @@ _PyState_AddModule(PyThreadState *tstate, PyObject* module, PyModuleDef* def) + return -1; + } + +- PyInterpreterState *interp = tstate->interp; ++ interp = tstate->interp; + if (!interp->modules_by_index) { + interp->modules_by_index = PyList_New(0); + if (!interp->modules_by_index) { +@@ -944,14 +2101,18 @@ _PyState_AddModule(PyThreadState *tstate, PyObject* module, PyModuleDef* def) + int + PyState_AddModule(PyObject* module, PyModuleDef* def) + { ++ PyThreadState *tstate; ++ PyInterpreterState *interp; ++ Py_ssize_t index; ++ + if (!def) { + Py_FatalError("module definition is NULL"); + return -1; + } + +- PyThreadState *tstate = _PyThreadState_GET(); +- PyInterpreterState *interp = tstate->interp; +- Py_ssize_t index = def->m_base.m_index; ++ tstate = _PyThreadState_GET(); ++ interp = tstate->interp; ++ index = def->m_base.m_index; + if (interp->modules_by_index && + index < PyList_GET_SIZE(interp->modules_by_index) && + module == PyList_GET_ITEM(interp->modules_by_index, index)) +@@ -965,8 +2126,12 @@ PyState_AddModule(PyObject* module, PyModuleDef* def) + int + PyState_RemoveModule(PyModuleDef* def) + { +- PyThreadState *tstate = _PyThreadState_GET(); +- PyInterpreterState *interp = tstate->interp; ++ PyThreadState *tstate; ++ PyInterpreterState *interp; ++ Py_ssize_t index; ++ ++ tstate = _PyThreadState_GET(); ++ interp = tstate->interp; + + if (def->m_slots) { + _PyErr_SetString(tstate, +@@ -975,7 +2140,7 @@ PyState_RemoveModule(PyModuleDef* def) + return -1; + } + +- Py_ssize_t index = def->m_base.m_index; ++ index = def->m_base.m_index; + if (index == 0) { + Py_FatalError("invalid module index"); + } +@@ -994,16 +2159,18 @@ PyState_RemoveModule(PyModuleDef* def) + void + _PyInterpreterState_ClearModules(PyInterpreterState *interp) + { ++ Py_ssize_t i; ++ + if (!interp->modules_by_index) { + return; + } + +- Py_ssize_t i; + for (i = 0; i < PyList_GET_SIZE(interp->modules_by_index); i++) { + PyObject *m = PyList_GET_ITEM(interp->modules_by_index, i); + if (PyModule_Check(m)) { ++ PyModuleDef *md; + /* cleanup the saved copy of module dicts */ +- PyModuleDef *md = PyModule_GetDef(m); ++ md = PyModule_GetDef(m); + if (md) { + Py_CLEAR(md->m_base.m_copy); + } +@@ -1074,12 +2241,16 @@ static void + tstate_delete_common(PyThreadState *tstate, + struct _gilstate_runtime_state *gilstate) + { ++ PyInterpreterState *interp; ++ _PyRuntimeState *runtime; ++ _PyStackChunk *chunk; ++ + _Py_EnsureTstateNotNULL(tstate); +- PyInterpreterState *interp = tstate->interp; ++ interp = tstate->interp; + if (interp == NULL) { + Py_FatalError("NULL interpreter"); + } +- _PyRuntimeState *runtime = interp->runtime; ++ runtime = interp->runtime; + + HEAD_LOCK(runtime); + if (tstate->prev) { +@@ -1098,7 +2269,7 @@ tstate_delete_common(PyThreadState *tstate, + { + PyThread_tss_set(&gilstate->autoTSSkey, NULL); + } +- _PyStackChunk *chunk = tstate->datastack_chunk; ++ chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; +@@ -1131,8 +2302,10 @@ PyThreadState_Delete(PyThreadState *tstate) + void + _PyThreadState_DeleteCurrent(PyThreadState *tstate) + { ++ struct _gilstate_runtime_state *gilstate; ++ + _Py_EnsureTstateNotNULL(tstate); +- struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate; ++ gilstate = &tstate->interp->runtime->gilstate; + tstate_delete_common(tstate, gilstate); + _PyRuntimeGILState_SetThreadState(gilstate, NULL); + _PyEval_ReleaseLock(tstate); +@@ -1159,12 +2332,14 @@ void + _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate) + { + PyInterpreterState *interp = tstate->interp; ++ PyThreadState *list; ++ PyThreadState *p, *next; + + HEAD_LOCK(runtime); + /* Remove all thread states, except tstate, from the linked list of + thread states. This will allow calling PyThreadState_Clear() + without holding the lock. */ +- PyThreadState *list = interp->threads.head; ++ list = interp->threads.head; + if (list == tstate) { + list = tstate->next; + } +@@ -1181,7 +2356,6 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate) + /* Clear and deallocate all stale thread states. Even if this + executes Python code, we should be safe since it executes + in the current thread, not one of the stale threads. */ +- PyThreadState *p, *next; + for (p = list; p; p = next) { + next = p->next; + PyThreadState_Clear(p); +@@ -1279,15 +2453,18 @@ PyThreadState_GetInterpreter(PyThreadState *tstate) + PyFrameObject* + PyThreadState_GetFrame(PyThreadState *tstate) + { ++ _PyInterpreterFrame *f; ++ PyFrameObject *frame; ++ + assert(tstate != NULL); +- _PyInterpreterFrame *f = tstate->cframe->current_frame; ++ f = tstate->cframe->current_frame; + while (f && _PyFrame_IsIncomplete(f)) { + f = f->previous; + } + if (f == NULL) { + return NULL; + } +- PyFrameObject *frame = _PyFrame_GetFrameObject(f); ++ frame = _PyFrame_GetFrameObject(f); + if (frame == NULL) { + PyErr_Clear(); + } +@@ -1317,6 +2494,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) + { + _PyRuntimeState *runtime = &_PyRuntime; + PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp; ++ PyThreadState *tstate; + + /* Although the GIL is held, a few C API functions can be called + * without the GIL held, and in particular some that create and +@@ -1325,7 +2503,9 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) + * head_mutex for the duration. + */ + HEAD_LOCK(runtime); +- for (PyThreadState *tstate = interp->threads.head; tstate != NULL; tstate = tstate->next) { ++ for (tstate = interp->threads.head; tstate != NULL; tstate = tstate->next) { ++ PyObject *old_exc; ++ + if (tstate->thread_id != id) { + continue; + } +@@ -1337,7 +2517,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) + * deadlock, we need to release head_mutex before + * the decref. + */ +- PyObject *old_exc = tstate->async_exc; ++ old_exc = tstate->async_exc; + Py_XINCREF(exc); + tstate->async_exc = exc; + HEAD_UNLOCK(runtime); +@@ -1389,17 +2569,22 @@ PyObject * + _PyThread_CurrentFrames(void) + { + PyThreadState *tstate = _PyThreadState_GET(); ++ PyObject *result; ++ int gc_was_enabled; ++ _PyRuntimeState *runtime; ++ PyInterpreterState *i; ++ + if (_PySys_Audit(tstate, "sys._current_frames", NULL) < 0) { + return NULL; + } + +- PyObject *result = PyDict_New(); ++ result = PyDict_New(); + if (result == NULL) { + return NULL; + } + + // gh-106883: Disable the GC as this can cause the interpreter to deadlock +- int gc_was_enabled = PyGC_Disable(); ++ gc_was_enabled = PyGC_Disable(); + + /* for i in all interpreters: + * for t in all of i's thread states: +@@ -1407,29 +2592,33 @@ _PyThread_CurrentFrames(void) + * Because these lists can mutate even when the GIL is held, we + * need to grab head_mutex for the duration. + */ +- _PyRuntimeState *runtime = tstate->interp->runtime; ++ runtime = tstate->interp->runtime; + HEAD_LOCK(runtime); +- PyInterpreterState *i; + for (i = runtime->interpreters.head; i != NULL; i = i->next) { + PyThreadState *t; + for (t = i->threads.head; t != NULL; t = t->next) { +- _PyInterpreterFrame *frame = t->cframe->current_frame; ++ _PyInterpreterFrame *frame; ++ PyObject *id; ++ PyObject *frameobj; ++ int stat; ++ ++ frame = t->cframe->current_frame; + while (frame && _PyFrame_IsIncomplete(frame)) { + frame = frame->previous; + } + if (frame == NULL) { + continue; + } +- PyObject *id = PyLong_FromUnsignedLong(t->thread_id); ++ id = PyLong_FromUnsignedLong(t->thread_id); + if (id == NULL) { + goto fail; + } +- PyObject *frameobj = (PyObject *)_PyFrame_GetFrameObject(frame); ++ frameobj = (PyObject *)_PyFrame_GetFrameObject(frame); + if (frameobj == NULL) { + Py_DECREF(id); + goto fail; + } +- int stat = PyDict_SetItem(result, id, frameobj); ++ stat = PyDict_SetItem(result, id, frameobj); + Py_DECREF(id); + if (stat < 0) { + goto fail; +@@ -1456,6 +2645,10 @@ PyObject * + _PyThread_CurrentExceptions(void) + { + PyThreadState *tstate = _PyThreadState_GET(); ++ PyObject *result; ++ int gc_was_enabled; ++ _PyRuntimeState *runtime; ++ PyInterpreterState *i; + + _Py_EnsureTstateNotNULL(tstate); + +@@ -1463,13 +2656,13 @@ _PyThread_CurrentExceptions(void) + return NULL; + } + +- PyObject *result = PyDict_New(); ++ result = PyDict_New(); + if (result == NULL) { + return NULL; + } + + // gh-106883: Disable the GC as this can cause the interpreter to deadlock +- int gc_was_enabled = PyGC_Disable(); ++ gc_was_enabled = PyGC_Disable(); + + /* for i in all interpreters: + * for t in all of i's thread states: +@@ -1477,26 +2670,30 @@ _PyThread_CurrentExceptions(void) + * Because these lists can mutate even when the GIL is held, we + * need to grab head_mutex for the duration. + */ +- _PyRuntimeState *runtime = tstate->interp->runtime; ++ runtime = tstate->interp->runtime; + HEAD_LOCK(runtime); +- PyInterpreterState *i; + for (i = runtime->interpreters.head; i != NULL; i = i->next) { + PyThreadState *t; + for (t = i->threads.head; t != NULL; t = t->next) { +- _PyErr_StackItem *err_info = _PyErr_GetTopmostException(t); ++ _PyErr_StackItem *err_info; ++ PyObject *id; ++ PyObject *exc_info; ++ int stat; ++ ++ err_info = _PyErr_GetTopmostException(t); + if (err_info == NULL) { + continue; + } +- PyObject *id = PyLong_FromUnsignedLong(t->thread_id); ++ id = PyLong_FromUnsignedLong(t->thread_id); + if (id == NULL) { + goto fail; + } +- PyObject *exc_info = _PyErr_StackItemToExcInfoTuple(err_info); ++ exc_info = _PyErr_StackItemToExcInfoTuple(err_info); + if (exc_info == NULL) { + Py_DECREF(id); + goto fail; + } +- int stat = PyDict_SetItem(result, id, exc_info); ++ stat = PyDict_SetItem(result, id, exc_info); + Py_DECREF(id); + Py_DECREF(exc_info); + if (stat < 0) { +@@ -1559,6 +2756,8 @@ _PyGILState_Init(_PyRuntimeState *runtime) + PyStatus + _PyGILState_SetTstate(PyThreadState *tstate) + { ++ struct _gilstate_runtime_state *gilstate; ++ + if (!_Py_IsMainInterpreter(tstate->interp)) { + /* Currently, PyGILState is shared by all interpreters. The main + * interpreter is responsible to initialize it. */ +@@ -1569,7 +2768,7 @@ _PyGILState_SetTstate(PyThreadState *tstate) + assert(tstate != NULL); + assert(tstate->interp != NULL); + +- struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate; ++ gilstate = &tstate->interp->runtime->gilstate; + + gilstate->autoInterpreterState = tstate->interp; + assert(PyThread_tss_get(&gilstate->autoTSSkey) == NULL); +@@ -1676,6 +2875,7 @@ int + PyGILState_Check(void) + { + struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; ++ PyThreadState *tstate; + if (!gilstate->check_enabled) { + return 1; + } +@@ -1684,7 +2884,7 @@ PyGILState_Check(void) + return 1; + } + +- PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate); ++ tstate = _PyRuntimeGILState_GetThreadState(gilstate); + if (tstate == NULL) { + return 0; + } +@@ -1697,6 +2897,8 @@ PyGILState_Ensure(void) + { + _PyRuntimeState *runtime = &_PyRuntime; + struct _gilstate_runtime_state *gilstate = &runtime->gilstate; ++ PyThreadState *tcur; ++ int current; + + /* Note that we do not auto-init Python here - apart from + potential races with 2 threads auto-initializing, pep-311 +@@ -1708,8 +2910,7 @@ PyGILState_Ensure(void) + assert(_PyEval_ThreadsInitialized(runtime)); + assert(gilstate->autoInterpreterState); + +- PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey); +- int current; ++ tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey); + if (tcur == NULL) { + /* Create a new Python thread state for this thread */ + tcur = PyThreadState_New(gilstate->autoInterpreterState); +@@ -1841,24 +3042,27 @@ int + _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data) + { + PyThreadState *tstate = _PyThreadState_GET(); ++ PyInterpreterState *interp; ++ crossinterpdatafunc getdata; ++ int res; + #ifdef Py_DEBUG + // The caller must hold the GIL + _Py_EnsureTstateNotNULL(tstate); + #endif +- PyInterpreterState *interp = tstate->interp; ++ interp = tstate->interp; + + // Reset data before re-populating. +- *data = (_PyCrossInterpreterData){0}; ++ memset(data, 0, sizeof(*data)); + data->free = PyMem_RawFree; // Set a default that may be overridden. + + // Call the "getdata" func for the object. + Py_INCREF(obj); +- crossinterpdatafunc getdata = _lookup_getdata(obj); ++ getdata = _lookup_getdata(obj); + if (getdata == NULL) { + Py_DECREF(obj); + return -1; + } +- int res = getdata(obj, data); ++ res = getdata(obj, data); + Py_DECREF(obj); + if (res != 0) { + return -1; +@@ -1912,13 +3116,16 @@ _call_in_interpreter(struct _gilstate_runtime_state *gilstate, + void + _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data) + { ++ PyInterpreterState *interp; ++ struct _gilstate_runtime_state *gilstate; ++ + if (data->data == NULL && data->obj == NULL) { + // Nothing to release! + return; + } + + // Switch to the original interpreter. +- PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp); ++ interp = _PyInterpreterState_LookUpID(data->interp); + if (interp == NULL) { + // The interpreter was already destroyed. + if (data->free != NULL) { +@@ -1928,7 +3135,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data) + } + + // "Release" the data and/or the object. +- struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; ++ gilstate = &_PyRuntime.gilstate; + _call_in_interpreter(gilstate, interp, _release_xidata, data); + } + +@@ -1966,6 +3173,9 @@ int + _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, + crossinterpdatafunc getdata) + { ++ struct _xidregistry *xidregistry; ++ int res; ++ + if (!PyType_Check(cls)) { + PyErr_Format(PyExc_ValueError, "only classes may be registered"); + return -1; +@@ -1978,12 +3188,12 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, + // Make sure the class isn't ever deallocated. + Py_INCREF((PyObject *)cls); + +- struct _xidregistry *xidregistry = &_PyRuntime.xidregistry ; ++ xidregistry = &_PyRuntime.xidregistry; + PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK); + if (xidregistry->head == NULL) { + _register_builtins_for_crossinterpreter_data(xidregistry); + } +- int res = _register_xidata(xidregistry, cls, getdata); ++ res = _register_xidata(xidregistry, cls, getdata); + PyThread_release_lock(xidregistry->mutex); + return res; + } +@@ -1995,11 +3205,13 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, + crossinterpdatafunc + _PyCrossInterpreterData_Lookup(PyObject *obj) + { +- struct _xidregistry *xidregistry = &_PyRuntime.xidregistry ; ++ struct _xidregistry *xidregistry = &_PyRuntime.xidregistry; + PyObject *cls = PyObject_Type(obj); + crossinterpdatafunc getdata = NULL; ++ struct _xidregitem *cur; ++ + PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK); +- struct _xidregitem *cur = xidregistry->head; ++ cur = xidregistry->head; + if (cur == NULL) { + _register_builtins_for_crossinterpreter_data(xidregistry); + cur = xidregistry->head; +@@ -2189,8 +3401,10 @@ _PyInterpreterState_GetConfigCopy(PyConfig *config) + const PyConfig* + _Py_GetConfig(void) + { ++ PyThreadState *tstate; ++ + assert(PyGILState_Check()); +- PyThreadState *tstate = _PyThreadState_GET(); ++ tstate = _PyThreadState_GET(); + return _PyInterpreterState_GetConfig(tstate->interp); + } + +@@ -2200,10 +3414,13 @@ static PyObject ** + push_chunk(PyThreadState *tstate, int size) + { + int allocate_size = DATA_STACK_CHUNK_SIZE; ++ _PyStackChunk *new; ++ PyObject **res; ++ + while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) { + allocate_size *= 2; + } +- _PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk); ++ new = allocate_chunk(allocate_size, tstate->datastack_chunk); + if (new == NULL) { + return NULL; + } +@@ -2216,7 +3433,7 @@ push_chunk(PyThreadState *tstate, int size) + // When new is the "root" chunk (i.e. new->previous == NULL), we can keep + // _PyThreadState_PopFrame from freeing it later by "skipping" over the + // first element: +- PyObject **res = &new->data[new->previous == NULL]; ++ res = &new->data[new->previous == NULL]; + tstate->datastack_top = res + size; + return res; + } +@@ -2239,8 +3456,10 @@ _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size) + void + _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame) + { ++ PyObject **base; ++ + assert(tstate->datastack_chunk); +- PyObject **base = (PyObject **)frame; ++ base = (PyObject **)frame; + if (base == &tstate->datastack_chunk->data[0]) { + _PyStackChunk *chunk = tstate->datastack_chunk; + _PyStackChunk *previous = chunk->previous; diff --git a/compat/msvc600/pathcch.h b/compat/msvc600/pathcch.h new file mode 100644 index 0000000..d5b78e6 --- /dev/null +++ b/compat/msvc600/pathcch.h @@ -0,0 +1,84 @@ +#ifndef PYWIN9X_COMPAT_MSVC600_PATHCCH_H +#define PYWIN9X_COMPAT_MSVC600_PATHCCH_H + +/* + * Narrow PathCchFindExtension compatibility for the VC6/MSVC600 probe. + * + * CPython 3.11's Modules/getpath.c includes only to call + * PathCchFindExtension() from getpath_isxfile(). MSVC 6.0's Windows SDK + * predates PathCch, so provide just that one API shape for the project-local + * VC6 include path. Modern builds should keep using the platform SDK header; + * this file is not installed into CPython or a system include directory. + */ + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + +#ifndef _WINDOWS_ +#include +#endif +#include + +#ifndef PCWSTR +typedef const WCHAR *PCWSTR; +#endif +#ifndef PWSTR +typedef WCHAR *PWSTR; +#endif +#ifndef S_OK +#define S_OK ((HRESULT)0L) +#endif +#ifndef E_INVALIDARG +#define E_INVALIDARG ((HRESULT)0x80070057L) +#endif + +static HRESULT +PathCchFindExtension(PCWSTR pszPath, size_t cchPath, PCWSTR *ppszExt) +{ + size_t i; + size_t last_sep; + size_t last_dot; + int have_dot; + + if (pszPath == NULL || ppszExt == NULL || cchPath == 0) { + return E_INVALIDARG; + } + + last_sep = 0; + last_dot = 0; + have_dot = 0; + + for (i = 0; i < cchPath; ++i) { + WCHAR ch = pszPath[i]; + if (ch == L'\0') { + if (have_dot) { + *ppszExt = pszPath + last_dot; + } + else { + *ppszExt = pszPath + i; + } + return S_OK; + } + if (ch == L'\\' || ch == L'/' || ch == L':') { + last_sep = i + 1; + have_dot = 0; + } + else if (ch == L'.' && i >= last_sep) { + last_dot = i; + have_dot = 1; + } + } + + *ppszExt = NULL; + return E_INVALIDARG; +} + +#else +/* + * This compatibility header is intentionally scoped to VC6. If a modern + * compiler finds it, the include path is wrong: use the real Windows SDK + * pathcch.h instead to avoid shadowing the platform declaration. + */ +#error "compat/msvc600/pathcch.h is only for MSVC 6.0; use the Windows SDK pathcch.h on modern compilers" +#endif + +#endif /* PYWIN9X_COMPAT_MSVC600_PATHCCH_H */ diff --git a/compat/msvc600/stdint.h b/compat/msvc600/stdint.h new file mode 100644 index 0000000..7759721 --- /dev/null +++ b/compat/msvc600/stdint.h @@ -0,0 +1,45 @@ +#ifndef PYTHON_WIN9X_MSVC600_STDINT_H +#define PYTHON_WIN9X_MSVC600_STDINT_H + +/* VC6-only fallback for the C99 header. + * + * Visual C++ 6.0 (_MSC_VER 1200) predates C99 and ships no . This + * project-local header is found ahead of any system only because + * compat/msvc600 is placed first on the VC6 probe scripts' include path + * (scripts/vc6-probe.sh, scripts/vc6-probe-core.sh, scripts/vc6-probe- + * pythoncore-frontier.sh); it is never installed anywhere a standards- + * conforming compiler's own would be found instead, so it never + * shadows a real one. + * + * First consumer: cpython/Modules/_blake2/impl/blake2.h and + * blake2-impl.h, which use only uint8_t, uint32_t, and uint64_t (verified + * by grepping every fixed-width identifier used across Modules/_blake2/, + * including the blake2b/blake2s/*-ref.c reference implementations and + * clinic-generated wrappers: no int8_t/int16_t/int32_t/int64_t or intptr_t/ + * uintptr_t appear anywhere in that tree). `size_t` is used too, but that + * already comes from , which VC6 has natively. + * + * compat/msvc600/inttypes.h already defines exactly these typedefs (plus + * the PRI* macros CPython's own Include/pyport.h needs from a real C99 + * ) for this same VC6 target. Rather than re-declaring + * uint8_t/uint32_t/uint64_t a second time under a second include guard + * (which would risk a duplicate-typedef error in any translation unit that + * ends up including both this header and , e.g. anything that + * pulls in both Python.h and a -using third-party header like + * blake2.h), this header just forwards to it. inttypes.h's own include + * guard makes this forwarding idempotent no matter which of the two headers + * a given translation unit reaches first. + * + * Width assumptions (all already relied upon by inttypes.h and unchanged + * here): uint8_t = unsigned char (1 byte), uint32_t = unsigned long + * (4 bytes on Win32/ILP32), uint64_t = unsigned __int64 (VC6's non-standard + * 64-bit extension, 8 bytes). These match the sizes BLAKE2 requires. + */ + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 +#error "compat/msvc600/stdint.h is a VC6-only (_MSC_VER < 1300) fallback; a standard should be used instead." +#endif + +#include "inttypes.h" + +#endif /* PYTHON_WIN9X_MSVC600_STDINT_H */ diff --git a/scripts/fixtures/vc6_compound_literal_smoke.c b/scripts/fixtures/vc6_compound_literal_smoke.c index 73709db..b35bbdf 100644 --- a/scripts/fixtures/vc6_compound_literal_smoke.c +++ b/scripts/fixtures/vc6_compound_literal_smoke.c @@ -7,15 +7,16 @@ * three distinct patterns: * * 1. `status = _PyStatus_OK();` -- a compound-literal macro used as a - * plain assignment's right-hand side. Fixed by calling the existing - * public API function PyStatus_Ok() instead, which - * Python/initconfig.c defines as `return _PyStatus_OK();` -- the - * identical value, no header change needed. - * 2. `cf = _PyCompilerFlags_INIT;` -- likewise a compound-literal macro + * plain assignment's right-hand side. The shared macro now expands to + * a VC6-only internal helper that assigns PyStatus fields explicitly, + * while newer compilers keep the original compound-literal form. + * 2. `status = _PyStatus_ERR("...");` -- same compound-literal macro + * pattern for ERROR statuses, now using a VC6-only explicit helper. + * 3. `cf = _PyCompilerFlags_INIT;` -- likewise a compound-literal macro * used as a plain assignment. Fixed by assigning PyCompilerFlags's * two fields explicitly (cf_flags, cf_feature_version), matching the * macro's own definition field-for-field. - * 3. `_PyArgv args = { .argc = argc, ... };` -- a designated-initializer + * 4. `_PyArgv args = { .argc = argc, ... };` -- a designated-initializer * aggregate initializer with no macro involved. Fixed by declaring * the variable bare and assigning each field explicitly; field order * does not matter for plain assignment, unlike an initializer list. @@ -35,8 +36,18 @@ vc6_status_ok_smoke(void) { PyStatus status; - /* pattern 1: was `status = _PyStatus_OK();` */ - status = PyStatus_Ok(); + /* pattern 1: VC6-only _PyStatus_OK() macro fallback helper. */ + status = _PyStatus_OK(); + return status; +} + +PyStatus +vc6_status_error_smoke(void) +{ + PyStatus status; + + /* pattern 2: VC6-only _PyStatus_ERR() macro fallback helper. */ + status = _PyStatus_ERR("vc6 status error smoke"); return status; } diff --git a/scripts/fixtures/vc6_pathcch_smoke.c b/scripts/fixtures/vc6_pathcch_smoke.c new file mode 100644 index 0000000..27abc06 --- /dev/null +++ b/scripts/fixtures/vc6_pathcch_smoke.c @@ -0,0 +1,59 @@ +/* Focused compile smoke test for compat/msvc600/pathcch.h. + * + * The VC6 compatibility header intentionally implements only the single + * PathCch API used by cpython/Modules/getpath.c: PathCchFindExtension(). + * This fixture keeps the representative path cases in one place for the + * VC6 probe. The probe is compile-only, so the checks are ordinary C code + * that can also be run later by a tiny Windows harness if needed. + */ +#include +#include + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +static int +pathcch_expect_ext(PCWSTR path, size_t cch, size_t offset) +{ + PCWSTR ext; + HRESULT hr; + + ext = NULL; + hr = PathCchFindExtension(path, cch, &ext); + return SUCCEEDED(hr) && ext == path + offset; +} + +static int +pathcch_expect_invalid(PCWSTR path, size_t cch) +{ + PCWSTR ext; + HRESULT hr; + + ext = (PCWSTR)1; + hr = PathCchFindExtension(path, cch, &ext); + return FAILED(hr); +} + +int +vc6_pathcch_find_extension_smoke(void) +{ + static const WCHAR exe_path[] = L"C:\\Python311\\python.exe"; + static const WCHAR no_ext[] = L"C:\\Python311\\python"; + static const WCHAR dir_dot[] = L"C:\\tmp.dir\\python"; + static const WCHAR dotfile[] = L"C:\\Python311\\.pythonrc"; + static const WCHAR trailing_dir[] = L"C:\\bin\\python.exe\\"; + static const WCHAR multi_dot[] = L"C:\\tmp\\archive.tar.gz"; + int ok; + + ok = 1; + ok = ok && pathcch_expect_ext(exe_path, ARRAYSIZE(exe_path), 20); /* .exe */ + ok = ok && pathcch_expect_ext(no_ext, ARRAYSIZE(no_ext), 19); /* NUL */ + ok = ok && pathcch_expect_ext(dir_dot, ARRAYSIZE(dir_dot), 17); /* NUL, directory dot ignored */ + ok = ok && pathcch_expect_ext(dotfile, ARRAYSIZE(dotfile), 13); /* dotfile extension */ + ok = ok && pathcch_expect_ext(trailing_dir, ARRAYSIZE(trailing_dir), 18); /* NUL after separator */ + ok = ok && pathcch_expect_ext(multi_dot, ARRAYSIZE(multi_dot), 18); /* last suffix */ + ok = ok && pathcch_expect_invalid(exe_path, 4); /* too small: no NUL */ + ok = ok && pathcch_expect_invalid(NULL, ARRAYSIZE(exe_path)); + return ok ? 0 : 1; +} diff --git a/scripts/fixtures/vc6_stdint_smoke.c b/scripts/fixtures/vc6_stdint_smoke.c new file mode 100644 index 0000000..7788352 --- /dev/null +++ b/scripts/fixtures/vc6_stdint_smoke.c @@ -0,0 +1,76 @@ +/* Focused compile smoke test for compat/msvc600/stdint.h. + * + * The VC6 compatibility header forwards to the existing + * compat/msvc600/inttypes.h typedefs. This fixture exercises exactly the + * subset that cpython/Modules/_blake2/impl/blake2-impl.h needs: uint8_t, + * uint32_t, and uint64_t, in the same load/store/rotate shapes that file + * uses, plus a compile-time width check for each. It also includes + * alongside in the same translation unit, the way + * a Python.h + blake2.h translation unit would, to guard against the + * duplicate-typedef failure mode the stdint.h header is designed to avoid. + */ +#include +#include +#include +#include + +typedef char vc6_stdint_check_uint8_is_1_byte[(sizeof(uint8_t) == 1) ? 1 : -1]; +typedef char vc6_stdint_check_uint32_is_4_bytes[(sizeof(uint32_t) == 4) ? 1 : -1]; +typedef char vc6_stdint_check_uint64_is_8_bytes[(sizeof(uint64_t) == 8) ? 1 : -1]; + +static uint32_t +vc6_stdint_load32(const void *src) +{ + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= ((uint32_t)(*p++)) << 8; + w |= ((uint32_t)(*p++)) << 16; + w |= ((uint32_t)(*p++)) << 24; + return w; +} + +static uint64_t +vc6_stdint_load64(const void *src) +{ + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= ((uint64_t)(*p++)) << 8; + w |= ((uint64_t)(*p++)) << 16; + w |= ((uint64_t)(*p++)) << 24; + w |= ((uint64_t)(*p++)) << 32; + w |= ((uint64_t)(*p++)) << 40; + w |= ((uint64_t)(*p++)) << 48; + w |= ((uint64_t)(*p++)) << 56; + return w; +} + +static uint32_t +vc6_stdint_rotl32(const uint32_t w, const unsigned c) +{ + return (w << c) | (w >> (32 - c)); +} + +static uint64_t +vc6_stdint_rotl64(const uint64_t w, const unsigned c) +{ + return (w << c) | (w >> (64 - c)); +} + +int +vc6_stdint_smoke(void) +{ + static const uint8_t bytes32[4] = { 0x01, 0x02, 0x03, 0x04 }; + static const uint8_t bytes64[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + uint32_t w32; + uint64_t w64; + int ok; + + w32 = vc6_stdint_load32(bytes32); + w64 = vc6_stdint_load64(bytes64); + + ok = 1; + ok = ok && (w32 == 0x04030201UL); + ok = ok && (vc6_stdint_rotl32(w32, 8) == ((w32 << 8) | (w32 >> 24))); + ok = ok && (vc6_stdint_rotl64(w64, 8) == ((w64 << 8) | (w64 >> 56))); + return ok ? 0 : 1; +} diff --git a/scripts/generate-getpath-frozen.sh b/scripts/generate-getpath-frozen.sh new file mode 100755 index 0000000..dbe318d --- /dev/null +++ b/scripts/generate-getpath-frozen.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# +# Generate the CPython frozen getpath.py header into ignored build output. +# +# CPython's build documents this target in Makefile.pre.in: +# Python/frozen_modules/getpath.h: Modules/getpath.py ... +# Programs/_freeze_module.py getpath Modules/getpath.py Python/frozen_modules/getpath.h +# +# This script intentionally writes under build/generated/cpython/... so the +# repository does not track generated bytecode headers or vendor files. +# +# Usage: +# scripts/generate-getpath-frozen.sh [output-root] +# +# Output: +# /cpython/Python/frozen_modules/getpath.h +# default output-root: build/generated + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CPYTHON_ROOT="$REPO_ROOT/cpython" +OUTPUT_ROOT="${1:-$REPO_ROOT/build/generated}" +OUT_DIR="$OUTPUT_ROOT/cpython/Python/frozen_modules" +OUT_HEADER="$OUT_DIR/getpath.h" +FREEZE_SCRIPT="$CPYTHON_ROOT/Programs/_freeze_module.py" +INPUT="$CPYTHON_ROOT/Modules/getpath.py" + +usage() { + sed -n '11,19p' "$REPO_ROOT/scripts/generate-getpath-frozen.sh" +} + +if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then + usage + exit 0 +fi + +for required in "$CPYTHON_ROOT" "$FREEZE_SCRIPT" "$INPUT"; do + if [ ! -e "$required" ]; then + echo "generate-getpath-frozen: missing prerequisite: $required" >&2 + exit 2 + fi +done + +if ! command -v python3 >/dev/null 2>&1; then + echo "generate-getpath-frozen: missing prerequisite: python3" >&2 + exit 2 +fi + +mkdir -p "$OUT_DIR" +python3 "$FREEZE_SCRIPT" getpath "$INPUT" "$OUT_HEADER" +status=$? +if [ "$status" -ne 0 ]; then + echo "generate-getpath-frozen: _freeze_module.py failed with exit $status" >&2 + exit "$status" +fi + +if [ ! -s "$OUT_HEADER" ]; then + echo "generate-getpath-frozen: expected nonempty output missing: $OUT_HEADER" >&2 + exit 2 +fi + +printf '%s\n' "${OUT_HEADER#$REPO_ROOT/}" diff --git a/scripts/generate-getpath-frozen.test.sh b/scripts/generate-getpath-frozen.test.sh new file mode 100755 index 0000000..9b7a964 --- /dev/null +++ b/scripts/generate-getpath-frozen.test.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +# +# Regression tests for reproducible getpath.py frozen-header generation. + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +GENERATOR="$REPO_ROOT/scripts/generate-getpath-frozen.sh" +TMP_ROOT="$REPO_ROOT/build/test-getpath-frozen" +OUT_HEADER="$TMP_ROOT/cpython/Python/frozen_modules/getpath.h" +DIRECT_HEADER="$TMP_ROOT/direct/getpath.h" + +fail=0 +pass() { echo "ok - $1"; } +bad() { echo "not ok - $1"; fail=1; } + +rm -rf "$TMP_ROOT" +out="$($GENERATOR "$TMP_ROOT" 2>&1)" +status=$? +if [ "$status" -eq 0 ]; then + pass "generator exits 0" +else + bad "generator exits 0 (got exit $status)" + echo "$out" +fi + +if [ "$out" = "build/test-getpath-frozen/cpython/Python/frozen_modules/getpath.h" ]; then + pass "generator reports the project-local build-relative output path" +else + bad "generator reports the project-local build-relative output path (got: $out)" +fi + +if [ -s "$OUT_HEADER" ]; then + pass "generator writes a nonempty getpath.h under build/" +else + bad "generator writes a nonempty getpath.h under build/" +fi + +first_line="$(sed -n '1p' "$OUT_HEADER" 2>/dev/null)" +if [ "$first_line" = '/* Auto-generated by Programs/_freeze_module.py */' ]; then + pass "generated header records the host-Python _freeze_module.py path" +else + bad "generated header records the host-Python _freeze_module.py path (got: $first_line)" +fi + +second_line="$(sed -n '2p' "$OUT_HEADER" 2>/dev/null)" +if [ "$second_line" = 'const unsigned char _Py_M__getpath[] = {' ]; then + pass "generated header declares the expected getpath frozen symbol" +else + bad "generated header declares the expected getpath frozen symbol (got: $second_line)" +fi + +python3 - "$OUT_HEADER" <<'PY' +import marshal +import re +import sys +from pathlib import Path +path = Path(sys.argv[1]) +text = path.read_text() +if not text.endswith('};\n'): + raise SystemExit('header does not end with closing array marker') +match = re.search(r'const unsigned char _Py_M__getpath\[\] = \{\n(?P.*?)\};\n\Z', text, re.S) +if not match: + raise SystemExit('array body not found') +lines = match.group('body').splitlines() +values = [] +for index, line in enumerate(lines, 1): + if not line.startswith(' '): + raise SystemExit(f'line {index} is not four-space indented') + payload = line.strip() + if not payload.endswith(','): + raise SystemExit(f'line {index} is missing trailing comma') + nums = [part for part in payload[:-1].split(',') if part] + if len(nums) > 16: + raise SystemExit(f'line {index} has more than 16 bytes') + if index < len(lines) and len(nums) != 16: + raise SystemExit(f'non-final line {index} has {len(nums)} bytes, expected 16') + for num in nums: + value = int(num) + if not 0 <= value <= 255: + raise SystemExit(f'byte out of range: {value}') + values.append(value) +code = marshal.loads(bytes(values)) +if code.co_filename != '': + raise SystemExit(f'unexpected code filename: {code.co_filename!r}') +if code.co_name != '': + raise SystemExit(f'unexpected code name: {code.co_name!r}') +print('format-ok') +PY +format_status=$? +if [ "$format_status" -eq 0 ]; then + pass "generated byte array unmarshals as frozen getpath code with CPython format" +else + bad "generated byte array unmarshals as frozen getpath code with CPython format" +fi + +mkdir -p "$(dirname "$DIRECT_HEADER")" +python3 "$REPO_ROOT/cpython/Programs/_freeze_module.py" getpath \ + "$REPO_ROOT/cpython/Modules/getpath.py" "$DIRECT_HEADER" +if cmp -s "$OUT_HEADER" "$DIRECT_HEADER"; then + pass "generator output matches direct Programs/_freeze_module.py invocation exactly" +else + bad "generator output matches direct Programs/_freeze_module.py invocation exactly" +fi + +frontier_out="$(bash "$REPO_ROOT/scripts/vc6-probe-pythoncore-frontier.sh" --list-only 2>&1)" +frontier_status=$? +if [ "$frontier_status" -eq 0 ] && printf '%s\n' "$frontier_out" | grep -q $'^compile\tcpython/Modules/getpath.c\t'; then + pass "frontier list still starts from Modules/getpath.c without requiring generated output" +else + bad "frontier list still starts from Modules/getpath.c without requiring generated output" + echo "$frontier_out" +fi + +if [ "$fail" -ne 0 ]; then + echo "FAILED" + exit 1 +fi +echo "ALL TESTS PASSED" diff --git a/scripts/vc6-probe-core.test.sh b/scripts/vc6-probe-core.test.sh index 4bf4ef1..989ae61 100755 --- a/scripts/vc6-probe-core.test.sh +++ b/scripts/vc6-probe-core.test.sh @@ -261,11 +261,17 @@ EOF # --- positive case: the isolated compound-literal/designated- # initializer smoke fixture compiles clean. It exercises, self- # contained (aside from the real Python.h/pycore_initconfig.h types - # it needs), the three replacement patterns applied to main.c: calling - # PyStatus_Ok() instead of the _PyStatus_OK() compound-literal macro, - # explicit field assignment instead of the _PyCompilerFlags_INIT - # compound-literal macro, and explicit field assignment instead of a - # _PyArgv designated-initializer aggregate. --- + # it needs), the four replacement patterns now in use: the VC6-only + # _PyStatus_OK() helper (not PyStatus_Ok(), avoiding recursion), the + # VC6-only _PyStatus_ERR() helper, explicit field assignment instead of + # the _PyCompilerFlags_INIT compound-literal macro, and explicit field + # assignment instead of a _PyArgv designated-initializer aggregate. --- + if grep -q '#[[:space:]]*define[[:space:]]*_PyStatus_OK().*PyStatus_Ok' "$REPO_ROOT/cpython/Include/internal/pycore_initconfig.h"; then + bad "pycore_initconfig.h: VC6 _PyStatus_OK() helper does not recurse through PyStatus_Ok()" + else + pass "pycore_initconfig.h: VC6 _PyStatus_OK() helper does not recurse through PyStatus_Ok()" + fi + out_compound="$("$PROBE" scripts/fixtures/vc6_compound_literal_smoke.c 2>&1)" status_compound=$? diff --git a/scripts/vc6-probe-minlink.sh b/scripts/vc6-probe-minlink.sh new file mode 100755 index 0000000..80441f1 --- /dev/null +++ b/scripts/vc6-probe-minlink.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# +# Minimal VC6 link-frontier probe for the Windows 9x port. +# +# This is deliberately smaller than CPython's full PCbuild/pythoncore.vcxproj: +# it compiles only the translation units already proven by the core compile +# probes plus the tiny Programs/python.c executable entry point, then invokes +# LINK.EXE under Wine. A successful executable link is not expected yet; the +# purpose of this milestone is to verify that the build can get past CL.EXE +# for the current frontier and reach a real VC6 linker diagnostic with a +# reproducible command line. +# +# The MSVC600 bundle is an external, local-only prerequisite; nothing under +# MSVC600/ is part of this project's source. +# +# Usage: +# scripts/vc6-probe-minlink.sh +# +# Environment: +# MSVC600_ROOT override the MSVC600 location (default: /MSVC600) +# WINEPREFIX override the Wine prefix (default: ~/.wine-win9xport) + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# Reuse winpath()/strip_prefix() from vc6-probe.sh instead of duplicating +# them; sourcing it does not run the probe itself (see its own guard). +# shellcheck source=scripts/vc6-probe.sh +source "$REPO_ROOT/scripts/vc6-probe.sh" + +run_probe_minlink() { + MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}" + BUILD_DIR="$REPO_ROOT/build/vc6-probe-minlink" + + CL="$MSVC600_ROOT/VC98/Bin/CL.EXE" + LINK="$MSVC600_ROOT/VC98/Bin/LINK.EXE" + VCVARS="$MSVC600_ROOT/VC98/Bin/VCVARS32.BAT" + + # Keep this list intentionally tiny and aligned with the post-core-probe + # milestone: python.vcxproj's single executable TU plus the three core TUs + # that are currently known to compile under scripts/vc6-probe-core.sh. + SOURCES=( + "cpython/Programs/python.c" + "cpython/Modules/main.c" + "cpython/Python/pylifecycle.c" + "cpython/Python/pystate.c" + ) + + for required in "$CL" "$LINK" "$VCVARS" "$MSVC600_ROOT/VC98/Include" \ + "$MSVC600_ROOT/VC98/Lib" "$MSVC600_ROOT/Common/MSDev98/Bin"; do + if [ ! -e "$required" ]; then + echo "vc6-probe-minlink: missing prerequisite: $required" >&2 + return 2 + fi + done + local source_rel + for source_rel in "${SOURCES[@]}"; do + if [ ! -e "$REPO_ROOT/$source_rel" ]; then + echo "vc6-probe-minlink: missing source: $REPO_ROOT/$source_rel" >&2 + return 2 + fi + done + + if ! command -v wine >/dev/null 2>&1; then + echo "vc6-probe-minlink: wine is not installed" >&2 + return 2 + fi + + export WINEPREFIX="${WINEPREFIX:-$HOME/.wine-win9xport}" + export WINEDEBUG="${WINEDEBUG:--all}" + + # CL.EXE loads C1/C2 from VC98/Bin and MSPDB60.DLL from Common/MSDev98/Bin; + # LINK.EXE also needs the VC98 tools and default libraries. + export WINEPATH="$(winpath "$MSVC600_ROOT/VC98/Bin");$(winpath "$MSVC600_ROOT/Common/MSDev98/Bin")" + + rm -rf "$BUILD_DIR" + mkdir -p "$BUILD_DIR" + + INCLUDE_ARGS=( + "$(winpath "$REPO_ROOT/compat/msvc600")" + "$(winpath "$REPO_ROOT/cpython/Include/internal")" + "$(winpath "$REPO_ROOT/cpython/Include")" + "$(winpath "$REPO_ROOT/cpython/PC")" + "$(winpath "$MSVC600_ROOT/VC98/Include")" + ) + + echo "== MSVC600 minimal link-frontier probe ==" + echo "sources:" + for source_rel in "${SOURCES[@]}"; do + echo " - $source_rel" + done + echo "prefix : $WINEPREFIX" + echo + + local obj_args="" + local source_abs obj_name obj_abs cmd status + for source_rel in "${SOURCES[@]}"; do + source_abs="$REPO_ROOT/$source_rel" + obj_name="${source_rel#cpython/}" + obj_name="${obj_name//\//_}" + obj_name="${obj_name%.c}.obj" + obj_abs="$BUILD_DIR/$obj_name" + obj_args+=" $(winpath "$obj_abs")" + + cmd="call $(winpath "$VCVARS") && cd /d $(winpath "$REPO_ROOT/cpython") && cl /nologo /D Py_BUILD_CORE /D Py_BUILD_CORE_BUILTIN /D Py_ENABLE_SHARED /D _USRDLL" + for include_arg in "${INCLUDE_ARGS[@]}"; do + cmd+=" /I $include_arg" + done + cmd+=" /c $(winpath "$source_abs") /Fo$(winpath "$obj_abs")" + + wine cmd /c "$cmd" 2>&1 | + grep -v '^[0-9a-f]\{4\}:err:' | + strip_prefix "$(winpath "$REPO_ROOT")\\" + status="${PIPESTATUS[0]}" + if [ "$status" -ne 0 ]; then + echo + echo "== cl.exe exit status: $status ==" + echo "vc6-probe-minlink: compile failed before link at $source_rel" >&2 + return "$status" + fi + done + + echo + echo "== LINK.EXE attempt ==" + cmd="call $(winpath "$VCVARS") && cd /d $(winpath "$REPO_ROOT/cpython") && link /nologo /subsystem:console /out:$(winpath "$BUILD_DIR/python-min.exe") /libpath:$(winpath "$MSVC600_ROOT/VC98/Lib")$obj_args kernel32.lib user32.lib advapi32.lib shell32.lib version.lib ws2_32.lib" + + wine cmd /c "$cmd" 2>&1 | + grep -v '^[0-9a-f]\{4\}:err:' | + strip_prefix "$(winpath "$REPO_ROOT")\\" + status="${PIPESTATUS[0]}" + echo + echo "== link.exe exit status: $status ==" + return "$status" +} + +if [ "${BASH_SOURCE[0]}" = "${0}" ]; then + run_probe_minlink "$@" + exit "$?" +fi diff --git a/scripts/vc6-probe-pathcch.test.sh b/scripts/vc6-probe-pathcch.test.sh new file mode 100755 index 0000000..01867e7 --- /dev/null +++ b/scripts/vc6-probe-pathcch.test.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# +# Regression tests for the narrow VC6 compat/msvc600/pathcch.h shim. +# +# Skipped (not failed) when Wine + MSVC600 are unavailable, matching the other +# VC6 probe test scripts. The live check is compile-only: it verifies that the +# fixture using representative PathCchFindExtension paths reaches cl.exe exit 0. +# +# Usage: scripts/vc6-probe-pathcch.test.sh + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PROBE="$REPO_ROOT/scripts/vc6-probe-core.sh" + +fail=0 +pass() { echo "ok - $1"; } +bad() { echo "not ok - $1"; fail=1; } + +if grep -q 'PathCchFindExtension' "$REPO_ROOT/compat/msvc600/pathcch.h" && \ + grep -q 'defined(_MSC_VER).*1200' "$REPO_ROOT/compat/msvc600/pathcch.h"; then + pass "compat/msvc600/pathcch.h provides a VC6-scoped PathCchFindExtension shim" +else + bad "compat/msvc600/pathcch.h provides a VC6-scoped PathCchFindExtension shim" +fi + +MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}" +if command -v wine >/dev/null 2>&1 && [ -e "$MSVC600_ROOT/VC98/Bin/CL.EXE" ]; then + out="$($PROBE scripts/fixtures/vc6_pathcch_smoke.c 2>&1)" + status=$? + + if [ "$status" -eq 0 ]; then + pass "PathCchFindExtension smoke fixture compiles under VC6 (exit 0)" + else + bad "PathCchFindExtension smoke fixture compiles under VC6 (exit $status)" + echo "$out" + fi + + if printf '%s' "$out" | grep -q "Cannot open include file: 'pathcch.h'"; then + bad "pathcch smoke fixture does not regress to missing pathcch.h" + else + pass "pathcch smoke fixture does not regress to missing pathcch.h" + fi + + if printf '%s' "$out" | grep -qi 'error'; then + bad "pathcch smoke fixture: no compiler errors in output" + else + pass "pathcch smoke fixture: no compiler errors in output" + fi +else + echo "skip - wine/MSVC600 not available; skipping live pathcch integration check" +fi + +if [ "$fail" -ne 0 ]; then + echo "FAILED" + exit 1 +fi +echo "ALL TESTS PASSED" diff --git a/scripts/vc6-probe-pythoncore-frontier.sh b/scripts/vc6-probe-pythoncore-frontier.sh new file mode 100755 index 0000000..5a96ed1 --- /dev/null +++ b/scripts/vc6-probe-pythoncore-frontier.sh @@ -0,0 +1,376 @@ +#!/usr/bin/env bash +# +# Source-list-driven VC6 compile frontier for CPython's pythoncore project. +# +# This reads cpython/PCbuild/pythoncore.vcxproj entries, safely +# normalizes their Windows-style paths into project-local cpython/... sources, +# reports entries that this VC6/Wine frontier intentionally cannot consume +# yet, and compiles supported sources one at a time into build artifacts. It +# stops at the first cl.exe failure and returns cl.exe's real exit status. +# +# This is a compile-only (/c) frontier: no pythoncore.dll/python.exe link or +# runtime success is claimed. +# +# The MSVC600 bundle is an external, local-only prerequisite; nothing under +# MSVC600/ is part of this project's source. +# +# Usage: +# scripts/vc6-probe-pythoncore-frontier.sh +# scripts/vc6-probe-pythoncore-frontier.sh --list-only +# scripts/vc6-probe-pythoncore-frontier.sh --limit N +# +# Environment: +# MSVC600_ROOT override the MSVC600 location (default: /MSVC600) +# WINEPREFIX override the Wine prefix (default: ~/.wine-win9xport) +# VC6_FRONTIER_FORCE set to 1 to ignore incremental object freshness + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# Reuse winpath()/strip_prefix() from vc6-probe.sh instead of duplicating +# them; sourcing it does not run the probe itself (see its own guard). +# shellcheck source=scripts/vc6-probe.sh +source "$REPO_ROOT/scripts/vc6-probe.sh" + +FRONTIER_SCRIPT="$REPO_ROOT/scripts/vc6-probe-pythoncore-frontier.sh" +PROJECT_REL="cpython/PCbuild/pythoncore.vcxproj" +PROJECT_ABS="$REPO_ROOT/$PROJECT_REL" +BUILD_DIR="$REPO_ROOT/build/vc6-probe-pythoncore-frontier" +SOURCE_LIST_TSV="$BUILD_DIR/pythoncore-sources.tsv" +GENERATED_ROOT="$REPO_ROOT/build/generated" +GENERATED_CPYTHON_ROOT="$GENERATED_ROOT/cpython" +GETPATH_GENERATOR="$REPO_ROOT/scripts/generate-getpath-frozen.sh" +GETPATH_FROZEN_HEADER="$GENERATED_CPYTHON_ROOT/Python/frozen_modules/getpath.h" + +usage() { + sed -n '15,27p' "$FRONTIER_SCRIPT" +} + +emit_source_list() { + python3 - "$PROJECT_ABS" "$REPO_ROOT" <<'PY' +import os +import posixpath +import sys +import xml.etree.ElementTree as ET + +project = os.path.abspath(sys.argv[1]) +repo = os.path.abspath(sys.argv[2]) +source_root = os.path.join(repo, "cpython") +project_dir = os.path.dirname(project) +ns = "{http://schemas.microsoft.com/developer/msbuild/2003}" + +substitutions = { + "$(PyVPath)": r"..\\..", + "$(PyDebugExt)": "", + "$(SysWinVer)": "3.11", +} + +def expand_msbuild(value): + for key, repl in substitutions.items(): + value = value.replace(key, repl) + return value + +def normalize_include(include): + raw = include.strip() + expanded = expand_msbuild(raw) + if "$" in expanded or "%" in expanded: + return None, "unsupported-msbuild-macro" + path = expanded.replace("\\", "/") + if len(path) >= 2 and path[1] == ":": + return None, "absolute-windows-path" + abs_path = os.path.abspath(os.path.join(project_dir, path)) + try: + rel_to_source = os.path.relpath(abs_path, source_root) + except ValueError: + return None, "outside-cpython-tree" + rel_posix = rel_to_source.replace(os.sep, "/") + if rel_posix == ".." or rel_posix.startswith("../") or posixpath.isabs(rel_posix): + return None, "outside-cpython-tree" + norm = posixpath.normpath(rel_posix) + if norm == "." or norm.startswith("../") or "/../" in f"/{norm}/": + return None, "unsafe-normalized-path" + return "cpython/" + norm, "" + +def split_definitions(text): + if not text: + return [] + text = expand_msbuild(" ".join(text.split())) + defs = [] + for chunk in text.split(";"): + chunk = chunk.strip() + if not chunk or chunk == "%(PreprocessorDefinitions)": + continue + if "$" in chunk or "%" in chunk: + defs.append("UNSUPPORTED_MSBUILD_DEFINE=" + chunk) + else: + defs.append(chunk) + return defs + +def classify(rel, inherited_condition, own_condition): + cond = f"{inherited_condition or ''} {own_condition or ''}" + if "IncludeExternals" in cond: + return "skip-external IncludeExternals-conditioned source" + if rel is None: + return "skip-unsupported" + if rel == "cpython/Python/deepfreeze/deepfreeze.c": + return "skip-generated deepfreeze source" + return "compile" + +def walk(node, inherited_condition=""): + condition = node.attrib.get("Condition", "") + combined = " ".join(x for x in (inherited_condition, condition) if x) + if node.tag == ns + "ClCompile" and "Include" in node.attrib: + include = node.attrib["Include"] + rel, norm_error = normalize_include(include) + defs = [] + for child in node: + if child.tag == ns + "PreprocessorDefinitions": + defs.extend(split_definitions(child.text or "")) + action = classify(rel, inherited_condition, condition) + reason = action + if action == "compile" and norm_error: + action = "skip-unsupported" + reason = f"skip-unsupported {norm_error}" + elif action == "skip-unsupported" and norm_error: + reason = f"skip-unsupported {norm_error}" + display_rel = rel or include.replace("\\", "/") + print("\t".join([action, display_rel, include, " ".join(defs), reason])) + for child in node: + walk(child, combined) + +root = ET.parse(project).getroot() +walk(root) +PY +} + +quote_define_for_cmd() { + local define="$1" + # Keep CL's /D string literal quotes after CL reads the generated response + # file. CL interprets C-string backslashes in /D values while parsing the + # define, so double the define's own backslashes before protecting literal + # quotes for CL's command-line parser. + # Example: VPATH="..\\.." must arrive at C preprocessing as "..\\..", not + # "..\.." and not an unterminated string. + define="${define//\\/\\\\}" + define="${define//\"/\\\"}" + printf '%s' "$define" +} + +render_compile_command_for_test() { + local cmd='cl /nologo' + local define + for define in "$@"; do + cmd+=" /D $(quote_define_for_cmd "$define")" + done + printf '%s' "$cmd" +} + +obj_name_for_source() { + local source_rel="$1" + source_rel="${source_rel#cpython/}" + source_rel="${source_rel//\//_}" + printf '%s' "${source_rel%.c}.obj" +} + +generate_getpath_frozen_header() { + if [ ! -x "$GETPATH_GENERATOR" ]; then + echo "vc6-probe-pythoncore-frontier: missing prerequisite: executable $GETPATH_GENERATOR" >&2 + return 2 + fi + "$GETPATH_GENERATOR" "$GENERATED_ROOT" >/dev/null +} + +source_for_compile() { + local source_rel="$1" + local source_abs="$2" + if [ "$source_rel" != "cpython/Modules/getpath.c" ]; then + printf '%s' "$source_abs" + return 0 + fi + + # Modules/getpath.c includes "../Python/frozen_modules/getpath.h" relative + # to the compiling source file. Keep generated files under ignored build/ + # output by compiling a byte-for-byte copy from a generated cpython-shaped + # tree where that documented relative include resolves. + if [ ! -s "$GETPATH_FROZEN_HEADER" ]; then + echo "vc6-probe-pythoncore-frontier: missing generated getpath header: $GETPATH_FROZEN_HEADER" >&2 + return 2 + fi + local generated_source="$GENERATED_CPYTHON_ROOT/Modules/getpath.c" + mkdir -p "$(dirname "$generated_source")" + cp "$source_abs" "$generated_source" + printf '%s' "$generated_source" +} + +run_probe_pythoncore_frontier() { + local list_only=0 limit=0 arg + while [ "$#" -gt 0 ]; do + arg="$1" + case "$arg" in + --list-only) + list_only=1 + shift + ;; + --limit) + if [ "$#" -lt 2 ]; then + echo "vc6-probe-pythoncore-frontier: --limit requires a number" >&2 + return 2 + fi + limit="$2" + case "$limit" in + ''|*[!0-9]*) echo "vc6-probe-pythoncore-frontier: invalid --limit: $limit" >&2; return 2 ;; + esac + shift 2 + ;; + -h|--help) + usage + return 0 + ;; + *) + echo "vc6-probe-pythoncore-frontier: unknown argument: $arg" >&2 + usage >&2 + return 2 + ;; + esac + done + + mkdir -p "$BUILD_DIR" + emit_source_list > "$SOURCE_LIST_TSV" + + if [ "$list_only" -eq 1 ]; then + cat "$SOURCE_LIST_TSV" + return 0 + fi + + MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}" + local CL="$MSVC600_ROOT/VC98/Bin/CL.EXE" + local VCVARS="$MSVC600_ROOT/VC98/Bin/VCVARS32.BAT" + + generate_getpath_frozen_header || return $? + + for required in "$PROJECT_ABS" "$CL" "$VCVARS" "$MSVC600_ROOT/VC98/Include" \ + "$MSVC600_ROOT/Common/MSDev98/Bin"; do + if [ ! -e "$required" ]; then + echo "vc6-probe-pythoncore-frontier: missing prerequisite: $required" >&2 + return 2 + fi + done + + if ! command -v wine >/dev/null 2>&1; then + echo "vc6-probe-pythoncore-frontier: wine is not installed" >&2 + return 2 + fi + + export WINEPREFIX="${WINEPREFIX:-$HOME/.wine-win9xport}" + export WINEDEBUG="${WINEDEBUG:--all}" + + # CL.EXE loads C1/C2 from VC98/Bin and MSPDB60.DLL from Common/MSDev98/Bin. + export WINEPATH="$(winpath "$MSVC600_ROOT/VC98/Bin");$(winpath "$MSVC600_ROOT/Common/MSDev98/Bin")" + + local INCLUDE_ARGS=( + "$(winpath "$REPO_ROOT/compat/msvc600")" + "$(winpath "$REPO_ROOT/cpython/Python")" + "$(winpath "$REPO_ROOT/cpython/Include/internal")" + "$(winpath "$REPO_ROOT/cpython/Include")" + "$(winpath "$REPO_ROOT/cpython/PC")" + "$(winpath "$MSVC600_ROOT/VC98/Include")" + ) + + local COMMON_DEFINES=( + "_USRDLL" + "Py_BUILD_CORE" + "Py_BUILD_CORE_BUILTIN" + "Py_ENABLE_SHARED" + 'MS_DLL_ID="3.11"' + ) + + echo "== MSVC600 pythoncore compile-frontier probe ==" + echo "project: $PROJECT_REL" + echo "list : ${SOURCE_LIST_TSV#$REPO_ROOT/}" + echo "prefix : $WINEPREFIX" + echo + + local action source_rel raw_include defs reason + local total=0 skipped=0 compiled=0 cached=0 considered=0 + while IFS=$'\t' read -r action source_rel raw_include defs reason; do + total=$((total + 1)) + if [ "$action" != "compile" ]; then + skipped=$((skipped + 1)) + echo "skip: $source_rel ($reason; raw=$raw_include)" + continue + fi + if [ "$limit" -ne 0 ] && [ "$considered" -ge "$limit" ]; then + break + fi + considered=$((considered + 1)) + + local source_abs="$REPO_ROOT/$source_rel" + if [ ! -f "$source_abs" ]; then + echo "vc6-probe-pythoncore-frontier: missing source from project list: $source_rel" >&2 + echo "== frontier summary: total=$total compiled=$compiled cached=$cached skipped=$skipped ==" + return 2 + fi + + local obj_abs="$BUILD_DIR/$(obj_name_for_source "$source_rel")" + local compile_source_abs + compile_source_abs="$(source_for_compile "$source_rel" "$source_abs")" || return $? + if [ "${VC6_FRONTIER_FORCE:-0}" != "1" ] && [ -f "$obj_abs" ] && \ + [ "$obj_abs" -nt "$source_abs" ] && [ "$obj_abs" -nt "$PROJECT_ABS" ] && \ + [ "$obj_abs" -nt "$FRONTIER_SCRIPT" ] && [ "$obj_abs" -nt "$GETPATH_FROZEN_HEADER" ]; then + cached=$((cached + 1)) + echo "cached: $source_rel -> ${obj_abs#$REPO_ROOT/}" + continue + fi + + echo "compile: $source_rel -> ${obj_abs#$REPO_ROOT/}" + local rsp_abs="${obj_abs%.obj}.rsp" + local include_arg define + { + printf '/nologo\r\n' + for define in "${COMMON_DEFINES[@]}"; do + printf '/D %s\r\n' "$(quote_define_for_cmd "$define")" + done + if [ -n "$defs" ]; then + for define in $defs; do + if [ "${define#UNSUPPORTED_MSBUILD_DEFINE=}" != "$define" ]; then + echo "vc6-probe-pythoncore-frontier: unsupported per-file define in $source_rel: ${define#UNSUPPORTED_MSBUILD_DEFINE=}" >&2 + echo "== frontier summary: total=$total compiled=$compiled cached=$cached skipped=$skipped ==" + return 2 + fi + printf '/D %s\r\n' "$(quote_define_for_cmd "$define")" + done + fi + for include_arg in "${INCLUDE_ARGS[@]}"; do + printf '/I %s\r\n' "$include_arg" + done + printf '/c\r\n' + printf '%s\r\n' "$(winpath "$compile_source_abs")" + printf '/Fo%s\r\n' "$(winpath "$obj_abs")" + } > "$rsp_abs" + local cmd="call $(winpath "$VCVARS") && cd /d $(winpath "$REPO_ROOT/cpython") && cl @$(winpath "$rsp_abs")" + + wine cmd /c "$cmd" 2>&1 | + grep -v '^[0-9a-f]\{4\}:err:' | + strip_prefix "$(winpath "$REPO_ROOT")\\" + local status="${PIPESTATUS[0]}" + if [ "$status" -ne 0 ]; then + echo + echo "== cl.exe exit status: $status ==" + echo "vc6-probe-pythoncore-frontier: first compile blocker: $source_rel" >&2 + echo "== frontier summary: total=$total compiled=$compiled cached=$cached skipped=$skipped ==" + return "$status" + fi + compiled=$((compiled + 1)) + done < "$SOURCE_LIST_TSV" + + echo + echo "== frontier summary: total=$total compiled=$compiled cached=$cached skipped=$skipped ==" + echo "vc6-probe-pythoncore-frontier: supported pythoncore compile frontier completed" + return 0 +} + +if [ "${BASH_SOURCE[0]}" = "${0}" ]; then + run_probe_pythoncore_frontier "$@" + exit "$?" +fi diff --git a/scripts/vc6-probe-pythoncore-frontier.test.sh b/scripts/vc6-probe-pythoncore-frontier.test.sh new file mode 100755 index 0000000..6c61939 --- /dev/null +++ b/scripts/vc6-probe-pythoncore-frontier.test.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +# +# Regression tests for scripts/vc6-probe-pythoncore-frontier.sh. +# +# The no-toolchain checks exercise the source-list parser/normalizer and the +# per-file define handling that make the frontier source-list-driven. When +# Wine + MSVC600 are available, a bounded live run verifies that the harness +# reports cl.exe's real first-blocker status. +# +# Usage: scripts/vc6-probe-pythoncore-frontier.test.sh + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PROBE="$REPO_ROOT/scripts/vc6-probe-pythoncore-frontier.sh" + +fail=0 +pass() { echo "ok - $1"; } +bad() { echo "not ok - $1"; fail=1; } + +out="$($PROBE --list-only 2>&1)" +status=$? + +if [ "$status" -eq 0 ]; then + pass "frontier --list-only exits 0" +else + bad "frontier --list-only exits 0 (got exit $status)" + echo "$out" +fi + +count="$(printf '%s\n' "$out" | awk 'NF { n++ } END { print n+0 }')" +if [ "$count" -eq 198 ]; then + pass "frontier parses all 198 pythoncore.vcxproj ClCompile entries" +else + bad "frontier parses all 198 pythoncore.vcxproj ClCompile entries (got $count)" +fi + +first_fields="$(printf '%s\n' "$out" | awk -F '\t' 'NR == 1 { print $1 "|" $2 "|" $3 }')" +if [ "$first_fields" = 'compile|cpython/Modules/getpath.c|..\Modules\getpath.c' ]; then + pass "frontier normalizes the first Windows-style source path to cpython/Modules/getpath.c" +else + bad "frontier normalizes the first Windows-style source path to cpython/Modules/getpath.c (got: $first_fields)" +fi + +getpath_defs="$(printf '%s\n' "$out" | awk -F '\t' '$2 == "cpython/Modules/getpath.c" { print $4; exit }')" +case "$getpath_defs" in + *'PREFIX=NULL'*'EXEC_PREFIX=NULL'*'VERSION=NULL'*'VPATH="..\\.."'*'PYDEBUGEXT=""'*'PLATLIBDIR="DLLs"'*) + pass "frontier preserves getpath.c per-file defines with project-local substitutions" + ;; + *) + bad "frontier preserves getpath.c per-file defines with project-local substitutions (got: $getpath_defs)" + ;; +esac + +sysmodule_defs="$(printf '%s\n' "$out" | awk -F '\t' '$2 == "cpython/Python/sysmodule.c" { print $4; exit }')" +case "$sysmodule_defs" in + *'VPATH="..\\.."'*) + pass "frontier preserves sysmodule.c VPATH per-file define" + ;; + *) + bad "frontier preserves sysmodule.c VPATH per-file define (got: $sysmodule_defs)" + ;; +esac + +# Source the probe after --list-only so the guarded helper definitions can be +# tested without launching Wine or requiring MSVC600. +# shellcheck source=scripts/vc6-probe-pythoncore-frontier.sh +source "$PROBE" +rendered_cmd="$(render_compile_command_for_test 'VPATH="..\\.."' 'PYDEBUGEXT=""' 'PLATLIBDIR="DLLs"')" +case "$rendered_cmd" in + *' /D VPATH=\"..\\\\..\"'*' /D PYDEBUGEXT=\"\"'*' /D PLATLIBDIR=\"DLLs\"'*) + pass "frontier renders quoted per-file string defines safely for CL response files" + ;; + *) + bad "frontier renders quoted per-file string defines safely for CL response files (got: $rendered_cmd)" + ;; +esac + +if printf '%s\n' "$out" | grep -q $'^skip-generated deepfreeze source\tcpython/Python/deepfreeze/deepfreeze.c\t'; then + pass "frontier reports the generated deepfreeze source instead of compiling it blindly" +else + bad "frontier reports the generated deepfreeze source instead of compiling it blindly" +fi + +if printf '%s\n' "$out" | grep -q $'^skip-external IncludeExternals-conditioned source\tcpython/Modules/zlibmodule.c\t'; then + pass "frontier reports IncludeExternals-conditioned in-tree zlibmodule.c as external" +else + bad "frontier reports IncludeExternals-conditioned in-tree zlibmodule.c as external" +fi + +if printf '%s\n' "$out" | grep -q $'^skip-external IncludeExternals-conditioned source\t$(zlibDir)/adler32.c\t'; then + pass "frontier reports macro-based zlibDir sources as external without normalizing outside the repo" +else + bad "frontier reports macro-based zlibDir sources as external without normalizing outside the repo" +fi + +if printf '%s\n' "$out" | cut -f2 | grep -q '\\'; then + bad "frontier normalized source column contains no backslashes" +else + pass "frontier normalized source column contains no backslashes" +fi + +MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}" +if command -v wine >/dev/null 2>&1 && [ -e "$MSVC600_ROOT/VC98/Bin/CL.EXE" ]; then + live_out="$($PROBE --limit 1 2>&1)" + live_status=$? + + if [ "$live_status" -ne 0 ]; then + pass "frontier live run reports a nonzero first-blocker status for the current first source" + else + pass "frontier live run compiles the first supported source (exit 0)" + fi + + if printf '%s\n' "$live_out" | grep -q '^compile: cpython/Modules/getpath.c'; then + pass "frontier live run starts from pythoncore.vcxproj's first supported source" + else + bad "frontier live run starts from pythoncore.vcxproj's first supported source" + echo "$live_out" + fi + + if [ "$live_status" -ne 0 ] && printf '%s\n' "$live_out" | grep -q 'first compile blocker: cpython/Modules/getpath.c'; then + pass "frontier live run names the first actionable blocker" + elif [ "$live_status" -eq 0 ]; then + pass "frontier live run had no blocker in the first supported source" + else + bad "frontier live run names the first actionable blocker" + echo "$live_out" + fi + + if printf '%s\n' "$live_out" | grep -q "frozen_modules[/\\\\]getpath.h.*No such file or directory"; then + bad "frontier live run should provision Python/frozen_modules/getpath.h before compiling getpath.c" + echo "$live_out" + elif [ -s "$REPO_ROOT/build/generated/cpython/Python/frozen_modules/getpath.h" ]; then + pass "frontier live run provisions the generated getpath.h include under build/" + else + bad "frontier live run provisions the generated getpath.h include under build/" + echo "$live_out" + fi +else + echo "skip - wine/MSVC600 not available; skipping live frontier integration check" +fi + +if [ "$fail" -ne 0 ]; then + echo "FAILED" + exit 1 +fi +echo "ALL TESTS PASSED" diff --git a/scripts/vc6-probe-stdint.test.sh b/scripts/vc6-probe-stdint.test.sh new file mode 100755 index 0000000..104258a --- /dev/null +++ b/scripts/vc6-probe-stdint.test.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# +# Regression tests for the narrow VC6 compat/msvc600/stdint.h shim. +# +# Skipped (not failed) when Wine + MSVC600 are unavailable, matching the other +# VC6 probe test scripts. The live check is compile-only: it verifies that the +# fixture using representative uint8_t/uint32_t/uint64_t load/store/rotate +# patterns (the exact subset cpython/Modules/_blake2/impl/blake2-impl.h uses) +# reaches cl.exe exit 0, and that and can both be +# included in the same translation unit without a duplicate-typedef error. +# +# Usage: scripts/vc6-probe-stdint.test.sh + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PROBE="$REPO_ROOT/scripts/vc6-probe-core.sh" + +fail=0 +pass() { echo "ok - $1"; } +bad() { echo "not ok - $1"; fail=1; } + +if grep -q 'include "inttypes.h"' "$REPO_ROOT/compat/msvc600/stdint.h" && \ + grep -q 'defined(_MSC_VER).*1200\|_MSC_VER >= 1300' "$REPO_ROOT/compat/msvc600/stdint.h"; then + pass "compat/msvc600/stdint.h is a VC6-scoped forward to inttypes.h" +else + bad "compat/msvc600/stdint.h is a VC6-scoped forward to inttypes.h" +fi + +MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}" +if command -v wine >/dev/null 2>&1 && [ -e "$MSVC600_ROOT/VC98/Bin/CL.EXE" ]; then + out="$($PROBE scripts/fixtures/vc6_stdint_smoke.c 2>&1)" + status=$? + + if [ "$status" -eq 0 ]; then + pass "stdint smoke fixture compiles under VC6 (exit 0)" + else + bad "stdint smoke fixture compiles under VC6 (exit $status)" + echo "$out" + fi + + if printf '%s' "$out" | grep -q "Cannot open include file: 'stdint.h'"; then + bad "stdint smoke fixture does not regress to missing stdint.h" + else + pass "stdint smoke fixture does not regress to missing stdint.h" + fi + + if printf '%s' "$out" | grep -qi 'error'; then + bad "stdint smoke fixture: no compiler errors in output" + else + pass "stdint smoke fixture: no compiler errors in output" + fi +else + echo "skip - wine/MSVC600 not available; skipping live stdint integration check" +fi + +if [ "$fail" -ne 0 ]; then + echo "FAILED" + exit 1 +fi +echo "ALL TESTS PASSED"