Bug 1155472 - Add the ES6 grammar parametrization to all the Parser methods, so that the permissibility of |in|, |yield| as keyword, &c. is specified directly, not by inspecting instantaneous statefulness. Don't change the statefulness yet, tho -- stop relying on it (where appropriate) in a later patch. r=efaust
authorJeff Walden <jwalden@mit.edu>
Tue, 07 Apr 2015 16:24:33 -0700
changeset 243323 d7a5e972e003b26a47476b46ca6366e05f830c39
parent 243322 03335da9925a4be70809949aa3194078f7578df0
child 243324 0055add82982188ea1744cafb9122ae75e1cca5e
push id59652
push userjwalden@mit.edu
push dateMon, 11 May 2015 22:11:22 +0000
treeherdermozilla-inbound@0055add82982 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1155472
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1155472 - Add the ES6 grammar parametrization to all the Parser methods, so that the permissibility of |in|, |yield| as keyword, &c. is specified directly, not by inspecting instantaneous statefulness. Don't change the statefulness yet, tho -- stop relying on it (where appropriate) in a later patch. r=efaust
js/src/asmjs/AsmJSValidate.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -493,17 +493,17 @@ ParseVarOrConstStatement(AsmJSParser& pa
     TokenKind tk;
     if (!PeekToken(parser, &tk))
         return false;
     if (tk != TOK_VAR && tk != TOK_CONST) {
         *var = nullptr;
         return true;
     }
 
-    *var = parser.statement();
+    *var = parser.statement(YieldIsName);
     if (!*var)
         return false;
 
     MOZ_ASSERT((*var)->isKind(PNK_VAR) || (*var)->isKind(PNK_CONST));
     return true;
 }
 
 /*****************************************************************************/
