LibJS: Reject arguments/eval in strict mode destructuring and arrows

Check identifier name validity for destructuring assignment pattern
bound names, and validate arrow function parameters after the arrow
is confirmed rather than during speculative parameter parsing.

This fixes arguments/eval as destructuring assignment targets and as
arrow function parameter names in strict mode.
This commit is contained in:
Andreas Kling 2026-03-19 20:04:41 -05:00 committed by Andreas Kling
parent 66dbb355fe
commit 49cc44a3eb
3 changed files with 26 additions and 7 deletions

View file

@ -1307,7 +1307,12 @@ impl Parser<'_> {
}
let token = self.consume();
let value = Utf16String::from(self.token_value(&token));
self.check_identifier_name_for_assignment_validity(&value, false);
// Skip validity check for arrow functions; arrow parameter
// parsing is speculative and errors would abort the parse.
// The check runs after the arrow is confirmed instead.
if !is_arrow {
self.check_identifier_name_for_assignment_validity(&value, false);
}
let id = Rc::new(Identifier::new(
self.range_from(formal_parameters_start),
value.clone(),

View file

@ -856,8 +856,11 @@ impl Parser<'_> {
// Register synthesized identifiers with the scope collector so
// they get resolved as locals during analyze().
for (name, id) in self.pattern_bound_names.drain(..) {
self.scope_collector.register_identifier(id, &name, None);
let bound_names: Vec<_> = self.pattern_bound_names.drain(..).collect();
for (name, id) in &bound_names {
self.check_identifier_name_for_assignment_validity(name, false);
self.scope_collector
.register_identifier(id.clone(), name, None);
}
self.pattern_bound_names = saved_bound_names;
self.consume();
@ -2457,8 +2460,12 @@ impl Parser<'_> {
self.scope_collector.close_scope();
self.pattern_bound_names = saved_pattern_bound_names;
if has_use_strict || fn_kind != FunctionKind::Normal {
self.check_parameters_post_body(&parameter_info, has_use_strict, fn_kind);
if has_use_strict || fn_kind != FunctionKind::Normal || self.flags.strict_mode {
self.check_parameters_post_body(
&parameter_info,
has_use_strict || self.flags.strict_mode,
fn_kind,
);
}
self.flags.await_expression_is_valid = saved_await_body;
@ -2505,6 +2512,10 @@ impl Parser<'_> {
self.scope_collector.close_scope();
self.pattern_bound_names = saved_pattern_bound_names;
if self.flags.strict_mode || fn_kind != FunctionKind::Normal {
self.check_parameters_post_body(&parameter_info, self.flags.strict_mode, fn_kind);
}
self.flags.await_expression_is_valid = saved_await_body;
self.flags.in_class_static_init_block = saved_static_init;
self.flags.in_formal_parameter_context = saved_formal_parameter_ctx;

View file

@ -979,8 +979,11 @@ impl Parser<'_> {
{
let pattern = self.synthesize_binding_pattern(init_start);
for (name, id) in self.pattern_bound_names.drain(..) {
self.scope_collector.register_identifier(id, &name, None);
let bound_names: Vec<_> = self.pattern_bound_names.drain(..).collect();
for (name, id) in &bound_names {
self.check_identifier_name_for_assignment_validity(name, false);
self.scope_collector
.register_identifier(id.clone(), name, None);
}
ForInOfLhs::Pattern(pattern)
} else {