jscript: Don't expose named functions in expressions as a local variable in ES5 mode.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2021-04-21 17:23:17 +02:00 committed by Alexandre Julliard
parent 609e9de65c
commit e764509466
4 changed files with 44 additions and 4 deletions

View File

@ -1887,8 +1887,12 @@ static HRESULT visit_function_expression(compiler_ctx_t *ctx, function_expressio
expr->func_id = ctx->func->func_cnt++; expr->func_id = ctx->func->func_cnt++;
ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr); ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
return !expr->identifier || expr->event_target || alloc_variable(ctx, expr->identifier) if(!expr->identifier || expr->event_target)
? S_OK : E_OUTOFMEMORY; return S_OK;
if(!expr->is_statement && ctx->parser->script->version >= SCRIPTLANGUAGEVERSION_ES5)
return S_OK;
return alloc_variable(ctx, expr->identifier) ? S_OK : E_OUTOFMEMORY;
} }
static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr) static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
@ -2069,7 +2073,15 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
case STAT_CONTINUE: case STAT_CONTINUE:
case STAT_EMPTY: case STAT_EMPTY:
break; break;
case STAT_EXPR: case STAT_EXPR: {
expression_statement_t *expr_stat = (expression_statement_t*)stat;
if(expr_stat->expr) {
if(expr_stat->expr->type == EXPR_FUNC)
((function_expression_t*)expr_stat->expr)->is_statement = TRUE;
hres = visit_expression(ctx, expr_stat->expr);
}
break;
}
case STAT_RETURN: case STAT_RETURN:
case STAT_THROW: { case STAT_THROW: {
expression_statement_t *expr_stat = (expression_statement_t*)stat; expression_statement_t *expr_stat = (expression_statement_t*)stat;
@ -2410,7 +2422,8 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
return hres; return hres;
TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name)); TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name));
if(func->funcs[i].name && !func->funcs[i].event_target) { if((ctx->parser->script->version < SCRIPTLANGUAGEVERSION_ES5 || iter->is_statement) &&
func->funcs[i].name && !func->funcs[i].event_target) {
local_ref_t *local_ref = lookup_local(func, func->funcs[i].name); local_ref_t *local_ref = lookup_local(func, func->funcs[i].name);
func->funcs[i].local_ref = local_ref->ref; func->funcs[i].local_ref = local_ref->ref;
TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name)); TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name));

View File

@ -302,6 +302,7 @@ typedef struct _function_expression_t {
const WCHAR *src_str; const WCHAR *src_str;
DWORD src_len; DWORD src_len;
unsigned func_id; unsigned func_id;
BOOL is_statement;
struct _function_expression_t *next; /* for compiler */ struct _function_expression_t *next; /* for compiler */
} function_expression_t; } function_expression_t;

View File

@ -1386,6 +1386,7 @@ static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *ide
ret->event_target = event_target; ret->event_target = event_target;
ret->src_str = src_str; ret->src_str = src_str;
ret->src_len = src_len; ret->src_len = src_len;
ret->is_statement = FALSE;
ret->next = NULL; ret->next = NULL;
return &ret->expr; return &ret->expr;

View File

@ -538,6 +538,7 @@ sync_test("delete_prop", function() {
}); });
var func_scope_val = 1; var func_scope_val = 1;
var func_scope_val2 = 2;
sync_test("func_scope", function() { sync_test("func_scope", function() {
var func_scope_val = 2; var func_scope_val = 2;
@ -571,4 +572,28 @@ sync_test("func_scope", function() {
window = 1; window = 1;
ok(window === window.self, "window = " + window); ok(window === window.self, "window = " + window);
! function func_scope_val2() {};
ok(window.func_scope_val2 === 2, "window.func_scope_val2 = " + window.func_scope_val2);
var o = {};
(function(x) {
ok(x === o, "x = " + x);
! function x() {};
ok(x === o, "x != o");
})(o);
(function(x) {
ok(x === o, "x = " + x);
1, function x() {};
ok(x === o, "x != o");
})(o);
(function() {
! function x() {};
try {
x();
ok(false, "expected exception");
}catch(e) {}
})(o);
}); });