@@ -7599,17 +7599,19 @@ ParseFunction(ModuleCompiler& m, ParseNo
 
     Directives newDirectives = directives;
     AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
                             outerpc->staticLevel + 1, outerpc->blockidGen,
                             /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         return false;
 
-    if (!m.parser().functionArgsAndBodyGeneric(fn, fun, Normal, Statement)) {
+    if (!m.parser().functionArgsAndBodyGeneric(InAllowed, YieldIsName, fn, fun, Normal,
+                                               Statement))
+    {
         if (tokenStream.hadError() || directives == newDirectives)
             return false;
 
         return m.fail(nullptr, "encountered new directive");
     }
 
     MOZ_ASSERT(!tokenStream.hadError());
     MOZ_ASSERT(directives == newDirectives);
@@ -8177,17 +8179,17 @@ CheckModuleReturn(ModuleCompiler& m)
     if (!PeekToken(m.parser(), &tk))
         return false;
     if (tk != TOK_RETURN) {
         if (tk == TOK_RC || tk == TOK_EOF)
             return m.fail(nullptr, "expecting return statement");
         return m.fail(nullptr, "invalid asm.js statement");
     }
 
-    ParseNode* returnStmt = m.parser().statement();
+    ParseNode* returnStmt = m.parser().statement(YieldIsName);
     if (!returnStmt)
         return false;
 
     ParseNode* returnExpr = ReturnExpr(returnStmt);
     if (!returnExpr)
         return m.fail(returnStmt, "export statement must return something");
 
     if (returnExpr->isKind(PNK_OBJECT)) {
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -337,17 +337,17 @@ frontend::CompileScript(ExclusiveContext
         if (!parser.tokenStream.peekToken(&tt, TokenStream::Operand))
             return nullptr;
         if (tt == TOK_EOF)
             break;
 
         TokenStream::Position pos(parser.keepAtoms);
         parser.tokenStream.tell(&pos);
 
-        ParseNode* pn = parser.statement(canHaveDirectives);
+        ParseNode* pn = parser.statement(YieldIsName, canHaveDirectives);
         if (!pn) {
             if (parser.hadAbortedSyntaxParse()) {
                 // Parsing inner functions lazily may lead the parser into an
                 // unrecoverable state and may require starting over on the top
                 // level statement. Restart the parse; syntax parsing has
                 // already been disabled for the parser and the result will not
                 // be ambiguous.
                 parser.clearAbortedSyntaxParse();
@@ -361,17 +361,17 @@ frontend::CompileScript(ExclusiveContext
                 pc.reset();
                 pc.emplace(&parser, (GenericParseContext*) nullptr, (ParseNode*) nullptr,
                            &globalsc, (Directives*) nullptr, staticLevel, /* bodyid = */ 0,
                            script->bindings.numBlockScoped());
                 if (!pc->init(parser.tokenStream))
                     return nullptr;
                 MOZ_ASSERT(parser.pc == pc.ptr());
 
-                pn = parser.statement();
+                pn = parser.statement(YieldIsName);
             }
             if (!pn) {
                 MOZ_ASSERT(!parser.hadAbortedSyntaxParse());
                 return nullptr;
             }
         }
 
         // Accumulate the maximum block scope depth, so that emitTree can assert
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -702,17 +702,17 @@ Parser<ParseHandler>::parse(JSObject* ch
                                  /* allowSuperProperty = */ false);
     ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
                                         &globalsc, /* newDirectives = */ nullptr,
                                         /* staticLevel = */ 0, /* bodyid = */ 0,
                                         /* blockScopeDepth = */ 0);
     if (!globalpc.init(tokenStream))
         return null();
 
-    Node pn = statements();
+    Node pn = statements(YieldIsName);
     if (pn) {
         TokenKind tt;
         if (!tokenStream.getToken(&tt))
             return null();
         if (tt != TOK_EOF) {
             report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
                    "script", TokenKindToDesc(tt));
             return null();
@@ -822,17 +822,18 @@ Parser<FullParseHandler>::standaloneFunc
     if (!funpc.init(tokenStream))
         return null();
 
     for (unsigned i = 0; i < formals.length(); i++) {
         if (!defineArg(fn, formals[i]))
             return null();
     }
 
-    ParseNode* pn = functionBody(Statement, StatementListBody);
+    YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+    ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
     if (!pn)
         return null();
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
     if (tt != TOK_EOF) {
         report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
@@ -995,49 +996,50 @@ Parser<SyntaxParseHandler>::checkFunctio
         }
     }
 
     return true;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType type)
+Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHandling,
+                                   FunctionSyntaxKind kind, FunctionBodyType type)
 {
     MOZ_ASSERT(pc->sc->isFunctionBox());
     MOZ_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
 
 #ifdef DEBUG
     uint32_t startYieldOffset = pc->lastYieldOffset;
 #endif
 
     Node pn;
     if (type == StatementListBody) {
-        pn = statements();
+        pn = statements(yieldHandling);
         if (!pn)
             return null();
     } else {
         MOZ_ASSERT(type == ExpressionBody);
 
-        Node kid = assignExpr();
+        Node kid = assignExpr(inHandling, yieldHandling);
         if (!kid)
             return null();
 
         pn = handler.newReturnStatement(kid, null(), handler.getPosition(kid));
         if (!pn)
             return null();
     }
 
     switch (pc->generatorKind()) {
       case NotGenerator:
         MOZ_ASSERT(pc->lastYieldOffset == startYieldOffset);
         break;
 
       case LegacyGenerator:
-        // FIXME: Catch these errors eagerly, in yieldExpression().
+        // FIXME: Catch these errors eagerly, in Parser::yieldExpression.
         MOZ_ASSERT(pc->lastYieldOffset != startYieldOffset);
         if (kind == Arrow) {
             reportWithOffset(ParseError, false, pc->lastYieldOffset,
                              JSMSG_YIELD_IN_ARROW, js_yield_str);
             return null();
         }
         if (type == ExpressionBody) {
             reportBadReturn(pn, ParseError,
@@ -1548,18 +1550,18 @@ Parser<ParseHandler>::bindDestructuringA
     if (!parser->checkStrictBinding(name, data->pn))
         return false;
 
     return pc->define(parser->tokenStream, name, data->pn, Definition::VAR);
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, FunctionType type, Node* listp,
-                                        Node funcpn, bool* hasRest)
+Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
+                                        FunctionType type, Node* listp, Node funcpn, bool* hasRest)
 {
     FunctionBox* funbox = pc->sc->asFunctionBox();
 
     *hasRest = false;
 
     bool parenFreeArrow = false;
     if (kind == Arrow) {
         TokenKind tt;
@@ -1642,17 +1644,18 @@ Parser<ParseHandler>::functionArguments(
                  * local variables initialized from properties of a single
                  * anonymous positional parameter, so here we must tweak our
                  * binder and its data.
                  */
                 BindData<ParseHandler> data(context);
                 data.pn = ParseHandler::null();
                 data.op = JSOP_DEFVAR;
                 data.binder = bindDestructuringArg;
-                Node lhs = destructuringExprWithoutYield(&data, tt, JSMSG_YIELD_IN_DEFAULT);
+                Node lhs = destructuringExprWithoutYield(yieldHandling, &data, tt,
+                                                         JSMSG_YIELD_IN_DEFAULT);
                 if (!lhs)
                     return false;
 
                 /*
                  * Synthesize a destructuring assignment from the single
                  * anonymous positional parameter into the destructuring
                  * left-hand-side expression and accumulate it in list.
                  */
@@ -1676,28 +1679,35 @@ Parser<ParseHandler>::functionArguments(
                     *listp = list;
                 }
                 break;
               }
 
               case TOK_YIELD:
                 if (!checkYieldNameValidity())
                     return false;
+                MOZ_ASSERT(yieldHandling == YieldIsName);
                 goto TOK_NAME;
 
               case TOK_TRIPLEDOT:
               {
                 if (type == Setter) {
                     report(ParseError, false, null(),
                            JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
                     return false;
                 }
                 *hasRest = true;
                 if (!tokenStream.getToken(&tt))
                     return false;
+                // FIXME: This fails to handle a rest parameter named |yield|
+                //        correctly outside of generators: that is,
+                //        |var f = (...yield) => 42;| should be valid code!
+                //        When this is fixed, make sure to consult both
+                //        |yieldHandling| and |checkYieldNameValidity| for
+                //        correctness until legacy generator syntax is removed.
                 if (tt != TOK_NAME) {
                     report(ParseError, false, null(), JSMSG_NO_REST_NAME);
                     return false;
                 }
                 disallowDuplicateArgs = true;
                 if (duplicatedArg) {
                     // Has duplicated args before the rest parameter.
                     report(ParseError, false, duplicatedArg, JSMSG_BAD_DUP_ARGS);
@@ -1737,17 +1747,17 @@ Parser<ParseHandler>::functionArguments(
                     }
                     if (!hasDefaults) {
                         hasDefaults = true;
 
                         // The Function.length property is the number of formals
                         // before the first default argument.
                         funbox->length = pc->numArgs() - 1;
                     }
-                    Node def_expr = assignExprWithoutYield(JSMSG_YIELD_IN_DEFAULT);
+                    Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT);
                     if (!def_expr)
                         return false;
                     handler.setLastFunctionArgumentDefault(funcpn, def_expr);
                 }
 
                 break;
               }
 
@@ -2067,19 +2077,20 @@ Parser<SyntaxParseHandler>::checkFunctio
         return abortIfSyntaxParser();
     }
 
     return true;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::addExprAndGetNextTemplStrToken(Node nodeList, TokenKind* ttp)
-{
-    Node pn = expr();
+Parser<ParseHandler>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
+                                                     TokenKind* ttp)
+{
+    Node pn = expr(InAllowed, yieldHandling);
     if (!pn)
         return false;
     handler.addList(nodeList, pn);
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return false;
     if (tt != TOK_RC) {
@@ -2087,64 +2098,65 @@ Parser<ParseHandler>::addExprAndGetNextT
         return false;
     }
 
     return tokenStream.getToken(ttp, TokenStream::TemplateTail);
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::taggedTemplate(Node nodeList, TokenKind tt)
+Parser<ParseHandler>::taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt)
 {
     Node callSiteObjNode = handler.newCallSiteObject(pos().begin, pc->blockidGen);
     if (!callSiteObjNode)
         return false;
     handler.addList(nodeList, callSiteObjNode);
 
     while (true) {
         if (!appendToCallSiteObj(callSiteObjNode))
             return false;
         if (tt != TOK_TEMPLATE_HEAD)
             break;
 
-        if (!addExprAndGetNextTemplStrToken(nodeList, &tt))
+        if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
             return false;
     }
     handler.setEndPosition(nodeList, callSiteObjNode);
     return true;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::templateLiteral()
+Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
 {
     Node pn = noSubstitutionTemplate();
     if (!pn)
         return null();
     Node nodeList = handler.newList(PNK_TEMPLATE_STRING_LIST, pn);
 
     TokenKind tt;
     do {
-        if (!addExprAndGetNextTemplStrToken(nodeList, &tt))
+        if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
             return null();
 
         pn = noSubstitutionTemplate();
         if (!pn)
             return null();
 
         handler.addList(nodeList, pn);
     } while (tt == TOK_TEMPLATE_HEAD);
     return nodeList;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::functionDef(HandlePropertyName funName,
-                                  FunctionType type, FunctionSyntaxKind kind,
-                                  GeneratorKind generatorKind, InvokedPrediction invoked)
+Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHandling,
+                                  HandlePropertyName funName, FunctionType type,
+                                  FunctionSyntaxKind kind, GeneratorKind generatorKind,
+                                  InvokedPrediction invoked)
 {
     MOZ_ASSERT_IF(kind == Statement, funName);
 
     /* Make a TOK_FUNCTION node. */
     Node pn = handler.newFunctionDefinition();
     if (!pn)
         return null();
 
@@ -2178,18 +2190,21 @@ Parser<ParseHandler>::functionDef(Handle
     // of directives.
     Directives directives(pc);
     Directives newDirectives = directives;
 
     TokenStream::Position start(keepAtoms);
     tokenStream.tell(&start);
 
     while (true) {
-        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives))
+        if (functionArgsAndBody(inHandling, pn, fun, type, kind, generatorKind, directives,
+                                &newDirectives))
+        {
             break;
+        }
         if (tokenStream.hadError() || directives == newDirectives)
             return null();
 
         // Assignment must be monotonic to prevent reparsing iloops
         MOZ_ASSERT_IF(directives.strict(), newDirectives.strict());
         MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
         directives = newDirectives;
 
@@ -2282,29 +2297,31 @@ Parser<SyntaxParseHandler>::finishFuncti
     PropagateTransitiveParseFlags(funbox, lazy);
 
     fun->initLazyScript(lazy);
     return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::functionArgsAndBody(ParseNode* pn, HandleFunction fun,
-                                              FunctionType type, FunctionSyntaxKind kind,
-                                              GeneratorKind generatorKind,
+Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode* pn,
+                                              HandleFunction fun, FunctionType type,
+                                              FunctionSyntaxKind kind, GeneratorKind generatorKind,
                                               Directives inheritedDirectives,
                                               Directives* newDirectives)
 {
     ParseContext<FullParseHandler>* outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
     if (!funbox)
         return false;
 
+    YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+
     // Try a syntax parse for this inner function.
     do {
         // If we're assuming this function is an IIFE, always perform a full
         // parse to avoid the overhead of a lazy syntax-only parse. Although
         // the prediction may be incorrect, IIFEs are common enough that it
         // pays off for lots of code.
         if (pn->isLikelyIIFE() && !funbox->isGenerator())
             break;
@@ -2321,18 +2338,19 @@ Parser<FullParseHandler>::functionArgsAn
                 return false;
 
             ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
                                                    newDirectives, outerpc->staticLevel + 1,
                                                    outerpc->blockidGen, /* blockScopeDepth = */ 0);
             if (!funpc.init(tokenStream))
                 return false;
 
-            if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
-                                                    fun, type, kind))
+            if (!parser->functionArgsAndBodyGeneric(inHandling, yieldHandling,
+                                                    SyntaxParseHandler::NodeGeneric, fun, type,
+                                                    kind))
             {
                 if (parser->hadAbortedSyntaxParse()) {
                     // Try again with a full parse.
                     parser->clearAbortedSyntaxParse();
                     MOZ_ASSERT_IF(parser->context->isJSContext(),
                                   !parser->context->asJSContext()->isExceptionPending());
                     break;
                 }
@@ -2360,17 +2378,17 @@ Parser<FullParseHandler>::functionArgsAn
 
     // Continue doing a full parse for this inner function.
     ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
                                          outerpc->staticLevel + 1, outerpc->blockidGen,
                                          /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         return false;
 
-    if (!functionArgsAndBodyGeneric(pn, fun, type, kind))
+    if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, type, kind))
         return false;
 
     if (!leaveFunction(pn, outerpc, kind))
         return false;
 
     pn->pn_blockid = outerpc->blockid();
 
     /*
@@ -2380,17 +2398,17 @@ Parser<FullParseHandler>::functionArgsAn
      * parents: any local can be read at runtime.
      */
     PropagateTransitiveParseFlags(funbox, outerpc->sc);
     return true;
 }
 
 template <>
 bool
-Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
+Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
                                                 FunctionType type, FunctionSyntaxKind kind,
                                                 GeneratorKind generatorKind,
                                                 Directives inheritedDirectives,
                                                 Directives* newDirectives)
 {
     ParseContext<SyntaxParseHandler>* outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
@@ -2400,17 +2418,18 @@ Parser<SyntaxParseHandler>::functionArgs
 
     // Initialize early for possible flags mutation via destructuringExpr.
     ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
                                            outerpc->staticLevel + 1, outerpc->blockidGen,
                                            /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         return false;
 
-    if (!functionArgsAndBodyGeneric(pn, fun, type, kind))
+    YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+    if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, type, kind))
         return false;
 
     if (!leaveFunction(pn, outerpc, kind))
         return false;
 
     // This is a lazy function inner to another lazy function. Remember the
     // inner function so that if the outer function is eventually parsed we do
     // not need any further parsing or processing of the inner function.
@@ -2461,18 +2480,19 @@ Parser<FullParseHandler>::standaloneLazy
 
     Directives newDirectives = directives;
     ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
                                          &newDirectives, staticLevel, /* bodyid = */ 0,
                                          /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         return null();
 
+    YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
     FunctionSyntaxKind syntaxKind = fun->isMethod() ? Method : Statement;
-    if (!functionArgsAndBodyGeneric(pn, fun, Normal, syntaxKind)) {
+    if (!functionArgsAndBodyGeneric(InAllowed, yieldHandling, pn, fun, Normal, syntaxKind)) {
         MOZ_ASSERT(directives == newDirectives);
         return null();
     }
 
     if (fun->isNamedLambda()) {
         if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) {
             Definition* dn = p.value().get<FullParseHandler>();
             if (!ConvertDefinitionToNamedLambdaUse(tokenStream, pc, funbox, dn))
@@ -2488,26 +2508,28 @@ Parser<FullParseHandler>::standaloneLazy
     if (!FoldConstants(context, &pn, this))
         return null();
 
     return pn;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
+Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
+                                                 YieldHandling yieldHandling, Node pn,
+                                                 HandleFunction fun, FunctionType type,
                                                  FunctionSyntaxKind kind)
 {
     // Given a properly initialized parse context, try to parse an actual
     // function without concern for conversion to strict mode, use of lazy
     // parsing and such.
 
     Node prelude = null();
     bool hasRest;
-    if (!functionArguments(kind, type, &prelude, pn, &hasRest))
+    if (!functionArguments(yieldHandling, kind, type, &prelude, pn, &hasRest))
         return false;
 
     FunctionBox* funbox = pc->sc->asFunctionBox();
 
     fun->setArgCount(pc->numArgs());
     if (hasRest)
         fun->setHasRest();
 
@@ -2543,17 +2565,17 @@ Parser<ParseHandler>::functionArgsAndBod
 
         tokenStream.ungetToken();
         bodyType = ExpressionBody;
 #if JS_HAS_EXPR_CLOSURES
         fun->setIsExprBody();
 #endif
     }
 
-    Node body = functionBody(kind, bodyType);
+    Node body = functionBody(inHandling, yieldHandling, kind, bodyType);
     if (!body)
         return false;
 
     if (kind != Method && fun->name() && !checkStrictBinding(fun->name(), pn))
         return false;
 
     if (bodyType == StatementListBody) {
         bool matched;
@@ -2588,17 +2610,17 @@ Parser<ParseHandler>::checkYieldNameVali
         report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
         return false;
     }
     return true;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt()
+Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
     RootedPropertyName name(context);
     GeneratorKind generatorKind = NotGenerator;
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
@@ -2621,17 +2643,17 @@ Parser<ParseHandler>::functionStmt()
         return null();
     }
 
     /* We forbid function statements in strict mode code. */
     if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
         !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
         return null();
 
-    return functionDef(name, Normal, Statement, generatorKind);
+    return functionDef(InAllowed, yieldHandling, name, Normal, Statement, generatorKind);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
@@ -2652,17 +2674,18 @@ Parser<ParseHandler>::functionExpr(Invok
     } else if (tt == TOK_YIELD) {
         if (!checkYieldNameValidity())
             return null();
         name = tokenStream.currentName();
     } else {
         tokenStream.ungetToken();
     }
 
-    return functionDef(name, Normal, Expression, generatorKind, invoked);
+    YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+    return functionDef(InAllowed, yieldHandling, name, Normal, Expression, generatorKind, invoked);
 }
 
 /*
  * Return true if this node, known to be an unparenthesized string literal,
  * could be the string of a directive in a Directive Prologue. Directive
  * strings never contain escape sequences or line continuations.
  * isEscapeFreeStringLiteral, below, checks whether the node itself could be
  * a directive.
@@ -2803,17 +2826,17 @@ Parser<ParseHandler>::maybeParseDirectiv
 
 /*
  * Parse the statements in a block, creating a StatementList node that lists
  * the statements.  If called from block-parsing code, the caller must match
  * '{' before and '}' after.
  */
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::statements()
+Parser<ParseHandler>::statements(YieldHandling yieldHandling)
 {
     JS_CHECK_RECURSION(context, return null());
 
     Node pn = handler.newStatementList(pc->blockid(), pos());
     if (!pn)
         return null();
 
     Node saveBlock = pc->blockNode;
@@ -2833,17 +2856,17 @@ Parser<ParseHandler>::statements()
         if (tt == TOK_EOF || tt == TOK_RC)
             break;
         if (afterReturn) {
             TokenPos pos(0, 0);
             if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
                 return null();
             statementBegin = pos.begin;
         }
-        Node next = statement(canHaveDirectives);
+        Node next = statement(yieldHandling, canHaveDirectives);
         if (!next) {
             if (tokenStream.isEOF())
                 isUnexpectedEOF_ = true;
             return null();
         }
         if (!warnedAboutStatementsAfterReturn) {
             if (afterReturn) {
                 if (!handler.isStatementPermittedAfterReturnStatement(next)) {
@@ -2875,43 +2898,49 @@ Parser<ParseHandler>::statements()
     if (pc->blockNode != pn)
         pn = pc->blockNode;
     pc->blockNode = saveBlock;
     return pn;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::condition()
+Parser<ParseHandler>::condition(InHandling inHandling, YieldHandling yieldHandling)
 {
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
-    Node pn = exprInParens();
+    Node pn = exprInParens(inHandling, yieldHandling);
     if (!pn)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
     if (handler.isUnparenthesizedAssignment(pn)) {
         if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
             return null();
     }
     return pn;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
+Parser<ParseHandler>::matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label)
 {
     TokenKind tt;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return false;
+
     if (tt == TOK_NAME) {
         tokenStream.consumeKnownToken(TOK_NAME);
+        MOZ_ASSERT_IF(tokenStream.currentName() == context->names().yield,
+                      yieldHandling == YieldIsName);
         label.set(tokenStream.currentName());
     } else if (tt == TOK_YIELD) {
+        // We might still consider |yield| to be valid here, contrary to ES6.
+        // Fix bug 1104014, then stop shipping legacy generators in chrome
+        // code, then remove this check!
         tokenStream.consumeKnownToken(TOK_YIELD);
         if (!checkYieldNameValidity())
             return false;
         label.set(tokenStream.currentName());
     } else {
         label.set(nullptr);
     }
     return true;
@@ -3516,37 +3545,39 @@ template <>
 bool
 Parser<SyntaxParseHandler>::checkDestructuring(BindData<SyntaxParseHandler>* data, Node left)
 {
     return abortIfSyntaxParser();
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::destructuringExpr(BindData<ParseHandler>* data, TokenKind tt)
+Parser<ParseHandler>::destructuringExpr(YieldHandling yieldHandling, BindData<ParseHandler>* data,
+                                        TokenKind tt)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
 
     pc->inDeclDestructuring = true;
-    Node pn = primaryExpr(tt);
+    Node pn = primaryExpr(yieldHandling, tt);
     pc->inDeclDestructuring = false;
     if (!pn)
         return null();
     if (!checkDestructuring(data, pn))
         return null();
     return pn;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::destructuringExprWithoutYield(BindData<ParseHandler>* data, TokenKind tt,
+Parser<ParseHandler>::destructuringExprWithoutYield(YieldHandling yieldHandling,
+                                                    BindData<ParseHandler>* data, TokenKind tt,
                                                     unsigned msg)
 {
     uint32_t startYieldOffset = pc->lastYieldOffset;
-    Node res = destructuringExpr(data, tt);
+    Node res = destructuringExpr(yieldHandling, data, tt);
     if (res && pc->lastYieldOffset != startYieldOffset) {
         reportWithOffset(ParseError, false, pc->lastYieldOffset,
                          msg, js_yield_str);
         return null();
     }
     return res;
 }
 
@@ -3630,29 +3661,30 @@ Parser<SyntaxParseHandler>::pushLetScope
 
 /*
  * Parse a let block statement or let expression (determined by 'letContext').
  * In both cases, bindings are not hoisted to the top of the enclosing block
  * and thus must be carefully injected between variables() and the let body.
  */
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::deprecatedLetBlockOrExpression(LetContext letContext)
+Parser<ParseHandler>::deprecatedLetBlockOrExpression(YieldHandling yieldHandling,
+                                                     LetContext letContext)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
 
     RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
     if (!blockObj)
         return null();
 
     uint32_t begin = pos().begin;
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
 
-    Node vars = variables(PNK_LET, nullptr, blockObj, DontHoistVars);
+    Node vars = variables(yieldHandling, PNK_LET, nullptr, blockObj, DontHoistVars);
     if (!vars)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
 
     StmtInfoPC stmtInfo(context);
     Node block = pushLetScope(blockObj, &stmtInfo);
     if (!block)
@@ -3693,27 +3725,27 @@ Parser<ParseHandler>::deprecatedLetBlock
              */
             needExprStmt = true;
             letContext = LetExpression;
         }
     }
 
     Node expr;
     if (letContext == LetStatement) {
-        expr = statements();
+        expr = statements(yieldHandling);
         if (!expr)
             return null();
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
 
         addTelemetry(JSCompartment::DeprecatedLetBlock);
         if (!report(ParseWarning, pc->sc->strict(), expr, JSMSG_DEPRECATED_LET_BLOCK))
             return null();
     } else {
         MOZ_ASSERT(letContext == LetExpression);
-        expr = assignExpr();
+        expr = assignExpr(InAllowed, yieldHandling);
         if (!expr)
             return null();
 
         addTelemetry(JSCompartment::DeprecatedLetExpression);
         if (!report(ParseWarning, pc->sc->strict(), expr, JSMSG_DEPRECATED_LET_EXPRESSION))
             return null();
     }
     handler.setLexicalScopeBody(block, expr);
@@ -3743,25 +3775,25 @@ PushBlocklikeStatement(TokenStream& ts, 
                        ParseContext<ParseHandler>* pc)
 {
     PushStatementPC(pc, stmt, type);
     return GenerateBlockId(ts, pc, stmt->blockid);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::blockStatement()
+Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
 
     StmtInfoPC stmtInfo(context);
     if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_BLOCK, pc))
         return null();
 
-    Node list = statements();
+    Node list = statements(yieldHandling);
     if (!list)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
     PopStatementPC(tokenStream, pc);
     return list;
 }
 
@@ -3797,17 +3829,18 @@ Parser<ParseHandler>::newBindingNode(Pro
 
 /*
  * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
  * expression, block statement, non-top-level let declaration in statement
  * context, and the let-initializer of a for-statement.
  */
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::variables(ParseNodeKind kind, bool* psimple,
+Parser<ParseHandler>::variables(YieldHandling yieldHandling,
+                                ParseNodeKind kind, bool* psimple,
                                 StaticBlockObject* blockObj, VarContext varContext)
 {
     /*
      * The four options here are:
      * - PNK_VAR:   We're parsing var declarations.
      * - PNK_CONST: We're parsing const declarations.
      * - PNK_GLOBALCONST: We're parsing const declarations at toplevel (see bug 589119).
      * - PNK_LET:   We are parsing a let declaration.
@@ -3854,17 +3887,17 @@ Parser<ParseHandler>::variables(ParseNod
             TokenKind tt;
             if (!tokenStream.getToken(&tt))
                 return null();
             if (tt == TOK_LB || tt == TOK_LC) {
                 if (psimple)
                     *psimple = false;
 
                 pc->inDeclDestructuring = true;
-                pn2 = primaryExpr(tt);
+                pn2 = primaryExpr(yieldHandling, tt);
                 pc->inDeclDestructuring = false;
                 if (!pn2)
                     return null();
 
                 bool parsingForInOrOfInit = false;
                 if (pc->parsingForInit) {
                     bool isForIn, isForOf;
                     if (!matchInOrOf(&isForIn, &isForOf))
@@ -3882,17 +3915,17 @@ Parser<ParseHandler>::variables(ParseNod
                 if (parsingForInOrOfInit) {
                     tokenStream.ungetToken();
                     handler.addList(pn, pn2);
                     break;
                 }
 
                 MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
 
-                Node init = assignExpr();
+                Node init = assignExpr(InAllowed, yieldHandling);
                 if (!init)
                     return null();
 
                 if (!bindBeforeInitializer && !checkDestructuring(&data, pn2))
                     return null();
 
                 pn2 = handler.newBinary(PNK_ASSIGN, pn2, init);
                 if (!pn2)
@@ -3935,17 +3968,17 @@ Parser<ParseHandler>::variables(ParseNod
                 //
                 // If we are not parsing a let declaration, bind the name
                 // now. Otherwise we must wait until after parsing the initializing
                 // assignment.
                 bool bindBeforeInitializer = kind != PNK_LET && kind != PNK_CONST;
                 if (bindBeforeInitializer && !data.binder(&data, name, this))
                     return null();
 
-                Node init = assignExpr();
+                Node init = assignExpr(InAllowed, yieldHandling);
                 if (!init)
                     return null();
 
                 if (!bindBeforeInitializer && !data.binder(&data, name, this))
                     return null();
 
                 if (!handler.finishInitializerAssignment(pn2, init, data.op))
                     return null();
@@ -4097,17 +4130,17 @@ Parser<FullParseHandler>::makeInitialize
     if (!bindInitialized(&data, dn))
         return null();
 
     return dn;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::lexicalDeclaration(bool isConst)
+Parser<FullParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isConst)
 {
     handler.disableSyntaxParser();
 
     if (!checkAndPrepareLexical(isConst, pos()))
         return null();
 
     /*
      * Parse body-level lets without a new block object. ES6 specs
@@ -4124,73 +4157,74 @@ Parser<FullParseHandler>::lexicalDeclara
      * other bugs are fixed.
      */
     ParseNodeKind kind = PNK_LET;
     if (pc->atGlobalLevel())
         kind = isConst ? PNK_GLOBALCONST : PNK_VAR;
     else if (isConst)
         kind = PNK_CONST;
 
-    ParseNode* pn = variables(kind, nullptr,
+    ParseNode* pn = variables(yieldHandling, kind, nullptr,
                               CurrentLexicalStaticBlock(pc),
                               HoistVars);
     if (!pn)
         return null();
     pn->pn_xflags = PNX_POPVAR;
     return MatchOrInsertSemicolon(tokenStream) ? pn : nullptr;
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::lexicalDeclaration(bool)
+Parser<SyntaxParseHandler>::lexicalDeclaration(YieldHandling, bool)
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::letDeclarationOrBlock()
+Parser<FullParseHandler>::letDeclarationOrBlock(YieldHandling yieldHandling)
 {
     handler.disableSyntaxParser();
 
     /* Check for a let statement or let expression. */
     TokenKind tt;
     if (!tokenStream.peekToken(&tt))
         return null();
     if (tt == TOK_LP) {
-        ParseNode* node = deprecatedLetBlockOrExpression(LetStatement);
+        ParseNode* node =
+            deprecatedLetBlockOrExpression(yieldHandling, LetStatement);
         if (!node)
             return nullptr;
 
         if (node->isKind(PNK_LETBLOCK)) {
             MOZ_ASSERT(node->isArity(PN_BINARY));
         } else {
             MOZ_ASSERT(node->isKind(PNK_SEMI));
             MOZ_ASSERT(node->pn_kid->isKind(PNK_LETEXPR));
             MOZ_ASSERT(node->pn_kid->isArity(PN_BINARY));
         }
 
         return node;
     }
 
-    ParseNode* decl = lexicalDeclaration(/* isConst = */ false);
+    ParseNode* decl = lexicalDeclaration(yieldHandling, /* isConst = */ false);
     if (!decl)
         return nullptr;
 
     // let-declarations at global scope are currently treated as plain old var.
     // See bug 589199.
     MOZ_ASSERT(decl->isKind(PNK_LET) || decl->isKind(PNK_VAR));
     MOZ_ASSERT(decl->isArity(PN_LIST));
     return decl;
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::letDeclarationOrBlock()
+Parser<SyntaxParseHandler>::letDeclarationOrBlock(YieldHandling yieldHandling)
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 template<typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::importDeclaration()
@@ -4424,40 +4458,41 @@ Parser<ParseHandler>::exportDeclaration(
         }
 
         kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
         if (!kid)
             return null();
         break;
 
       case TOK_FUNCTION:
-        kid = functionStmt();
+        kid = functionStmt(YieldIsKeyword);
         if (!kid)
             return null();
         break;
 
-      case TOK_VAR:
-        kid = variables(PNK_VAR);
+      case TOK_VAR: kid = variables(YieldIsName, PNK_VAR);
         if (!kid)
             return null();
         kid->pn_xflags = PNX_POPVAR;
 
         kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
         if (!kid)
             return null();
         break;
 
       case TOK_NAME:
         // Handle the form |export a| in the same way as |export let a|, by
         // acting as if we've just seen the let keyword. Simply unget the token
         // and fall through.
+        //
+        // XXX This |export foo = 5| syntax is *not* in ES6!  Remove it!
         tokenStream.ungetToken();
       case TOK_LET:
       case TOK_CONST:
-        kid = lexicalDeclaration(tt == TOK_CONST);
+        kid = lexicalDeclaration(YieldIsName, tt == TOK_CONST);
         if (!kid)
             return null();
         break;
 
       default:
         report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT);
         return null();
     }
@@ -4470,81 +4505,81 @@ SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::exportDeclaration()
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::expressionStatement(InvokedPrediction invoked)
+Parser<ParseHandler>::expressionStatement(YieldHandling yieldHandling, InvokedPrediction invoked)
 {
     tokenStream.ungetToken();
-    Node pnexpr = expr(invoked);
+    Node pnexpr = expr(InAllowed, yieldHandling, invoked);
     if (!pnexpr)
         return null();
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
     return handler.newExprStatement(pnexpr, pos().end);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::ifStatement()
+Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
 
     /* An IF node has three kids: condition, then, and optional else. */
-    Node cond = condition();
+    Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
 
     TokenKind tt;
     if (!tokenStream.peekToken(&tt, TokenStream::Operand))
         return null();
     if (tt == TOK_SEMI) {
         if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT))
             return null();
     }
 
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_IF);
-    Node thenBranch = statement();
+    Node thenBranch = statement(yieldHandling);
     if (!thenBranch)
         return null();
 
     Node elseBranch;
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_ELSE, TokenStream::Operand))
         return null();
     if (matched) {
         stmtInfo.type = STMT_ELSE;
-        elseBranch = statement();
+        elseBranch = statement(yieldHandling);
         if (!elseBranch)
             return null();
     } else {
         elseBranch = null();
     }
 
     PopStatementPC(tokenStream, pc);
     return handler.newIfStatement(begin, cond, thenBranch, elseBranch);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::doWhileStatement()
+Parser<ParseHandler>::doWhileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_DO_LOOP);
-    Node body = statement();
+    Node body = statement(yieldHandling);
     if (!body)
         return null();
     MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
-    Node cond = condition();
+    Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
     PopStatementPC(tokenStream, pc);
 
     // The semicolon after do-while is even more optional than most
     // semicolons in JS.  Web compat required this by 2004:
     //   http://bugzilla.mozilla.org/show_bug.cgi?id=238945
     // ES3 and ES5 disagreed, but ES6 conforms to Web reality:
@@ -4552,25 +4587,25 @@ Parser<ParseHandler>::doWhileStatement()
     bool ignored;
     if (!tokenStream.matchToken(&ignored, TOK_SEMI))
         return null();
     return handler.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::whileStatement()
+Parser<ParseHandler>::whileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_WHILE_LOOP);
-    Node cond = condition();
+    Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
-    Node body = statement();
+    Node body = statement(yieldHandling);
     if (!body)
         return null();
     PopStatementPC(tokenStream, pc);
     return handler.newWhileStatement(begin, cond, body);
 }
 
 template <typename ParseHandler>
 bool
