Bug 967434 - Remove JS_HAS_DESTRUCTURING ifdefs
☠☠ backed out by bde35d854a92 ☠ ☠
authorAndy Wingo <wingo@igalia.com>
Tue, 04 Feb 2014 15:43:00 +0100
changeset 166713 d45ebc647b513047d2ec30a64b31dbf718a93238
parent 166712 cdc2338e71a305acb62d23d2006a131408d7538c
child 166714 d983a44ff5b8eeff2f8061a7171b067e2bc57ea7
push id39271
push userwingo@igalia.com
push dateTue, 04 Feb 2014 14:44:01 +0000
treeherdermozilla-inbound@d45ebc647b51 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs967434
milestone30.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 967434 - Remove JS_HAS_DESTRUCTURING ifdefs
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/Parser.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2891,18 +2891,16 @@ MaybeEmitVarDecl(ExclusiveContext *cx, B
  */
 enum VarEmitOption
 {
     DefineVars        = 0,
     PushInitialValues = 1,
     InitializeVars    = 2
 };
 
-#if JS_HAS_DESTRUCTURING
-
 typedef bool
 (*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
 
 static bool
 EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
     if (!BindNameToSlot(cx, bce, pn))
@@ -3340,76 +3338,66 @@ MaybeEmitLetGroupDecl(ExclusiveContext *
                 return false;
         }
 
         *pop = JSOP_NOP;
     }
     return true;
 }
 
-#endif /* JS_HAS_DESTRUCTURING */
-
 static bool
 EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
               bool isLet = false)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
     JS_ASSERT(isLet == (emitOption == PushInitialValues));
 
     ParseNode *next;
     for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
         next = pn2->pn_next;
 
         ParseNode *pn3;
         if (!pn2->isKind(PNK_NAME)) {
-#if JS_HAS_DESTRUCTURING
             if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
                 /*
                  * Emit variable binding ops, but not destructuring ops.  The
                  * parser (see Parser::variables) has ensured that our caller
                  * will be the PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and
                  * that case will emit the destructuring code only after
                  * emitting an enumerating opcode and a branch that tests
                  * whether the enumeration ended.
                  */
                 JS_ASSERT(emitOption == DefineVars);
                 JS_ASSERT(pn->pn_count == 1);
                 if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
                     return false;
                 break;
             }
-#endif
 
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
              */
             JS_ASSERT(pn2->isKind(PNK_ASSIGN));
             JS_ASSERT(pn2->isOp(JSOP_NOP));
             JS_ASSERT(emitOption != DefineVars);
 
             /*
              * To allow the front end to rewrite var f = x; as f = x; when a
              * function f(){} precedes the var, detect simple name assignment
              * here and initialize the name.
              */
