diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6ffc1631593c..cb5a81ec913e 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -4963,6 +4963,24 @@ IsLegacyIterator(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +EnableExpressionClosures(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS::ContextOptionsRef(cx).setExpressionClosures(true); + args.rval().setUndefined(); + return true; +} + +static bool +DisableExpressionClosures(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS::ContextOptionsRef(cx).setExpressionClosures(false); + args.rval().setUndefined(); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'zone' [, 'shrinking'])", @@ -5579,6 +5597,14 @@ gc::ZealModeHelpText), "getTimeZone()", " Get the current time zone.\n"), + JS_FN_HELP("enableExpressionClosures", EnableExpressionClosures, 0, 0, +"enableExpressionClosures()", +" Enables the deprecated, non-standard expression closures.\n"), + + JS_FN_HELP("disableExpressionClosures", DisableExpressionClosures, 0, 0, +"disableExpressionClosures()", +" Disables the deprecated, non-standard expression closures.\n"), + JS_FS_HELP_END }; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 79f681339e19..e8ae47e9dacf 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3260,15 +3260,15 @@ Parser::skipLazyInnerFunction(ParseNode* funcNode, uint if (!tokenStream.advance(fun->lazyScript()->end())) return false; -#if JS_HAS_EXPR_CLOSURES - // Only expression closure can be Statement kind. - // If we remove expression closure, we can remove isExprBody flag from - // LazyScript and JSScript. - if (kind == Statement && funbox->isExprBody()) { - if (!matchOrInsertSemicolon()) - return false; + if (allowExpressionClosures()) { + // Only expression closure can be Statement kind. + // If we remove expression closure, we can remove isExprBody flag from + // LazyScript and JSScript. + if (kind == Statement && funbox->isExprBody()) { + if (!matchOrInsertSemicolon()) + return false; + } } -#endif // Append possible Annex B function box only upon successfully parsing. if (tryAnnexB && !pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) @@ -3778,14 +3778,14 @@ GeneralParser::functionFormalParametersAndBody(InHandling i return false; } -#if JS_HAS_EXPR_CLOSURES - this->addTelemetry(DeprecatedLanguageExtension::ExpressionClosure); - if (!warnOnceAboutExprClosure()) + if (allowExpressionClosures()) { + this->addTelemetry(DeprecatedLanguageExtension::ExpressionClosure); + if (!warnOnceAboutExprClosure()) + return false; + } else { + error(JSMSG_CURLY_BEFORE_BODY); return false; -#else - error(JSMSG_CURLY_BEFORE_BODY); - return false; -#endif + } } anyChars.ungetToken(); @@ -3847,9 +3847,8 @@ GeneralParser::functionFormalParametersAndBody(InHandling i JSMSG_CURLY_OPENED, openedPos)); funbox->setEnd(anyChars); } else { -#if !JS_HAS_EXPR_CLOSURES - MOZ_ASSERT(kind == Arrow); -#endif + MOZ_ASSERT_IF(!allowExpressionClosures(), kind == Arrow); + if (anyChars.hadError()) return false; funbox->setEnd(anyChars); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 561ed3778c38..46d64ee999b2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -340,7 +340,9 @@ class ParserBase bool hasValidSimpleStrictParameterNames(); - + bool allowExpressionClosures() const { + return options().expressionClosuresOption; + } /* * Create a new function object given a name (which is optional if this is * a function expression). @@ -703,6 +705,7 @@ class GeneralParser using Base::isValidSimpleAssignmentTarget; using Base::pc; using Base::usedNames; + using Base::allowExpressionClosures; private: using Base::checkAndMarkSuperScope; @@ -1403,6 +1406,7 @@ class Parser final using Base::pos; using Base::ss; using Base::tokenStream; + using Base::allowExpressionClosures; private: using Base::alloc; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9f461beae4c9..c283bbe903a5 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3991,6 +3991,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp canLazilyParse = rhs.canLazilyParse; strictOption = rhs.strictOption; extraWarningsOption = rhs.extraWarningsOption; + expressionClosuresOption = rhs.expressionClosuresOption; werrorOption = rhs.werrorOption; asmJSOption = rhs.asmJSOption; throwOnAsmJSValidationFailureOption = rhs.throwOnAsmJSValidationFailureOption; @@ -4112,6 +4113,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx) { strictOption = cx->options().strictMode(); extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx); + expressionClosuresOption = cx->options().expressionClosures(); isProbablySystemOrAddonCode = cx->compartment()->isProbablySystemOrAddonCode(); werrorOption = cx->options().werror(); if (!cx->options().asmJS()) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 7a1200eced7e..16538dca1d28 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1117,6 +1117,7 @@ class JS_PUBLIC_API(ContextOptions) { #ifdef FUZZING , fuzzing_(false) #endif + , expressionClosures_(false) { } @@ -1272,6 +1273,12 @@ class JS_PUBLIC_API(ContextOptions) { } #endif + bool expressionClosures() const { return expressionClosures_; } + ContextOptions& setExpressionClosures(bool flag) { + expressionClosures_ = flag; + return *this; + } + void disableOptionsForSafeMode() { setBaseline(false); setIon(false); @@ -1302,6 +1309,7 @@ class JS_PUBLIC_API(ContextOptions) { #ifdef FUZZING bool fuzzing_ : 1; #endif + bool expressionClosures_ : 1; }; @@ -3668,6 +3676,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) canLazilyParse(true), strictOption(false), extraWarningsOption(false), + expressionClosuresOption(false), werrorOption(false), asmJSOption(AsmJSOption::Disabled), throwOnAsmJSValidationFailureOption(false), @@ -3702,6 +3711,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) bool canLazilyParse; bool strictOption; bool extraWarningsOption; + bool expressionClosuresOption; bool werrorOption; AsmJSOption asmJSOption; bool throwOnAsmJSValidationFailureOption; diff --git a/js/src/jsversion.h b/js/src/jsversion.h index 82343696adca..061a50e1eafe 100644 --- a/js/src/jsversion.h +++ b/js/src/jsversion.h @@ -14,10 +14,6 @@ #define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ #define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ -#ifndef NIGHTLY_BUILD -#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ -#endif - /* * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support; * support likely to be made opt-in at some future time.