@@ -4624,17 +4659,17 @@ Parser<FullParseHandler>::checkForHeadCo
             return false;
         // PNK_ASSIGN nodes (destructuring assignment) are always assignments.
     }
     return true;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::forStatement()
+Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
     uint32_t begin = pos().begin;
 
     StmtInfoPC forStmt(context);
     PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
 
     bool isForEach = false;
@@ -4688,35 +4723,36 @@ Parser<FullParseHandler>::forStatement()
              * A side effect of this restriction is that (unparenthesized)
              * expressions involving an 'in' operator are illegal in the init
              * clause of an ordinary for loop.
              */
             pc->parsingForInit = true;
             if (tt == TOK_VAR) {
                 isForDecl = true;
                 tokenStream.consumeKnownToken(tt);
-                pn1 = variables(PNK_VAR);
+                pn1 = variables(yieldHandling, PNK_VAR);
             } else if (tt == TOK_LET || tt == TOK_CONST) {
                 handler.disableSyntaxParser();
                 bool constDecl = tt == TOK_CONST;
                 tokenStream.consumeKnownToken(tt);
                 if (!tokenStream.peekToken(&tt))
                     return null();
                 if (tt == TOK_LP) {
-                    pn1 = deprecatedLetBlockOrExpression(LetExpression);
+                    pn1 = deprecatedLetBlockOrExpression(yieldHandling, LetExpression);
                 } else {
                     isForDecl = true;
                     blockObj = StaticBlockObject::create(context);
                     if (!blockObj)
                         return null();
-                    pn1 = variables(constDecl ? PNK_CONST : PNK_LET, nullptr, blockObj,
+                    pn1 = variables(yieldHandling,
+                                    constDecl ? PNK_CONST : PNK_LET, nullptr, blockObj,
                                     DontHoistVars);
                 }
             } else {
-                pn1 = expr();
+                pn1 = expr(InProhibited, yieldHandling);
             }
             pc->parsingForInit = false;
             if (!pn1)
                 return null();
         }
     }
 
     MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
@@ -4840,17 +4876,19 @@ Parser<FullParseHandler>::forStatement()
             MOZ_ASSERT(!blockObj);
             pn2 = pn1;
             pn1 = nullptr;
 
             if (!checkAndMarkAsAssignmentLhs(pn2, PlainAssignment))
                 return null();
         }
 
