From: Francis De Brabandere <francisdb@gmail.com> Drop the over-aggressive var loop in check_script_collisions so that top-level Dim re-declarations across separate ParseScriptText calls silently succeed (matching native VBScript). Add cross-parse class collision checks for new Sub/Function declarations and Const decls so they error 1041 when the name is already taken by an existing class (also matching native). Removes the todo_wine markers added by the previous commit. --- dlls/vbscript/compile.c | 59 +++++++++++++++++++++++++++++----- dlls/vbscript/tests/vbscript.c | 31 ++++++++---------- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 3c347f72686..0b3fbaf97d9 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -2213,22 +2213,65 @@ static BOOL lookup_script_identifier(compile_ctx_t *ctx, script_ctx_t *script, c return FALSE; } -static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script) +/* Returns TRUE if `name` matches a class declared in any prior parse + * still kept on this script. Used to enforce native semantics where + * Sub/Function/Const declarations cannot reuse an existing class name. */ +static BOOL lookup_existing_class(compile_ctx_t *ctx, script_ctx_t *script, const WCHAR *name) { - unsigned i, var_cnt = ctx->code->main_code.var_cnt; - var_desc_t *vars = ctx->code->main_code.vars; + ScriptDisp *contexts[] = { + ctx->code->named_item ? ctx->code->named_item->script_obj : NULL, + script->script_obj + }; class_desc_t *class; + vbscode_t *code; + unsigned c; - for(i = 0; i < var_cnt; i++) { - if(lookup_script_identifier(ctx, script, vars[i].name)) { - return MAKE_VBSERROR(VBSE_NAME_REDEFINED); + for(c = 0; c < ARRAY_SIZE(contexts); c++) { + if(!contexts[c]) continue; + for(class = contexts[c]->classes; class; class = class->next) { + if(!vbs_wcsicmp(class->name, name)) + return TRUE; + } + } + + LIST_FOR_EACH_ENTRY(code, &script->code_list, vbscode_t, entry) { + if(!code->pending_exec || (code->named_item && code->named_item != ctx->code->named_item)) + continue; + for(class = code->classes; class; class = class->next) { + if(!vbs_wcsicmp(class->name, name)) + return TRUE; } } + return FALSE; +} + +static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script) +{ + class_desc_t *class; + function_t *func; + const_decl_t *konst; + + /* Native rule: top-level Dim is permissive and never errors when + * cross-parse re-declared, so we don't check vars here. Const is + * caught at runtime by interp_const, so we don't double-check. + * + * What this layer enforces: declaring a new Class, or a Sub / + * Function / Const, when the name is already used by a Class from + * a previous parse. */ for(class = ctx->code->classes; class; class = class->next) { - if(lookup_script_identifier(ctx, script, class->name)) { + if(lookup_script_identifier(ctx, script, class->name)) + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); + } + + for(func = ctx->code->funcs; func; func = func->next) { + if(lookup_existing_class(ctx, script, func->name)) + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); + } + + for(konst = ctx->const_decls; konst; konst = konst->next) { + if(lookup_existing_class(ctx, script, konst->name)) return MAKE_VBSERROR(VBSE_NAME_REDEFINED); - } } return S_OK; diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index f17bc385cb4..b247e9060be 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -2915,10 +2915,9 @@ static void test_const_at_top_level(void) /* Cross-parse name redefinition semantics: parse declaration `first`, * then declaration `second` on the same script object. Expect the * second parse to either succeed (S_OK) or report `expected_err` via - * OnScriptError. todo says the assertion should match native but - * Wine currently diverges. */ + * OnScriptError. */ static void run_cross_parse_redef(unsigned line, const WCHAR *first, const WCHAR *second, - int expected_err, BOOL todo) + int expected_err) { IActiveScriptParse *parser; IActiveScript *vbscript; @@ -2962,11 +2961,11 @@ static void run_cross_parse_redef(unsigned line, const WCHAR *first, const WCHAR expect_OnLeaveScript = called_OnLeaveScript = 0; expect_OnScriptError = called_OnScriptError = 0; if (expected_err) { - todo_wine_if(todo) ok_(__FILE__,line)(last_script_error == expected_err, + ok_(__FILE__,line)(last_script_error == expected_err, "second parse for %s: expected err %d, got err=%d hr=%08lx\n", wine_dbgstr_w(second), expected_err, last_script_error, hr); } else { - todo_wine_if(todo) ok_(__FILE__,line)(hr == S_OK && last_script_error == 0, + ok_(__FILE__,line)(hr == S_OK && last_script_error == 0, "second parse for %s: expected S_OK, got hr=%08lx err=%d\n", wine_dbgstr_w(second), hr, last_script_error); } @@ -2984,10 +2983,8 @@ static void run_cross_parse_redef(unsigned line, const WCHAR *first, const WCHAR IActiveScript_Release(vbscript); } -#define cross_parse_ok(a, b) run_cross_parse_redef(__LINE__, a, b, 0, FALSE) -#define cross_parse_ok_todo(a, b) run_cross_parse_redef(__LINE__, a, b, 0, TRUE) -#define cross_parse_err(a, b, e) run_cross_parse_redef(__LINE__, a, b, e, FALSE) -#define cross_parse_err_todo(a, b, e) run_cross_parse_redef(__LINE__, a, b, e, TRUE) +#define cross_parse_ok(a, b) run_cross_parse_redef(__LINE__, a, b, 0) +#define cross_parse_err(a, b, e) run_cross_parse_redef(__LINE__, a, b, e) static void test_cross_parse_name_redef(void) { @@ -3007,17 +3004,17 @@ static void test_cross_parse_name_redef(void) /* Anything followed by Dim: native always accepts. Wine currently * errors -- needs the over-aggressive var loop dropped. */ - cross_parse_ok_todo(dim, dim); - cross_parse_ok_todo(konst, dim); - cross_parse_ok_todo(sub, dim); - cross_parse_ok_todo(func, dim); - cross_parse_ok_todo(cls, dim); + cross_parse_ok(dim, dim); + cross_parse_ok(konst, dim); + cross_parse_ok(sub, dim); + cross_parse_ok(func, dim); + cross_parse_ok(cls, dim); /* Class-then-X: native errors for Const/Sub/Func because the name * is taken. Wine currently allows -- needs added cross-parse check. */ - cross_parse_err_todo(cls, konst, 1041); - cross_parse_err_todo(cls, sub, 1041); - cross_parse_err_todo(cls, func, 1041); + cross_parse_err(cls, konst, 1041); + cross_parse_err(cls, sub, 1041); + cross_parse_err(cls, func, 1041); cross_parse_err (cls, cls, 1041); /* Wine already catches this */ /* Cases Wine and native already agree on. */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10852