Bug 1609547 - Do not treat underscode after decimal point a numeric separator. r=jwalden
☠☠ backed out by c697754d9059 ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Thu, 16 Jan 2020 06:08:48 +0000
changeset 510439 572928224d2df10c447e9af20d961702df474d12
parent 510438 259b0925375efedccee0c478ac90bf6c78ff3618
child 510440 4a3321b64a58ff2725e01470099c97cd90cda0f2
push id37021
push userrmaries@mozilla.com
push dateThu, 16 Jan 2020 09:46:51 +0000
treeherdermozilla-central@7541d616ff87 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1609547
milestone74.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 1609547 - Do not treat underscode after decimal point a numeric separator. r=jwalden Differential Revision: https://phabricator.services.mozilla.com/D60063
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/tests/non262/Number/numericSeparator.js
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -2407,16 +2407,28 @@ void SourceUnits<Utf8Unit>::consumeRestO
     consumeKnownCodePoint(peeked);
   }
 }
 
 template <typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE MOZ_ALWAYS_INLINE bool
 TokenStreamSpecific<Unit, AnyCharsAccess>::matchInteger(
     IsIntegerUnit isIntegerUnit, int32_t* nextUnit) {
+  int32_t unit = getCodeUnit();
+  if (!isIntegerUnit(unit)) {
+    *nextUnit = unit;
+    return true;
+  }
+  return matchIntegerAfterFirstDigit(isIntegerUnit, nextUnit);
+}
+
+template <typename Unit, class AnyCharsAccess>
+MOZ_MUST_USE MOZ_ALWAYS_INLINE bool
+TokenStreamSpecific<Unit, AnyCharsAccess>::matchIntegerAfterFirstDigit(
+    IsIntegerUnit isIntegerUnit, int32_t* nextUnit) {
   int32_t unit;
   while (true) {
     unit = getCodeUnit();
     if (isIntegerUnit(unit)) {
       continue;
     }
     if (unit != '_') {
       break;
@@ -2441,17 +2453,17 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
     int32_t unit, TokenStart start, const Unit* numStart, Modifier modifier,
     TokenKind* out) {
   // Run the bad-token code for every path out of this function except the
   // one success-case.
   auto noteBadToken = MakeScopeExit([this]() { this->badToken(); });
 
   // Consume integral component digits.
   if (IsAsciiDigit(unit)) {
-    if (!matchInteger(IsAsciiDigit, &unit)) {
+    if (!matchIntegerAfterFirstDigit(IsAsciiDigit, &unit)) {
       return false;
     }
   }
 
   // Numbers contain no escapes, so we can read directly from |sourceUnits|.
   double dval;
   bool isBigInt = false;
   DecimalPoint decimalPoint = NoDecimal;
@@ -2487,17 +2499,17 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
       // Exponential notation must contain at least one digit.
       if (!IsAsciiDigit(unit)) {
         ungetCodeUnit(unit);
         error(JSMSG_MISSING_EXPONENT);
         return false;
       }
 
       // Consume exponential digits.
-      if (!matchInteger(IsAsciiDigit, &unit)) {
+      if (!matchIntegerAfterFirstDigit(IsAsciiDigit, &unit)) {
         return false;
       }
     }
 
     ungetCodeUnit(unit);
 
     // "0." and "0e..." numbers parse "." or "e..." here.  Neither range
     // contains a number, so we can't use |FullStringToDouble|.  (Parse
@@ -2888,49 +2900,49 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_HEXDIGITS);
           return badToken();
         }
 
         // one past the '0x'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        if (!matchInteger(IsAsciiHexDigit, &unit)) {
+        if (!matchIntegerAfterFirstDigit(IsAsciiHexDigit, &unit)) {
           return badToken();
         }
       } else if (unit == 'b' || unit == 'B') {
         radix = 2;
         unit = getCodeUnit();
         if (!IsAsciiBinary(unit)) {
           // NOTE: |unit| may be EOF here.
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_BINARY_DIGITS);
           return badToken();
         }
 
         // one past the '0b'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        if (!matchInteger(IsAsciiBinary, &unit)) {
+        if (!matchIntegerAfterFirstDigit(IsAsciiBinary, &unit)) {
           return badToken();
         }
       } else if (unit == 'o' || unit == 'O') {
         radix = 8;
         unit = getCodeUnit();
         if (!IsAsciiOctal(unit)) {
           // NOTE: |unit| may be EOF here.
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_OCTAL_DIGITS);
           return badToken();
         }
 
         // one past the '0o'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        if (!matchInteger(IsAsciiOctal, &unit)) {
+        if (!matchIntegerAfterFirstDigit(IsAsciiOctal, &unit)) {
           return badToken();
         }
       } else if (IsAsciiDigit(unit)) {
         // Octal integer literals are not permitted in strict mode code.
         if (!strictModeError(JSMSG_DEPRECATED_OCTAL)) {
           return badToken();
         }
 
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -2517,16 +2517,18 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     }
   }
 
   MOZ_MUST_USE bool putIdentInCharBuffer(const Unit* identStart);
 
   using IsIntegerUnit = bool (*)(int32_t);
   MOZ_MUST_USE MOZ_ALWAYS_INLINE bool matchInteger(IsIntegerUnit isIntegerUnit,
                                                    int32_t* nextUnit);
+  MOZ_MUST_USE MOZ_ALWAYS_INLINE bool matchIntegerAfterFirstDigit(
+      IsIntegerUnit isIntegerUnit, int32_t* nextUnit);
 
   /**
    * Tokenize a decimal number that begins at |numStart| into the provided
    * token.
    *
    * |unit| must be one of these values:
    *
    *   1. The first decimal digit in the integral part of a decimal number
--- a/js/src/tests/non262/Number/numericSeparator.js
+++ b/js/src/tests/non262/Number/numericSeparator.js
@@ -1,9 +1,10 @@
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
 assertThrowsInstanceOf(function() { eval('let a = 100_00_;'); }, SyntaxError);
 assertThrowsInstanceOf(() => eval("let b = 10__;"), SyntaxError);
+assertThrowsInstanceOf(() => eval("let b = 1._2;"), SyntaxError);
 
 if (typeof reportCompare === "function")
   reportCompare(true, true);