-        pn3 = (headKind == PNK_FOROF) ? assignExpr() : expr();
+        pn3 = (headKind == PNK_FOROF)
+              ? assignExpr(InAllowed, yieldHandling)
+              : expr(InAllowed, yieldHandling);
         if (!pn3)
             return null();
 
         if (blockObj) {
             /*
              * Now that the pn3 has been parsed, push the let scope. To hold
              * the blockObj for the emitter, wrap the PNK_LEXICALSCOPE node
              * created by PushLetScope around the for's initializer. This also
@@ -4935,43 +4973,43 @@ Parser<FullParseHandler>::forStatement()
         /* Parse the loop condition or null into pn2. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_SEMI) {
             pn2 = nullptr;
         } else {
-            pn2 = expr();
+            pn2 = expr(InAllowed, yieldHandling);
             if (!pn2)
                 return null();
         }
 
         /* Parse the update expression or null into pn3. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_RP) {
             pn3 = nullptr;
         } else {
-            pn3 = expr();
+            pn3 = expr(InAllowed, yieldHandling);
             if (!pn3)
                 return null();
         }
     }
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     TokenPos headPos(begin, pos().end);
     ParseNode* forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
     if (!forHead)
         return null();
 
     /* Parse the loop body. */
-    ParseNode* body = statement();
+    ParseNode* body = statement(yieldHandling);
     if (!body)
         return null();
 
     if (blockObj)
         PopStatementPC(tokenStream, pc);
     PopStatementPC(tokenStream, pc);
 
     ParseNode* forLoop = handler.newForStatement(begin, forHead, body, iflags);
@@ -4991,17 +5029,17 @@ Parser<FullParseHandler>::forStatement()
         forLetImpliedBlock->pn_pos = forLoop->pn_pos;
         return handler.newLetBlock(forLetDecl, forLetImpliedBlock, forLoop->pn_pos);
     }
     return forLoop;
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::forStatement()
+Parser<SyntaxParseHandler>::forStatement(YieldHandling yieldHandling)
 {
     /*
      * 'for' statement parsing is fantastically complicated and requires being
      * able to inspect the parse tree for previous parts of the 'for'. Syntax
      * parsing of 'for' statements is thus done separately, and only handles
      * the types of 'for' statements likely to be seen in web content.
      */
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
@@ -5038,24 +5076,24 @@ Parser<SyntaxParseHandler>::forStatement
         if (tt == TOK_SEMI) {
             lhsNode = null();
         } else {
             /* Set lhsNode to a var list or an initializing expression. */
             pc->parsingForInit = true;
             if (tt == TOK_VAR) {
                 isForDecl = true;
                 tokenStream.consumeKnownToken(tt);
-                lhsNode = variables(PNK_VAR, &simpleForDecl);
+                lhsNode = variables(yieldHandling, PNK_VAR, &simpleForDecl);
             }
             else if (tt == TOK_CONST || tt == TOK_LET) {
                 JS_ALWAYS_FALSE(abortIfSyntaxParser());
                 return null();
             }
             else {
-                lhsNode = expr();
+                lhsNode = expr(InProhibited, yieldHandling);
             }
             if (!lhsNode)
                 return null();
             pc->parsingForInit = false;
         }
     }
 
     /*
@@ -5086,59 +5124,59 @@ Parser<SyntaxParseHandler>::forStatement
         if (!simpleForDecl) {
             JS_ALWAYS_FALSE(abortIfSyntaxParser());
             return null();
         }
 
         if (!isForDecl && !checkAndMarkAsAssignmentLhs(lhsNode, PlainAssignment))
             return null();
 
-        if (!expr())
+        if (!(isForIn ? expr(InAllowed, yieldHandling) : assignExpr(InAllowed, yieldHandling)))
             return null();
     } else {
         /* Parse the loop condition or null. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt != TOK_SEMI) {
-            if (!expr())
+            if (!expr(InAllowed, yieldHandling))
                 return null();
         }
 
         /* Parse the update expression or null. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt != TOK_RP) {
-            if (!expr())
+            if (!expr(InAllowed, yieldHandling))
                 return null();
         }
     }
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     /* Parse the loop body. */
-    if (!statement())
+    if (!statement(yieldHandling))
         return null();
 
     PopStatementPC(tokenStream, pc);
     return SyntaxParseHandler::NodeGeneric;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::switchStatement()
+Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_SWITCH));
     uint32_t begin = pos().begin;
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
 
-    Node discriminant = exprInParens();
+    Node discriminant = exprInParens(InAllowed, yieldHandling);
     if (!discriminant)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
 
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_SWITCH);
@@ -5169,17 +5207,17 @@ Parser<ParseHandler>::switchStatement()
                 report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS);
                 return null();
             }
             seenDefault = true;
             caseExpr = null();  // The default case has pn_left == nullptr.
             break;
 
           case TOK_CASE:
-            caseExpr = expr();
+            caseExpr = expr(InAllowed, yieldHandling);
             if (!caseExpr)
                 return null();
             break;
 
           default:
             report(ParseError, false, null(), JSMSG_BAD_SWITCH);
             return null();
         }
@@ -5199,17 +5237,17 @@ Parser<ParseHandler>::switchStatement()
             if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT)
                 break;
             if (afterReturn) {
                 TokenPos pos(0, 0);
                 if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
                     return null();
                 statementBegin = pos.begin;
             }
-            Node stmt = statement();
+            Node stmt = statement(yieldHandling);
             if (!stmt)
                 return null();
             if (!warnedAboutStatementsAfterReturn) {
                 if (afterReturn) {
                     if (!handler.isStatementPermittedAfterReturnStatement(stmt)) {
                         if (!reportWithOffset(ParseWarning, false, statementBegin,
                                               JSMSG_STMT_AFTER_RETURN))
                         {
@@ -5257,23 +5295,23 @@ Parser<ParseHandler>::switchStatement()
 
     handler.setEndPosition(caseList, pos().end);
 
     return handler.newSwitchStatement(begin, discriminant, caseList);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::continueStatement()
+Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CONTINUE));
     uint32_t begin = pos().begin;
 
     RootedPropertyName label(context);
-    if (!matchLabel(&label))
+    if (!matchLabel(yieldHandling, &label))
         return null();
 
     StmtInfoPC* stmt = pc->topStmt;
     if (label) {
         for (StmtInfoPC* stmt2 = nullptr; ; stmt = stmt->down) {
             if (!stmt) {
                 report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
                 return null();
@@ -5304,23 +5342,23 @@ Parser<ParseHandler>::continueStatement(
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
 
     return handler.newContinueStatement(label, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::breakStatement()
+Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_BREAK));
     uint32_t begin = pos().begin;
 
     RootedPropertyName label(context);
-    if (!matchLabel(&label))
+    if (!matchLabel(yieldHandling, &label))
         return null();
     StmtInfoPC* stmt = pc->topStmt;
     if (label) {
         for (; ; stmt = stmt->down) {
             if (!stmt) {
                 report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
                 return null();
             }
@@ -5341,25 +5379,22 @@ Parser<ParseHandler>::breakStatement()
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
 
     return handler.newBreakStatement(label, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::returnStatement()
+Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN));
     uint32_t begin = pos().begin;
 
-    if (!pc->sc->isFunctionBox()) {
-        report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
-        return null();
-    }
+    MOZ_ASSERT(pc->sc->isFunctionBox());
 
     // Parse an optional operand.
     //
     // This is ugly, but we don't want to require a semicolon.
     Node exprNode;
     TokenKind tt;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return null();
@@ -5367,17 +5402,17 @@ Parser<ParseHandler>::returnStatement()
       case TOK_EOL:
       case TOK_EOF:
       case TOK_SEMI:
       case TOK_RC:
         exprNode = null();
         pc->funHasReturnVoid = true;
         break;
       default: {
-        exprNode = expr();
+        exprNode = expr(InAllowed, yieldHandling);
         if (!exprNode)
             return null();
         pc->funHasReturnExpr = true;
       }
     }
 
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
@@ -5419,17 +5454,17 @@ Parser<ParseHandler>::newYieldExpression
         return null();
     if (isYieldStar)
         return handler.newYieldStarExpression(begin, expr, generator);
     return handler.newYieldExpression(begin, expr, generator);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::yieldExpression()
+Parser<ParseHandler>::yieldExpression(InHandling inHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
     uint32_t begin = pos().begin;
 
     switch (pc->generatorKind()) {
       case StarGenerator:
       {
         MOZ_ASSERT(pc->sc->isFunctionBox());
@@ -5459,17 +5494,17 @@ Parser<ParseHandler>::yieldExpression()
             // No value.
             exprNode = null();
             break;
           case TOK_MUL:
             kind = PNK_YIELD_STAR;
             tokenStream.consumeKnownToken(TOK_MUL);
             // Fall through.
           default:
-            exprNode = assignExpr();
+            exprNode = assignExpr(inHandling, YieldIsKeyword);
             if (!exprNode)
                 return null();
         }
         return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
       }
 
       case NotGenerator:
         // We are in code that has not seen a yield, but we are in JS 1.7 or
@@ -5517,31 +5552,31 @@ Parser<ParseHandler>::yieldExpression()
           case TOK_RB:
           case TOK_RP:
           case TOK_COLON:
           case TOK_COMMA:
             // No value.
             exprNode = null();
             break;
           default:
-            exprNode = assignExpr();
+            exprNode = assignExpr(inHandling, YieldIsKeyword);
             if (!exprNode)
                 return null();
         }
 
         return newYieldExpression(begin, exprNode);
       }
     }
 
     MOZ_CRASH("yieldExpr");
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::withStatement()
+Parser<FullParseHandler>::withStatement(YieldHandling yieldHandling)
 {
     // test262/ch12/12.10/12.10-0-1.js fails if we try to parse with-statements
     // in syntax-parse mode. See bug 892583.
     if (handler.syntaxParser) {
         handler.disableSyntaxParser();
         abortedSyntaxParse = true;
         return null();
     }
@@ -5554,33 +5589,33 @@ Parser<FullParseHandler>::withStatement(
     // use reportStrictModeError.  However, 'with' is the sole instance of a
     // construct that is forbidden in strict mode code, but doesn't even merit a
     // warning under JSOPTION_EXTRA_WARNINGS.  See
     // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
     if (pc->sc->strict() && !report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
         return null();
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
-    Node objectExpr = exprInParens();
+    Node objectExpr = exprInParens(InAllowed, yieldHandling);
     if (!objectExpr)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
 
     bool oldParsingWith = pc->parsingWith;
     pc->parsingWith = true;
 
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_WITH);
     Rooted<StaticWithObject*> staticWith(context, StaticWithObject::create(context));
     if (!staticWith)
         return null();
     staticWith->initEnclosingNestedScopeFromParser(pc->staticScope);
     FinishPushNestedScope(pc, &stmtInfo, *staticWith);
 
-    Node innerBlock = statement();
+    Node innerBlock = statement(yieldHandling);
     if (!innerBlock)
         return null();
 
     PopStatementPC(tokenStream, pc);
 
     pc->sc->setBindingsAccessedDynamically();
     pc->parsingWith = oldParsingWith;
 
@@ -5598,54 +5633,54 @@ Parser<FullParseHandler>::withStatement(
     ObjectBox* staticWithBox = newObjectBox(staticWith);
     if (!staticWithBox)
         return null();
     return handler.newWithStatement(begin, objectExpr, innerBlock, staticWithBox);
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::withStatement()
+Parser<SyntaxParseHandler>::withStatement(YieldHandling yieldHandling)
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return null();
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::labeledStatement()
+Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     RootedPropertyName label(context, tokenStream.currentName());
     for (StmtInfoPC* stmt = pc->topStmt; stmt; stmt = stmt->down) {
         if (stmt->type == STMT_LABEL && stmt->label == label) {
             report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
             return null();
         }
     }
 
     tokenStream.consumeKnownToken(TOK_COLON);
 
     /* Push a label struct and parse the statement. */
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_LABEL);
     stmtInfo.label = label;
-    Node pn = statement();
+    Node pn = statement(yieldHandling);
     if (!pn)
         return null();
 
     /* Pop the label, set pn_expr, and return early. */
     PopStatementPC(tokenStream, pc);
 
     return handler.newLabeledStatement(label, pn, begin);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::throwStatement()
+Parser<ParseHandler>::throwStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_THROW));
     uint32_t begin = pos().begin;
 
     /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
     TokenKind tt;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return null();
@@ -5653,29 +5688,29 @@ Parser<ParseHandler>::throwStatement()
         report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW);
         return null();
     }
     if (tt == TOK_EOL) {
         report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW);
         return null();
     }
 
-    Node throwExpr = expr();
+    Node throwExpr = expr(InAllowed, yieldHandling);
     if (!throwExpr)
         return null();
 
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
 
     return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::tryStatement()
+Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_TRY));
     uint32_t begin = pos().begin;
 
     /*
      * try nodes are ternary.
      * kid1 is the try statement
      * kid2 is the catch node list or null
@@ -5692,17 +5727,17 @@ Parser<ParseHandler>::tryStatement()
      *
      * finally nodes are TOK_LC statement lists.
      */
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
     StmtInfoPC stmtInfo(context);
     if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_TRY, pc))
         return null();
-    Node innerBlock = statements();
+    Node innerBlock = statements(yieldHandling);
     if (!innerBlock)
         return null();
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
     PopStatementPC(tokenStream, pc);
 
     bool hasUnconditionalCatch = false;
     Node catchList = null();
     TokenKind tt;
