163 lines
4.2 KiB
C
163 lines
4.2 KiB
C
/* 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;
|
|
}
|