Repository: babel/babel (TypeScript)

Issue:
[Bug]: Babel throws on computed property access `using[x]`
### 💻

- [X] Would you like to work on a fix?

### How are you using Babel?

Programmatic API (`babel.transform`, `babel.parse`)

### Input code

```js
var using = [];
using[0];
```

[REPL](https://babel.dev/repl#?browsers=&build=&builtIns=false&corejs=3.21&spec=false&loose=true&code_lz=G4QwTgBArgzglgOwOYQLwQNoF0DcAoWRJDABlyA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Ctypescript&prettier=false&targets=&version=7.20.4&externalPlugins=&assumptions=%7B%7D)

### Configuration file name

_No response_

### Configuration

REPL

### Current and expected behavior

Current: Babel throws "Support for the experimental syntax 'explicitResourceManagement' isn't currently enabled (2:1)"

Expected: Babel parses it successfully.

### Environment

REPL

### Possible solution

_No response_

### Additional context

This is a regression introduced in https://github.com/babel/babel/pull/14968.

The bug is already covered in the test case

https://github.com/babel/babel/blob/e7405b99695b4b499a7a9494e4b5ecb1adc2e445/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/input.js#L3

but the behaviour is not correct since it is already valid JS.


Hints:
Hey @JLHwung! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.
Note that https://github.com/babel/babel/blob/e7405b99695b4b499a7a9494e4b5ecb1adc2e445/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/input.js#L2

will be valid under the [Extractors proposal](https://github.com/tc39/proposal-extractors). I tend to remove the recoverable errors for the using-binding-pattern scenario.

Patch:
diff --git a/packages/babel-parser/src/parser/expression.ts b/packages/babel-parser/src/parser/expression.ts
--- a/packages/babel-parser/src/parser/expression.ts
+++ b/packages/babel-parser/src/parser/expression.ts
@@ -1304,10 +1304,8 @@ export default abstract class ExpressionParser extends LValParser {
             if (type === tt._function) {
               this.resetPreviousNodeTrailingComments(id);
               this.next();
-              return this.parseFunction(
+              return this.parseAsyncFunctionExpression(
                 this.startNodeAtNode(id),
-                undefined,
-                true,
               );
             } else if (tokenIsIdentifier(type)) {
               // If the next token begins with "=", commit to parsing an async
@@ -2407,13 +2405,10 @@ export default abstract class ExpressionParser extends LValParser {
 
   // Initialize empty function node.
 
-  initFunction(
-    node: N.BodilessFunctionOrMethodBase,
-    isAsync?: boolean | null,
-  ): void {
+  initFunction(node: N.BodilessFunctionOrMethodBase, isAsync: boolean): void {
     node.id = null;
     node.generator = false;
-    node.async = !!isAsync;
+    node.async = isAsync;
   }
 
   // Parse object or class method.
@@ -2429,7 +2424,7 @@ export default abstract class ExpressionParser extends LValParser {
     inClassScope: boolean = false,
   ): T {
     this.initFunction(node, isAsync);
-    node.generator = !!isGenerator;
+    node.generator = isGenerator;
     const allowModifiers = isConstructor; // For TypeScript parameter properties
     this.scope.enter(
       SCOPE_FUNCTION |
diff --git a/packages/babel-parser/src/parser/statement.ts b/packages/babel-parser/src/parser/statement.ts
--- a/packages/babel-parser/src/parser/statement.ts
+++ b/packages/babel-parser/src/parser/statement.ts
@@ -46,10 +46,21 @@ import type Parser from "./index";
 const loopLabel = { kind: "loop" } as const,
   switchLabel = { kind: "switch" } as const;
 
-const FUNC_NO_FLAGS = 0b000,
-  FUNC_STATEMENT = 0b001,
-  FUNC_HANGING_STATEMENT = 0b010,
-  FUNC_NULLABLE_ID = 0b100;
+export const enum ParseFunctionFlag {
+  Expression = 0b0000,
+  Declaration = 0b0001,
+  HangingDeclaration = 0b0010,
+  NullableId = 0b0100,
+  Async = 0b1000,
+}
+
+export const enum ParseStatementFlag {
+  StatementOnly = 0b0000,
+  AllowImportExport = 0b0001,
+  AllowDeclaration = 0b0010,
+  AllowFunctionDeclaration = 0b0100,
+  AllowLabeledFunction = 0b1000,
+}
 
 const loneSurrogate = /[\uD800-\uDFFF]/u;
 
@@ -277,42 +288,16 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.finishNode(node, "InterpreterDirective");
   }
 
-  isLet(context?: string | null): boolean {
+  isLet(): boolean {
     if (!this.isContextual(tt._let)) {
       return false;
     }
-    return this.hasFollowingIdentifier(context);
+    return this.hasFollowingBindingAtom();
   }
 
-  /**
-   * Assuming we have seen a contextual `let`, check if it starts a variable declaration
-   so that `left` should be interpreted as a `let` keyword.
-   *
-   * @param {?string} context When `context` is non nullish, it will return early and _skip_ checking
-                              if the next token after `let` is `{` or a keyword relational operator
-   * @returns {boolean}
-   * @memberof StatementParser
-   */
-  hasFollowingIdentifier(context?: string | null): boolean {
-    const next = this.nextTokenStart();
-    const nextCh = this.codePointAtPos(next);
-    // For ambiguous cases, determine if a LexicalDeclaration (or only a
-    // Statement) is allowed here. If context is not empty then only a Statement
-    // is allowed. However, `let [` is an explicit negative lookahead for
-    // ExpressionStatement, so special-case it first.
-    // Also, `let \` is never valid as an expression so this must be a keyword.
-    if (
-      nextCh === charCodes.backslash ||
-      nextCh === charCodes.leftSquareBracket
-    ) {
-      return true;
-    }
-    if (context) return false;
-
-    if (nextCh === charCodes.leftCurlyBrace) return true;
-
-    if (isIdentifierStart(nextCh)) {
-      keywordRelationalOperator.lastIndex = next;
+  chStartsBindingIdentifier(ch: number, pos: number) {
+    if (isIdentifierStart(ch)) {
+      keywordRelationalOperator.lastIndex = pos;
       if (keywordRelationalOperator.test(this.input)) {
         // We have seen `in` or `instanceof` so far, now check if the identfier
         // ends here
@@ -322,8 +307,46 @@ export default abstract class StatementParser extends ExpressionParser {
         }
       }
       return true;
+    } else if (ch === charCodes.backslash) {
+      return true;
+    } else {
+      return false;
     }
-    return false;
+  }
+
+  chStartsBindingPattern(ch: number) {
+    return (
+      ch === charCodes.leftSquareBracket || ch === charCodes.leftCurlyBrace
+    );
+  }
+
+  /**
+   * Assuming we have seen a contextual `let` and declaration is allowed, check if it
+   * starts a variable declaration so that it should be interpreted as a keyword.
+   *
+   * @returns {boolean}
+   * @memberof StatementParser
+   */
+  hasFollowingBindingAtom(): boolean {
+    const next = this.nextTokenStart();
+    const nextCh = this.codePointAtPos(next);
+    return (
+      this.chStartsBindingPattern(nextCh) ||
+      this.chStartsBindingIdentifier(nextCh, next)
+    );
+  }
+
+  /**
+   * Assuming we have seen a contextual `using` and declaration is allowed, check if it
+   * starts a variable declaration so that it should be interpreted as a keyword.
+   *
+   * @returns {boolean}
+   * @memberof StatementParser
+   */
+  hasFollowingBindingIdentifier(): boolean {
+    const next = this.nextTokenStart();
+    const nextCh = this.codePointAtPos(next);
+    return this.chStartsBindingIdentifier(nextCh, next);
   }
 
   startsUsingForOf(): boolean {
@@ -337,6 +360,35 @@ export default abstract class StatementParser extends ExpressionParser {
     }
   }
 
+  // https://tc39.es/ecma262/#prod-ModuleItem
+  parseModuleItem(this: Parser) {
+    return this.parseStatementLike(
+      ParseStatementFlag.AllowImportExport |
+        ParseStatementFlag.AllowDeclaration |
+        ParseStatementFlag.AllowFunctionDeclaration |
+        ParseStatementFlag.AllowLabeledFunction,
+    );
+  }
+
+  // https://tc39.es/ecma262/#prod-StatementListItem
+  parseStatementListItem(this: Parser) {
+    return this.parseStatementLike(
+      ParseStatementFlag.AllowDeclaration |
+        ParseStatementFlag.AllowFunctionDeclaration |
+        ParseStatementFlag.AllowLabeledFunction,
+    );
+  }
+
+  parseStatementOrFunctionDeclaration(
+    this: Parser,
+    disallowLabeledFunction: boolean,
+  ) {
+    return this.parseStatementLike(
+      ParseStatementFlag.AllowFunctionDeclaration |
+        (disallowLabeledFunction ? 0 : ParseStatementFlag.AllowLabeledFunction),
+    );
+  }
+
   // Parse a single statement.
   //
   // If expecting a statement and finding a slash operator, parse a
@@ -344,29 +396,42 @@ export default abstract class StatementParser extends ExpressionParser {
   // `if (foo) /blah/.exec(foo)`, where looking at the previous token
   // does not help.
   // https://tc39.es/ecma262/#prod-Statement
+  parseStatement(this: Parser) {
+    return this.parseStatementLike(ParseStatementFlag.StatementOnly);
+  }
+
   // ImportDeclaration and ExportDeclaration are also handled here so we can throw recoverable errors
   // when they are not at the top level
-  parseStatement(
+  parseStatementLike(
     this: Parser,
-    context?: string | null,
-    topLevel?: boolean,
-  ): N.Statement {
+    flags: ParseStatementFlag,
+  ):
+    | N.Statement
+    | N.Declaration
+    | N.ImportDeclaration
+    | N.ExportDefaultDeclaration
+    | N.ExportNamedDeclaration
+    | N.ExportAllDeclaration {
     let decorators: N.Decorator[] | null = null;
 
     if (this.match(tt.at)) {
       decorators = this.parseDecorators(true);
     }
-    return this.parseStatementContent(context, topLevel, decorators);
+    return this.parseStatementContent(flags, decorators);
   }
 
   parseStatementContent(
     this: Parser,
-    context?: string | null,
-    topLevel?: boolean | null,
+    flags: ParseStatementFlag,
     decorators?: N.Decorator[] | null,
   ): N.Statement {
     const starttype = this.state.type;
     const node = this.startNode();
+    const allowDeclaration = !!(flags & ParseStatementFlag.AllowDeclaration);
+    const allowFunctionDeclaration = !!(
+      flags & ParseStatementFlag.AllowFunctionDeclaration
+    );
+    const topLevel = flags & ParseStatementFlag.AllowImportExport;
 
     // Most types of statements are recognized by the keyword they
     // start with. Many are trivial to parse, some require a bit of
@@ -380,26 +445,25 @@ export default abstract class StatementParser extends ExpressionParser {
       case tt._debugger:
         return this.parseDebuggerStatement(node as Undone<N.DebuggerStatement>);
       case tt._do:
-        return this.parseDoStatement(node as Undone<N.DoWhileStatement>);
+        return this.parseDoWhileStatement(node as Undone<N.DoWhileStatement>);
       case tt._for:
         return this.parseForStatement(node as Undone<N.ForStatement>);
       case tt._function:
         if (this.lookaheadCharCode() === charCodes.dot) break;
-        if (context) {
+        if (!allowDeclaration) {
           if (this.state.strict) {
             this.raise(Errors.StrictFunction, { at: this.state.startLoc });
-          } else if (context !== "if" && context !== "label") {
+          } else if (!allowFunctionDeclaration) {
             this.raise(Errors.SloppyFunction, { at: this.state.startLoc });
           }
         }
         return this.parseFunctionStatement(
           node as Undone<N.FunctionDeclaration>,
           false,
-          !context,
+          !allowDeclaration && allowFunctionDeclaration,
         );
-
       case tt._class:
-        if (context) this.unexpected();
+        if (!allowDeclaration) this.unexpected();
         return this.parseClass(
           this.maybeTakeDecorators(
             decorators,
@@ -421,31 +485,56 @@ export default abstract class StatementParser extends ExpressionParser {
 
       case tt._using:
         // using [no LineTerminator here] BindingList[+Using]
-        if (this.hasFollowingLineBreak()) {
+        if (
+          this.hasFollowingLineBreak() ||
+          this.state.containsEsc ||
+          !this.hasFollowingBindingIdentifier()
+        ) {
           break;
         }
-      // fall through
-      case tt._let:
-        if (this.state.containsEsc || !this.hasFollowingIdentifier(context)) {
+        this.expectPlugin("explicitResourceManagement");
+        if (!this.scope.inModule && this.scope.inTopLevel) {
+          this.raise(Errors.UnexpectedUsingDeclaration, {
+            at: this.state.startLoc,
+          });
+        } else if (!allowDeclaration) {
+          this.raise(Errors.UnexpectedLexicalDeclaration, {
+            at: this.state.startLoc,
+          });
+        }
+        return this.parseVarStatement(
+          node as Undone<N.VariableDeclaration>,
+          "using",
+        );
+      case tt._let: {
+        if (this.state.containsEsc) {
           break;
         }
-      // fall through
-      case tt._const:
-      case tt._var: {
-        const kind = this.state.value;
-        if (kind === "using") {
-          this.expectPlugin("explicitResourceManagement");
-          if (!this.scope.inModule && this.scope.inTopLevel) {
-            this.raise(Errors.UnexpectedUsingDeclaration, {
-              at: this.state.startLoc,
-            });
+        // `let [` is an explicit negative lookahead for
+        // ExpressionStatement, so special-case it first.
+        const next = this.nextTokenStart();
+        const nextCh = this.codePointAtPos(next);
+        if (nextCh !== charCodes.leftSquareBracket) {
+          if (!allowDeclaration && this.hasFollowingLineBreak()) break;
+          if (
+            !this.chStartsBindingIdentifier(nextCh, next) &&
+            nextCh !== charCodes.leftCurlyBrace
+          ) {
+            break;
           }
         }
-        if (context && kind !== "var") {
+      }
+      // fall through
+      case tt._const: {
+        if (!allowDeclaration) {
           this.raise(Errors.UnexpectedLexicalDeclaration, {
             at: this.state.startLoc,
           });
         }
+      }
+      // fall through
+      case tt._var: {
+        const kind = this.state.value;
         return this.parseVarStatement(
           node as Undone<N.VariableDeclaration>,
           kind,
@@ -516,16 +605,16 @@ export default abstract class StatementParser extends ExpressionParser {
 
       default: {
         if (this.isAsyncFunction()) {
-          if (context) {
+          if (!allowDeclaration) {
             this.raise(Errors.AsyncFunctionInSingleStatementContext, {
               at: this.state.startLoc,
             });
           }
-          this.next();
+          this.next(); // eat 'async'
           return this.parseFunctionStatement(
             node as Undone<N.FunctionDeclaration>,
             true,
-            !context,
+            !allowDeclaration && allowFunctionDeclaration,
           );
         }
       }
@@ -549,7 +638,7 @@ export default abstract class StatementParser extends ExpressionParser {
         maybeName,
         // @ts-expect-error migrate to Babel types
         expr,
-        context,
+        flags,
       );
     } else {
       return this.parseExpressionStatement(
@@ -749,7 +838,8 @@ export default abstract class StatementParser extends ExpressionParser {
     return val;
   }
 
-  parseDoStatement(
+  // https://tc39.es/ecma262/#prod-DoWhileStatement
+  parseDoWhileStatement(
     this: Parser,
     node: Undone<N.DoWhileStatement>,
   ): N.DoWhileStatement {
@@ -763,7 +853,7 @@ export default abstract class StatementParser extends ExpressionParser {
       // outside of the loop body.
       this.withSmartMixTopicForbiddingContext(() =>
         // Parse the loop body's body.
-        this.parseStatement("do"),
+        this.parseStatement(),
       );
 
     this.state.labels.pop();
@@ -808,9 +898,9 @@ export default abstract class StatementParser extends ExpressionParser {
     const startsWithUsing =
       this.isContextual(tt._using) && !this.hasFollowingLineBreak();
     const isLetOrUsing =
-      (startsWithLet && this.hasFollowingIdentifier()) ||
+      (startsWithLet && this.hasFollowingBindingAtom()) ||
       (startsWithUsing &&
-        this.hasFollowingIdentifier() &&
+        this.hasFollowingBindingIdentifier() &&
         this.startsUsingForOf());
     if (this.match(tt._var) || this.match(tt._const) || isLetOrUsing) {
       const initNode = this.startNode<N.VariableDeclaration>();
@@ -881,25 +971,35 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.parseFor(node as Undone<N.ForStatement>, init);
   }
 
+  // https://tc39.es/ecma262/#prod-HoistableDeclaration
   parseFunctionStatement(
     this: Parser,
     node: Undone<N.FunctionDeclaration>,
-    isAsync?: boolean,
-    declarationPosition?: boolean,
+    isAsync: boolean,
+    isHangingDeclaration: boolean,
   ): N.FunctionDeclaration {
-    this.next();
+    this.next(); // eat 'function'
     return this.parseFunction(
       node,
-      FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT),
-      isAsync,
+      ParseFunctionFlag.Declaration |
+        (isHangingDeclaration ? ParseFunctionFlag.HangingDeclaration : 0) |
+        (isAsync ? ParseFunctionFlag.Async : 0),
     );
   }
 
+  // https://tc39.es/ecma262/#prod-IfStatement
   parseIfStatement(this: Parser, node: Undone<N.IfStatement>) {
     this.next();
     node.test = this.parseHeaderExpression();
-    node.consequent = this.parseStatement("if");
-    node.alternate = this.eat(tt._else) ? this.parseStatement("if") : null;
+    // Annex B.3.3
+    // https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses
+    node.consequent = this.parseStatementOrFunctionDeclaration(
+      // https://tc39.es/ecma262/#sec-if-statement-static-semantics-early-errors
+      true,
+    );
+    node.alternate = this.eat(tt._else)
+      ? this.parseStatementOrFunctionDeclaration(true)
+      : null;
     return this.finishNode(node, "IfStatement");
   }
 
@@ -924,6 +1024,7 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.finishNode(node, "ReturnStatement");
   }
 
+  // https://tc39.es/ecma262/#prod-SwitchStatement
   parseSwitchStatement(this: Parser, node: Undone<N.SwitchStatement>) {
     this.next();
     node.discriminant = this.parseHeaderExpression();
@@ -959,7 +1060,7 @@ export default abstract class StatementParser extends ExpressionParser {
         this.expect(tt.colon);
       } else {
         if (cur) {
-          cur.consequent.push(this.parseStatement(null));
+          cur.consequent.push(this.parseStatementListItem());
         } else {
           this.unexpected();
         }
@@ -1039,6 +1140,8 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.finishNode(node, "TryStatement");
   }
 
+  // https://tc39.es/ecma262/#prod-VariableStatement
+  // https://tc39.es/ecma262/#prod-LexicalDeclaration
   parseVarStatement(
     this: Parser,
     node: Undone<N.VariableDeclaration>,
@@ -1051,6 +1154,7 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.finishNode(node, "VariableDeclaration");
   }
 
+  // https://tc39.es/ecma262/#prod-WhileStatement
   parseWhileStatement(
     this: Parser,
     node: Undone<N.WhileStatement>,
@@ -1066,7 +1170,7 @@ export default abstract class StatementParser extends ExpressionParser {
       // They are permitted in test expressions, outside of the loop body.
       this.withSmartMixTopicForbiddingContext(() =>
         // Parse loop body.
-        this.parseStatement("while"),
+        this.parseStatement(),
       );
 
     this.state.labels.pop();
@@ -1092,7 +1196,7 @@ export default abstract class StatementParser extends ExpressionParser {
       // part of the outer context, outside of the with statement's body.
       this.withSmartMixTopicForbiddingContext(() =>
         // Parse the statement body.
-        this.parseStatement("with"),
+        this.parseStatement(),
       );
 
     return this.finishNode(node, "WithStatement");
@@ -1103,12 +1207,13 @@ export default abstract class StatementParser extends ExpressionParser {
     return this.finishNode(node, "EmptyStatement");
   }
 
+  // https://tc39.es/ecma262/#prod-LabelledStatement
   parseLabeledStatement(
     this: Parser,
     node: Undone<N.LabeledStatement>,
     maybeName: string,
     expr: N.Identifier,
-    context?: string | null,
+    flags: ParseStatementFlag,
   ): N.LabeledStatement {
     for (const label of this.state.labels) {
       if (label.name === maybeName) {
@@ -1139,13 +1244,11 @@ export default abstract class StatementParser extends ExpressionParser {
       kind: kind,
       statementStart: this.state.start,
     });
-    node.body = this.parseStatement(
-      context
-        ? context.indexOf("label") === -1
-          ? context + "label"
-          : context
-        : "label",
-    );
+    // https://tc39.es/ecma262/#prod-LabelledItem
+    node.body =
+      flags & ParseStatementFlag.AllowLabeledFunction
+        ? this.parseStatementOrFunctionDeclaration(false)
+        : this.parseStatement();
 
     this.state.labels.pop();
     node.label = expr;
@@ -1238,7 +1341,9 @@ export default abstract class StatementParser extends ExpressionParser {
     let parsedNonDirective = false;
 
     while (!this.match(end)) {
-      const stmt = this.parseStatement(null, topLevel);
+      const stmt = topLevel
+        ? this.parseModuleItem()
+        : this.parseStatementListItem();
 
       if (directives && !parsedNonDirective) {
         if (this.isValidDirective(stmt)) {
@@ -1296,7 +1401,7 @@ export default abstract class StatementParser extends ExpressionParser {
       // outside of the loop body.
       this.withSmartMixTopicForbiddingContext(() =>
         // Parse the loop body.
-        this.parseStatement("for"),
+        this.parseStatement(),
       );
 
     this.scope.exit();
@@ -1357,7 +1462,7 @@ export default abstract class StatementParser extends ExpressionParser {
       // They are permitted in test expressions, outside of the loop body.
       this.withSmartMixTopicForbiddingContext(() =>
         // Parse loop body.
-        this.parseStatement("for"),
+        this.parseStatement(),
       );
 
     this.scope.exit();
@@ -1417,9 +1522,6 @@ export default abstract class StatementParser extends ExpressionParser {
     kind: "var" | "let" | "const" | "using",
   ): void {
     const id = this.parseBindingAtom();
-    if (kind === "using" && id.type !== "Identifier") {
-      this.raise(Errors.UsingDeclarationHasBindingPattern, { at: id });
-    }
     this.checkLVal(id, {
       in: { type: "VariableDeclarator" },
       binding: kind === "var" ? BIND_VAR : BIND_LEXICAL,
@@ -1427,29 +1529,40 @@ export default abstract class StatementParser extends ExpressionParser {
     decl.id = id;
   }
 
-  // Parse a function declaration or literal (depending on the
-  // `isStatement` parameter).
+  // https://tc39.es/ecma262/#prod-AsyncFunctionExpression
+  parseAsyncFunctionExpression(
+    this: Parser,
+    node: Undone<N.FunctionExpression>,
+  ): N.FunctionExpression {
+    return this.parseFunction(node, ParseFunctionFlag.Async);
+  }
+
+  // Parse a function declaration or expression (depending on the
+  // ParseFunctionFlag.Declaration flag).
 
   parseFunction<T extends N.NormalFunction>(
     this: Parser,
     node: Undone<T>,
-    statement: number = FUNC_NO_FLAGS,
-    isAsync: boolean = false,
+    flags: ParseFunctionFlag = ParseFunctionFlag.Expression,
   ): T {
-    const isStatement = statement & FUNC_STATEMENT;
-    const isHangingStatement = statement & FUNC_HANGING_STATEMENT;
-    const requireId = !!isStatement && !(statement & FUNC_NULLABLE_ID);
+    const hangingDeclaration = flags & ParseFunctionFlag.HangingDeclaration;
+    const isDeclaration = !!(flags & ParseFunctionFlag.Declaration);
+    const requireId = isDeclaration && !(flags & ParseFunctionFlag.NullableId);
+    const isAsync = !!(flags & ParseFunctionFlag.Async);
 
     this.initFunction(node, isAsync);
 
-    if (this.match(tt.star) && isHangingStatement) {
-      this.raise(Errors.GeneratorInSingleStatementContext, {
-        at: this.state.startLoc,
-      });
+    if (this.match(tt.star)) {
+      if (hangingDeclaration) {
+        this.raise(Errors.GeneratorInSingleStatementContext, {
+          at: this.state.startLoc,
+        });
+      }
+      this.next(); // eat *
+      node.generator = true;
     }
-    node.generator = this.eat(tt.star);
 
-    if (isStatement) {
+    if (isDeclaration) {
       node.id = this.parseFunctionId(requireId);
     }
 
@@ -1458,7 +1571,7 @@ export default abstract class StatementParser extends ExpressionParser {
     this.scope.enter(SCOPE_FUNCTION);
     this.prodParam.enter(functionFlags(isAsync, node.generator));
 
-    if (!isStatement) {
+    if (!isDeclaration) {
       node.id = this.parseFunctionId();
     }
 
@@ -1471,14 +1584,14 @@ export default abstract class StatementParser extends ExpressionParser {
       // Parse the function body.
       this.parseFunctionBodyAndFinish(
         node,
-        isStatement ? "FunctionDeclaration" : "FunctionExpression",
+        isDeclaration ? "FunctionDeclaration" : "FunctionExpression",
       );
     });
 
     this.prodParam.exit();
     this.scope.exit();
 
-    if (isStatement && !isHangingStatement) {
+    if (isDeclaration && !hangingDeclaration) {
       // We need to register this _after_ parsing the function body
       // because of TypeScript body-less function declarations,
       // which shouldn't be added to the scope.
@@ -2339,18 +2452,20 @@ export default abstract class StatementParser extends ExpressionParser {
   parseExportDefaultExpression(this: Parser): N.Expression | N.Declaration {
     const expr = this.startNode();
 
-    const isAsync = this.isAsyncFunction();
-
-    if (this.match(tt._function) || isAsync) {
+    if (this.match(tt._function)) {
       this.next();
-      if (isAsync) {
-        this.next();
-      }
-
       return this.parseFunction(
-        expr as Undone<N.FunctionExpression>,
-        FUNC_STATEMENT | FUNC_NULLABLE_ID,
-        isAsync,
+        expr as Undone<N.FunctionDeclaration>,
+        ParseFunctionFlag.Declaration | ParseFunctionFlag.NullableId,
+      );
+    } else if (this.isAsyncFunction()) {
+      this.next(); // eat 'async'
+      this.next(); // eat 'function'
+      return this.parseFunction(
+        expr as Undone<N.FunctionDeclaration>,
+        ParseFunctionFlag.Declaration |
+          ParseFunctionFlag.NullableId |
+          ParseFunctionFlag.Async,
       );
     }
 
@@ -2386,6 +2501,7 @@ export default abstract class StatementParser extends ExpressionParser {
     return res;
   }
 
+  // https://tc39.es/ecma262/#prod-ExportDeclaration
   parseExportDeclaration(
     this: Parser,
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -2399,7 +2515,7 @@ export default abstract class StatementParser extends ExpressionParser {
       );
       return node;
     }
-    return this.parseStatement(null) as N.Declaration;
+    return this.parseStatementListItem() as N.Declaration;
   }
 
   isExportDefaultSpecifier(): boolean {
diff --git a/packages/babel-parser/src/plugins/estree.ts b/packages/babel-parser/src/plugins/estree.ts
--- a/packages/babel-parser/src/plugins/estree.ts
+++ b/packages/babel-parser/src/plugins/estree.ts
@@ -120,10 +120,7 @@ export default (superClass: typeof Parser) =>
     // Overrides
     // ==================================
 
-    initFunction(
-      node: N.BodilessFunctionOrMethodBase,
-      isAsync?: boolean | null,
-    ): void {
+    initFunction(node: N.BodilessFunctionOrMethodBase, isAsync: boolean): void {
       super.initFunction(node, isAsync);
       node.expression = false;
     }
diff --git a/packages/babel-parser/src/plugins/flow/index.ts b/packages/babel-parser/src/plugins/flow/index.ts
--- a/packages/babel-parser/src/plugins/flow/index.ts
+++ b/packages/babel-parser/src/plugins/flow/index.ts
@@ -28,6 +28,7 @@ import {
   type BindingTypes,
 } from "../../util/scopeflags";
 import type { ExpressionErrors } from "../../parser/util";
+import type { ParseStatementFlag } from "../../parser/statement";
 import { Errors, ParseErrorEnum } from "../../parse-error";
 import { cloneIdentifier, type Undone } from "../../parser/node";
 
@@ -1932,7 +1933,7 @@ export default (superClass: typeof Parser) =>
     }
 
     // interfaces and enums
-    parseStatement(context?: string | null, topLevel?: boolean): N.Statement {
+    parseStatementLike(flags: ParseStatementFlag): N.Statement {
       // strict mode handling of `interface` since it's a reserved word
       if (this.state.strict && this.isContextual(tt._interface)) {
         const lookahead = this.lookahead();
@@ -1946,7 +1947,7 @@ export default (superClass: typeof Parser) =>
         this.next();
         return this.flowParseEnumDeclaration(node);
       }
-      const stmt = super.parseStatement(context, topLevel);
+      const stmt = super.parseStatementLike(flags);
       // We will parse a flow pragma in any comment before the first statement.
       if (this.flowPragma === undefined && !this.isValidDirective(stmt)) {
         this.flowPragma = null;
diff --git a/packages/babel-parser/src/plugins/placeholders.ts b/packages/babel-parser/src/plugins/placeholders.ts
--- a/packages/babel-parser/src/plugins/placeholders.ts
+++ b/packages/babel-parser/src/plugins/placeholders.ts
@@ -152,13 +152,11 @@ export default (superClass: typeof Parser) =>
      * parser/statement.js                                          *
      * ============================================================ */
 
-    hasFollowingIdentifier(context?: string | null): boolean {
-      if (super.hasFollowingIdentifier(context)) {
+    chStartsBindingIdentifier(ch: number, pos: number): boolean {
+      if (super.chStartsBindingIdentifier(ch, pos)) {
         return true;
       }
 
-      if (context) return false;
-
       // Accept "let %%" as the start of "let %%placeholder%%", as though the
       // placeholder were an identifier.
       const nextToken = this.lookahead();
@@ -196,7 +194,7 @@ export default (superClass: typeof Parser) =>
         const stmt: N.LabeledStatement = node;
         stmt.label = this.finishPlaceholder(expr, "Identifier");
         this.next();
-        stmt.body = super.parseStatement("label");
+        stmt.body = super.parseStatementOrFunctionDeclaration(false);
         return this.finishNode(stmt, "LabeledStatement");
       }
 
diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts
--- a/packages/babel-parser/src/plugins/typescript/index.ts
+++ b/packages/babel-parser/src/plugins/typescript/index.ts
@@ -35,6 +35,7 @@ import {
 import TypeScriptScopeHandler from "./scope";
 import * as charCodes from "charcodes";
 import type { ExpressionErrors } from "../../parser/util";
+import type { ParseStatementFlag } from "../../parser/statement";
 import { PARAM } from "../../util/production-parameter";
 import { Errors, ParseErrorEnum } from "../../parse-error";
 import { cloneIdentifier, type Undone } from "../../parser/node";
@@ -2009,7 +2010,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
           return super.parseFunctionStatement(
             nany,
             /* async */ false,
-            /* declarationPosition */ true,
+            /* isHangingDeclaration */ false,
           );
         }
 
@@ -2757,7 +2758,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
 
     parseVarStatement(
       node: N.VariableDeclaration,
-      kind: "var" | "let" | "const",
+      kind: "var" | "let" | "const" | "using",
       allowMissingInitializer: boolean = false,
     ) {
       const { isAmbientContext } = this.state;
@@ -2804,8 +2805,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
     }
 
     parseStatementContent(
-      context?: string | null,
-      topLevel?: boolean | null,
+      flags: ParseStatementFlag,
       decorators?: N.Decorator[] | null,
     ): N.Statement {
       if (this.match(tt._const) && this.isLookaheadContextual("enum")) {
@@ -2825,7 +2825,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
         if (result) return result;
       }
 
-      return super.parseStatementContent(context, topLevel, decorators);
+      return super.parseStatementContent(flags, decorators);
     }
 
     parseAccessModifier(): N.Accessibility | undefined | null {
@@ -3280,7 +3280,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
     // `let x: number;`
     parseVarId(
       decl: N.VariableDeclarator,
-      kind: "var" | "let" | "const",
+      kind: "var" | "let" | "const" | "using",
     ): void {
       super.parseVarId(decl, kind);
       if (


Test patch:
diff --git a/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js b/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js
@@ -0,0 +1 @@
+if (1) foo: bar: function foo(){}
diff --git a/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/output.json b/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/output.json
@@ -0,0 +1,66 @@
+{
+  "type": "File",
+  "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+  "errors": [
+    "SyntaxError: In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement. (1:17)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "IfStatement",
+        "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+        "test": {
+          "type": "NumericLiteral",
+          "start":4,"end":5,"loc":{"start":{"line":1,"column":4,"index":4},"end":{"line":1,"column":5,"index":5}},
+          "extra": {
+            "rawValue": 1,
+            "raw": "1"
+          },
+          "value": 1
+        },
+        "consequent": {
+          "type": "LabeledStatement",
+          "start":7,"end":33,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":33,"index":33}},
+          "body": {
+            "type": "LabeledStatement",
+            "start":12,"end":33,"loc":{"start":{"line":1,"column":12,"index":12},"end":{"line":1,"column":33,"index":33}},
+            "body": {
+              "type": "FunctionDeclaration",
+              "start":17,"end":33,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":33,"index":33}},
+              "id": {
+                "type": "Identifier",
+                "start":26,"end":29,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":29,"index":29},"identifierName":"foo"},
+                "name": "foo"
+              },
+              "generator": false,
+              "async": false,
+              "params": [],
+              "body": {
+                "type": "BlockStatement",
+                "start":31,"end":33,"loc":{"start":{"line":1,"column":31,"index":31},"end":{"line":1,"column":33,"index":33}},
+                "body": [],
+                "directives": []
+              }
+            },
+            "label": {
+              "type": "Identifier",
+              "start":12,"end":15,"loc":{"start":{"line":1,"column":12,"index":12},"end":{"line":1,"column":15,"index":15},"identifierName":"bar"},
+              "name": "bar"
+            }
+          },
+          "label": {
+            "type": "Identifier",
+            "start":7,"end":10,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":10,"index":10},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "alternate": null
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/input.js b/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/input.js
@@ -0,0 +1 @@
+while (1) function *foo() {}
diff --git a/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/output.json b/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/generators/invalid-sloppy-function/output.json
@@ -0,0 +1,47 @@
+{
+  "type": "File",
+  "start":0,"end":28,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":28,"index":28}},
+  "errors": [
+    "SyntaxError: In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement. (1:10)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":28,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":28,"index":28}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "WhileStatement",
+        "start":0,"end":28,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":28,"index":28}},
+        "test": {
+          "type": "NumericLiteral",
+          "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8}},
+          "extra": {
+            "rawValue": 1,
+            "raw": "1"
+          },
+          "value": 1
+        },
+        "body": {
+          "type": "FunctionDeclaration",
+          "start":10,"end":28,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":28,"index":28}},
+          "id": {
+            "type": "Identifier",
+            "start":20,"end":23,"loc":{"start":{"line":1,"column":20,"index":20},"end":{"line":1,"column":23,"index":23},"identifierName":"foo"},
+            "name": "foo"
+          },
+          "generator": true,
+          "async": false,
+          "params": [],
+          "body": {
+            "type": "BlockStatement",
+            "start":26,"end":28,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":28,"index":28}},
+            "body": [],
+            "directives": []
+          }
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/input.js
@@ -0,0 +1,3 @@
+do let
+[x] = 0
+while (false);
diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/let/let-array-with-newline/output.json
@@ -0,0 +1,56 @@
+{
+  "type": "File",
+  "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":14,"index":29}},
+  "errors": [
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (1:3)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":14,"index":29}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "DoWhileStatement",
+        "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":14,"index":29}},
+        "body": {
+          "type": "VariableDeclaration",
+          "start":3,"end":14,"loc":{"start":{"line":1,"column":3,"index":3},"end":{"line":2,"column":7,"index":14}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":7,"end":14,"loc":{"start":{"line":2,"column":0,"index":7},"end":{"line":2,"column":7,"index":14}},
+              "id": {
+                "type": "ArrayPattern",
+                "start":7,"end":10,"loc":{"start":{"line":2,"column":0,"index":7},"end":{"line":2,"column":3,"index":10}},
+                "elements": [
+                  {
+                    "type": "Identifier",
+                    "start":8,"end":9,"loc":{"start":{"line":2,"column":1,"index":8},"end":{"line":2,"column":2,"index":9},"identifierName":"x"},
+                    "name": "x"
+                  }
+                ]
+              },
+              "init": {
+                "type": "NumericLiteral",
+                "start":13,"end":14,"loc":{"start":{"line":2,"column":6,"index":13},"end":{"line":2,"column":7,"index":14}},
+                "extra": {
+                  "rawValue": 0,
+                  "raw": "0"
+                },
+                "value": 0
+              }
+            }
+          ],
+          "kind": "let"
+        },
+        "test": {
+          "type": "BooleanLiteral",
+          "start":22,"end":27,"loc":{"start":{"line":3,"column":7,"index":22},"end":{"line":3,"column":12,"index":27}},
+          "value": false
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/input.js
@@ -0,0 +1,2 @@
+while (0) let
+\u0061 = 1;
diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2015/let/let-with-linebreak-and-escaped/output.json
@@ -0,0 +1,58 @@
+{
+  "type": "File",
+  "start":0,"end":25,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":11,"index":25}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":25,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":11,"index":25}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "WhileStatement",
+        "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
+        "test": {
+          "type": "NumericLiteral",
+          "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8}},
+          "extra": {
+            "rawValue": 0,
+            "raw": "0"
+          },
+          "value": 0
+        },
+        "body": {
+          "type": "ExpressionStatement",
+          "start":10,"end":13,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":13,"index":13}},
+          "expression": {
+            "type": "Identifier",
+            "start":10,"end":13,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":13,"index":13},"identifierName":"let"},
+            "name": "let"
+          }
+        }
+      },
+      {
+        "type": "ExpressionStatement",
+        "start":14,"end":25,"loc":{"start":{"line":2,"column":0,"index":14},"end":{"line":2,"column":11,"index":25}},
+        "expression": {
+          "type": "AssignmentExpression",
+          "start":14,"end":24,"loc":{"start":{"line":2,"column":0,"index":14},"end":{"line":2,"column":10,"index":24}},
+          "operator": "=",
+          "left": {
+            "type": "Identifier",
+            "start":14,"end":20,"loc":{"start":{"line":2,"column":0,"index":14},"end":{"line":2,"column":6,"index":20},"identifierName":"a"},
+            "name": "a"
+          },
+          "right": {
+            "type": "NumericLiteral",
+            "start":23,"end":24,"loc":{"start":{"line":2,"column":9,"index":23},"end":{"line":2,"column":10,"index":24}},
+            "extra": {
+              "rawValue": 1,
+              "raw": "1"
+            },
+            "value": 1
+          }
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/es2015/statements/label-invalid-let/output.json b/packages/babel-parser/test/fixtures/es2015/statements/label-invalid-let/output.json
--- a/packages/babel-parser/test/fixtures/es2015/statements/label-invalid-let/output.json
+++ b/packages/babel-parser/test/fixtures/es2015/statements/label-invalid-let/output.json
@@ -2,7 +2,7 @@
   "type": "File",
   "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
   "errors": [
-    "SyntaxError: Missing semicolon. (1:8)"
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (1:5)"
   ],
   "program": {
     "type": "Program",
@@ -12,30 +12,29 @@
     "body": [
       {
         "type": "LabeledStatement",
-        "start":0,"end":8,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":8,"index":8}},
+        "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
         "body": {
-          "type": "ExpressionStatement",
-          "start":5,"end":8,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":8,"index":8}},
-          "expression": {
-            "type": "Identifier",
-            "start":5,"end":8,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":8,"index":8},"identifierName":"let"},
-            "name": "let"
-          }
+          "type": "VariableDeclaration",
+          "start":5,"end":13,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":13,"index":13}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":9,"end":12,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":12,"index":12}},
+              "id": {
+                "type": "Identifier",
+                "start":9,"end":12,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":12,"index":12},"identifierName":"bar"},
+                "name": "bar"
+              },
+              "init": null
+            }
+          ],
+          "kind": "let"
         },
         "label": {
           "type": "Identifier",
           "start":0,"end":3,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":3,"index":3},"identifierName":"foo"},
           "name": "foo"
         }
-      },
-      {
-        "type": "ExpressionStatement",
-        "start":9,"end":13,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":13,"index":13}},
-        "expression": {
-          "type": "Identifier",
-          "start":9,"end":12,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":12,"index":12},"identifierName":"bar"},
-          "name": "bar"
-        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/328/output.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/328/output.json
--- a/packages/babel-parser/test/fixtures/es2015/uncategorised/328/output.json
+++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/328/output.json
@@ -2,7 +2,7 @@
   "type": "File",
   "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
   "errors": [
-    "SyntaxError: Missing semicolon. (1:10)"
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (1:7)"
   ],
   "program": {
     "type": "Program",
@@ -12,7 +12,7 @@
     "body": [
       {
         "type": "IfStatement",
-        "start":0,"end":10,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":10,"index":10}},
+        "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
         "test": {
           "type": "NumericLiteral",
           "start":4,"end":5,"loc":{"start":{"line":1,"column":4,"index":4},"end":{"line":1,"column":5,"index":5}},
@@ -23,38 +23,31 @@
           "value": 1
         },
         "consequent": {
-          "type": "ExpressionStatement",
-          "start":7,"end":10,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":10,"index":10}},
-          "expression": {
-            "type": "Identifier",
-            "start":7,"end":10,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":10,"index":10},"identifierName":"let"},
-            "name": "let"
-          }
+          "type": "VariableDeclaration",
+          "start":7,"end":18,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":18,"index":18}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":11,"end":17,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":17,"index":17}},
+              "id": {
+                "type": "Identifier",
+                "start":11,"end":12,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":12,"index":12},"identifierName":"x"},
+                "name": "x"
+              },
+              "init": {
+                "type": "NumericLiteral",
+                "start":15,"end":17,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":17,"index":17}},
+                "extra": {
+                  "rawValue": 10,
+                  "raw": "10"
+                },
+                "value": 10
+              }
+            }
+          ],
+          "kind": "let"
         },
         "alternate": null
-      },
-      {
-        "type": "ExpressionStatement",
-        "start":11,"end":18,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":18,"index":18}},
-        "expression": {
-          "type": "AssignmentExpression",
-          "start":11,"end":17,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":17,"index":17}},
-          "operator": "=",
-          "left": {
-            "type": "Identifier",
-            "start":11,"end":12,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":12,"index":12},"identifierName":"x"},
-            "name": "x"
-          },
-          "right": {
-            "type": "NumericLiteral",
-            "start":15,"end":17,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":17,"index":17}},
-            "extra": {
-              "rawValue": 10,
-              "raw": "10"
-            },
-            "value": 10
-          }
-        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/input.js b/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/input.js
@@ -0,0 +1 @@
+while (1) async function *foo(){}
diff --git a/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/output.json b/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-generator-inside-loop/output.json
@@ -0,0 +1,47 @@
+{
+  "type": "File",
+  "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+  "errors": [
+    "SyntaxError: Async functions can only be declared at the top level or inside a block. (1:10)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "WhileStatement",
+        "start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":33,"index":33}},
+        "test": {
+          "type": "NumericLiteral",
+          "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8}},
+          "extra": {
+            "rawValue": 1,
+            "raw": "1"
+          },
+          "value": 1
+        },
+        "body": {
+          "type": "FunctionDeclaration",
+          "start":10,"end":33,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":33,"index":33}},
+          "id": {
+            "type": "Identifier",
+            "start":26,"end":29,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":29,"index":29},"identifierName":"foo"},
+            "name": "foo"
+          },
+          "generator": true,
+          "async": true,
+          "params": [],
+          "body": {
+            "type": "BlockStatement",
+            "start":31,"end":33,"loc":{"start":{"line":1,"column":31,"index":31},"end":{"line":1,"column":33,"index":33}},
+            "body": [],
+            "directives": []
+          }
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0141/output.json b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0141/output.json
--- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0141/output.json
+++ b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0141/output.json
@@ -2,7 +2,7 @@
   "type": "File",
   "start":0,"end":19,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":19,"index":19}},
   "errors": [
-    "SyntaxError: Missing semicolon. (1:12)"
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (1:9)"
   ],
   "program": {
     "type": "Program",
@@ -12,45 +12,38 @@
     "body": [
       {
         "type": "IfStatement",
-        "start":0,"end":12,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":12,"index":12}},
+        "start":0,"end":19,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":19,"index":19}},
         "test": {
           "type": "BooleanLiteral",
           "start":3,"end":7,"loc":{"start":{"line":1,"column":3,"index":3},"end":{"line":1,"column":7,"index":7}},
           "value": true
         },
         "consequent": {
-          "type": "ExpressionStatement",
-          "start":9,"end":12,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":12,"index":12}},
-          "expression": {
-            "type": "Identifier",
-            "start":9,"end":12,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":12,"index":12},"identifierName":"let"},
-            "name": "let"
-          }
+          "type": "VariableDeclaration",
+          "start":9,"end":19,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":19,"index":19}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":13,"end":18,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":18,"index":18}},
+              "id": {
+                "type": "Identifier",
+                "start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"a"},
+                "name": "a"
+              },
+              "init": {
+                "type": "NumericLiteral",
+                "start":17,"end":18,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":18,"index":18}},
+                "extra": {
+                  "rawValue": 1,
+                  "raw": "1"
+                },
+                "value": 1
+              }
+            }
+          ],
+          "kind": "let"
         },
         "alternate": null
-      },
-      {
-        "type": "ExpressionStatement",
-        "start":13,"end":19,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":19,"index":19}},
-        "expression": {
-          "type": "AssignmentExpression",
-          "start":13,"end":18,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":18,"index":18}},
-          "operator": "=",
-          "left": {
-            "type": "Identifier",
-            "start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"a"},
-            "name": "a"
-          },
-          "right": {
-            "type": "NumericLiteral",
-            "start":17,"end":18,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":18,"index":18}},
-            "extra": {
-              "rawValue": 1,
-              "raw": "1"
-            },
-            "value": 1
-          }
-        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/input.js
@@ -0,0 +1,8 @@
+{
+  while (1) using a;
+  for (;;) using b;
+  do using c; while (1);
+  if (1) using d;
+  with (1) using e;
+  label: using f;
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-in-single-statement-context/output.json
@@ -0,0 +1,199 @@
+{
+  "type": "File",
+  "start":0,"end":125,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":125}},
+  "errors": [
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (2:12)",
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (3:11)",
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (4:5)",
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (5:9)",
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (6:11)",
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (7:9)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":125,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":125}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "BlockStatement",
+        "start":0,"end":125,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":125}},
+        "body": [
+          {
+            "type": "WhileStatement",
+            "start":4,"end":22,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":20,"index":22}},
+            "test": {
+              "type": "NumericLiteral",
+              "start":11,"end":12,"loc":{"start":{"line":2,"column":9,"index":11},"end":{"line":2,"column":10,"index":12}},
+              "extra": {
+                "rawValue": 1,
+                "raw": "1"
+              },
+              "value": 1
+            },
+            "body": {
+              "type": "VariableDeclaration",
+              "start":14,"end":22,"loc":{"start":{"line":2,"column":12,"index":14},"end":{"line":2,"column":20,"index":22}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":20,"end":21,"loc":{"start":{"line":2,"column":18,"index":20},"end":{"line":2,"column":19,"index":21}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":20,"end":21,"loc":{"start":{"line":2,"column":18,"index":20},"end":{"line":2,"column":19,"index":21},"identifierName":"a"},
+                    "name": "a"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            }
+          },
+          {
+            "type": "ForStatement",
+            "start":25,"end":42,"loc":{"start":{"line":3,"column":2,"index":25},"end":{"line":3,"column":19,"index":42}},
+            "init": null,
+            "test": null,
+            "update": null,
+            "body": {
+              "type": "VariableDeclaration",
+              "start":34,"end":42,"loc":{"start":{"line":3,"column":11,"index":34},"end":{"line":3,"column":19,"index":42}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":40,"end":41,"loc":{"start":{"line":3,"column":17,"index":40},"end":{"line":3,"column":18,"index":41}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":40,"end":41,"loc":{"start":{"line":3,"column":17,"index":40},"end":{"line":3,"column":18,"index":41},"identifierName":"b"},
+                    "name": "b"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            }
+          },
+          {
+            "type": "DoWhileStatement",
+            "start":45,"end":67,"loc":{"start":{"line":4,"column":2,"index":45},"end":{"line":4,"column":24,"index":67}},
+            "body": {
+              "type": "VariableDeclaration",
+              "start":48,"end":56,"loc":{"start":{"line":4,"column":5,"index":48},"end":{"line":4,"column":13,"index":56}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":54,"end":55,"loc":{"start":{"line":4,"column":11,"index":54},"end":{"line":4,"column":12,"index":55}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":54,"end":55,"loc":{"start":{"line":4,"column":11,"index":54},"end":{"line":4,"column":12,"index":55},"identifierName":"c"},
+                    "name": "c"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            },
+            "test": {
+              "type": "NumericLiteral",
+              "start":64,"end":65,"loc":{"start":{"line":4,"column":21,"index":64},"end":{"line":4,"column":22,"index":65}},
+              "extra": {
+                "rawValue": 1,
+                "raw": "1"
+              },
+              "value": 1
+            }
+          },
+          {
+            "type": "IfStatement",
+            "start":70,"end":85,"loc":{"start":{"line":5,"column":2,"index":70},"end":{"line":5,"column":17,"index":85}},
+            "test": {
+              "type": "NumericLiteral",
+              "start":74,"end":75,"loc":{"start":{"line":5,"column":6,"index":74},"end":{"line":5,"column":7,"index":75}},
+              "extra": {
+                "rawValue": 1,
+                "raw": "1"
+              },
+              "value": 1
+            },
+            "consequent": {
+              "type": "VariableDeclaration",
+              "start":77,"end":85,"loc":{"start":{"line":5,"column":9,"index":77},"end":{"line":5,"column":17,"index":85}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":83,"end":84,"loc":{"start":{"line":5,"column":15,"index":83},"end":{"line":5,"column":16,"index":84}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":83,"end":84,"loc":{"start":{"line":5,"column":15,"index":83},"end":{"line":5,"column":16,"index":84},"identifierName":"d"},
+                    "name": "d"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            },
+            "alternate": null
+          },
+          {
+            "type": "WithStatement",
+            "start":88,"end":105,"loc":{"start":{"line":6,"column":2,"index":88},"end":{"line":6,"column":19,"index":105}},
+            "object": {
+              "type": "NumericLiteral",
+              "start":94,"end":95,"loc":{"start":{"line":6,"column":8,"index":94},"end":{"line":6,"column":9,"index":95}},
+              "extra": {
+                "rawValue": 1,
+                "raw": "1"
+              },
+              "value": 1
+            },
+            "body": {
+              "type": "VariableDeclaration",
+              "start":97,"end":105,"loc":{"start":{"line":6,"column":11,"index":97},"end":{"line":6,"column":19,"index":105}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":103,"end":104,"loc":{"start":{"line":6,"column":17,"index":103},"end":{"line":6,"column":18,"index":104}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":103,"end":104,"loc":{"start":{"line":6,"column":17,"index":103},"end":{"line":6,"column":18,"index":104},"identifierName":"e"},
+                    "name": "e"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            }
+          },
+          {
+            "type": "LabeledStatement",
+            "start":108,"end":123,"loc":{"start":{"line":7,"column":2,"index":108},"end":{"line":7,"column":17,"index":123}},
+            "body": {
+              "type": "VariableDeclaration",
+              "start":115,"end":123,"loc":{"start":{"line":7,"column":9,"index":115},"end":{"line":7,"column":17,"index":123}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":121,"end":122,"loc":{"start":{"line":7,"column":15,"index":121},"end":{"line":7,"column":16,"index":122}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":121,"end":122,"loc":{"start":{"line":7,"column":15,"index":121},"end":{"line":7,"column":16,"index":122},"identifierName":"f"},
+                    "name": "f"
+                  },
+                  "init": null
+                }
+              ],
+              "kind": "using"
+            },
+            "label": {
+              "type": "Identifier",
+              "start":108,"end":113,"loc":{"start":{"line":7,"column":2,"index":108},"end":{"line":7,"column":7,"index":113},"identifierName":"label"},
+              "name": "label"
+            }
+          }
+        ],
+        "directives": []
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/input.js
@@ -0,0 +1,3 @@
+{
+  label: using x = bar();
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/options.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/options.json
@@ -0,0 +1,3 @@
+{
+  "sourceType": "script"
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-labeled-using-binding/output.json
@@ -0,0 +1,58 @@
+{
+  "type": "File",
+  "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":29}},
+  "errors": [
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (2:9)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":29}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "BlockStatement",
+        "start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":29}},
+        "body": [
+          {
+            "type": "LabeledStatement",
+            "start":4,"end":27,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":25,"index":27}},
+            "body": {
+              "type": "VariableDeclaration",
+              "start":11,"end":27,"loc":{"start":{"line":2,"column":9,"index":11},"end":{"line":2,"column":25,"index":27}},
+              "declarations": [
+                {
+                  "type": "VariableDeclarator",
+                  "start":17,"end":26,"loc":{"start":{"line":2,"column":15,"index":17},"end":{"line":2,"column":24,"index":26}},
+                  "id": {
+                    "type": "Identifier",
+                    "start":17,"end":18,"loc":{"start":{"line":2,"column":15,"index":17},"end":{"line":2,"column":16,"index":18},"identifierName":"x"},
+                    "name": "x"
+                  },
+                  "init": {
+                    "type": "CallExpression",
+                    "start":21,"end":26,"loc":{"start":{"line":2,"column":19,"index":21},"end":{"line":2,"column":24,"index":26}},
+                    "callee": {
+                      "type": "Identifier",
+                      "start":21,"end":24,"loc":{"start":{"line":2,"column":19,"index":21},"end":{"line":2,"column":22,"index":24},"identifierName":"bar"},
+                      "name": "bar"
+                    },
+                    "arguments": []
+                  }
+                }
+              ],
+              "kind": "using"
+            },
+            "label": {
+              "type": "Identifier",
+              "start":4,"end":9,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":7,"index":9},"identifierName":"label"},
+              "name": "label"
+            }
+          }
+        ],
+        "directives": []
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js
@@ -0,0 +1 @@
+label: using x = bar();
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/options.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/options.json
@@ -0,0 +1,3 @@
+{
+  "sourceType": "script"
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-script-top-level-labeled-using-binding/output.json
@@ -0,0 +1,51 @@
+{
+  "type": "File",
+  "start":0,"end":23,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":23,"index":23}},
+  "errors": [
+    "SyntaxError: Using declaration cannot appear in the top level when source type is `script`. (1:7)"
+  ],
+  "program": {
+    "type": "Program",
+    "start":0,"end":23,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":23,"index":23}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "LabeledStatement",
+        "start":0,"end":23,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":23,"index":23}},
+        "body": {
+          "type": "VariableDeclaration",
+          "start":7,"end":23,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":23,"index":23}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":13,"end":22,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":22,"index":22}},
+              "id": {
+                "type": "Identifier",
+                "start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"x"},
+                "name": "x"
+              },
+              "init": {
+                "type": "CallExpression",
+                "start":17,"end":22,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":22,"index":22}},
+                "callee": {
+                  "type": "Identifier",
+                  "start":17,"end":20,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":20,"index":20},"identifierName":"bar"},
+                  "name": "bar"
+                },
+                "arguments": []
+              }
+            }
+          ],
+          "kind": "using"
+        },
+        "label": {
+          "type": "Identifier",
+          "start":0,"end":5,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":5,"index":5},"identifierName":"label"},
+          "name": "label"
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/input.js
@@ -0,0 +1,3 @@
+{
+  using { foo } = f();
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/options.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-declaration/options.json
@@ -0,0 +1,3 @@
+{
+  "throws": "Unexpected token (2:16)"
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/input.js
@@ -0,0 +1,3 @@
+{
+  for (using { qux } of h());
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/options.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern-for-lhs/options.json
@@ -0,0 +1,3 @@
+{
+  "throws": "Unexpected token, expected \")\" (2:24)"
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/input.js
deleted file mode 100644
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/input.js
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  using { foo } = f();
-  using [ bar ] = g();
-  for (using { qux } of h());
-  for (using [ quux ] of i());
-}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/output.json
deleted file mode 100644
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/invalid-using-binding-pattern/output.json
+++ /dev/null
@@ -1,204 +0,0 @@
-{
-  "type": "File",
-  "start":0,"end":110,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":110}},
-  "errors": [
-    "SyntaxError: Using declaration cannot have destructuring patterns. (2:8)",
-    "SyntaxError: Using declaration cannot have destructuring patterns. (3:8)",
-    "SyntaxError: Using declaration cannot have destructuring patterns. (4:13)",
-    "SyntaxError: Using declaration cannot have destructuring patterns. (5:13)"
-  ],
-  "program": {
-    "type": "Program",
-    "start":0,"end":110,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":110}},
-    "sourceType": "script",
-    "interpreter": null,
-    "body": [
-      {
-        "type": "BlockStatement",
-        "start":0,"end":110,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":110}},
-        "body": [
-          {
-            "type": "VariableDeclaration",
-            "start":4,"end":24,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":22,"index":24}},
-            "declarations": [
-              {
-                "type": "VariableDeclarator",
-                "start":10,"end":23,"loc":{"start":{"line":2,"column":8,"index":10},"end":{"line":2,"column":21,"index":23}},
-                "id": {
-                  "type": "ObjectPattern",
-                  "start":10,"end":17,"loc":{"start":{"line":2,"column":8,"index":10},"end":{"line":2,"column":15,"index":17}},
-                  "properties": [
-                    {
-                      "type": "ObjectProperty",
-                      "start":12,"end":15,"loc":{"start":{"line":2,"column":10,"index":12},"end":{"line":2,"column":13,"index":15}},
-                      "key": {
-                        "type": "Identifier",
-                        "start":12,"end":15,"loc":{"start":{"line":2,"column":10,"index":12},"end":{"line":2,"column":13,"index":15},"identifierName":"foo"},
-                        "name": "foo"
-                      },
-                      "computed": false,
-                      "method": false,
-                      "shorthand": true,
-                      "value": {
-                        "type": "Identifier",
-                        "start":12,"end":15,"loc":{"start":{"line":2,"column":10,"index":12},"end":{"line":2,"column":13,"index":15},"identifierName":"foo"},
-                        "name": "foo"
-                      },
-                      "extra": {
-                        "shorthand": true
-                      }
-                    }
-                  ]
-                },
-                "init": {
-                  "type": "CallExpression",
-                  "start":20,"end":23,"loc":{"start":{"line":2,"column":18,"index":20},"end":{"line":2,"column":21,"index":23}},
-                  "callee": {
-                    "type": "Identifier",
-                    "start":20,"end":21,"loc":{"start":{"line":2,"column":18,"index":20},"end":{"line":2,"column":19,"index":21},"identifierName":"f"},
-                    "name": "f"
-                  },
-                  "arguments": []
-                }
-              }
-            ],
-            "kind": "using"
-          },
-          {
-            "type": "VariableDeclaration",
-            "start":27,"end":47,"loc":{"start":{"line":3,"column":2,"index":27},"end":{"line":3,"column":22,"index":47}},
-            "declarations": [
-              {
-                "type": "VariableDeclarator",
-                "start":33,"end":46,"loc":{"start":{"line":3,"column":8,"index":33},"end":{"line":3,"column":21,"index":46}},
-                "id": {
-                  "type": "ArrayPattern",
-                  "start":33,"end":40,"loc":{"start":{"line":3,"column":8,"index":33},"end":{"line":3,"column":15,"index":40}},
-                  "elements": [
-                    {
-                      "type": "Identifier",
-                      "start":35,"end":38,"loc":{"start":{"line":3,"column":10,"index":35},"end":{"line":3,"column":13,"index":38},"identifierName":"bar"},
-                      "name": "bar"
-                    }
-                  ]
-                },
-                "init": {
-                  "type": "CallExpression",
-                  "start":43,"end":46,"loc":{"start":{"line":3,"column":18,"index":43},"end":{"line":3,"column":21,"index":46}},
-                  "callee": {
-                    "type": "Identifier",
-                    "start":43,"end":44,"loc":{"start":{"line":3,"column":18,"index":43},"end":{"line":3,"column":19,"index":44},"identifierName":"g"},
-                    "name": "g"
-                  },
-                  "arguments": []
-                }
-              }
-            ],
-            "kind": "using"
-          },
-          {
-            "type": "ForOfStatement",
-            "start":50,"end":77,"loc":{"start":{"line":4,"column":2,"index":50},"end":{"line":4,"column":29,"index":77}},
-            "await": false,
-            "left": {
-              "type": "VariableDeclaration",
-              "start":55,"end":68,"loc":{"start":{"line":4,"column":7,"index":55},"end":{"line":4,"column":20,"index":68}},
-              "declarations": [
-                {
-                  "type": "VariableDeclarator",
-                  "start":61,"end":68,"loc":{"start":{"line":4,"column":13,"index":61},"end":{"line":4,"column":20,"index":68}},
-                  "id": {
-                    "type": "ObjectPattern",
-                    "start":61,"end":68,"loc":{"start":{"line":4,"column":13,"index":61},"end":{"line":4,"column":20,"index":68}},
-                    "properties": [
-                      {
-                        "type": "ObjectProperty",
-                        "start":63,"end":66,"loc":{"start":{"line":4,"column":15,"index":63},"end":{"line":4,"column":18,"index":66}},
-                        "key": {
-                          "type": "Identifier",
-                          "start":63,"end":66,"loc":{"start":{"line":4,"column":15,"index":63},"end":{"line":4,"column":18,"index":66},"identifierName":"qux"},
-                          "name": "qux"
-                        },
-                        "computed": false,
-                        "method": false,
-                        "shorthand": true,
-                        "value": {
-                          "type": "Identifier",
-                          "start":63,"end":66,"loc":{"start":{"line":4,"column":15,"index":63},"end":{"line":4,"column":18,"index":66},"identifierName":"qux"},
-                          "name": "qux"
-                        },
-                        "extra": {
-                          "shorthand": true
-                        }
-                      }
-                    ]
-                  },
-                  "init": null
-                }
-              ],
-              "kind": "using"
-            },
-            "right": {
-              "type": "CallExpression",
-              "start":72,"end":75,"loc":{"start":{"line":4,"column":24,"index":72},"end":{"line":4,"column":27,"index":75}},
-              "callee": {
-                "type": "Identifier",
-                "start":72,"end":73,"loc":{"start":{"line":4,"column":24,"index":72},"end":{"line":4,"column":25,"index":73},"identifierName":"h"},
-                "name": "h"
-              },
-              "arguments": []
-            },
-            "body": {
-              "type": "EmptyStatement",
-              "start":76,"end":77,"loc":{"start":{"line":4,"column":28,"index":76},"end":{"line":4,"column":29,"index":77}}
-            }
-          },
-          {
-            "type": "ForOfStatement",
-            "start":80,"end":108,"loc":{"start":{"line":5,"column":2,"index":80},"end":{"line":5,"column":30,"index":108}},
-            "await": false,
-            "left": {
-              "type": "VariableDeclaration",
-              "start":85,"end":99,"loc":{"start":{"line":5,"column":7,"index":85},"end":{"line":5,"column":21,"index":99}},
-              "declarations": [
-                {
-                  "type": "VariableDeclarator",
-                  "start":91,"end":99,"loc":{"start":{"line":5,"column":13,"index":91},"end":{"line":5,"column":21,"index":99}},
-                  "id": {
-                    "type": "ArrayPattern",
-                    "start":91,"end":99,"loc":{"start":{"line":5,"column":13,"index":91},"end":{"line":5,"column":21,"index":99}},
-                    "elements": [
-                      {
-                        "type": "Identifier",
-                        "start":93,"end":97,"loc":{"start":{"line":5,"column":15,"index":93},"end":{"line":5,"column":19,"index":97},"identifierName":"quux"},
-                        "name": "quux"
-                      }
-                    ]
-                  },
-                  "init": null
-                }
-              ],
-              "kind": "using"
-            },
-            "right": {
-              "type": "CallExpression",
-              "start":103,"end":106,"loc":{"start":{"line":5,"column":25,"index":103},"end":{"line":5,"column":28,"index":106}},
-              "callee": {
-                "type": "Identifier",
-                "start":103,"end":104,"loc":{"start":{"line":5,"column":25,"index":103},"end":{"line":5,"column":26,"index":104},"identifierName":"i"},
-                "name": "i"
-              },
-              "arguments": []
-            },
-            "body": {
-              "type": "EmptyStatement",
-              "start":107,"end":108,"loc":{"start":{"line":5,"column":29,"index":107},"end":{"line":5,"column":30,"index":108}}
-            }
-          }
-        ],
-        "directives": []
-      }
-    ],
-    "directives": []
-  }
-}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/input.js
@@ -0,0 +1 @@
+using (x);
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-callee/output.json
@@ -0,0 +1,33 @@
+{
+  "type": "File",
+  "start":0,"end":10,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":10,"index":10}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":10,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":10,"index":10}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "ExpressionStatement",
+        "start":0,"end":10,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":10,"index":10}},
+        "expression": {
+          "type": "CallExpression",
+          "start":0,"end":9,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":9,"index":9}},
+          "callee": {
+            "type": "Identifier",
+            "start":0,"end":5,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":5,"index":5},"identifierName":"using"},
+            "name": "using"
+          },
+          "arguments": [
+            {
+              "type": "Identifier",
+              "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"x"},
+              "name": "x"
+            }
+          ]
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/input.js
@@ -0,0 +1,2 @@
+using [x] = 0;
+for (using [x] of []);
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/options.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/options.json
@@ -0,0 +1,3 @@
+{
+  "plugins": []
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member-no-plugin/output.json
@@ -0,0 +1,75 @@
+{
+  "type": "File",
+  "start":0,"end":37,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":22,"index":37}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":37,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":22,"index":37}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "ExpressionStatement",
+        "start":0,"end":14,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":14,"index":14}},
+        "expression": {
+          "type": "AssignmentExpression",
+          "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
+          "operator": "=",
+          "left": {
+            "type": "MemberExpression",
+            "start":0,"end":9,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":9,"index":9}},
+            "object": {
+              "type": "Identifier",
+              "start":0,"end":5,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":5,"index":5},"identifierName":"using"},
+              "name": "using"
+            },
+            "computed": true,
+            "property": {
+              "type": "Identifier",
+              "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"x"},
+              "name": "x"
+            }
+          },
+          "right": {
+            "type": "NumericLiteral",
+            "start":12,"end":13,"loc":{"start":{"line":1,"column":12,"index":12},"end":{"line":1,"column":13,"index":13}},
+            "extra": {
+              "rawValue": 0,
+              "raw": "0"
+            },
+            "value": 0
+          }
+        }
+      },
+      {
+        "type": "ForOfStatement",
+        "start":15,"end":37,"loc":{"start":{"line":2,"column":0,"index":15},"end":{"line":2,"column":22,"index":37}},
+        "await": false,
+        "left": {
+          "type": "MemberExpression",
+          "start":20,"end":29,"loc":{"start":{"line":2,"column":5,"index":20},"end":{"line":2,"column":14,"index":29}},
+          "object": {
+            "type": "Identifier",
+            "start":20,"end":25,"loc":{"start":{"line":2,"column":5,"index":20},"end":{"line":2,"column":10,"index":25},"identifierName":"using"},
+            "name": "using"
+          },
+          "computed": true,
+          "property": {
+            "type": "Identifier",
+            "start":27,"end":28,"loc":{"start":{"line":2,"column":12,"index":27},"end":{"line":2,"column":13,"index":28},"identifierName":"x"},
+            "name": "x"
+          }
+        },
+        "right": {
+          "type": "ArrayExpression",
+          "start":33,"end":35,"loc":{"start":{"line":2,"column":18,"index":33},"end":{"line":2,"column":20,"index":35}},
+          "elements": []
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":36,"end":37,"loc":{"start":{"line":2,"column":21,"index":36},"end":{"line":2,"column":22,"index":37}}
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/input.js
@@ -0,0 +1,2 @@
+using [x] = 0;
+for (using [x] of []);
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-computed-member/output.json
@@ -0,0 +1,75 @@
+{
+  "type": "File",
+  "start":0,"end":37,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":22,"index":37}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":37,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":22,"index":37}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "ExpressionStatement",
+        "start":0,"end":14,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":14,"index":14}},
+        "expression": {
+          "type": "AssignmentExpression",
+          "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
+          "operator": "=",
+          "left": {
+            "type": "MemberExpression",
+            "start":0,"end":9,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":9,"index":9}},
+            "object": {
+              "type": "Identifier",
+              "start":0,"end":5,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":5,"index":5},"identifierName":"using"},
+              "name": "using"
+            },
+            "computed": true,
+            "property": {
+              "type": "Identifier",
+              "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"x"},
+              "name": "x"
+            }
+          },
+          "right": {
+            "type": "NumericLiteral",
+            "start":12,"end":13,"loc":{"start":{"line":1,"column":12,"index":12},"end":{"line":1,"column":13,"index":13}},
+            "extra": {
+              "rawValue": 0,
+              "raw": "0"
+            },
+            "value": 0
+          }
+        }
+      },
+      {
+        "type": "ForOfStatement",
+        "start":15,"end":37,"loc":{"start":{"line":2,"column":0,"index":15},"end":{"line":2,"column":22,"index":37}},
+        "await": false,
+        "left": {
+          "type": "MemberExpression",
+          "start":20,"end":29,"loc":{"start":{"line":2,"column":5,"index":20},"end":{"line":2,"column":14,"index":29}},
+          "object": {
+            "type": "Identifier",
+            "start":20,"end":25,"loc":{"start":{"line":2,"column":5,"index":20},"end":{"line":2,"column":10,"index":25},"identifierName":"using"},
+            "name": "using"
+          },
+          "computed": true,
+          "property": {
+            "type": "Identifier",
+            "start":27,"end":28,"loc":{"start":{"line":2,"column":12,"index":27},"end":{"line":2,"column":13,"index":28},"identifierName":"x"},
+            "name": "x"
+          }
+        },
+        "right": {
+          "type": "ArrayExpression",
+          "start":33,"end":35,"loc":{"start":{"line":2,"column":18,"index":33},"end":{"line":2,"column":20,"index":35}},
+          "elements": []
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":36,"end":37,"loc":{"start":{"line":2,"column":21,"index":36},"end":{"line":2,"column":22,"index":37}}
+        }
+      }
+    ],
+    "directives": []
+  }
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/input.js
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/input.js
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/input.js
@@ -1 +1,4 @@
 for (using in []);
+for (using.foo in []);
+for (using().foo in []);
+for (using``.foo in []);
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/output.json
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/output.json
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-in/output.json
@@ -1,9 +1,9 @@
 {
   "type": "File",
-  "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
+  "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":91}},
   "program": {
     "type": "Program",
-    "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
+    "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":91}},
     "sourceType": "script",
     "interpreter": null,
     "body": [
@@ -24,6 +24,115 @@
           "type": "EmptyStatement",
           "start":17,"end":18,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":18,"index":18}}
         }
+      },
+      {
+        "type": "ForInStatement",
+        "start":19,"end":41,"loc":{"start":{"line":2,"column":0,"index":19},"end":{"line":2,"column":22,"index":41}},
+        "left": {
+          "type": "MemberExpression",
+          "start":24,"end":33,"loc":{"start":{"line":2,"column":5,"index":24},"end":{"line":2,"column":14,"index":33}},
+          "object": {
+            "type": "Identifier",
+            "start":24,"end":29,"loc":{"start":{"line":2,"column":5,"index":24},"end":{"line":2,"column":10,"index":29},"identifierName":"using"},
+            "name": "using"
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":30,"end":33,"loc":{"start":{"line":2,"column":11,"index":30},"end":{"line":2,"column":14,"index":33},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "ArrayExpression",
+          "start":37,"end":39,"loc":{"start":{"line":2,"column":18,"index":37},"end":{"line":2,"column":20,"index":39}},
+          "elements": []
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":40,"end":41,"loc":{"start":{"line":2,"column":21,"index":40},"end":{"line":2,"column":22,"index":41}}
+        }
+      },
+      {
+        "type": "ForInStatement",
+        "start":42,"end":66,"loc":{"start":{"line":3,"column":0,"index":42},"end":{"line":3,"column":24,"index":66}},
+        "left": {
+          "type": "MemberExpression",
+          "start":47,"end":58,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":16,"index":58}},
+          "object": {
+            "type": "CallExpression",
+            "start":47,"end":54,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":12,"index":54}},
+            "callee": {
+              "type": "Identifier",
+              "start":47,"end":52,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":10,"index":52},"identifierName":"using"},
+              "name": "using"
+            },
+            "arguments": []
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":55,"end":58,"loc":{"start":{"line":3,"column":13,"index":55},"end":{"line":3,"column":16,"index":58},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "ArrayExpression",
+          "start":62,"end":64,"loc":{"start":{"line":3,"column":20,"index":62},"end":{"line":3,"column":22,"index":64}},
+          "elements": []
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":65,"end":66,"loc":{"start":{"line":3,"column":23,"index":65},"end":{"line":3,"column":24,"index":66}}
+        }
+      },
+      {
+        "type": "ForInStatement",
+        "start":67,"end":91,"loc":{"start":{"line":4,"column":0,"index":67},"end":{"line":4,"column":24,"index":91}},
+        "left": {
+          "type": "MemberExpression",
+          "start":72,"end":83,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":16,"index":83}},
+          "object": {
+            "type": "TaggedTemplateExpression",
+            "start":72,"end":79,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":12,"index":79}},
+            "tag": {
+              "type": "Identifier",
+              "start":72,"end":77,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":10,"index":77},"identifierName":"using"},
+              "name": "using"
+            },
+            "quasi": {
+              "type": "TemplateLiteral",
+              "start":77,"end":79,"loc":{"start":{"line":4,"column":10,"index":77},"end":{"line":4,"column":12,"index":79}},
+              "expressions": [],
+              "quasis": [
+                {
+                  "type": "TemplateElement",
+                  "start":78,"end":78,"loc":{"start":{"line":4,"column":11,"index":78},"end":{"line":4,"column":11,"index":78}},
+                  "value": {
+                    "raw": "",
+                    "cooked": ""
+                  },
+                  "tail": true
+                }
+              ]
+            }
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":80,"end":83,"loc":{"start":{"line":4,"column":13,"index":80},"end":{"line":4,"column":16,"index":83},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "ArrayExpression",
+          "start":87,"end":89,"loc":{"start":{"line":4,"column":20,"index":87},"end":{"line":4,"column":22,"index":89}},
+          "elements": []
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":90,"end":91,"loc":{"start":{"line":4,"column":23,"index":90},"end":{"line":4,"column":24,"index":91}}
+        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/input.js b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/input.js
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/input.js
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/input.js
@@ -1 +1,4 @@
 for (using of of);
+for (using.foo of of);
+for (using().foo of of);
+for (using``.foo of of);
diff --git a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/output.json b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/output.json
--- a/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/output.json
+++ b/packages/babel-parser/test/fixtures/experimental/explicit-resource-management/valid-using-as-identifier-for-of/output.json
@@ -1,9 +1,9 @@
 {
   "type": "File",
-  "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
+  "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":91}},
   "program": {
     "type": "Program",
-    "start":0,"end":18,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":18,"index":18}},
+    "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":91}},
     "sourceType": "script",
     "interpreter": null,
     "body": [
@@ -25,6 +25,118 @@
           "type": "EmptyStatement",
           "start":17,"end":18,"loc":{"start":{"line":1,"column":17,"index":17},"end":{"line":1,"column":18,"index":18}}
         }
+      },
+      {
+        "type": "ForOfStatement",
+        "start":19,"end":41,"loc":{"start":{"line":2,"column":0,"index":19},"end":{"line":2,"column":22,"index":41}},
+        "await": false,
+        "left": {
+          "type": "MemberExpression",
+          "start":24,"end":33,"loc":{"start":{"line":2,"column":5,"index":24},"end":{"line":2,"column":14,"index":33}},
+          "object": {
+            "type": "Identifier",
+            "start":24,"end":29,"loc":{"start":{"line":2,"column":5,"index":24},"end":{"line":2,"column":10,"index":29},"identifierName":"using"},
+            "name": "using"
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":30,"end":33,"loc":{"start":{"line":2,"column":11,"index":30},"end":{"line":2,"column":14,"index":33},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "Identifier",
+          "start":37,"end":39,"loc":{"start":{"line":2,"column":18,"index":37},"end":{"line":2,"column":20,"index":39},"identifierName":"of"},
+          "name": "of"
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":40,"end":41,"loc":{"start":{"line":2,"column":21,"index":40},"end":{"line":2,"column":22,"index":41}}
+        }
+      },
+      {
+        "type": "ForOfStatement",
+        "start":42,"end":66,"loc":{"start":{"line":3,"column":0,"index":42},"end":{"line":3,"column":24,"index":66}},
+        "await": false,
+        "left": {
+          "type": "MemberExpression",
+          "start":47,"end":58,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":16,"index":58}},
+          "object": {
+            "type": "CallExpression",
+            "start":47,"end":54,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":12,"index":54}},
+            "callee": {
+              "type": "Identifier",
+              "start":47,"end":52,"loc":{"start":{"line":3,"column":5,"index":47},"end":{"line":3,"column":10,"index":52},"identifierName":"using"},
+              "name": "using"
+            },
+            "arguments": []
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":55,"end":58,"loc":{"start":{"line":3,"column":13,"index":55},"end":{"line":3,"column":16,"index":58},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "Identifier",
+          "start":62,"end":64,"loc":{"start":{"line":3,"column":20,"index":62},"end":{"line":3,"column":22,"index":64},"identifierName":"of"},
+          "name": "of"
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":65,"end":66,"loc":{"start":{"line":3,"column":23,"index":65},"end":{"line":3,"column":24,"index":66}}
+        }
+      },
+      {
+        "type": "ForOfStatement",
+        "start":67,"end":91,"loc":{"start":{"line":4,"column":0,"index":67},"end":{"line":4,"column":24,"index":91}},
+        "await": false,
+        "left": {
+          "type": "MemberExpression",
+          "start":72,"end":83,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":16,"index":83}},
+          "object": {
+            "type": "TaggedTemplateExpression",
+            "start":72,"end":79,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":12,"index":79}},
+            "tag": {
+              "type": "Identifier",
+              "start":72,"end":77,"loc":{"start":{"line":4,"column":5,"index":72},"end":{"line":4,"column":10,"index":77},"identifierName":"using"},
+              "name": "using"
+            },
+            "quasi": {
+              "type": "TemplateLiteral",
+              "start":77,"end":79,"loc":{"start":{"line":4,"column":10,"index":77},"end":{"line":4,"column":12,"index":79}},
+              "expressions": [],
+              "quasis": [
+                {
+                  "type": "TemplateElement",
+                  "start":78,"end":78,"loc":{"start":{"line":4,"column":11,"index":78},"end":{"line":4,"column":11,"index":78}},
+                  "value": {
+                    "raw": "",
+                    "cooked": ""
+                  },
+                  "tail": true
+                }
+              ]
+            }
+          },
+          "computed": false,
+          "property": {
+            "type": "Identifier",
+            "start":80,"end":83,"loc":{"start":{"line":4,"column":13,"index":80},"end":{"line":4,"column":16,"index":83},"identifierName":"foo"},
+            "name": "foo"
+          }
+        },
+        "right": {
+          "type": "Identifier",
+          "start":87,"end":89,"loc":{"start":{"line":4,"column":20,"index":87},"end":{"line":4,"column":22,"index":89},"identifierName":"of"},
+          "name": "of"
+        },
+        "body": {
+          "type": "EmptyStatement",
+          "start":90,"end":91,"loc":{"start":{"line":4,"column":23,"index":90},"end":{"line":4,"column":24,"index":91}}
+        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/placeholders/variable/let-context-3/output.json b/packages/babel-parser/test/fixtures/placeholders/variable/let-context-3/output.json
--- a/packages/babel-parser/test/fixtures/placeholders/variable/let-context-3/output.json
+++ b/packages/babel-parser/test/fixtures/placeholders/variable/let-context-3/output.json
@@ -2,7 +2,7 @@
   "type": "File",
   "start":0,"end":32,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":32,"index":32}},
   "errors": [
-    "SyntaxError: Missing semicolon. (1:13)"
+    "SyntaxError: Lexical declaration cannot appear in a single-statement context. (1:10)"
   ],
   "program": {
     "type": "Program",
@@ -12,51 +12,44 @@
     "body": [
       {
         "type": "IfStatement",
-        "start":0,"end":13,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":13,"index":13}},
+        "start":0,"end":32,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":32,"index":32}},
         "test": {
           "type": "Identifier",
           "start":4,"end":8,"loc":{"start":{"line":1,"column":4,"index":4},"end":{"line":1,"column":8,"index":8},"identifierName":"cond"},
           "name": "cond"
         },
         "consequent": {
-          "type": "ExpressionStatement",
-          "start":10,"end":13,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":13,"index":13}},
-          "expression": {
-            "type": "Identifier",
-            "start":10,"end":13,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":13,"index":13},"identifierName":"let"},
-            "name": "let"
-          }
+          "type": "VariableDeclaration",
+          "start":10,"end":32,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":32,"index":32}},
+          "declarations": [
+            {
+              "type": "VariableDeclarator",
+              "start":14,"end":31,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":31,"index":31}},
+              "id": {
+                "type": "Placeholder",
+                "start":14,"end":21,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":21,"index":21}},
+                "name": {
+                  "type": "Identifier",
+                  "start":16,"end":19,"loc":{"start":{"line":1,"column":16,"index":16},"end":{"line":1,"column":19,"index":19},"identifierName":"LHS"},
+                  "name": "LHS"
+                },
+                "expectedNode": "Pattern"
+              },
+              "init": {
+                "type": "Placeholder",
+                "start":24,"end":31,"loc":{"start":{"line":1,"column":24,"index":24},"end":{"line":1,"column":31,"index":31}},
+                "name": {
+                  "type": "Identifier",
+                  "start":26,"end":29,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":29,"index":29},"identifierName":"RHS"},
+                  "name": "RHS"
+                },
+                "expectedNode": "Expression"
+              }
+            }
+          ],
+          "kind": "let"
         },
         "alternate": null
-      },
-      {
-        "type": "ExpressionStatement",
-        "start":14,"end":32,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":32,"index":32}},
-        "expression": {
-          "type": "AssignmentExpression",
-          "start":14,"end":31,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":31,"index":31}},
-          "operator": "=",
-          "left": {
-            "type": "Placeholder",
-            "start":14,"end":21,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":21,"index":21}},
-            "name": {
-              "type": "Identifier",
-              "start":16,"end":19,"loc":{"start":{"line":1,"column":16,"index":16},"end":{"line":1,"column":19,"index":19},"identifierName":"LHS"},
-              "name": "LHS"
-            },
-            "expectedNode": "Pattern"
-          },
-          "right": {
-            "type": "Placeholder",
-            "start":24,"end":31,"loc":{"start":{"line":1,"column":24,"index":24},"end":{"line":1,"column":31,"index":31}},
-            "name": {
-              "type": "Identifier",
-              "start":26,"end":29,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":29,"index":29},"identifierName":"RHS"},
-              "name": "RHS"
-            },
-            "expectedNode": "Expression"
-          }
-        }
       }
     ],
     "directives": []
diff --git a/packages/babel-parser/test/fixtures/placeholders/variable/using-init/input.js b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/input.js
@@ -0,0 +1,3 @@
+{
+  using %%LHS%% = %%RHS%%;
+}
diff --git a/packages/babel-parser/test/fixtures/placeholders/variable/using-init/options.json b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/options.json
@@ -0,0 +1,3 @@
+{
+  "plugins": ["placeholders", "explicitResourceManagement"]
+}
diff --git a/packages/babel-parser/test/fixtures/placeholders/variable/using-init/output.json b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/placeholders/variable/using-init/output.json
@@ -0,0 +1,51 @@
+{
+  "type": "File",
+  "start":0,"end":30,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":30}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":30,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":30}},
+    "sourceType": "script",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "BlockStatement",
+        "start":0,"end":30,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":30}},
+        "body": [
+          {
+            "type": "VariableDeclaration",
+            "start":4,"end":28,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":26,"index":28}},
+            "declarations": [
+              {
+                "type": "VariableDeclarator",
+                "start":10,"end":27,"loc":{"start":{"line":2,"column":8,"index":10},"end":{"line":2,"column":25,"index":27}},
+                "id": {
+                  "type": "Placeholder",
+                  "start":10,"end":17,"loc":{"start":{"line":2,"column":8,"index":10},"end":{"line":2,"column":15,"index":17}},
+                  "name": {
+                    "type": "Identifier",
+                    "start":12,"end":15,"loc":{"start":{"line":2,"column":10,"index":12},"end":{"line":2,"column":13,"index":15},"identifierName":"LHS"},
+                    "name": "LHS"
+                  },
+                  "expectedNode": "Pattern"
+                },
+                "init": {
+                  "type": "Placeholder",
+                  "start":20,"end":27,"loc":{"start":{"line":2,"column":18,"index":20},"end":{"line":2,"column":25,"index":27}},
+                  "name": {
+                    "type": "Identifier",
+                    "start":22,"end":25,"loc":{"start":{"line":2,"column":20,"index":22},"end":{"line":2,"column":23,"index":25},"identifierName":"RHS"},
+                    "name": "RHS"
+                  },
+                  "expectedNode": "Expression"
+                }
+              }
+            ],
+            "kind": "using"
+          }
+        ],
+        "directives": []
+      }
+    ],
+    "directives": []
+  }
+}