@@ -5751,22 +5786,29 @@ Parser<ParseHandler>::tryStatement()
             MOZ_ASSERT(data.let.blockObj);
 
             if (!tokenStream.getToken(&tt))
                 return null();
             Node catchName;
             switch (tt) {
               case TOK_LB:
               case TOK_LC:
-                catchName = destructuringExpr(&data, tt);
+                catchName = destructuringExpr(yieldHandling, &data, tt);
                 if (!catchName)
                     return null();
                 break;
 
               case TOK_YIELD:
+                if (yieldHandling == YieldIsKeyword) {
+                    report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
+                    return null();
+                }
+
+                // Even if yield is *not* necessarily a keyword, we still must
+                // check its validity for legacy generators.
                 if (!checkYieldNameValidity())
                     return null();
                 // Fall through.
               case TOK_NAME:
               {
                 RootedPropertyName label(context, tokenStream.currentName());
                 catchName = newBindingNode(label, false);
                 if (!catchName)
@@ -5788,25 +5830,25 @@ Parser<ParseHandler>::tryStatement()
              * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
              * to avoid conflicting with the JS2/ECMAv4 type annotation
              * catchguard syntax.
              */
             bool matched;
             if (!tokenStream.matchToken(&matched, TOK_IF))
                 return null();
             if (matched) {
-                catchGuard = expr();
+                catchGuard = expr(InAllowed, yieldHandling);
                 if (!catchGuard)
                     return null();
             }
 #endif
             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
 
             MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
-            Node catchBody = statements();
+            Node catchBody = statements(yieldHandling);
             if (!catchBody)
                 return null();
             MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
             PopStatementPC(tokenStream, pc);
 
             if (!catchGuard)
                 hasUnconditionalCatch = true;
 
@@ -5821,17 +5863,17 @@ Parser<ParseHandler>::tryStatement()
     }
 
     Node finallyBlock = null();
 
     if (tt == TOK_FINALLY) {
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
         if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_FINALLY, pc))
             return null();
-        finallyBlock = statements();
+        finallyBlock = statements(yieldHandling);
         if (!finallyBlock)
             return null();
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
         PopStatementPC(tokenStream, pc);
     } else {
         tokenStream.ungetToken();
     }
     if (!catchList && !finallyBlock) {
@@ -5855,32 +5897,34 @@ Parser<ParseHandler>::debuggerStatement(
     pc->sc->setBindingsAccessedDynamically();
     pc->sc->setHasDebuggerStatement();
 
     return handler.newDebuggerStatement(p);
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::classDefinition(ClassContext classContext)
+Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
+                                          ClassContext classContext)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
 
     bool savedStrictness = setLocalStrictMode(true);
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
 
     RootedPropertyName name(context);
     if (tt == TOK_NAME) {
         name = tokenStream.currentName();
     } else if (tt == TOK_YIELD) {
         if (!checkYieldNameValidity())
             return null();
+        MOZ_ASSERT(yieldHandling != YieldIsKeyword);
         name = tokenStream.currentName();
     } else if (classContext == ClassStatement) {
         // Class statements must have a bound name
         report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT);
         return null();
     } else {
         // Make sure to put it back, whatever it was
         tokenStream.ungetToken();
@@ -5906,24 +5950,24 @@ Parser<FullParseHandler>::classDefinitio
 
     ParseNode* classHeritage = null();
     bool hasHeritage;
     if (!tokenStream.matchToken(&hasHeritage, TOK_EXTENDS))
         return null();
     if (hasHeritage) {
         if (!tokenStream.getToken(&tt))
             return null();
-        classHeritage = memberExpr(tt, true);
+        classHeritage = memberExpr(yieldHandling, tt, true);
         if (!classHeritage)
             return null();
     }
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS);
 
-    ParseNode* classMethods = propertyList(ClassBody);
+    ParseNode* classMethods = propertyList(yieldHandling, ClassBody);
     if (!classMethods)
         return null();
 
     ParseNode* nameNode = null();
     ParseNode* methodsOrBlock = classMethods;
     if (name) {
         ParseNode* innerBinding = makeInitializedLexicalBinding(name, true, namePos);
         if (!innerBinding)
@@ -5949,165 +5993,178 @@ Parser<FullParseHandler>::classDefinitio
 
     MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
 
     return handler.newClass(nameNode, classHeritage, methodsOrBlock);
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::classDefinition(ClassContext classContext)
+Parser<SyntaxParseHandler>::classDefinition(YieldHandling yieldHandling, ClassContext classContext)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::statement(bool canHaveDirectives)
+Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirectives)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     JS_CHECK_RECURSION(context, return null());
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
+
     switch (tt) {
       // BlockStatement[?Yield, ?Return]
       case TOK_LC:
-        return blockStatement();
+        return blockStatement(yieldHandling);
 
       // VariableStatement[?Yield]
       case TOK_VAR: {
-        Node pn = variables(PNK_VAR);
+        Node pn = variables(yieldHandling, PNK_VAR);
         if (!pn)
             return null();
 
         // Tell js_EmitTree to generate a final POP.
         handler.setListFlag(pn, PNX_POPVAR);
 
         if (!MatchOrInsertSemicolon(tokenStream))
             return null();
         return pn;
       }
 
       // EmptyStatement
       case TOK_SEMI:
         return handler.newEmptyStatement(pos());
 
-      // ExpressionStatement[?Yield]
+      // ExpressionStatement[?Yield].
+      //
+      // These should probably be handled by a single ExpressionStatement
+      // function in a default, not split up this way.
       case TOK_STRING:
         if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
             if (!abortIfSyntaxParser())
                 return null();
             if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
                 return null();
         }
-        return expressionStatement();
+        return expressionStatement(yieldHandling);
 
       case TOK_YIELD: {
         TokenKind next;
         TokenStream::Modifier modifier = yieldExpressionsSupported()
                                          ? TokenStream::Operand
                                          : TokenStream::None;
         if (!tokenStream.peekToken(&next, modifier))
             return null();
         if (next == TOK_COLON) {
             if (!checkYieldNameValidity())
                 return null();
-            return labeledStatement();
-        }
-        return expressionStatement();
+            return labeledStatement(yieldHandling);
+        }
+        return expressionStatement(yieldHandling);
       }
 
       case TOK_NAME: {
         TokenKind next;
         if (!tokenStream.peekToken(&next))
             return null();
         if (next == TOK_COLON)
-            return labeledStatement();
-        return expressionStatement();
+            return labeledStatement(yieldHandling);
+        return expressionStatement(yieldHandling);
       }
 
       case TOK_NEW:
-        return expressionStatement(PredictInvoked);
+        return expressionStatement(yieldHandling, PredictInvoked);
 
       default:
-        return expressionStatement();
+        return expressionStatement(yieldHandling);
 
       // IfStatement[?Yield, ?Return]
       case TOK_IF:
-        return ifStatement();
+        return ifStatement(yieldHandling);
 
       // BreakableStatement[?Yield, ?Return]
       //
       // BreakableStatement[Yield, Return]:
       //   IterationStatement[?Yield, ?Return]
       //   SwitchStatement[?Yield, ?Return]
       case TOK_DO:
-        return doWhileStatement();
+        return doWhileStatement(yieldHandling);
 
       case TOK_WHILE:
-        return whileStatement();
+        return whileStatement(yieldHandling);
 
       case TOK_FOR:
-        return forStatement();
+        return forStatement(yieldHandling);
 
       case TOK_SWITCH:
-        return switchStatement();
+        return switchStatement(yieldHandling);
 
       // ContinueStatement[?Yield]
       case TOK_CONTINUE:
-        return continueStatement();
+        return continueStatement(yieldHandling);
 
       // BreakStatement[?Yield]
       case TOK_BREAK:
-        return breakStatement();
+        return breakStatement(yieldHandling);
 
       // [+Return] ReturnStatement[?Yield]
       case TOK_RETURN:
-        return returnStatement();
+        // The Return parameter is only used here, and the effect is easily
+        // detected this way, so don't bother passing around an extra parameter
+        // everywhere.
+        if (!pc->sc->isFunctionBox()) {
+            report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
+            return null();
+        }
+        return returnStatement(yieldHandling);
 
       // WithStatement[?Yield, ?Return]
       case TOK_WITH:
-        return withStatement();
+        return withStatement(yieldHandling);
 
       // LabelledStatement[?Yield, ?Return]
       // This is really handled by TOK_NAME and TOK_YIELD cases above.
 
       // ThrowStatement[?Yield]
       case TOK_THROW:
-        return throwStatement();
+        return throwStatement(yieldHandling);
 
       // TryStatement[?Yield, ?Return]
       case TOK_TRY:
-        return tryStatement();
+        return tryStatement(yieldHandling);
 
       // DebuggerStatement
       case TOK_DEBUGGER:
         return debuggerStatement();
 
       // HoistableDeclaration[?Yield]
       case TOK_FUNCTION:
-        return functionStmt();
+        return functionStmt(yieldHandling);
 
       // ClassDeclaration[?Yield]
       case TOK_CLASS:
         if (!abortIfSyntaxParser())
             return null();
-        return classDefinition(ClassStatement);
+        return classDefinition(yieldHandling, ClassStatement);
 
       // LexicalDeclaration[In, ?Yield]
       case TOK_LET:
-        return letDeclarationOrBlock();
+        // [In] is the default behavior, because for-loops currently specially
+        // parse their heads to handle |in| in this situation.
+        return letDeclarationOrBlock(yieldHandling);
       case TOK_CONST:
         if (!abortIfSyntaxParser())
             return null();
-        return lexicalDeclaration(/* isConst = */ true);
+        return lexicalDeclaration(yieldHandling, /* isConst = */ true);
 
       // ImportDeclaration (only inside modules)
       case TOK_IMPORT:
         return importDeclaration();
 
       // ExportDeclaration (only inside modules)
       case TOK_EXPORT:
         return exportDeclaration();
