Bug 1288460 - Allow escape sequences in the keyword-like but non-reserved 'static' Identifier (in non-strict code). r=arai
authorJeff Walden <jwalden@mit.edu>
Tue, 30 Aug 2016 09:37:26 -0700
changeset 313555 240e3c1ab62217ac892c3d58c719750e20f5bcc4
parent 313554 869a5b6dae7834e2d33e92486b5fd9629f6c3000
child 313556 ea7a9ba853405d5f05dd4b62cf83ebc54bbc1968
push id81655
push userjwalden@mit.edu
push dateMon, 12 Sep 2016 19:36:27 +0000
treeherdermozilla-inbound@fd6cde155f4b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1288460
milestone51.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 1288460 - Allow escape sequences in the keyword-like but non-reserved 'static' Identifier (in non-strict code). r=arai
CLOBBER
js/src/frontend/Parser.cpp
js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js
js/src/vm/Keywords.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1288460 requires a clobber due to bug 1298779.
+Bug 1288460 requires another clobber due to bug 1298779.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -843,16 +843,17 @@ bool
 Parser<ParseHandler>::checkStrictBinding(PropertyName* name, TokenPos pos)
 {
     if (!pc->sc()->needStrictChecks())
         return true;
 
     if (name == context->names().eval ||
         name == context->names().arguments ||
         name == context->names().let ||
+        name == context->names().static_ ||
         IsKeyword(name))
     {
         JSAutoByteString bytes;
         if (!AtomToPrintableString(context, name, &bytes))
             return false;
         return reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin,
                                 JSMSG_BAD_BINDING, bytes.ptr());
     }
@@ -6301,16 +6302,23 @@ Parser<ParseHandler>::classDefinition(Yi
         if (tt == TOK_RC)
             break;
 
         if (tt == TOK_SEMI)
             continue;
 
         bool isStatic = false;
         if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) {
+            MOZ_ASSERT(pc->sc()->strict(), "classes are always strict");
+
+            // Strict mode forbids "class" as Identifier, so it can only be the
+            // unescaped keyword.
+            if (!checkUnescapedName())
+                return null();
+
             if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
                 return null();
             if (tt == TOK_RC) {
                 tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
                 report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                        "property name", TokenKindToDesc(tt));
                 return null();
             }
@@ -8243,16 +8251,18 @@ Parser<ParseHandler>::labelOrIdentifierR
     if (tok.type == TOK_NAME) {
         ident = tok.name();
         MOZ_ASSERT(ident != context->names().yield,
                    "tokenizer should have treated 'yield' as TOK_YIELD");
 
         if (pc->sc()->strict()) {
             const char* badName = ident == context->names().let
                                   ? "let"
+                                  : ident == context->names().static_
+                                  ? "static"
                                   : nullptr;
             if (badName) {
                 report(ParseError, false, null(), JSMSG_RESERVED_ID, badName);
                 return nullptr;
             }
         }
     } else {
         MOZ_ASSERT(tok.type == TOK_YIELD);
@@ -8291,16 +8301,18 @@ Parser<ParseHandler>::bindingIdentifier(
                                   : nullptr;
             if (badName) {
                 report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName);
                 return nullptr;
             }
 
             badName = ident == context->names().let
                       ? "let"
+                      : ident == context->names().static_
+                      ? "static"
                       : nullptr;
             if (badName) {
                 report(ParseError, false, null(), JSMSG_RESERVED_ID, badName);
                 return nullptr;
             }
         }
     } else {
         MOZ_ASSERT(tok.type == TOK_YIELD);
--- a/js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js
+++ b/js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js
@@ -39,14 +39,19 @@ function t(code)
   }
 }
 
 t("l\\u0065t: 42;");
 t("if (1) l\\u0065t: 42;");
 t("l\\u0065t = 42;");
 t("if (1) l\\u0065t = 42;");
 
+t("st\\u0061tic: 42;");
+t("if (1) st\\u0061tic: 42;");
+t("st\\u0061tic = 42;");
+t("if (1) st\\u0061tic = 42;");
+
 /******************************************************************************/
 
 if (typeof reportCompare === "function")
   reportCompare(true, true);
 
 print("Tests complete");
--- a/js/src/vm/Keywords.h
+++ b/js/src/vm/Keywords.h
@@ -50,17 +50,16 @@
     macro(enum, enum_, TOK_RESERVED) \
     /* Future reserved keywords, but only in strict mode. */ \
     macro(implements, implements, TOK_STRICT_RESERVED) \
     macro(interface, interface, TOK_STRICT_RESERVED) \
     macro(package, package, TOK_STRICT_RESERVED) \
     macro(private, private_, TOK_STRICT_RESERVED) \
     macro(protected, protected_, TOK_STRICT_RESERVED) \
     macro(public, public_, TOK_STRICT_RESERVED) \
-    macro(static, static_, TOK_STRICT_RESERVED) \
     /* \
      * Yield is a token inside function*.  Outside of a function*, it is a \
      * future reserved keyword in strict mode, but a keyword in JS1.7 even \
      * when strict.  Punt logic to parser. \
      */ \
     macro(yield, yield, TOK_YIELD)
 
 #endif /* vm_Keywords_h */