Commit ceb92ebf authored by adamk's avatar adamk Committed by Commit bot

Disallow destructuring in legacy sloppy for-in loop parsing

For web compat reasons, we support an initializer in the declaration
part of a for-in loop. But we should disallow this for destructured
declarations (just as we do for lexical declarations). In fact, without
disallowing it, we crash.

Also fix up the PreParser to have the same restrictions here as the parser
(the lexical check was missing there), verified by running the message tests
with --min-preparse-length=0.

In fixing the logic I've also cleaned up the code a bit, removing the
only-called-once DeclarationParsingResult::SingleName method.

BUG=v8:811
LOG=n

Review URL: https://codereview.chromium.org/1471973003

Cr-Commit-Position: refs/heads/master@{#32236}
parent 9278b7b0
...@@ -2381,16 +2381,6 @@ Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) { ...@@ -2381,16 +2381,6 @@ Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
} }
const AstRawString* Parser::DeclarationParsingResult::SingleName() const {
if (declarations.length() != 1) return nullptr;
const Declaration& declaration = declarations.at(0);
if (declaration.pattern->IsVariableProxy()) {
return declaration.pattern->AsVariableProxy()->raw_name();
}
return nullptr;
}
Block* Parser::DeclarationParsingResult::BuildInitializationBlock( Block* Parser::DeclarationParsingResult::BuildInitializationBlock(
ZoneList<const AstRawString*>* names, bool* ok) { ZoneList<const AstRawString*>* names, bool* ok) {
Block* result = descriptor.parser->factory()->NewBlock( Block* result = descriptor.parser->factory()->NewBlock(
...@@ -3678,9 +3668,12 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3678,9 +3668,12 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
*ok = false; *ok = false;
return nullptr; return nullptr;
} }
DeclarationParsingResult::Declaration& decl =
parsing_result.declarations[0];
if (parsing_result.first_initializer_loc.IsValid() && if (parsing_result.first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE || (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(parsing_result.descriptor.mode))) { IsLexicalVariableMode(parsing_result.descriptor.mode) ||
!decl.pattern->IsVariableProxy())) {
if (mode == ForEachStatement::ITERATE) { if (mode == ForEachStatement::ITERATE) {
ReportMessageAt(parsing_result.first_initializer_loc, ReportMessageAt(parsing_result.first_initializer_loc,
MessageTemplate::kForOfLoopInitializer); MessageTemplate::kForOfLoopInitializer);
...@@ -3693,22 +3686,21 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3693,22 +3686,21 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
return nullptr; return nullptr;
} }
DCHECK(parsing_result.declarations.length() == 1);
Block* init_block = nullptr; Block* init_block = nullptr;
// special case for legacy for (var/const x =.... in) // special case for legacy for (var/const x =.... in)
if (!IsLexicalVariableMode(parsing_result.descriptor.mode) && if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
parsing_result.declarations[0].initializer != nullptr) { decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
const AstRawString* name =
decl.pattern->AsVariableProxy()->raw_name();
VariableProxy* single_var = scope_->NewUnresolved( VariableProxy* single_var = scope_->NewUnresolved(
factory(), parsing_result.SingleName(), Variable::NORMAL, factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
each_beg_pos, each_end_pos);
init_block = factory()->NewBlock( init_block = factory()->NewBlock(
nullptr, 2, true, parsing_result.descriptor.declaration_pos); nullptr, 2, true, parsing_result.descriptor.declaration_pos);
init_block->statements()->Add( init_block->statements()->Add(
factory()->NewExpressionStatement( factory()->NewExpressionStatement(
factory()->NewAssignment( factory()->NewAssignment(Token::ASSIGN, single_var,
Token::ASSIGN, single_var, decl.initializer,
parsing_result.declarations[0].initializer,
RelocInfo::kNoPosition), RelocInfo::kNoPosition),
RelocInfo::kNoPosition), RelocInfo::kNoPosition),
zone()); zone());
...@@ -3752,9 +3744,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3752,9 +3744,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
auto each_initialization_block = auto each_initialization_block =
factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
{ {
DCHECK(parsing_result.declarations.length() == 1);
DeclarationParsingResult::Declaration decl =
parsing_result.declarations[0];
auto descriptor = parsing_result.descriptor; auto descriptor = parsing_result.descriptor;
descriptor.declaration_pos = RelocInfo::kNoPosition; descriptor.declaration_pos = RelocInfo::kNoPosition;
descriptor.initialization_pos = RelocInfo::kNoPosition; descriptor.initialization_pos = RelocInfo::kNoPosition;
......
...@@ -1020,7 +1020,6 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -1020,7 +1020,6 @@ class Parser : public ParserBase<ParserTraits> {
Block* BuildInitializationBlock(ZoneList<const AstRawString*>* names, Block* BuildInitializationBlock(ZoneList<const AstRawString*>* names,
bool* ok); bool* ok);
const AstRawString* SingleName() const;
DeclarationDescriptor descriptor; DeclarationDescriptor descriptor;
List<Declaration> declarations; List<Declaration> declarations;
......
...@@ -495,8 +495,8 @@ PreParser::Statement PreParser::ParseVariableStatement( ...@@ -495,8 +495,8 @@ PreParser::Statement PreParser::ParseVariableStatement(
// VariableStatement :: // VariableStatement ::
// VariableDeclarations ';' // VariableDeclarations ';'
Statement result = ParseVariableDeclarations(var_context, nullptr, nullptr, Statement result = ParseVariableDeclarations(
nullptr, CHECK_OK); var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return result; return result;
} }
...@@ -508,9 +508,9 @@ PreParser::Statement PreParser::ParseVariableStatement( ...@@ -508,9 +508,9 @@ PreParser::Statement PreParser::ParseVariableStatement(
// to initialize it properly. This mechanism is also used for the parsing // to initialize it properly. This mechanism is also used for the parsing
// of 'for-in' loops. // of 'for-in' loops.
PreParser::Statement PreParser::ParseVariableDeclarations( PreParser::Statement PreParser::ParseVariableDeclarations(
VariableDeclarationContext var_context, int* num_decl, VariableDeclarationContext var_context, int* num_decl, bool* is_lexical,
Scanner::Location* first_initializer_loc, Scanner::Location* bindings_loc, bool* is_binding_pattern, Scanner::Location* first_initializer_loc,
bool* ok) { Scanner::Location* bindings_loc, bool* ok) {
// VariableDeclarations :: // VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
// //
...@@ -526,6 +526,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -526,6 +526,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
// BindingPattern '=' AssignmentExpression // BindingPattern '=' AssignmentExpression
bool require_initializer = false; bool require_initializer = false;
bool lexical = false; bool lexical = false;
bool is_pattern = false;
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
if (is_strong(language_mode())) { if (is_strong(language_mode())) {
Scanner::Location location = scanner()->peek_location(); Scanner::Location location = scanner()->peek_location();
...@@ -589,7 +590,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -589,7 +590,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
} }
} }
bool is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral(); is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral();
bool is_for_iteration_variable = bool is_for_iteration_variable =
var_context == kForStatement && var_context == kForStatement &&
...@@ -623,7 +624,9 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -623,7 +624,9 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
Scanner::Location(bindings_start, scanner()->location().end_pos); Scanner::Location(bindings_start, scanner()->location().end_pos);
} }
if (num_decl != NULL) *num_decl = nvars; if (num_decl != nullptr) *num_decl = nvars;
if (is_lexical != nullptr) *is_lexical = lexical;
if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern;
return Statement::Default(); return Statement::Default();
} }
...@@ -912,11 +915,13 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -912,11 +915,13 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && IsNextLetKeyword())) { (peek() == Token::LET && IsNextLetKeyword())) {
int decl_count; int decl_count;
bool is_lexical;
bool is_binding_pattern;
Scanner::Location first_initializer_loc = Scanner::Location::invalid(); Scanner::Location first_initializer_loc = Scanner::Location::invalid();
Scanner::Location bindings_loc = Scanner::Location::invalid(); Scanner::Location bindings_loc = Scanner::Location::invalid();
ParseVariableDeclarations(kForStatement, &decl_count, ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
&first_initializer_loc, &bindings_loc, &is_binding_pattern, &first_initializer_loc,
CHECK_OK); &bindings_loc, CHECK_OK);
bool accept_IN = decl_count >= 1; bool accept_IN = decl_count >= 1;
if (accept_IN && CheckInOrOf(&mode, ok)) { if (accept_IN && CheckInOrOf(&mode, ok)) {
if (!*ok) return Statement::Default(); if (!*ok) return Statement::Default();
...@@ -930,7 +935,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -930,7 +935,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
return Statement::Default(); return Statement::Default();
} }
if (first_initializer_loc.IsValid() && if (first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
is_lexical || is_binding_pattern)) {
if (mode == ForEachStatement::ITERATE) { if (mode == ForEachStatement::ITERATE) {
ReportMessageAt(first_initializer_loc, ReportMessageAt(first_initializer_loc,
MessageTemplate::kForOfLoopInitializer); MessageTemplate::kForOfLoopInitializer);
......
...@@ -1845,7 +1845,8 @@ class PreParser : public ParserBase<PreParserTraits> { ...@@ -1845,7 +1845,8 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseVariableStatement(VariableDeclarationContext var_context, Statement ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok); bool* ok);
Statement ParseVariableDeclarations(VariableDeclarationContext var_context, Statement ParseVariableDeclarations(VariableDeclarationContext var_context,
int* num_decl, int* num_decl, bool* is_lexical,
bool* is_binding_pattern,
Scanner::Location* first_initializer_loc, Scanner::Location* first_initializer_loc,
Scanner::Location* bindings_loc, Scanner::Location* bindings_loc,
bool* ok); bool* ok);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-destructuring-bind
function f() {
for (var [x, y] = {} in {});
}
*%(basename)s:8: SyntaxError: for-in loop variable declaration may not have an initializer.
for (var [x, y] = {} in {});
^^^^^^
SyntaxError: for-in loop variable declaration may not have an initializer.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment