port: add MSVC600 CPython compatibility layer
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user