Commit 05f01b3f authored by conradw's avatar conradw Committed by Commit bot

[strong] Class constructor bodies cannot contain "use strong" directive

Since the constructor is also the class object itself, allowing it to
retroactively become a strong object would have unintuitive consequences
wrt the strength of the other functions of the class, and whether instances
would be considered instances of a strong class.

BUG=v8:3956
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30519}
parent d1fa7bcc
......@@ -335,6 +335,8 @@ class CallSite {
T(StrictWith, "Strict mode code may not include a with statement") \
T(StrongArguments, \
"In strong mode, 'arguments' is deprecated, use '...args' instead") \
T(StrongConstructorDirective, \
"\"use strong\" directive is disallowed in class constructor body") \
T(StrongConstructorReturnMisplaced, \
"In strong mode, returning from a constructor before its super " \
"constructor invocation or all assignments to 'this' is deprecated") \
......
......@@ -1321,6 +1321,25 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
token_loc.end_pos - token_loc.beg_pos ==
ast_value_factory()->use_strong_string()->length() + 2;
if (use_strict_found || use_strong_found) {
// Strong mode implies strict mode. If there are several "use strict"
// / "use strong" directives, do the strict mode changes only once.
if (is_sloppy(scope_->language_mode())) {
scope_->SetLanguageMode(
static_cast<LanguageMode>(scope_->language_mode() | STRICT));
}
if (use_strong_found) {
scope_->SetLanguageMode(
static_cast<LanguageMode>(scope_->language_mode() | STRONG));
if (i::IsConstructor(function_state_->kind())) {
// "use strong" cannot occur in a class constructor body, to avoid
// unintuitive strong class object semantics.
ParserTraits::ReportMessageAt(
token_loc, MessageTemplate::kStrongConstructorDirective);
*ok = false;
return nullptr;
}
}
if (!scope_->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
......@@ -1334,18 +1353,6 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
*ok = false;
return nullptr;
}
// Strong mode implies strict mode. If there are several "use strict"
// / "use strong" directives, do the strict mode changes only once.
if (is_sloppy(scope_->language_mode())) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRICT));
}
if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRONG));
}
// Because declarations in strict eval code don't leak into the scope
// of the eval call, it is likely that functions declared in strict
// eval code will be used within the eval code, so lazy parsing is
......
......@@ -262,6 +262,14 @@ void PreParser::ParseStatementList(int end_token, bool* ok,
} else if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRONG));
if (i::IsConstructor(function_state_->kind())) {
// "use strong" cannot occur in a class constructor body, to avoid
// unintuitive strong class object semantics.
PreParserTraits::ReportMessageAt(
token_loc, MessageTemplate::kStrongConstructorDirective);
*ok = false;
return;
}
} else if (!statement.IsStringLiteral()) {
directive_prologue = false;
}
......
......@@ -6108,6 +6108,33 @@ TEST(StrongConstructorReturns) {
}
TEST(StrongConstructorDirective) {
const char* context_data[][2] = {{"class c { ", " }"},
{"(class c { ", " });"},
{"let a = (class c { ", " });"},
{NULL}};
const char* error_data[] = {
"constructor() { \"use strong\" }",
"constructor(...rest) { \"use strong\" }",
"foo() {} constructor() { \"use strong\" }",
"foo(...rest) { \"use strict\" } constructor() { \"use strong\" }", NULL};
const char* success_data[] = {
"constructor() { \"use strict\" }", "foo() { \"use strong\" }",
"foo() { \"use strong\" } constructor() {}", NULL};
static const ParserFlag always_flags[] = {
kAllowHarmonyRestParameters, kAllowHarmonySloppy, kAllowHarmonySloppyLet,
kAllowStrongMode};
RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(StrongUndefinedLocal) {
const char* context_data[][2] = {{"", ""}, {NULL}};
......
......@@ -176,10 +176,6 @@ function generateSpread(n) {
let defs = [
`'use strong';
class C { constructor(${genParams(parameterCount)}) {} }`,
`'use strict';
class C {
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}`,
];
for (let def of defs) {
let calls = [
......@@ -217,15 +213,6 @@ function generateSpread(n) {
super(${genArgs(argumentCount)});
}
}`,
`'use strict';
class B {
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}
class C extends B {
constructor() {
super(${genArgs(argumentCount)});
}
}`,
];
for (let def of defs) {
let code = `${def}; new C();`;
......@@ -253,11 +240,6 @@ function generateSpread(n) {
constructor(${genParams(parameterCount)}) {}
}
class C extends B {}`,
`'use strict';
class B {
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}
class C extends B {}`,
];
for (let def of defs) {
let code = `${def}; new C(${genArgs(argumentCount)})`;
......
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