Ensure scopes are backed by blocks in the body of for loops
Clusterfuzz testing discovered that sloppy-mode block-scoped function declarations introduce lexically-scoped variables in scopes that were thrown away under the expectation that no lexically-scoped variables were introduced. These cases are: for (;;) function foo() {} for (x in y) function foo() {} This patch ensures that a block is created in those cases to hold the lexically scoped variable. Usually, scope analysis should discover that that block is not important, and it should not have a runtime representation. BUG=chromium:536750,chromium:536751 LOG=Y R=adamk Review URL: https://codereview.chromium.org/1382123002 Cr-Commit-Position: refs/heads/master@{#31109}
This commit is contained in:
parent
12d288736d
commit
2d4085622a
@ -3786,12 +3786,19 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
// Make a block around the statement in case a lexical binding
|
||||
// is introduced, e.g. by a FunctionDeclaration.
|
||||
Block* block =
|
||||
factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
|
||||
Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
||||
InitializeForEachStatement(loop, expression, enumerable, body);
|
||||
block->statements()->Add(body, zone());
|
||||
InitializeForEachStatement(loop, expression, enumerable, block);
|
||||
scope_ = saved_scope;
|
||||
for_scope->set_end_position(scanner()->location().end_pos);
|
||||
for_scope = for_scope->FinalizeBlockScope();
|
||||
DCHECK(for_scope == NULL);
|
||||
if (for_scope != nullptr) {
|
||||
block->set_scope(for_scope);
|
||||
}
|
||||
// Parsed for-in loop.
|
||||
return loop;
|
||||
|
||||
@ -3861,10 +3868,20 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
// const x = i;
|
||||
// for (; c; n) b
|
||||
// }
|
||||
DCHECK(init != NULL);
|
||||
//
|
||||
// or, desugar
|
||||
// for (; c; n) b
|
||||
// into
|
||||
// {
|
||||
// for (; c; n) b
|
||||
// }
|
||||
// just in case b introduces a lexical binding some other way, e.g., if b
|
||||
// is a FunctionDeclaration.
|
||||
Block* block =
|
||||
factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
|
||||
block->statements()->Add(init, zone());
|
||||
if (init != nullptr) {
|
||||
block->statements()->Add(init, zone());
|
||||
}
|
||||
block->statements()->Add(loop, zone());
|
||||
block->set_scope(for_scope);
|
||||
loop->Initialize(NULL, cond, next, body);
|
||||
|
11
test/mjsunit/regress/regress-536751.js
Normal file
11
test/mjsunit/regress/regress-536751.js
Normal file
@ -0,0 +1,11 @@
|
||||
// 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-sloppy --harmony-sloppy-function --harmony-sloppy-let
|
||||
|
||||
// At some point, this code led to DCHECK errors in debug mode
|
||||
|
||||
for (; false;) function foo() {};
|
||||
|
||||
for (x in []) function foo() {};
|
Loading…
Reference in New Issue
Block a user