@@ -951,6 +951,7 @@ fn parse_for_statement(t: &[TokenData], index: &mut usize) -> Result<Statement,
951951 } else if let Some ( expr) = init_expr {
952952 match expr {
953953 Expr :: Property ( _, _) | Expr :: Index ( _, _) | Expr :: PrivateMember ( _, _) | Expr :: Array ( _) | Expr :: Object ( _) => {
954+ check_destructuring_expr_strict ( & expr) ?;
954955 if is_for_await {
955956 StatementKind :: ForAwaitOfExpr ( expr, iterable, body_stmts)
956957 } else {
@@ -1119,6 +1120,7 @@ fn parse_for_statement(t: &[TokenData], index: &mut usize) -> Result<Statement,
11191120 | Expr :: Var ( _, _, _)
11201121 | Expr :: Array ( _)
11211122 | Expr :: Object ( _) => {
1123+ check_destructuring_expr_strict ( & expr) ?;
11221124 return Ok ( Statement {
11231125 kind : Box :: new ( StatementKind :: ForInExpr ( expr, rhs, body_stmts) ) ,
11241126 line,
@@ -3624,6 +3626,36 @@ fn parse_logical_and(tokens: &[TokenData], index: &mut usize) -> Result<Expr, JS
36243626 Ok ( left)
36253627 }
36263628}
3629+ /// Check if an expression used as a for-of/for-in destructuring target contains
3630+ /// `eval` or `arguments` as simple assignment targets (strict mode restriction).
3631+ fn check_destructuring_expr_strict ( expr : & Expr ) -> Result < ( ) , JSError > {
3632+ if !strict_binding_checks ( ) {
3633+ return Ok ( ( ) ) ;
3634+ }
3635+ match expr {
3636+ Expr :: Var ( name, _, _) if name == "eval" || name == "arguments" => Err ( raise_parse_error ! ( & format!(
3637+ "'{}' can't be defined or assigned to in strict mode code" ,
3638+ name
3639+ ) ) ) ,
3640+ Expr :: Array ( elements) => {
3641+ for inner in elements. iter ( ) . flatten ( ) {
3642+ match inner {
3643+ Expr :: Spread ( s) => check_destructuring_expr_strict ( s) ?,
3644+ Expr :: Assign ( lhs, _) => check_destructuring_expr_strict ( lhs) ?,
3645+ other => check_destructuring_expr_strict ( other) ?,
3646+ }
3647+ }
3648+ Ok ( ( ) )
3649+ }
3650+ Expr :: Object ( pairs) => {
3651+ for ( _, val, _, _) in pairs {
3652+ check_destructuring_expr_strict ( val) ?;
3653+ }
3654+ Ok ( ( ) )
3655+ }
3656+ _ => Ok ( ( ) ) ,
3657+ }
3658+ }
36273659fn parse_logical_or ( tokens : & [ TokenData ] , index : & mut usize ) -> Result < Expr , JSError > {
36283660 let left = parse_logical_and ( tokens, index) ?;
36293661 let mut look = * index;
@@ -3644,8 +3676,8 @@ fn parse_logical_or(tokens: &[TokenData], index: &mut usize) -> Result<Expr, JSE
36443676/// Check if tokens in range [start..end) contain || or && at paren depth 0.
36453677fn has_bare_logical_in_range ( tokens : & [ TokenData ] , start : usize , end : usize ) -> bool {
36463678 let mut depth = 0usize ;
3647- for i in start.. end {
3648- match & tokens [ i ] . token {
3679+ for td in tokens . iter ( ) . take ( end) . skip ( start ) {
3680+ match & td . token {
36493681 Token :: LParen | Token :: LBracket | Token :: LBrace => depth += 1 ,
36503682 Token :: RParen | Token :: RBracket | Token :: RBrace => {
36513683 depth = depth. saturating_sub ( 1 ) ;
@@ -4400,13 +4432,13 @@ fn parse_primary(tokens: &[TokenData], index: &mut usize, allow_call: bool) -> R
44004432 let msg = format ! ( "Private field '{prop_name}' cannot be deleted" ) ;
44014433 return Err ( raise_parse_error_with_token ! ( token_data, msg) ) ;
44024434 }
4403- if let Expr :: Var ( ..) = & inner {
4404- if strict_binding_checks ( ) {
4405- return Err ( raise_parse_error_with_token ! (
4406- token_data ,
4407- "Delete of an unqualified identifier in strict mode"
4408- ) ) ;
4409- }
4435+ if let Expr :: Var ( ..) = & inner
4436+ && strict_binding_checks ( )
4437+ {
4438+ return Err ( raise_parse_error_with_token ! (
4439+ token_data ,
4440+ "Delete of an unqualified identifier in strict mode"
4441+ ) ) ;
44104442 }
44114443 Expr :: Delete ( Box :: new ( inner) )
44124444 }
@@ -6425,6 +6457,12 @@ pub fn parse_array_destructuring_pattern(tokens: &[TokenData], index: &mut usize
64256457 if * index < tokens. len ( ) && matches ! ( tokens[ * index] . token, Token :: Spread ) {
64266458 * index += 1 ;
64276459 if let Some ( Token :: Identifier ( name) ) = tokens. get ( * index) . map ( |t| t. token . clone ( ) ) {
6460+ if strict_binding_checks ( ) && ( name == "eval" || name == "arguments" ) {
6461+ return Err ( raise_parse_error_with_token ! (
6462+ tokens[ * index] ,
6463+ format!( "'{}' can't be defined or assigned to in strict mode code" , name)
6464+ ) ) ;
6465+ }
64286466 * index += 1 ;
64296467 pattern. push ( DestructuringElement :: Rest ( name) ) ;
64306468 } else if * index < tokens. len ( )
@@ -6503,6 +6541,12 @@ pub fn parse_array_destructuring_pattern(tokens: &[TokenData], index: &mut usize
65036541 }
65046542 pattern. push ( DestructuringElement :: NestedObject ( nested_pattern, default_expr) ) ;
65056543 } else if let Some ( Token :: Identifier ( name) ) = tokens. get ( * index) . map ( |t| t. token . clone ( ) ) {
6544+ if strict_binding_checks ( ) && ( name == "eval" || name == "arguments" ) {
6545+ return Err ( raise_parse_error_with_token ! (
6546+ tokens[ * index] ,
6547+ format!( "'{}' can't be defined or assigned to in strict mode code" , name)
6548+ ) ) ;
6549+ }
65066550 * index += 1 ;
65076551 let mut default_expr: Option < Box < Expr > > = None ;
65086552 if * index < tokens. len ( ) && matches ! ( tokens[ * index] . token, Token :: Assign ) {
@@ -6614,6 +6658,12 @@ pub fn parse_object_destructuring_pattern(tokens: &[TokenData], index: &mut usiz
66146658 if * index < tokens. len ( ) && matches ! ( tokens[ * index] . token, Token :: Spread ) {
66156659 * index += 1 ;
66166660 if let Some ( Token :: Identifier ( name) ) = tokens. get ( * index) . map ( |t| t. token . clone ( ) ) {
6661+ if strict_binding_checks ( ) && ( name == "eval" || name == "arguments" ) {
6662+ return Err ( raise_parse_error_with_token ! (
6663+ tokens[ * index] ,
6664+ format!( "'{}' can't be defined or assigned to in strict mode code" , name)
6665+ ) ) ;
6666+ }
66176667 * index += 1 ;
66186668 pattern. push ( DestructuringElement :: Rest ( name) ) ;
66196669 } else {
@@ -6747,6 +6797,12 @@ pub fn parse_object_destructuring_pattern(tokens: &[TokenData], index: &mut usiz
67476797 }
67486798 DestructuringElement :: NestedObject ( nested, nested_default)
67496799 } else if let Some ( Token :: Identifier ( name) ) = tokens. get ( * index) . map ( |t| t. token . clone ( ) ) {
6800+ if strict_binding_checks ( ) && ( name == "eval" || name == "arguments" ) {
6801+ return Err ( raise_parse_error_with_token ! (
6802+ tokens[ * index] ,
6803+ format!( "'{}' can't be defined or assigned to in strict mode code" , name)
6804+ ) ) ;
6805+ }
67506806 * index += 1 ;
67516807 let mut default_expr: Option < Box < Expr > > = None ;
67526808 if * index < tokens. len ( ) && matches ! ( tokens[ * index] . token, Token :: Assign ) {
@@ -6818,6 +6874,13 @@ pub fn parse_object_destructuring_pattern(tokens: &[TokenData], index: &mut usiz
68186874 if !is_identifier_key {
68196875 return Err ( raise_parse_error_at ! ( tokens. get( * index) ) ) ;
68206876 }
6877+ let key = key_name. clone ( ) . unwrap_or_default ( ) ;
6878+ if strict_binding_checks ( ) && ( key == "eval" || key == "arguments" ) {
6879+ return Err ( raise_parse_error ! ( & format!(
6880+ "'{}' can't be defined or assigned to in strict mode code" ,
6881+ key
6882+ ) ) ) ;
6883+ }
68216884 let mut init_tokens: Vec < TokenData > = Vec :: new ( ) ;
68226885 if * index < tokens. len ( ) && matches ! ( tokens[ * index] . token, Token :: Assign ) {
68236886 * index += 1 ;
0 commit comments