-#if !JS_HAS_DESTRUCTURING
-            JS_ASSERT(pn2->pn_left->isKind(PNK_NAME));
-#else
-            if (pn2->pn_left->isKind(PNK_NAME))
-#endif
-            {
+            if (pn2->pn_left->isKind(PNK_NAME)) {
                 pn3 = pn2->pn_right;
                 pn2 = pn2->pn_left;
                 goto do_name;
             }
 
-#if JS_HAS_DESTRUCTURING
             ptrdiff_t stackDepthBefore = bce->stackDepth;
             JSOp op = JSOP_POP;
             if (pn->pn_count == 1) {
                 /*
                  * If this is the only destructuring assignment in the list,
                  * try to optimize to a group assignment.  If we're in a let
                  * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
                  * in pn->pn_op, to suppress a second (and misplaced) 'let'.
@@ -3447,17 +3435,16 @@ EmitVariables(ExclusiveContext *cx, Byte
 
             /* If we are not initializing, nothing to pop. */
             if (emitOption != InitializeVars) {
                 if (next)
                     continue;
                 break;
             }
             goto emit_note_pop;
-#endif
         }
 
         /*
          * Load initializer early to share code above that jumps to do_name.
          * NB: if this var redeclares an existing binding, then pn2 is linked
          * on its definition's use-chain and pn_expr has been overlayed with
          * pn_lexdef.
          */
@@ -3514,19 +3501,17 @@ EmitVariables(ExclusiveContext *cx, Byte
         if (!pn2->pn_cookie.isFree()) {
             if (!EmitVarOp(cx, pn2, op, bce))
                 return false;
         } else {
             if (!EmitIndexOp(cx, op, atomIndex, bce))
                 return false;
         }
 
-#if JS_HAS_DESTRUCTURING
     emit_note_pop:
-#endif
         if (!next)
             break;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
     }
 
     if (pn->pn_xflags & PNX_POPVAR) {
         if (Emit1(cx, bce, JSOP_POP) < 0)
@@ -3578,21 +3563,19 @@ EmitAssignment(ExclusiveContext *cx, Byt
       case PNK_ELEM:
         JS_ASSERT(lhs->isArity(PN_BINARY));
         if (!EmitTree(cx, bce, lhs->pn_left))
             return false;
         if (!EmitTree(cx, bce, lhs->pn_right))
             return false;
         offset += 2;
         break;
-#if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         break;
-#endif
       case PNK_CALL:
         JS_ASSERT(lhs->pn_xflags & PNX_SETCALL);
         if (!EmitTree(cx, bce, lhs))
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         break;
       default:
@@ -3724,23 +3707,21 @@ EmitAssignment(ExclusiveContext *cx, Byt
       case PNK_CALL:
         /* Do nothing. The JSOP_SETCALL we emitted will always throw. */
         JS_ASSERT(lhs->pn_xflags & PNX_SETCALL);
         break;
       case PNK_ELEM:
         if (Emit1(cx, bce, JSOP_SETELEM) < 0)
             return false;
         break;
-#if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         if (!EmitDestructuringOps(cx, bce, lhs))
             return false;
         break;
-#endif
       default:
         JS_ASSERT(0);
     }
     return true;
 }
 
 bool
 ParseNode::getConstantValue(ExclusiveContext *cx, bool strictChecks, MutableHandleValue vp)
@@ -3902,25 +3883,23 @@ EmitCatch(ExclusiveContext *cx, Bytecode
      * Dup the exception object if there is a guard for rethrowing to use
      * it later when rethrowing or in other catches.
      */
     if (pn->pn_kid2 && Emit1(cx, bce, JSOP_DUP) < 0)
         return false;
 
     ParseNode *pn2 = pn->pn_kid1;
     switch (pn2->getKind()) {
-#if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         if (!EmitDestructuringOps(cx, bce, pn2))
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         break;
-#endif
 
       case PNK_NAME:
         /* Inline and specialize BindNameToSlot for pn2. */
         JS_ASSERT(!pn2->pn_cookie.isFree());
         if (!EmitVarOp(cx, pn2, JSOP_SETLOCAL, bce))
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
@@ -4679,23 +4658,21 @@ EmitNormalFor(ExclusiveContext *cx, Byte
     JSOp op = JSOP_POP;
     ParseNode *pn3 = forHead->pn_kid1;
     if (!pn3) {
         // No initializer, but emit a nop so that there's somewhere to put the
         // SRC_FOR annotation that IonBuilder will look for.
         op = JSOP_NOP;
     } else {
         bce->emittingForInit = true;
-#if JS_HAS_DESTRUCTURING
         if (pn3->isKind(PNK_ASSIGN)) {
             JS_ASSERT(pn3->isOp(JSOP_NOP));
             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, GroupIsNotDecl, &op))
                 return false;
         }
-#endif
         if (op == JSOP_POP) {
             if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
                 return false;
             if (!EmitTree(cx, bce, pn3))
                 return false;
             if (pn3->isKind(PNK_VAR) || pn3->isKind(PNK_CONST) || pn3->isKind(PNK_LET)) {
                 /*
                  * Check whether a destructuring-initialized var decl
@@ -4755,23 +4732,21 @@ EmitNormalFor(ExclusiveContext *cx, Byte
     } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
 
     /* Check for update code to do before the condition (if any). */
     pn3 = forHead->pn_kid3;
     if (pn3) {
         if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
             return false;
         op = JSOP_POP;
-#if JS_HAS_DESTRUCTURING
         if (pn3->isKind(PNK_ASSIGN)) {
             JS_ASSERT(pn3->isOp(JSOP_NOP));
             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, GroupIsNotDecl, &op))
                 return false;
         }
-#endif
         if (op == JSOP_POP && !EmitTree(cx, bce, pn3))
             return false;
 
         /* Always emit the POP or NOP to help IonBuilder. */
         if (Emit1(cx, bce, op) < 0)
             return false;
 
         /* Restore the absolute line number for source note readers. */
@@ -5401,24 +5376,22 @@ EmitStatement(ExclusiveContext *cx, Byte
         {
             useful = true;
         }
     }
 
     if (useful) {
         JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
         JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
-#if JS_HAS_DESTRUCTURING
         if (!wantval &&
             pn2->isKind(PNK_ASSIGN) &&
             !MaybeEmitGroupAssignment(cx, bce, op, pn2, GroupIsNotDecl, &op))
         {
             return false;
         }
-#endif
         if (op != JSOP_NOP) {
             if (!EmitTree(cx, bce, pn2))
                 return false;
             if (Emit1(cx, bce, op) < 0)
                 return false;
         }
     } else if (!pn->isDirectivePrologueMember()) {
         /* Don't complain about directive prologue members; just don't emit their code. */
@@ -5885,22 +5858,20 @@ EmitConditionalExpression(ExclusiveConte
 
 /*
  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
  * the comment on EmitSwitch.
  */
 MOZ_NEVER_INLINE static bool
 EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-#if JS_HAS_DESTRUCTURING_SHORTHAND
     if (pn->pn_xflags & PNX_DESTRUCT) {
         bce->reportError(pn, JSMSG_BAD_OBJECT_INIT);
         return false;
     }
-#endif
 
     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
         return EmitSingletonInitialiser(cx, bce, pn);
 
     /*
      * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
      * a new object and defining (in source order) each property on the object
      * (or mutating the object's [[Prototype]], in the case of __proto__).
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -321,18 +321,16 @@ Definition::kindString(Kind kind)
 
     JS_ASSERT(unsigned(kind) <= unsigned(ARG));
     return table[kind];
 }
 
 namespace js {
 namespace frontend {
 
-#if JS_HAS_DESTRUCTURING
-
 /*
  * This function assumes the cloned tree is for use in the same statement and
  * binding context as the original tree.
  */
 template <>
 ParseNode *
 Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
 {
@@ -418,18 +416,16 @@ Parser<FullParseHandler>::cloneParseTree
         pn->pn_u = opn->pn_u;
         break;
 
 #undef NULLCHECK
     }
     return pn;
 }
 
-#endif /* JS_HAS_DESTRUCTURING */
-
 /*
  * Used by Parser::forStatement and comprehensionTail to clone the TARGET in
  *   for (var/const/let TARGET in EXPR)
  *
  * opn must be the pn_head of a node produced by Parser::variables, so its form
  * is known to be LHS = NAME | [LHS] | {id:LHS}.
  *
  * The cloned tree is for use only in the same statement and binding context as
@@ -442,17 +438,16 @@ Parser<FullParseHandler>::cloneLeftHandS
     ParseNode *pn = handler.new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
                                             opn->pn_pos);
     if (!pn)
         return nullptr;
     pn->setInParens(opn->isInParens());
     pn->setDefn(opn->isDefn());
     pn->setUsed(opn->isUsed());
 
-#if JS_HAS_DESTRUCTURING
     if (opn->isArity(PN_LIST)) {
         JS_ASSERT(opn->isKind(PNK_ARRAY) || opn->isKind(PNK_OBJECT));
         pn->makeEmpty();
         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
             ParseNode *pn2;
             if (opn->isKind(PNK_OBJECT)) {
                 JS_ASSERT(opn2->isArity(PN_BINARY));
                 JS_ASSERT(opn2->isKind(PNK_COLON));
@@ -474,17 +469,16 @@ Parser<FullParseHandler>::cloneLeftHandS
 
             if (!pn2)
                 return nullptr;
             pn->append(pn2);
         }
         pn->pn_xflags = opn->pn_xflags;
         return pn;
     }
-#endif
 
     JS_ASSERT(opn->isArity(PN_NAME));
     JS_ASSERT(opn->isKind(PNK_NAME));
 
     /* If opn is a definition or use, make pn a use. */
     pn->pn_u.name = opn->pn_u.name;
     pn->setOp(JSOP_SETNAME);
     if (opn->isUsed()) {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1502,17 +1502,16 @@ Parser<ParseHandler>::defineArg(Node fun
 
     if (!checkStrictBinding(name, argpn))
         return false;
 
     handler.addFunctionArgument(funcpn, argpn);
     return pc->define(tokenStream, name, argpn, Definition::ARG);
 }
 
-#if JS_HAS_DESTRUCTURING
 template <typename ParseHandler>
 /* static */ bool
 Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler> *data,
                                            HandlePropertyName name, Parser<ParseHandler> *parser)
 {
     ParseContext<ParseHandler> *pc = parser->pc;
     JS_ASSERT(pc->sc->isFunctionBox());
 
@@ -1521,17 +1520,16 @@ Parser<ParseHandler>::bindDestructuringA
         return false;
     }
 
     if (!parser->checkStrictBinding(name, data->pn))
         return false;
 
     return pc->define(parser->tokenStream, name, data->pn, Definition::VAR);
 }
-#endif /* JS_HAS_DESTRUCTURING */
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, Node funcpn,
                                         bool *hasRest)
 {
     FunctionBox *funbox = pc->sc->asFunctionBox();
 
@@ -1555,30 +1553,27 @@ Parser<ParseHandler>::functionArguments(
     Node argsbody = handler.newList(PNK_ARGSBODY);
     if (!argsbody)
         return false;
     handler.setFunctionBody(funcpn, argsbody);
 
     if (parenFreeArrow || !tokenStream.matchToken(TOK_RP)) {
         bool hasDefaults = false;
         Node duplicatedArg = null();
-#if JS_HAS_DESTRUCTURING
         Node list = null();
-#endif
 
         do {
             if (*hasRest) {
                 report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
                 return false;
             }
 
             TokenKind tt = tokenStream.getToken();
             JS_ASSERT_IF(parenFreeArrow, tt == TOK_NAME);
             switch (tt) {
-#if JS_HAS_DESTRUCTURING
               case TOK_LB:
               case TOK_LC:
               {
                 /* See comment below in the TOK_NAME case. */
                 if (duplicatedArg) {
                     report(ParseError, false, duplicatedArg, JSMSG_BAD_DUP_ARGS);
                     return false;
                 }
@@ -1625,17 +1620,16 @@ Parser<ParseHandler>::functionArguments(
                 } else {
                     list = handler.newList(PNK_VAR, item);
                     if (!list)
                         return false;
                     *listp = list;
                 }
                 break;
               }
-#endif /* JS_HAS_DESTRUCTURING */
 
               case TOK_YIELD:
                 if (!checkYieldNameValidity())
                     return false;
                 goto TOK_NAME;
 
               case TOK_TRIPLEDOT:
               {
@@ -2014,17 +2008,16 @@ Parser<ParseHandler>::functionDef(Handle
 
 template <>
 bool
 Parser<FullParseHandler>::finishFunctionDefinition(ParseNode *pn, FunctionBox *funbox,
                                                    ParseNode *prelude, ParseNode *body)
 {
     pn->pn_pos.end = pos().end;
 
-#if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, prepend the initializing
      * comma expression that we synthesized to body. If the body is a return
      * node, we must make a special PNK_SEQ node, to prepend the destructuring
      * code without bracing the decompilation of the function body.
      */
     if (prelude) {
         if (!body->isArity(PN_LIST)) {
@@ -2047,17 +2040,16 @@ Parser<FullParseHandler>::finishFunction
         item->pn_kid = prelude;
         item->pn_next = body->pn_head;
         body->pn_head = item;
         if (body->pn_tail == &body->pn_head)
             body->pn_tail = &item->pn_next;
         ++body->pn_count;
         body->pn_xflags |= PNX_DESTRUCT;
     }
-#endif
 
     JS_ASSERT(pn->pn_funbox == funbox);
     pn->pn_body->append(body);
     pn->pn_body->pn_pos = body->pn_pos;
 
     return true;
 }
 
@@ -2990,18 +2982,16 @@ Parser<ParseHandler>::noteNameUse(Handle
     handler.linkUseToDef(pn, dn);
 
     if (stmt && stmt->type == STMT_WITH)
         handler.setFlag(pn, PND_DEOPTIMIZED);
 
     return true;
 }
 
-#if JS_HAS_DESTRUCTURING
-
 template <>
 bool
 Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
 
     RootedPropertyName name(context, pn->pn_atom->asPropertyName());
 
@@ -3189,18 +3179,16 @@ Parser<ParseHandler>::destructuringExpr(
     pc->inDeclDestructuring = false;
     if (!pn)
         return null();
     if (!checkDestructuring(data, pn))
         return null();
     return pn;
 }
 
-#endif /* JS_HAS_DESTRUCTURING */
-
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
 {
     JS_ASSERT(blockObj);
 
     ObjectBox *blockbox = newObjectBox(blockObj);
     if (!blockbox)
@@ -3461,17 +3449,16 @@ Parser<ParseHandler>::variables(ParseNod
     bool first = true;
     Node pn2;
     do {
         if (psimple && !first)
             *psimple = false;
         first = false;
 
         TokenKind tt = tokenStream.getToken();
-#if JS_HAS_DESTRUCTURING
         if (tt == TOK_LB || tt == TOK_LC) {
             if (psimple)
                 *psimple = false;
 
             pc->inDeclDestructuring = true;
             pn2 = primaryExpr(tt);
             pc->inDeclDestructuring = false;
             if (!pn2)
@@ -3493,17 +3480,16 @@ Parser<ParseHandler>::variables(ParseNod
                 return null();
 
             pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
             if (!pn2)
                 return null();
             handler.addList(pn, pn2);
             continue;
         }
-#endif /* JS_HAS_DESTRUCTURING */
 
         if (tt != TOK_NAME) {
             if (tt == TOK_YIELD) {
                 if (!checkYieldNameValidity())
                     return null();
             } else {
                 if (tt != TOK_ERROR)
                     report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
@@ -4063,49 +4049,45 @@ Parser<FullParseHandler>::isValidForStat
                                                  ParseNodeKind headKind)
 {
     if (isForDecl) {
         if (pn1->pn_count > 1)
             return false;
         if (pn1->isOp(JSOP_DEFCONST))
             return false;
 
-#if JS_HAS_DESTRUCTURING
         // In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
         // Hence all other destructuring decls are banned there.
         if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN) {
             ParseNode *lhs = pn1->pn_head;
             if (lhs->isKind(PNK_ASSIGN))
                 lhs = lhs->pn_left;
 
             if (lhs->isKind(PNK_OBJECT))
                 return false;
             if (lhs->isKind(PNK_ARRAY) && lhs->pn_count != 2)
                 return false;
         }
-#endif
         return true;
     }
 
     switch (pn1->getKind()) {
       case PNK_NAME:
       case PNK_DOT:
       case PNK_CALL:
       case PNK_ELEM:
         return true;
 
-#if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         // In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
         // Hence all other destructuring left-hand sides are banned there.
         if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN)
             return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
         return true;
-#endif
 
       default:
         return false;
     }
 }
 
 template <>
 ParseNode *
@@ -4246,22 +4228,17 @@ Parser<FullParseHandler>::forStatement()
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else nullptr. Note that the "declaration with initializer" case
          * rewrites the loop-head, moving the decl and setting pn1 to nullptr.
          */
         if (isForDecl) {
             pn2 = pn1->pn_head;
-            if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
-#if JS_HAS_DESTRUCTURING
-                || pn2->isKind(PNK_ASSIGN)
-#endif
-                )
-            {
+            if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr()) || pn2->isKind(PNK_ASSIGN)) {
                 /*
                  * Declaration with initializer.
                  *
                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
                  * 'const' to hoist the initializer or the entire decl out of
                  * the loop head.
                  */
                 if (headKind == PNK_FOROF) {
@@ -4280,23 +4257,21 @@ Parser<FullParseHandler>::forStatement()
                  *
                  * Request JSOP_POP here since the var is for a simple
                  * name (it is not a destructuring binding's left-hand
                  * side) and it has an initializer.
                  */
                 pn1->pn_xflags |= PNX_POPVAR;
                 pn1 = nullptr;
 
-#if JS_HAS_DESTRUCTURING
                 if (pn2->isKind(PNK_ASSIGN)) {
                     pn2 = pn2->pn_left;
                     JS_ASSERT(pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT) ||
                               pn2->isKind(PNK_NAME));
                 }
-#endif
             }
         } else {
             /* Not a declaration. */
             JS_ASSERT(!blockObj);
             pn2 = pn1;
             pn1 = nullptr;
 
             if (!checkAndMarkAsAssignmentLhs(pn2, PlainAssignment))
@@ -4334,32 +4309,30 @@ Parser<FullParseHandler>::forStatement()
         }
 
         switch (pn2->getKind()) {
           case PNK_NAME:
             /* Beware 'for (arguments in ...)' with or without a 'var'. */
             pn2->markAsAssigned();
             break;
 
-#if JS_HAS_DESTRUCTURING
           case PNK_ASSIGN:
             MOZ_ASSUME_UNREACHABLE("forStatement TOK_ASSIGN");
 
           case PNK_ARRAY:
           case PNK_OBJECT:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
                 if (!isForEach && headKind == PNK_FORIN)
                     iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
-#endif
 
           default:;
         }
     } else {
         if (isForEach) {
             reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
             return null();
         }
@@ -5085,24 +5058,22 @@ Parser<ParseHandler>::tryStatement()
              */
             data.initLet(HoistVars, pc->staticScope->template as<StaticBlockObject>(),
                          JSMSG_TOO_MANY_CATCH_VARS);
             JS_ASSERT(data.let.blockObj);
 
             tt = tokenStream.getToken();
             Node catchName;
             switch (tt) {
-#if JS_HAS_DESTRUCTURING
               case TOK_LB:
               case TOK_LC:
                 catchName = destructuringExpr(&data, tt);
                 if (!catchName)
                     return null();
                 break;
-#endif
 
               case TOK_YIELD:
                 if (!checkYieldNameValidity())
                     return null();
                 // Fall through.
               case TOK_NAME:
               {
                 RootedPropertyName label(context, tokenStream.currentName());
@@ -5523,27 +5494,25 @@ Parser<FullParseHandler>::checkAndMarkAs
         }
         pn->markAsAssigned();
         break;
 
       case PNK_DOT:
       case PNK_ELEM:
         break;
 
-#if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         if (flavor == CompoundAssignment) {
             report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS);
             return false;
         }
         if (!checkDestructuring(nullptr, pn))
             return false;
         break;
-#endif
 
       case PNK_CALL:
         if (!makeSetCall(pn, JSMSG_BAD_LEFTSIDE_OF_ASS))
             return false;
         break;
 
       default:
         report(ParseError, false, pn, JSMSG_BAD_LEFTSIDE_OF_ASS);
@@ -6122,26 +6091,24 @@ Parser<FullParseHandler>::comprehensionT
             pn2->pn_iflags |= JSITER_FOREACH;
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
 
         uint32_t startYieldOffset = pc->lastYieldOffset;
 
         RootedPropertyName name(context);
         tt = tokenStream.getToken();
         switch (tt) {
-#if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             pc->inDeclDestructuring = true;
             pn3 = primaryExpr(tt);
             pc->inDeclDestructuring = false;
             if (!pn3)
                 return null();
             break;
-#endif
 
           case TOK_NAME:
             name = tokenStream.currentName();
 
             /*
              * Create a name node with pn_op JSOP_NAME.  We can't set pn_op to
              * JSOP_GETLOCAL here, because we don't yet know the block's depth
              * in the operand stack frame.  The code generator computes that,
@@ -6183,17 +6150,16 @@ Parser<FullParseHandler>::comprehensionT
 
         if (isGenexp && pc->lastYieldOffset != startYieldOffset) {
             reportWithOffset(ParseError, false, pc->lastYieldOffset,
                              JSMSG_BAD_GENEXP_BODY, js_yield_str);
             return null();
         }
 
         switch (tt) {
-#if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!checkDestructuring(&data, pn3))
                 return null();
 
             if (versionNumber() == JSVERSION_1_7 &&
                 !(pn2->pn_iflags & JSITER_FOREACH) &&
                 !isForOf)
@@ -6205,17 +6171,16 @@ Parser<FullParseHandler>::comprehensionT
                 }
 
                 JS_ASSERT(pn2->isOp(JSOP_ITER));
                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
                 JS_ASSERT(headKind == PNK_FORIN);
                 pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
-#endif
 
           case TOK_NAME:
             data.pn = pn3;
             if (!data.binder(&data, name, this))
                 return null();
             break;
 
           default:;
@@ -6916,17 +6881,16 @@ Parser<ParseHandler>::objectLiteral()
                  * the default Object.prototype.
                  */
                 if (!handler.isConstant(propexpr) || atom == context->names().proto)
                     handler.setListFlag(literal, PNX_NONCONST);
 
                 if (!handler.addPropertyDefinition(literal, propname, propexpr))
                     return null();
             }
-#if JS_HAS_DESTRUCTURING_SHORTHAND
             else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
                 /*
                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
                  */
                 if (!abortIfSyntaxParser())
                     return null();
                 tokenStream.ungetToken();
@@ -6935,17 +6899,16 @@ Parser<ParseHandler>::objectLiteral()
                 PropertyName *name = handler.isName(propname);
                 JS_ASSERT(atom);
                 propname = newName(name);
                 if (!propname)
                     return null();
                 if (!handler.addShorthandPropertyDefinition(literal, propname))
                     return null();
             }
-#endif
             else {
                 report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
                 return null();
             }
         } else {
             /* NB: Getter function in { get x(){} } is unnamed. */
             Rooted<PropertyName*> funName(context, nullptr);
             TokenStream::Position start(keepAtoms);