port: add MSVC600 CPython compatibility layer

This commit is contained in:
RayPals
2026-08-17 17:35:32 +00:00
parent 3f15bfa5f7
commit a7a9560e5c
13 changed files with 2652 additions and 35 deletions
+162
View File
@@ -0,0 +1,162 @@
/* Focused compile smoke test for the VC6 C89-mixed-declarations fixes
* applied to cpython/Modules/main.c.
*
* VC6 is a C89-only compiler (plus Microsoft extensions): block-scope
* declarations must precede all statements in that block. Modules/main.c
* declared many locals mid-function (typically right before first use,
* C99 style); the fix hoists each declaration to the top of its enclosing
* block, without initializer, and turns the original `TYPE name = expr;`
* into a plain `name = expr;` assignment at its original position. This
* changes no evaluation order and no semantics. See PORT_STATUS.md
* ("Modules/main.c mixed-declarations slice") for full detail.
*
* This fixture is deliberately self-contained (no CPython headers) so it
* exercises the *shape* of every hoist pattern used in main.c, independent
* of main.c's own evolution:
*
* 1. a bare declaration hoisted above an early-return statement
* (pymain_init's `preconfig`/`config`);
* 2. a declaration whose initializer is a side-effecting call, hoisted
* bare and assigned at its original site so the call itself still
* happens after the same preceding statements
* (pymain_import_readline's `mod`, pymain_run_file_obj's `fp`);
* 3. two declarations in a row where hoisting the first turns its site
* into an assignment statement, which would otherwise make the
* second declaration (immediately following) a new violation too
* (pymain_run_file_obj's `cf`/`run`);
* 4. a declaration inside a nested block (its own scope), after
* statements already executed in that block (pymain_run_stdin's
* nested `exitcode`);
* 5. a platform-conditional declaration with the same name but a
* different type per branch, hoisted under the same #ifdef structure
* at the top of the function (pymain_run_startup's `env`).
*/
#define TARGET_WINDOWS 1
/* --- pattern 1: bare declaration hoisted above an early return --- */
static int
decl_after_early_return(int flag)
{
int status;
int extra;
status = flag ? 0 : -1;
if (status != 0) {
return status;
}
extra = 7;
return extra;
}
/* --- pattern 2: side-effecting-initializer declaration hoisted bare,
* assigned at its original position so the call still happens after the
* same preceding statements --- */
static int
side_effect(int *counter)
{
(*counter)++;
return *counter;
}
static int
decl_with_side_effecting_init(int *counter)
{
int guard;
int value;
guard = (*counter < 0);
if (guard) {
return -1;
}
value = side_effect(counter);
return value;
}
/* --- pattern 3: two declarations in a row, first one hoisted becomes an
* assignment, so the second (immediately following) must hoist too --- */
static int
decl_pair_after_hoist(int *counter)
{
int guard;
int a;
int b;
guard = (*counter < 0);
if (guard) {
return -1;
}
a = side_effect(counter);
b = side_effect(counter);
return a + b;
}
/* --- pattern 4: nested-block declaration after statements already
* executed within that same nested block --- */
static int
decl_after_statement_in_nested_block(int interactive)
{
int outer_result = 0;
if (interactive) {
int inner_value;
outer_result += 1;
outer_result += 2;
inner_value = outer_result * 10;
return inner_value;
}
return outer_result;
}
/* --- pattern 5: platform-conditional declaration, same name, different
* type per branch, hoisted under the same #ifdef at the top --- */
static long
decl_platform_conditional(void)
{
int ret;
#ifdef TARGET_WINDOWS
const char *env;
#else
const long *env;
#endif
ret = 1;
if (!ret) {
return 0;
}
#ifdef TARGET_WINDOWS
env = "PYTHONSTARTUP";
if (env == 0) {
return 0;
}
return (long)env[0];
#else
env = 0;
if (env == 0) {
return 0;
}
return *env;
#endif
}
int
main(void)
{
int counter = 0;
int total = 0;
total += decl_after_early_return(1);
total += decl_with_side_effecting_init(&counter);
total += decl_pair_after_hoist(&counter);
total += decl_after_statement_in_nested_block(1);
total += (int)decl_platform_conditional();
return (total >= 0) ? 0 : 1;
}