Reviewers: Dan Ehrenberg, rossberg,

Message:
On 2015/09/03 00:10:29, rossberg wrote:
Hm, I don't quite understand this CL. It seems to special-case for-loops, but
there are many other constructs that could introduce conflicting bindings.
Shouldn't these conflicts be detected in a more central place? Specifically, I
think you want to invoke something similar to the existing
CheckConflictingDeclarations in the function that parses the `catch` phrase.

We will also have to deal with let-/const-bindings, but the for-of case is
particularly awkward because B.3.5 specifies that var-/for-/for-in-bindings
are fine.

I wasn't sure if there was a better way to make sure for-of acts correctly given
those constraints.

Description:
Do not permit binding over catch parameters in for-of

This is banned by the ES6 spec (see sections 13.15.1
and B.3.5). When done inside an eval, throw a runtime
SyntaxError. We should get an early SyntaxError otherwise.

[email protected]
LOG=N
BUG=v8:4231

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

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

Affected files (+49, -13 lines):
  M src/parser.h
  M src/parser.cc
  A + test/mjsunit/es6/try-catch-for-of.js


Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index d993d20595de80567f267e8410dfe77edcbe450c..51d665ad5596c98062ee5bf392e12e360f44aedc 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3617,13 +3617,13 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,

         DCHECK(parsing_result.declarations.length() == 1);
         Block* init_block = nullptr;
+        const AstRawString* name = parsing_result.SingleName();

         // special case for legacy for (var/const x =.... in)
         if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
             parsing_result.declarations[0].initializer != nullptr) {
           VariableProxy* single_var = scope_->NewUnresolved(
-              factory(), parsing_result.SingleName(), Variable::NORMAL,
-              each_beg_pos, each_end_pos);
+ factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
           init_block = factory()->NewBlock(
               nullptr, 2, true, parsing_result.descriptor.declaration_pos);
           init_block->AddStatement(
@@ -3636,6 +3636,16 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
               zone());
         }

+        // For some reason, we can't bind over catch parameters in for-of.
+        if (mode == ForEachStatement::ITERATE &&
+            IsDeclaredAsCatchParameter(scope_, name)) {
+ ParserTraits::ReportMessageAt(parsing_result.first_initializer_loc,
+                                        MessageTemplate::kVarRedeclaration,
+                                        name);
+          *ok = false;
+          return nullptr;
+        }
+
         // Rewrite a for-in/of statement of the form
         //
         //   for (let/const/var x in/of e) b
@@ -4816,6 +4826,13 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
   }
 }

+bool Parser::IsDeclaredAsCatchParameter(Scope* scope,
+                                        const AstRawString* name) {
+  for (; scope != NULL; scope = scope->outer_scope())
+    if (scope->is_catch_scope() && scope->LookupLocal(name)) return true;
+  return false;
+}
+

// ----------------------------------------------------------------------------
 // Parser support
Index: src/parser.h
diff --git a/src/parser.h b/src/parser.h
index effa562e2bc9d25862bd37e8d57ac6ae9f87ee57..9964e20d005e27d633989830116dba4b6983ae3f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -1134,6 +1134,11 @@ class Parser : public ParserBase<ParserTraits> {
   // hoisted over such a scope.
   void CheckConflictingVarDeclarations(Scope* scope, bool* ok);

+ // Catch statements introduce some odd scoping constraints. You can't put a
+  // for-of statement that tries to bind to the same identifier as the
+  // CatchParameter, for example. (see B.3.5)
+  bool IsDeclaredAsCatchParameter(Scope* scope, const AstRawString* name);
+
   // Parser support
VariableProxy* NewUnresolved(const AstRawString* name, VariableMode mode);
   Variable* Declare(Declaration* declaration,
Index: test/mjsunit/es6/try-catch-for-of.js
diff --git a/test/mjsunit/d8-worker-spawn-worker.js b/test/mjsunit/es6/try-catch-for-of.js
similarity index 73%
copy from test/mjsunit/d8-worker-spawn-worker.js
copy to test/mjsunit/es6/try-catch-for-of.js
index a114d8587e0ebc7095565cfebb3634e7fdefbbe7..560aa3118a287a90148ae5b1f3365bc685602c01 100644
--- a/test/mjsunit/d8-worker-spawn-worker.js
+++ b/test/mjsunit/es6/try-catch-for-of.js
@@ -25,16 +25,30 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-if (this.Worker) {
-  var workerScript =
-    `var w = new Worker('postMessage(42)');
-     onmessage = function(parentMsg) {
-       w.postMessage(parentMsg);
-       var childMsg = w.getMessage();
-       postMessage(childMsg);
-     };`;
+// Test that we throw syntax errors when users attempt to shadow
+// try-catch bindings with for-of statements.

-  var w = new Worker(workerScript);
-  w.postMessage(9);
-  assertEquals(42, w.getMessage());
+function testEarlyError(s) {
+  assertThrows(function() {
+    eval("(function() { " + s + " })")
+  }, SyntaxError);
+}
+
+testEarlyError("try {} catch (e) { for (var e of []) {} }");
+
+assertThrows(function () {
+  try {
+    throw null;
+  } catch (e) {
+    eval("for (var e of []) {}");
+  }
+}, SyntaxError);
+
+// For-in statements should be fine, though.
+
+try {} catch (f) { for (var f in []) {} }
+try {
+  throw null;
+} catch (g) {
+  eval("for (var g in []) {}");
 }


--
--
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