@@ -6123,36 +6180,37 @@ Parser<ParseHandler>::statement(bool can
         return null();
 
       // NOTE: default case handled in the ExpressionStatement section.
     }
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::expr(InvokedPrediction invoked)
-{
-    Node pn = assignExpr(invoked);
+Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
+                           InvokedPrediction invoked)
+{
+    Node pn = assignExpr(inHandling, yieldHandling, invoked);
     if (!pn)
         return null();
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_COMMA))
         return null();
     if (matched) {
         Node seq = handler.newCommaExpressionList(pn);
         if (!seq)
             return null();
         while (true) {
             if (handler.isUnparenthesizedYieldExpression(pn)) {
                 report(ParseError, false, pn, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
                 return null();
             }
 
-            pn = assignExpr();
+            pn = assignExpr(inHandling, yieldHandling);
             if (!pn)
                 return null();
             handler.addList(seq, pn);
 
             if (!tokenStream.matchToken(&matched, TOK_COMMA))
                 return null();
             if (!matched)
                 break;
@@ -6247,41 +6305,45 @@ Precedence(ParseNodeKind pnk) {
 
     MOZ_ASSERT(pnk >= PNK_BINOP_FIRST);
     MOZ_ASSERT(pnk <= PNK_BINOP_LAST);
     return PrecedenceTable[pnk - PNK_BINOP_FIRST];
 }
 
 template <typename ParseHandler>
 MOZ_ALWAYS_INLINE typename ParseHandler::Node
-Parser<ParseHandler>::orExpr1(InvokedPrediction invoked)
+Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling,
+                              InvokedPrediction invoked)
 {
     // Shift-reduce parser for the left-associative binary operator part of
     // the JS syntax.
 
     // Conceptually there's just one stack, a stack of pairs (lhs, op).
     // It's implemented using two separate arrays, though.
     Node nodeStack[PRECEDENCE_CLASSES];
     ParseNodeKind kindStack[PRECEDENCE_CLASSES];
     int depth = 0;
 
     bool oldParsingForInit = pc->parsingForInit;
     pc->parsingForInit = false;
 
     Node pn;
     for (;;) {
-        pn = unaryExpr(invoked);
+        pn = unaryExpr(yieldHandling, invoked);
         if (!pn)
             return pn;
 
         // If a binary operator follows, consume it and compute the
         // corresponding operator.
         TokenKind tok;
         if (!tokenStream.getToken(&tok))
             return null();
+
+        // FIXME: Change this to use |inHandling == InAllowed|, not
+        // |pc->parsingForInit|.
         ParseNodeKind pnk;
         if (IsBinaryOpToken(tok, oldParsingForInit)) {
             pnk = BinaryOpTokenKindToParseNodeKind(tok);
         } else {
             tok = TOK_EOF;
             pnk = PNK_LIMIT;
         }
 
@@ -6313,37 +6375,38 @@ Parser<ParseHandler>::orExpr1(InvokedPre
 
     MOZ_ASSERT(depth == 0);
     pc->parsingForInit = oldParsingForInit;
     return pn;
 }
 
 template <typename ParseHandler>
 MOZ_ALWAYS_INLINE typename ParseHandler::Node
-Parser<ParseHandler>::condExpr1(InvokedPrediction invoked)
-{
-    Node condition = orExpr1(invoked);
+Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandling,
+                                InvokedPrediction invoked)
+{
+    Node condition = orExpr1(inHandling, yieldHandling, invoked);
     if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
         return condition;
 
     /*
      * Always accept the 'in' operator in the middle clause of a ternary,
      * where it's unambiguous, even if we might be parsing the init of a
      * for statement.
      */
     bool oldParsingForInit = pc->parsingForInit;
     pc->parsingForInit = false;
-    Node thenExpr = assignExpr();
+    Node thenExpr = assignExpr(InAllowed, yieldHandling);
     pc->parsingForInit = oldParsingForInit;
     if (!thenExpr)
         return null();
 
     MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
 
-    Node elseExpr = assignExpr();
+    Node elseExpr = assignExpr(inHandling, yieldHandling);
     if (!elseExpr)
         return null();
 
     // Advance to the next token; the caller is responsible for interpreting it.
     TokenKind ignored;
     if (!tokenStream.getToken(&ignored))
         return null();
     return handler.newConditional(condition, thenExpr, elseExpr);
@@ -6416,17 +6479,18 @@ Parser<SyntaxParseHandler>::checkAndMark
     {
         return abortIfSyntaxParser();
     }
     return checkStrictAssignment(pn);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::assignExpr(InvokedPrediction invoked)
+Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
+                                 InvokedPrediction invoked)
 {
     JS_CHECK_RECURSION(context, return null());
 
     // It's very common at this point to have a "detectably simple" expression,
     // i.e. a name/number/string token followed by one of the following tokens
     // that obviously isn't part of an expression: , ; : ) ] }
     //
     // (In Parsemark this happens 81.4% of the time;  in code with large
@@ -6441,17 +6505,17 @@ Parser<ParseHandler>::assignExpr(Invoked
         return null();
 
     bool endsExpr;
 
     if (tt == TOK_NAME) {
         if (!tokenStream.nextTokenEndsExpr(&endsExpr))
             return null();
         if (endsExpr)
-            return identifierName();
+            return identifierName(yieldHandling);
     }
 
     if (tt == TOK_NUMBER) {
         if (!tokenStream.nextTokenEndsExpr(&endsExpr))
             return null();
         if (endsExpr)
             return newNumber(tokenStream.currentToken());
     }
@@ -6459,26 +6523,26 @@ Parser<ParseHandler>::assignExpr(Invoked
     if (tt == TOK_STRING) {
         if (!tokenStream.nextTokenEndsExpr(&endsExpr))
             return null();
         if (endsExpr)
             return stringLiteral();
     }
 
     if (tt == TOK_YIELD && yieldExpressionsSupported())
-        return yieldExpression();
+        return yieldExpression(inHandling);
 
     tokenStream.ungetToken();
 
     // Save the tokenizer state in case we find an arrow function and have to
     // rewind.
     TokenStream::Position start(keepAtoms);
     tokenStream.tell(&start);
 
-    Node lhs = condExpr1(invoked);
+    Node lhs = condExpr1(inHandling, yieldHandling, invoked);
     if (!lhs)
         return null();
 
     ParseNodeKind kind;
     JSOp op;
     switch (tokenStream.currentToken().type) {
       case TOK_ASSIGN:       kind = PNK_ASSIGN;       op = JSOP_NOP;    break;
       case TOK_ADDASSIGN:    kind = PNK_ADDASSIGN;    op = JSOP_ADD;    break;
@@ -6506,32 +6570,32 @@ Parser<ParseHandler>::assignExpr(Invoked
         tokenStream.seek(start);
         if (!abortIfSyntaxParser())
             return null();
 
         TokenKind ignored;
         if (!tokenStream.peekToken(&ignored))
             return null();
 
-        return functionDef(NullPtr(), Normal, Arrow, NotGenerator);
+        return functionDef(inHandling, yieldHandling, NullPtr(), Normal, Arrow, NotGenerator);
       }
 
       default:
         MOZ_ASSERT(!tokenStream.isCurrentTokenAssignment());
         tokenStream.ungetToken();
         return lhs;
     }
 
     AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
     if (!checkAndMarkAsAssignmentLhs(lhs, flavor))
         return null();
 
     bool saved = pc->inDeclDestructuring;
     pc->inDeclDestructuring = false;
-    Node rhs = assignExpr();
+    Node rhs = assignExpr(inHandling, yieldHandling);
     pc->inDeclDestructuring = saved;
     if (!rhs)
         return null();
 
     return handler.newAssignment(kind, lhs, rhs, pc, op);
 }
 
 static const char incop_name_str[][10] = {"increment", "decrement"};
@@ -6578,85 +6642,86 @@ Parser<SyntaxParseHandler>::checkAndMark
     // inc/dec operands are the same as for assignment. There are differences,
     // such as destructuring; but if we hit any of those cases, we'll abort and
     // reparse in full mode.
     return checkAndMarkAsAssignmentLhs(kid, IncDecAssignment);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin)
-{
-    Node kid = unaryExpr();
+Parser<ParseHandler>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op,
+                                  uint32_t begin)
+{
+    Node kid = unaryExpr(yieldHandling);
     if (!kid)
         return null();
     return handler.newUnary(kind, op, begin, kid);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::unaryExpr(InvokedPrediction invoked)
+Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, InvokedPrediction invoked)
 {
     Node pn, pn2;
 
     JS_CHECK_RECURSION(context, return null());
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     uint32_t begin = pos().begin;
     switch (tt) {
       case TOK_TYPEOF:
-        return unaryOpExpr(PNK_TYPEOF, JSOP_TYPEOF, begin);
+        return unaryOpExpr(yieldHandling, PNK_TYPEOF, JSOP_TYPEOF, begin);
       case TOK_VOID:
-        return unaryOpExpr(PNK_VOID, JSOP_VOID, begin);
+        return unaryOpExpr(yieldHandling, PNK_VOID, JSOP_VOID, begin);
       case TOK_NOT:
-        return unaryOpExpr(PNK_NOT, JSOP_NOT, begin);
+        return unaryOpExpr(yieldHandling, PNK_NOT, JSOP_NOT, begin);
       case TOK_BITNOT:
-        return unaryOpExpr(PNK_BITNOT, JSOP_BITNOT, begin);
+        return unaryOpExpr(yieldHandling, PNK_BITNOT, JSOP_BITNOT, begin);
       case TOK_ADD:
-        return unaryOpExpr(PNK_POS, JSOP_POS, begin);
+        return unaryOpExpr(yieldHandling, PNK_POS, JSOP_POS, begin);
       case TOK_SUB:
-        return unaryOpExpr(PNK_NEG, JSOP_NEG, begin);
+        return unaryOpExpr(yieldHandling, PNK_NEG, JSOP_NEG, begin);
 
       case TOK_INC:
       case TOK_DEC:
       {
         TokenKind tt2;
         if (!tokenStream.getToken(&tt2, TokenStream::Operand))
             return null();
-        pn2 = memberExpr(tt2, true);
+        pn2 = memberExpr(yieldHandling, tt2, true);
         if (!pn2)
             return null();
         if (!checkAndMarkAsIncOperand(pn2, tt, true))
             return null();
         return handler.newUnary((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
                                 JSOP_NOP,
                                 begin,
                                 pn2);
       }
 
       case TOK_DELETE: {
-        Node expr = unaryExpr();
+        Node expr = unaryExpr(yieldHandling);
         if (!expr)
             return null();
 
         // Per spec, deleting any unary expression is valid -- it simply
         // returns true -- except for one case that is illegal in strict mode.
         if (handler.isName(expr)) {
             if (!report(ParseStrictError, pc->sc->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND))
                 return null();
             pc->sc->setBindingsAccessedDynamically();
         }
 
         return handler.newDelete(begin, expr);
       }
 
       default:
-        pn = memberExpr(tt, /* allowCallSyntax = */ true, invoked);
+        pn = memberExpr(yieldHandling, tt, /* allowCallSyntax = */ true, invoked);
         if (!pn)
             return null();
 
         /* Don't look across a newline boundary for a postfix incop. */
         if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_INC || tt == TOK_DEC) {
             tokenStream.consumeKnownToken(tt);
@@ -7064,17 +7129,17 @@ Parser<FullParseHandler>::legacyComprehe
 
         RootedPropertyName name(context);
         if (!tokenStream.getToken(&tt))
             return null();
         switch (tt) {
           case TOK_LB:
           case TOK_LC:
             pc->inDeclDestructuring = true;
-            pn3 = primaryExpr(tt);
+            pn3 = primaryExpr(YieldIsKeyword, tt);
             pc->inDeclDestructuring = false;
             if (!pn3)
                 return null();
             break;
 
           case TOK_NAME:
             name = tokenStream.currentName();
 
@@ -7108,17 +7173,17 @@ Parser<FullParseHandler>::legacyComprehe
                 MOZ_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
                 report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
                 return null();
             }
             pn2->pn_iflags = 0;
             headKind = PNK_FOROF;
         }
 
-        ParseNode* pn4 = expr();
+        ParseNode* pn4 = expr(InAllowed, YieldIsKeyword);
         if (!pn4)
             return null();
         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
         if (isGenexp && pc->lastYieldOffset != startYieldOffset) {
             reportWithOffset(ParseError, false, pc->lastYieldOffset,
                              JSMSG_BAD_GENEXP_BODY, js_yield_str);
             return null();
@@ -7169,17 +7234,17 @@ Parser<FullParseHandler>::legacyComprehe
         if (!matched)
             break;
     }
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_IF))
         return null();
     if (matched) {
-        ParseNode* cond = condition();
+        ParseNode* cond = condition(InAllowed, YieldIsKeyword);
         if (!cond)
             return null();
         ParseNode* ifNode = handler.new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, nullptr, nullptr,
                                                       cond->pn_pos);
         if (!ifNode)
             return null();
         *pnp = ifNode;
         pnp = &ifNode->pn_kid2;
@@ -7445,17 +7510,17 @@ Parser<ParseHandler>::comprehensionFor(G
     bool matched;
     if (!tokenStream.matchContextualKeyword(&matched, context->names().of))
         return null();
     if (!matched) {
         report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME);
         return null();
     }
 
-    Node rhs = assignExpr();
+    Node rhs = assignExpr(InAllowed, YieldIsKeyword);
     if (!rhs)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_OF_ITERABLE);
 
     TokenPos headPos(begin, pos().end);
 
     StmtInfoPC stmtInfo(context);
@@ -7496,17 +7561,17 @@ template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::comprehensionIf(GeneratorKind comprehensionKind)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_IF));
 
     uint32_t begin = pos().begin;
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
-    Node cond = assignExpr();
+    Node cond = assignExpr(InAllowed, YieldIsKeyword);
     if (!cond)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
     if (handler.isUnparenthesizedAssignment(cond)) {
         if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
             return null();
@@ -7533,17 +7598,17 @@ Parser<ParseHandler>::comprehensionTail(
 
     if (!tokenStream.matchToken(&matched, TOK_IF, TokenStream::Operand))
         return null();
     if (matched)
         return comprehensionIf(comprehensionKind);
 
     uint32_t begin = pos().begin;
 
-    Node bodyExpr = assignExpr();
+    Node bodyExpr = assignExpr(InAllowed, YieldIsKeyword);
     if (!bodyExpr)
         return null();
 
     if (comprehensionKind == NotGenerator)
         return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
 
     MOZ_ASSERT(comprehensionKind == StarGenerator);
     Node yieldExpr = newYieldExpression(begin, bodyExpr);
@@ -7620,31 +7685,31 @@ Parser<ParseHandler>::generatorComprehen
     handler.setBeginPosition(result, begin);
     handler.setEndPosition(result, pos().end);
 
     return result;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::assignExprWithoutYield(unsigned msg)
+Parser<ParseHandler>::assignExprWithoutYield(YieldHandling yieldHandling, unsigned msg)
 {
     uint32_t startYieldOffset = pc->lastYieldOffset;
-    Node res = assignExpr();
+    Node res = assignExpr(InAllowed, yieldHandling);
     if (res && pc->lastYieldOffset != startYieldOffset) {
         reportWithOffset(ParseError, false, pc->lastYieldOffset,
                          msg, js_yield_str);
         return null();
     }
     return res;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::argumentList(Node listNode, bool* isSpread)
+Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread)
 {
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_RP, TokenStream::Operand))
         return false;
     if (matched) {
         handler.setEndPosition(listNode, pos().end);
         return true;
     }
@@ -7658,17 +7723,17 @@ Parser<ParseHandler>::argumentList(Node 
         if (!tokenStream.matchToken(&matched, TOK_TRIPLEDOT, TokenStream::Operand))
             return false;
         if (matched) {
             spread = true;
             begin = pos().begin;
             *isSpread = true;
         }
 
-        Node argNode = assignExpr();
+        Node argNode = assignExpr(InAllowed, yieldHandling);
         if (!argNode)
             return false;
         if (spread) {
             argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
             if (!argNode)
                 return false;
         }
 
@@ -7745,17 +7810,18 @@ Parser<ParseHandler>::checkAndMarkSuperS
             break;
         }
     }
     return false;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax, InvokedPrediction invoked)
+Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool allowCallSyntax,
+                                 InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
 
     Node lhs;
 
     JS_CHECK_RECURSION(context, return null());
 
     bool isSuper = false;
@@ -7764,37 +7830,37 @@ Parser<ParseHandler>::memberExpr(TokenKi
     /* Check for new expression first. */
     if (tt == TOK_NEW) {
         lhs = handler.newList(PNK_NEW, JSOP_NEW);
         if (!lhs)
             return null();
 
         if (!tokenStream.getToken(&tt, TokenStream::Operand))
             return null();
-        Node ctorExpr = memberExpr(tt, false, PredictInvoked);
+        Node ctorExpr = memberExpr(yieldHandling, tt, false, PredictInvoked);
         if (!ctorExpr)
             return null();
 
         handler.addList(lhs, ctorExpr);
 
         bool matched;
         if (!tokenStream.matchToken(&matched, TOK_LP))
             return null();
         if (matched) {
             bool isSpread = false;
-            if (!argumentList(lhs, &isSpread))
+            if (!argumentList(yieldHandling, lhs, &isSpread))
                 return null();
             if (isSpread)
                 handler.setOp(lhs, JSOP_SPREADNEW);
         }
     } else if (tt == TOK_SUPER) {
         lhs = null();
         isSuper = true;
     } else {
-        lhs = primaryExpr(tt, invoked);
+        lhs = primaryExpr(yieldHandling, tt, invoked);
         if (!lhs)
             return null();
     }
 
     while (true) {
         if (!tokenStream.getToken(&tt))
             return null();
         if (tt == TOK_EOF)
@@ -7818,17 +7884,17 @@ Parser<ParseHandler>::memberExpr(TokenKi
                 }
                 if (!nextMember)
                     return null();
             } else {
                 report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT);
                 return null();
             }
         } else if (tt == TOK_LB) {
-            Node propExpr = expr();
+            Node propExpr = expr(InAllowed, yieldHandling);
             if (!propExpr)
                 return null();
 
             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
 
             if (isSuper) {
                 isSuper = false;
                 if (!checkAndMarkSuperScope()) {
@@ -7887,28 +7953,28 @@ Parser<ParseHandler>::memberExpr(TokenKi
                 }
             }
 
             handler.setBeginPosition(nextMember, lhs);
             handler.addList(nextMember, lhs);
 
             if (tt == TOK_LP) {
                 bool isSpread = false;
-                if (!argumentList(nextMember, &isSpread))
+                if (!argumentList(yieldHandling, nextMember, &isSpread))
                     return null();
                 if (isSpread) {
                     if (op == JSOP_EVAL)
                         op = JSOP_SPREADEVAL;
                     else if (op == JSOP_STRICTEVAL)
                         op = JSOP_STRICTSPREADEVAL;
                     else
                         op = JSOP_SPREADCALL;
                 }
             } else {
-                if (!taggedTemplate(nextMember, tt))
+                if (!taggedTemplate(yieldHandling, nextMember, tt))
                     return null();
             }
             handler.setOp(nextMember, op);
         } else {
             if (isSuper) {
                 report(ParseError, false, null(), JSMSG_BAD_SUPER);
                 return null();
             }
@@ -7931,19 +7997,27 @@ template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::newName(PropertyName* name)
 {
     return handler.newName(name, pc->blockid(), pos());
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::identifierName()
+Parser<ParseHandler>::identifierName(YieldHandling yieldHandling)
 {
     RootedPropertyName name(context, tokenStream.currentName());
+    if (yieldHandling == YieldIsKeyword && name == context->names().yield) {
+        report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
+        return null();
+    }
+
+    // If we're inside a function that later becomes a legacy generator, then
+    // a |yield| identifier name here will be detected by a subsequent
+    // |checkYieldNameValidity| call.
     Node pn = newName(name);
     if (!pn)
         return null();
 
     if (!pc->inDeclDestructuring && !noteNameUse(name, pn))
         return null();
 
     return pn;
@@ -7995,17 +8069,17 @@ Parser<ParseHandler>::newRegExp()
     if (!reobj)
         return null();
 
     return handler.newRegExp(reobj, pos(), *this);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::arrayInitializer()
+Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB));
 
     uint32_t begin = pos().begin;
     Node literal = handler.newArrayLiteral(begin, pc->blockidGen);
     if (!literal)
         return null();
 
@@ -8043,23 +8117,23 @@ Parser<ParseHandler>::arrayInitializer()
             if (tt == TOK_COMMA) {
                 tokenStream.consumeKnownToken(TOK_COMMA);
                 if (!handler.addElision(literal, pos()))
                     return null();
             } else if (tt == TOK_TRIPLEDOT) {
                 spread = true;
                 tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
                 uint32_t begin = pos().begin;
-                Node inner = assignExpr();
+                Node inner = assignExpr(InAllowed, yieldHandling);
                 if (!inner)
                     return null();
                 if (!handler.addSpreadElement(literal, begin, inner))
                     return null();
             } else {
-                Node element = assignExpr();
+                Node element = assignExpr(InAllowed, yieldHandling);
                 if (!element)
                     return null();
                 if (foldConstants && !FoldConstants(context, &element, this))
                     return null();
                 handler.addArrayElement(literal, element);
             }
 
             if (tt != TOK_COMMA) {
@@ -8139,27 +8213,27 @@ DoubleToAtom(ExclusiveContext* cx, doubl
 {
     // This is safe because doubles can not be moved.
     Value tmp = DoubleValue(value);
     return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::computedPropertyName(Node literal)
+Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, Node literal)
 {
     uint32_t begin = pos().begin;
 
     // Turn off the inDeclDestructuring flag when parsing computed property
     // names. In short, when parsing 'let {[x + y]: z} = obj;', noteNameUse()
     // should be called on x and y, but not on z. See the comment on
     // Parser<>::checkDestructuring() for details.
     bool saved = pc->inDeclDestructuring;
     pc->inDeclDestructuring = false;
-    Node assignNode = assignExpr();
+    Node assignNode = assignExpr(InAllowed, yieldHandling);
     pc->inDeclDestructuring = saved;
     if (!assignNode)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
     Node propname = handler.newComputedName(assignNode, begin, pos().end);
     if (!propname)
         return null();
@@ -8175,17 +8249,17 @@ Parser<ParseHandler>::newPropertyListNod
         return handler.newClassMethodList(pos().begin);
 
     MOZ_ASSERT(type == ObjectLiteral);
     return handler.newObjectLiteral(pos().begin);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::propertyList(PropListType type)
+Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType type)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
 
     Node propList = newPropertyListNode(type);
     if (!propList)
         return null();
 
     bool seenPrototypeMutation = false;
@@ -8229,17 +8303,17 @@ Parser<ParseHandler>::propertyList(PropL
             if (!atom)
                 return null();
             propname = newNumber(tokenStream.currentToken());
             if (!propname)
                 return null();
             break;
 
           case TOK_LB: {
-              propname = computedPropertyName(propList);
+              propname = computedPropertyName(yieldHandling, propList);
               if (!propname)
                   return null();
               break;
           }
 
           case TOK_NAME: {
             atom = tokenStream.currentName();
             // Do not look for accessor syntax on generators
@@ -8285,17 +8359,17 @@ Parser<ParseHandler>::propertyList(PropL
             } else if (tt == TOK_NUMBER) {
                 atom = DoubleToAtom(context, tokenStream.currentToken().number());
                 if (!atom)
                     return null();
                 propname = newNumber(tokenStream.currentToken());
                 if (!propname)
                     return null();
             } else if (tt == TOK_LB) {
-                propname = computedPropertyName(propList);
+                propname = computedPropertyName(yieldHandling, propList);
                 if (!propname)
                     return null();
             } else {
                 // Not an accessor property after all.
                 tokenStream.ungetToken();
                 propname = handler.newObjectLiteralPropertyName(atom, pos());
                 if (!propname)
                     return null();
@@ -8365,17 +8439,17 @@ Parser<ParseHandler>::propertyList(PropL
                     report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
                     return null();
                 }
                 if (isGenerator) {
                     report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
                     return null();
                 }
 
-                Node propexpr = assignExpr();
+                Node propexpr = assignExpr(InAllowed, yieldHandling);
                 if (!propexpr)
                     return null();
 
                 if (foldConstants && !FoldConstants(context, &propexpr, this))
                     return null();
 
                 if (atom == context->names().proto) {
                     if (seenPrototypeMutation) {
@@ -8411,35 +8485,38 @@ Parser<ParseHandler>::propertyList(PropL
                     report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
                     return null();
                 }
 
                 tokenStream.ungetToken();
                 if (!tokenStream.checkForKeyword(atom, nullptr))
                     return null();
 
-                Node nameExpr = identifierName();
+                Node nameExpr = identifierName(yieldHandling);
                 if (!nameExpr)
                     return null();
 
                 if (!handler.addShorthand(propList, propname, nameExpr))
                     return null();
             } else if (tt == TOK_LP) {
                 tokenStream.ungetToken();
-                if (!methodDefinition(type, propList, propname, Normal,
-                                      isGenerator ? StarGenerator : NotGenerator, isStatic, op)) {
+                if (!methodDefinition(yieldHandling, type, propList, propname, Normal,
+                                      isGenerator ? StarGenerator : NotGenerator, isStatic, op))
+                {
                     return null();
                 }
             } else {
                 report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
                 return null();
             }
         } else {
-            if (!methodDefinition(type, propList, propname, op == JSOP_INITPROP_GETTER ? Getter : Setter,
-                                  NotGenerator, isStatic, op)) {
+            if (!methodDefinition(yieldHandling, type, propList, propname,
+                                  op == JSOP_INITPROP_GETTER ? Getter : Setter, NotGenerator,
+                                  isStatic, op))
+            {
                 return null();
             }
         }
 
         if (type == ObjectLiteral) {
             TokenKind tt;
             if (!tokenStream.getToken(&tt))
                 return null();
@@ -8459,67 +8536,68 @@ Parser<ParseHandler>::propertyList(PropL
     }
 
     handler.setEndPosition(propList, pos().end);
     return propList;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::methodDefinition(PropListType listType, Node propList, Node propname,
-                                       FunctionType type, GeneratorKind generatorKind,
-                                       bool isStatic, JSOp op)
+Parser<ParseHandler>::methodDefinition(YieldHandling yieldHandling, PropListType listType,
+                                       Node propList, Node propname, FunctionType type,
+                                       GeneratorKind generatorKind, bool isStatic, JSOp op)
 {
     /* NB: Getter function in { get x(){} } is unnamed. */
     RootedPropertyName funName(context);
     if (type == Normal && tokenStream.isCurrentTokenType(TOK_NAME))
         funName = tokenStream.currentName();
     else
         funName = nullptr;
 
-    Node fn = functionDef(funName, type, Method, generatorKind);
+    Node fn = functionDef(InAllowed, yieldHandling, funName, type, Method, generatorKind);
     if (!fn)
         return false;
 
     if (listType == ClassBody)
         return handler.addClassMethodDefinition(propList, propname, fn, op, isStatic);
 
     MOZ_ASSERT(listType == ObjectLiteral);
     return handler.addObjectMethodDefinition(propList, propname, fn, op);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::primaryExpr(TokenKind tt, InvokedPrediction invoked)
+Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TokenKind tt,
+                                  InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
     JS_CHECK_RECURSION(context, return null());
 
     switch (tt) {
       case TOK_FUNCTION:
         return functionExpr(invoked);
 
       case TOK_CLASS:
-        return classDefinition(ClassExpression);
+        return classDefinition(yieldHandling, ClassExpression);
 
       case TOK_LB:
-        return arrayInitializer();
+        return arrayInitializer(yieldHandling);
 
       case TOK_LC:
-        return propertyList(ObjectLiteral);
+        return propertyList(yieldHandling, ObjectLiteral);
 
       case TOK_LET:
-        return deprecatedLetBlockOrExpression(LetExpression);
+        return deprecatedLetBlockOrExpression(yieldHandling, LetExpression);
 
       case TOK_LP: {
         TokenKind next;
         if (!tokenStream.peekToken(&next, TokenStream::Operand))
             return null();
         if (next != TOK_RP)
-            return parenExprOrGeneratorComprehension();
+            return parenExprOrGeneratorComprehension(yieldHandling);
 
         // Not valid expression syntax, but this is valid in an arrow function
         // with no params: `() => body`.
         tokenStream.consumeKnownToken(next);
 
         if (!tokenStream.peekToken(&next))
             return null();
         if (next != TOK_ARROW) {
@@ -8530,30 +8608,30 @@ Parser<ParseHandler>::primaryExpr(TokenK
 
         // Now just return something that will allow parsing to continue.
         // It doesn't matter what; when we reach the =>, we will rewind and
         // reparse the whole arrow function. See Parser::assignExpr.
         return handler.newNullLiteral(pos());
       }
 
       case TOK_TEMPLATE_HEAD:
-        return templateLiteral();
+        return templateLiteral(yieldHandling);
 
       case TOK_NO_SUBS_TEMPLATE:
         return noSubstitutionTemplate();
 
       case TOK_STRING:
         return stringLiteral();
 
       case TOK_YIELD:
         if (!checkYieldNameValidity())
             return null();
         // Fall through.
       case TOK_NAME:
-        return identifierName();
+        return identifierName(yieldHandling);
 
       case TOK_REGEXP:
         return newRegExp();
 
       case TOK_NUMBER:
         return newNumber(tokenStream.currentToken());
 
       case TOK_TRUE:
@@ -8571,16 +8649,21 @@ Parser<ParseHandler>::primaryExpr(TokenK
         TokenKind next;
 
         // This isn't valid expression syntax, but it's valid in an arrow
         // function as a trailing rest param: `(a, b, ...rest) => body`.  Check
         // for a name, closing parenthesis, and arrow, and allow it only if all
         // are present.
         if (!tokenStream.getToken(&next))
             return null();
+        // FIXME: This fails to handle a rest parameter named |yield| correctly
+        //        outside of generators: |var f = (...yield) => 42;| should be
+        //        valid code!  When this is fixed, make sure to consult both
+        //        |yieldHandling| and |checkYieldNameValidity| for correctness
+        //        until legacy generator syntax is removed.
         if (next != TOK_NAME) {
             report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                    "rest argument name", TokenKindToDesc(next));
             return null();
         }
 
         if (!tokenStream.getToken(&next))
             return null();
@@ -8608,17 +8691,17 @@ Parser<ParseHandler>::primaryExpr(TokenK
         report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                "expression", TokenKindToDesc(tt));
         return null();
     }
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::parenExprOrGeneratorComprehension()
+Parser<ParseHandler>::parenExprOrGeneratorComprehension(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
     uint32_t begin = pos().begin;
     uint32_t startYieldOffset = pc->lastYieldOffset;
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_FOR, TokenStream::Operand))
         return null();
@@ -8627,17 +8710,17 @@ Parser<ParseHandler>::parenExprOrGenerat
 
     /*
      * Always accept the 'in' operator in a parenthesized expression,
      * where it's unambiguous, even if we might be parsing the init of a
      * for statement.
      */
     bool oldParsingForInit = pc->parsingForInit;
     pc->parsingForInit = false;
-    Node pn = expr(PredictInvoked);
+    Node pn = expr(InAllowed, yieldHandling, PredictInvoked);
     pc->parsingForInit = oldParsingForInit;
 
     if (!pn)
         return null();
 
 #if JS_HAS_GENERATOR_EXPRS
     if (!tokenStream.matchToken(&matched, TOK_FOR))
         return null();
@@ -8691,30 +8774,30 @@ Parser<ParseHandler>::parenExprOrGenerat
 //   with (_) {}
 //   foo(_) // must be first and only argument
 //
 // This is not the case for ES6 generator comprehensions; they must always be in
 // parentheses.
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::exprInParens()
+Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
     uint32_t begin = pos().begin;
     uint32_t startYieldOffset = pc->lastYieldOffset;
 
     /*
      * Always accept the 'in' operator in a parenthesized expression,
      * where it's unambiguous, even if we might be parsing the init of a
      * for statement.
      */
     bool oldParsingForInit = pc->parsingForInit;
     pc->parsingForInit = false;
-    Node pn = expr(PredictInvoked);
+    Node pn = expr(inHandling, yieldHandling, PredictInvoked);
     pc->parsingForInit = oldParsingForInit;
 
     if (!pn)
         return null();
 
 #if JS_HAS_GENERATOR_EXPRS
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_FOR))
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -326,16 +326,23 @@ struct BindData;
 
 class CompExprTransplanter;
 
 enum LetContext { LetExpression, LetStatement };
 enum VarContext { HoistVars, DontHoistVars };
 enum FunctionType { Getter, Setter, Normal };
 enum PropListType { ObjectLiteral, ClassBody };
 
+// Specify a value for an ES6 grammar parametrization.  We have no enum for
+// [Return] because its behavior is exactly equivalent to checking whether
+// we're in a function box -- easier and simpler than passing an extra
+// parameter everywhere.
+enum YieldHandling { YieldIsName, YieldIsKeyword };
+enum InHandling { InAllowed, InProhibited };
+
 template <typename ParseHandler>
 class Parser : private JS::AutoGCRooter, public StrictModeGetter
 {
   public:
     ExclusiveContext* const context;
     LifoAlloc& alloc;
 
     TokenStream         tokenStream;
@@ -455,30 +462,31 @@ class Parser : private JS::AutoGCRooter,
 
   private:
     Parser* thisForCtor() { return this; }
 
     JSAtom * stopStringCompression();
 
     Node stringLiteral();
     Node noSubstitutionTemplate();
-    Node templateLiteral();
-    bool taggedTemplate(Node nodeList, TokenKind tt);
+    Node templateLiteral(YieldHandling yieldHandling);
+    bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt);
     bool appendToCallSiteObj(Node callSiteObj);
-    bool addExprAndGetNextTemplStrToken(Node nodeList, TokenKind* ttp);
+    bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
+                                        TokenKind* ttp);
 
     inline Node newName(PropertyName* name);
     inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
 
     inline bool abortIfSyntaxParser();
 
   public:
+    /* Public entry points for parsing. */
+    Node statement(YieldHandling yieldHandling, bool canHaveDirectives = false);
 
-    /* Public entry points for parsing. */
-    Node statement(bool canHaveDirectives = false);
     bool maybeParseDirective(Node list, Node pn, bool* cont);
 
     // Parse a function, given only its body. Used for the Function and
     // Generator constructors.
     Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector& formals,
                                 GeneratorKind generatorKind,
                                 Directives inheritedDirectives, Directives* newDirectives);
 
@@ -487,19 +495,21 @@ class Parser : private JS::AutoGCRooter,
     Node standaloneLazyFunction(HandleFunction fun, unsigned staticLevel, bool strict,
                                 GeneratorKind generatorKind);
 
     /*
      * Parse a function body.  Pass StatementListBody if the body is a list of
      * statements; pass ExpressionBody if the body is a single expression.
      */
     enum FunctionBodyType { StatementListBody, ExpressionBody };
-    Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
+    Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
+                      FunctionBodyType type);
 
-    bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
+    bool functionArgsAndBodyGeneric(InHandling inHandling, YieldHandling yieldHandling, Node pn,
+                                    HandleFunction fun, FunctionType type,
                                     FunctionSyntaxKind kind);
 
     // Determine whether |yield| is a valid name in the current context, or
     // whether it's prohibited due to strictness, JS version, or occurrence
     // inside a star generator.
     bool checkYieldNameValidity();
     bool yieldExpressionsSupported() {
         return versionNumber() >= JSVERSION_1_7 || pc->isGenerator();
@@ -530,77 +540,84 @@ class Parser : private JS::AutoGCRooter,
      * Parsers whose name has a '1' suffix leave the TokenStream state
      * pointing to the token one past the end of the parsed fragment.  For a
      * number of the parsers this is convenient and avoids a lot of
      * unnecessary ungetting and regetting of tokens.
      *
      * Some parsers have two versions:  an always-inlined version (with an 'i'
      * suffix) and a never-inlined version (with an 'n' suffix).
      */
-    Node functionStmt();
+    Node functionStmt(YieldHandling yieldHandling);
     Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
-    Node statements();
+    Node statements(YieldHandling yieldHandling);
 
-    Node blockStatement();
-    Node ifStatement();
-    Node doWhileStatement();
-    Node whileStatement();
-    Node forStatement();
-    Node switchStatement();
-    Node continueStatement();
-    Node breakStatement();
-    Node returnStatement();
-    Node withStatement();
-    Node labeledStatement();
-    Node throwStatement();
-    Node tryStatement();
+    Node blockStatement(YieldHandling yieldHandling);
+    Node ifStatement(YieldHandling yieldHandling);
+    Node doWhileStatement(YieldHandling yieldHandling);
+    Node whileStatement(YieldHandling yieldHandling);
+    Node forStatement(YieldHandling yieldHandling);
+    Node switchStatement(YieldHandling yieldHandling);
+    Node continueStatement(YieldHandling yieldHandling);
+    Node breakStatement(YieldHandling yieldHandling);
+    Node returnStatement(YieldHandling yieldHandling);
+    Node withStatement(YieldHandling yieldHandling);
+    Node labeledStatement(YieldHandling yieldHandling);
+    Node throwStatement(YieldHandling yieldHandling);
+    Node tryStatement(YieldHandling yieldHandling);
     Node debuggerStatement();
 
-    Node lexicalDeclaration(bool isConst);
-    Node letDeclarationOrBlock();
+    Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
+    Node letDeclarationOrBlock(YieldHandling yieldHandling);
     Node importDeclaration();
     Node exportDeclaration();
-    Node expressionStatement(InvokedPrediction invoked = PredictUninvoked);
-    Node variables(ParseNodeKind kind, bool* psimple = nullptr,
-                   StaticBlockObject* blockObj = nullptr,
-                   VarContext varContext = HoistVars);
-    Node expr(InvokedPrediction invoked = PredictUninvoked);
-    Node assignExpr(InvokedPrediction invoked = PredictUninvoked);
-    Node assignExprWithoutYield(unsigned err);
-    Node yieldExpression();
-    Node condExpr1(InvokedPrediction invoked = PredictUninvoked);
-    Node orExpr1(InvokedPrediction invoked = PredictUninvoked);
-    Node unaryExpr(InvokedPrediction invoked = PredictUninvoked);
-    Node memberExpr(TokenKind tt, bool allowCallSyntax,
+    Node expressionStatement(YieldHandling yieldHandling,
+                             InvokedPrediction invoked = PredictUninvoked);
+    Node variables(YieldHandling yieldHandling,
+                   ParseNodeKind kind, bool* psimple = nullptr,
+                   StaticBlockObject* blockObj = nullptr, VarContext varContext = HoistVars);
+    Node expr(InHandling inHandling, YieldHandling yieldHandling,
+              InvokedPrediction invoked = PredictUninvoked);
+    Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
                     InvokedPrediction invoked = PredictUninvoked);
-    Node primaryExpr(TokenKind tt, InvokedPrediction invoked = PredictUninvoked);
-    Node parenExprOrGeneratorComprehension();
-    Node exprInParens();
+    Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
+    Node yieldExpression(InHandling inHandling);
+    Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
+                   InvokedPrediction invoked = PredictUninvoked);
+    Node orExpr1(InHandling inHandling, YieldHandling yieldHandling,
+                 InvokedPrediction invoked = PredictUninvoked);
+    Node unaryExpr(YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked);
+    Node memberExpr(YieldHandling yieldHandling, TokenKind tt, bool allowCallSyntax,
+                    InvokedPrediction invoked = PredictUninvoked);
+    Node primaryExpr(YieldHandling yieldHandling, TokenKind tt,
+                     InvokedPrediction invoked = PredictUninvoked);
+    Node parenExprOrGeneratorComprehension(YieldHandling yieldHandling);
+    Node exprInParens(InHandling inHandling, YieldHandling yieldHandling);
 
     bool checkAndMarkSuperScope();
 
-    bool methodDefinition(PropListType listType, Node propList, Node propname, FunctionType type,
-                          GeneratorKind generatorKind, bool isStatic, JSOp Op);
+    bool methodDefinition(YieldHandling yieldHandling, PropListType listType, Node propList,
+                          Node propname, FunctionType type, GeneratorKind generatorKind,
+                          bool isStatic, JSOp Op);
 
     /*
      * Additional JS parsers.
      */
-    bool functionArguments(FunctionSyntaxKind kind, FunctionType type, Node* list, Node funcpn,
-                           bool* hasRest);
+    bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, FunctionType type,
+                           Node* list, Node funcpn, bool* hasRest);
 
-    Node functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind,
-                     GeneratorKind generatorKind, InvokedPrediction invoked = PredictUninvoked);
-    bool functionArgsAndBody(Node pn, HandleFunction fun,
-                             FunctionType type, FunctionSyntaxKind kind,
-                             GeneratorKind generatorKind,
+    Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
+                     FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind,
+                     InvokedPrediction invoked = PredictUninvoked);
+    bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionType type,
+                             FunctionSyntaxKind kind, GeneratorKind generatorKind,
                              Directives inheritedDirectives, Directives* newDirectives);
 
-    Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
+    Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
 
-    Node condition();
+    Node condition(InHandling inHandling, YieldHandling yieldHandling);
 
     Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
                                       Node innerStmt);
 
     Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
                                  ParseContext<ParseHandler>* outerpc,
                                  unsigned innerBlockScopeDepth);
     Node legacyArrayComprehension(Node array);
@@ -608,27 +625,29 @@ class Parser : private JS::AutoGCRooter,
 
     Node comprehensionTail(GeneratorKind comprehensionKind);
     Node comprehensionIf(GeneratorKind comprehensionKind);
     Node comprehensionFor(GeneratorKind comprehensionKind);
     Node comprehension(GeneratorKind comprehensionKind);
     Node arrayComprehension(uint32_t begin);
     Node generatorComprehension(uint32_t begin);
 
-    bool argumentList(Node listNode, bool* isSpread);
-    Node deprecatedLetBlockOrExpression(LetContext letContext);
-    Node destructuringExpr(BindData<ParseHandler>* data, TokenKind tt);
-    Node destructuringExprWithoutYield(BindData<ParseHandler>* data, TokenKind tt, unsigned msg);
+    bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
+    Node deprecatedLetBlockOrExpression(YieldHandling yieldHandling, LetContext letContext);
+    Node destructuringExpr(YieldHandling yieldHandling, BindData<ParseHandler>* data,
+                           TokenKind tt);
+    Node destructuringExprWithoutYield(YieldHandling yieldHandling, BindData<ParseHandler>* data,
+                                       TokenKind tt, unsigned msg);
 
     enum ClassContext { ClassStatement, ClassExpression };
-    Node classDefinition(ClassContext classContext);
+    Node classDefinition(YieldHandling yieldHandling, ClassContext classContext);
 
-    Node identifierName();
+    Node identifierName(YieldHandling yieldHandling);
 
-    bool matchLabel(MutableHandle<PropertyName*> label);
+    bool matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label);
 
     bool allowsForEachIn() {
 #if !JS_HAS_FOR_EACH_IN
         return false;
 #else
         return versionNumber() >= JSVERSION_1_6;
 #endif
     }
@@ -657,21 +676,21 @@ class Parser : private JS::AutoGCRooter,
     bool checkStrictAssignment(Node lhs);
     bool checkStrictBinding(PropertyName* name, Node pn);
     bool defineArg(Node funcpn, HandlePropertyName name,
                    bool disallowDuplicateArgs = false, Node* duplicatedArg = nullptr);
     Node pushLexicalScope(StmtInfoPC* stmt);
     Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC* stmt);
     Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC* stmt);
     bool noteNameUse(HandlePropertyName name, Node pn);
-    Node computedPropertyName(Node literal);
-    Node arrayInitializer();
+    Node computedPropertyName(YieldHandling yieldHandling, Node literal);
+    Node arrayInitializer(YieldHandling yieldHandling);
     Node newRegExp();
 
-    Node propertyList(PropListType type);
+    Node propertyList(YieldHandling yieldHandling, PropListType type);
     Node newPropertyListNode(PropListType type);
 
     bool checkAndPrepareLexical(bool isConst, const TokenPos& errorPos);
     Node makeInitializedLexicalBinding(HandlePropertyName name, bool isConst, const TokenPos& pos);
 
     Node newBindingNode(PropertyName* name, bool functionScope, VarContext varContext = HoistVars);
     bool checkDestructuring(BindData<ParseHandler>* data, Node left);
     bool checkDestructuringObject(BindData<ParseHandler>* data, Node objectPattern);