Reviewers: rossberg,

Message:
PTAL

Description:
[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

Please review this at https://codereview.chromium.org/1314203002/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+64, -30 lines):
  M src/messages.h
  M src/parser.cc
  M src/preparser.cc
  M test/cctest/test-parsing.cc
  M test/mjsunit/strong/function-arity.js


Index: src/messages.h
diff --git a/src/messages.h b/src/messages.h
index f08135bb16e17c5db3d713a3514a418f12b44536..5c9c32357d5f3b01547a881a207be365c04c6825 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -334,6 +334,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") \
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index 7ddd0fce0c804b2924ce422307c0e0b12110ed07..c0d26cc15835e235a6e6bdd04bcef2f886858011 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -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
Index: src/preparser.cc
diff --git a/src/preparser.cc b/src/preparser.cc
index 7e75e78ef9c2e0753c26e6f8bf9f5303ddc02f70..1c8d9643f0c0f92b7edf21226a02f19400de2b50 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -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;
       }
Index: test/cctest/test-parsing.cc
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 1ea550caab1dc65b1fe0f320531bb250748c604d..d34d4b5aa22e310f8f3646c1ca1d4dc27899d39b 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -6098,6 +6098,41 @@ 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}};

Index: test/mjsunit/strong/function-arity.js
diff --git a/test/mjsunit/strong/function-arity.js b/test/mjsunit/strong/function-arity.js index 8eddc5e4a73bc916790d6d7162601e9746dfea38..64d76c1ac0fe65fbefdaf3a6db3157fb65a1f80d 100644
--- a/test/mjsunit/strong/function-arity.js
+++ b/test/mjsunit/strong/function-arity.js
@@ -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)})`;


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to