Bug 1361143 - Enforce lookahead restriction for "async function" in expression statements. r=shu
authorAndré Bargull <andre.bargull@gmail.com>
Tue, 02 May 2017 13:01:09 -0700
changeset 579411 61ea278ec2042af28a6aae57e148988778d1facb
parent 579410 714b7caf7e00baa43754fbd0f01f8175ef754c77
child 579412 8c48de4eaf82122b0c8e92845557bbca25aa07d5
push id59244
push usergsquelart@mozilla.com
push dateWed, 17 May 2017 09:45:34 +0000
reviewersshu
bugs1361143
milestone55.0a1
Bug 1361143 - Enforce lookahead restriction for "async function" in expression statements. r=shu
js/src/frontend/Parser.cpp
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5877,41 +5877,17 @@ Parser<ParseHandler, CharT>::consequentO
         return null();
 
     // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in
     // non-strict code act as if they were braced: |if (x) function f() {}|
     // parses as |if (x) { function f() {} }|.
     //
     // Careful!  FunctionDeclaration doesn't include generators or async
     // functions.
-    if (next == TOK_ASYNC) {
-        tokenStream.consumeKnownToken(next, TokenStream::Operand);
-
-        // Peek only on the same line: ExpressionStatement's lookahead
-        // restriction is phrased as
-        //
-        //   [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]
-        //
-        // meaning that code like this is valid:
-        //
-        //   if (true)
-        //     async       // ASI opportunity
-        //   function clownshoes() {}
-        TokenKind maybeFunction;
-        if (!tokenStream.peekTokenSameLine(&maybeFunction))
-            return null();
-
-        if (maybeFunction == TOK_FUNCTION) {
-            error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations");
-            return null();
-        }
-
-        // Otherwise this |async| begins an ExpressionStatement.
-        tokenStream.ungetToken();
-    } else if (next == TOK_FUNCTION) {
+    if (next == TOK_FUNCTION) {
         tokenStream.consumeKnownToken(next, TokenStream::Operand);
 
         // Parser::statement would handle this, but as this function handles
         // every other error case, it seems best to handle this.
         if (pc->sc()->strict()) {
             error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
             return null();
         }
@@ -7537,21 +7513,17 @@ Parser<ParseHandler, CharT>::statement(Y
         if (!tokenStream.peekToken(&next))
             return null();
 
         // |let| here can only be an Identifier, not a declaration.  Give nicer
         // errors for declaration-looking typos.
         if (tt == TOK_LET) {
             bool forbiddenLetDeclaration = false;
 
-            if (pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) {
-                // |let| can't be an Identifier in strict mode code.  Ditto for
-                // non-standard JavaScript 1.7+.
-                forbiddenLetDeclaration = true;
-            } else if (next == TOK_LB) {
+            if (next == TOK_LB) {
                 // Enforce ExpressionStatement's 'let [' lookahead restriction.
                 forbiddenLetDeclaration = true;
             } else if (next == TOK_LC || TokenKindIsPossibleIdentifier(next)) {
                 // 'let {' and 'let foo' aren't completely forbidden, if ASI
                 // causes 'let' to be the entire Statement.  But if they're
                 // same-line, we can aggressively give a better error message.
                 //
                 // Note that this ignores 'yield' as TOK_YIELD: we'll handle it
@@ -7566,16 +7538,38 @@ Parser<ParseHandler, CharT>::statement(Y
 
                 forbiddenLetDeclaration = nextSameLine != TOK_EOL;
             }
 
             if (forbiddenLetDeclaration) {
                 error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
                 return null();
             }
+        } else if (tt == TOK_ASYNC) {
+            // Peek only on the same line: ExpressionStatement's lookahead
+            // restriction is phrased as
+            //
+            //   [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]
+            //
+            // meaning that code like this is valid:
+            //
+            //   if (true)
+            //     async       // ASI opportunity
+            //   function clownshoes() {}
+            TokenKind maybeFunction;
+            if (!tokenStream.peekTokenSameLine(&maybeFunction))
+                return null();
+
+            if (maybeFunction == TOK_FUNCTION) {
+                error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations");
+                return null();
+            }
+
+            // Otherwise this |async| begins an ExpressionStatement or is a
+            // label name.
         }
 
         // NOTE: It's unfortunately allowed to have a label named 'let' in
         //       non-strict code.  💯
         if (next == TOK_COLON)
             return labeledStatement(yieldHandling);
 
         return expressionStatement(yieldHandling);