Block-scoped functions in evals are now only conditionally hoisted out.
Annex B.3.3 of the spec requires that sloppy-mode block-scoped functions declared by "eval" are hoisted unless doing so would cause an early error (which is to say, conflict with a lexical declaration). This patch amends the check for conflicting declarations to include those outside of the eval itself. BUG=v8:4468, v8:4479 Review-Url: https://codereview.chromium.org/2112163002 Cr-Commit-Position: refs/heads/master@{#37783}
This commit is contained in:
parent
da4f249150
commit
f6c6ae9034
@ -5233,7 +5233,11 @@ void Parser::InsertSloppyBlockFunctionVarBindings(Scope* scope,
|
|||||||
auto delegates = static_cast<SloppyBlockFunctionMap::Vector*>(p->value);
|
auto delegates = static_cast<SloppyBlockFunctionMap::Vector*>(p->value);
|
||||||
for (SloppyBlockFunctionStatement* delegate : *delegates) {
|
for (SloppyBlockFunctionStatement* delegate : *delegates) {
|
||||||
// Check if there's a conflict with a lexical declaration
|
// Check if there's a conflict with a lexical declaration
|
||||||
Scope* outer_scope = scope->outer_scope();
|
Scope* decl_scope = scope;
|
||||||
|
while (decl_scope->is_eval_scope()) {
|
||||||
|
decl_scope = decl_scope->outer_scope()->DeclarationScope();
|
||||||
|
}
|
||||||
|
Scope* outer_scope = decl_scope->outer_scope();
|
||||||
Scope* query_scope = delegate->scope()->outer_scope();
|
Scope* query_scope = delegate->scope()->outer_scope();
|
||||||
Variable* var = nullptr;
|
Variable* var = nullptr;
|
||||||
bool should_hoist = true;
|
bool should_hoist = true;
|
||||||
|
@ -124,8 +124,6 @@ try {
|
|||||||
}
|
}
|
||||||
assertTrue(caught);
|
assertTrue(caught);
|
||||||
|
|
||||||
// TODO(littledan): Hoisting x out of the block should be
|
|
||||||
// prevented in this case BUG(v8:4479)
|
|
||||||
caught = false
|
caught = false
|
||||||
try {
|
try {
|
||||||
(function() {
|
(function() {
|
||||||
@ -137,5 +135,4 @@ try {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
caught = true;
|
caught = true;
|
||||||
}
|
}
|
||||||
// TODO(littledan): switch to assertTrue when bug is fixed
|
assertFalse(caught);
|
||||||
assertTrue(caught);
|
|
||||||
|
@ -461,7 +461,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
throw 0;
|
throw 0;
|
||||||
} catch(f) {
|
} catch (f) {
|
||||||
{
|
{
|
||||||
assertEquals(4, f());
|
assertEquals(4, f());
|
||||||
|
|
||||||
@ -471,6 +471,8 @@
|
|||||||
|
|
||||||
assertEquals(4, f());
|
assertEquals(4, f());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertEquals(0, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(4, f());
|
assertEquals(4, f());
|
||||||
@ -479,7 +481,7 @@
|
|||||||
(function noHoistingThroughComplexCatch() {
|
(function noHoistingThroughComplexCatch() {
|
||||||
try {
|
try {
|
||||||
throw 0;
|
throw 0;
|
||||||
} catch({f}) {
|
} catch ({f}) {
|
||||||
{
|
{
|
||||||
assertEquals(4, f());
|
assertEquals(4, f());
|
||||||
|
|
||||||
@ -494,6 +496,26 @@
|
|||||||
assertThrows(()=>f, ReferenceError);
|
assertThrows(()=>f, ReferenceError);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function hoistingThroughWith() {
|
||||||
|
with ({f: 0}) {
|
||||||
|
assertEquals(0, f);
|
||||||
|
|
||||||
|
{
|
||||||
|
assertEquals(4, f());
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(4, f());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(0, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(4, f());
|
||||||
|
})();
|
||||||
|
|
||||||
// Test that hoisting from blocks does happen in global scope
|
// Test that hoisting from blocks does happen in global scope
|
||||||
function globalHoisted() { return 0; }
|
function globalHoisted() { return 0; }
|
||||||
{
|
{
|
||||||
@ -572,30 +594,63 @@ eval(`
|
|||||||
`);
|
`);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
// This test is incorrect BUG(v8:5168). The commented assertions are correct.
|
||||||
|
(function evalHoistingThroughSimpleCatch() {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (f) {
|
||||||
|
eval(`{ function f() {
|
||||||
|
return 4;
|
||||||
|
} }`);
|
||||||
|
|
||||||
|
// assertEquals(0, f);
|
||||||
|
assertEquals(4, f());
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertEquals(4, f());
|
||||||
|
assertEquals(undefined, f);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// This test is incorrect BUG(v8:5168). The commented assertions are correct.
|
||||||
|
(function evalHoistingThroughWith() {
|
||||||
|
with ({f: 0}) {
|
||||||
|
eval(`{ function f() {
|
||||||
|
return 4;
|
||||||
|
} }`);
|
||||||
|
|
||||||
|
// assertEquals(0, f);
|
||||||
|
assertEquals(4, f());
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertEquals(4, f());
|
||||||
|
assertEquals(undefined, f);
|
||||||
|
})();
|
||||||
|
|
||||||
let dontHoistGlobal;
|
let dontHoistGlobal;
|
||||||
{ function dontHoistGlobal() {} }
|
{ function dontHoistGlobal() {} }
|
||||||
assertEquals(undefined, dontHoistGlobal);
|
assertEquals(undefined, dontHoistGlobal);
|
||||||
|
|
||||||
let dontHoistEval;
|
let dontHoistEval;
|
||||||
// BUG(v8:) This shouldn't hoist and shouldn't throw
|
|
||||||
var throws = false;
|
var throws = false;
|
||||||
try {
|
try {
|
||||||
eval("{ function dontHoistEval() {} }");
|
eval("{ function dontHoistEval() {} }");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throws = true;
|
throws = true;
|
||||||
}
|
}
|
||||||
assertTrue(throws);
|
assertFalse(throws);
|
||||||
|
|
||||||
// When the global object is frozen, silently don't hoist
|
// When the global object is frozen, silently don't hoist
|
||||||
// Currently this actually throws BUG(v8:4452)
|
// Currently this actually throws BUG(v8:4452)
|
||||||
Object.freeze(this);
|
Object.freeze(this);
|
||||||
throws = false;
|
{
|
||||||
try {
|
let throws = false;
|
||||||
eval('{ function hoistWhenFrozen() {} }');
|
try {
|
||||||
} catch (e) {
|
eval('{ function hoistWhenFrozen() {} }');
|
||||||
throws = true;
|
} catch (e) {
|
||||||
|
throws = true;
|
||||||
|
}
|
||||||
|
assertFalse(this.hasOwnProperty("hoistWhenFrozen"));
|
||||||
|
assertThrows(() => hoistWhenFrozen, ReferenceError);
|
||||||
|
// Should be assertFalse BUG(v8:4452)
|
||||||
|
assertTrue(throws);
|
||||||
}
|
}
|
||||||
assertFalse(this.hasOwnProperty("hoistWhenFrozen"));
|
|
||||||
assertThrows(() => hoistWhenFrozen, ReferenceError);
|
|
||||||
// Should be assertFalse BUG(v8:4452)
|
|
||||||
assertTrue(throws);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user