I didn't realized that we can actually escape a dash inside bracket
expression: R"([\-])", in which case the dash should be treated
literally.

Tell me if you feel like we need more documentations. :P

Bootstrapped and tested on x86_64-linux-gnu.

Thanks!

-- 
Regards,
Tim Shen
commit 404a69b17f7fddc9856e9664e304f122601f212f
Author: Tim Shen <tims...@google.com>
Date:   Wed Aug 24 00:06:54 2016 -0700

    2016-08-25  Tim Shen  <tims...@google.com>
    
            PR libstdc++/77356
            * include/bits/regex_compiler.tcc(_M_insert_bracket_matcher,
            _M_expression_term): Modify to support dash literal.
            * include/bits/regex_scanner.h: Add dash as a token type to make
            a different from the mandated dash literal by escaping.
            * include/bits/regex_scanner.tcc(_M_scan_in_bracket): Emit dash
            token in bracket expression parsing.
            * testsuite/28_regex/regression.cc: Add new testcase.

diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc 
b/libstdc++-v3/include/bits/regex_compiler.tcc
index ff69e16..3ffa170 100644
--- a/libstdc++-v3/include/bits/regex_compiler.tcc
+++ b/libstdc++-v3/include/bits/regex_compiler.tcc
@@ -426,13 +426,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       pair<bool, _CharT> __last_char; // Optional<_CharT>
       __last_char.first = false;
       if (!(_M_flags & regex_constants::ECMAScript))
-       if (_M_try_char())
-         {
-           __matcher._M_add_char(_M_value[0]);
-           __last_char.first = true;
-           __last_char.second = _M_value[0];
-         }
+       {
+         if (_M_try_char())
+           {
+             __last_char.first = true;
+             __last_char.second = _M_value[0];
+           }
+         else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
+           {
+             __last_char.first = true;
+             __last_char.second = '-';
+           }
+       }
       while (_M_expression_term(__last_char, __matcher));
+      if (__last_char.first)
+       __matcher._M_add_char(__last_char.second);
       __matcher._M_ready();
       _M_stack.push(_StateSeqT(
                      *_M_nfa,
@@ -449,19 +457,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (_M_match_token(_ScannerT::_S_token_bracket_end))
        return false;
 
+      const auto __push_char = [&](_CharT __ch)
+      {
+       if (__last_char.first)
+         __matcher._M_add_char(__last_char.second);
+       else
+         __last_char.first = true;
+       __last_char.second = __ch;
+      };
+
       if (_M_match_token(_ScannerT::_S_token_collsymbol))
        {
          auto __symbol = __matcher._M_add_collate_element(_M_value);
          if (__symbol.size() == 1)
-           {
-             __last_char.first = true;
-             __last_char.second = __symbol[0];
-           }
+           __push_char(__symbol[0]);
+         else
+           __last_char.first = false;
        }
       else if (_M_match_token(_ScannerT::_S_token_equiv_class_name))
-       __matcher._M_add_equivalence_class(_M_value);
+       {
+         __last_char.first = false;
+         __matcher._M_add_equivalence_class(_M_value);
+       }
       else if (_M_match_token(_ScannerT::_S_token_char_class_name))
-       __matcher._M_add_character_class(_M_value, false);
+       {
+         __last_char.first = false;
+         __matcher._M_add_character_class(_M_value, false);
+       }
+      else if (_M_try_char())
+       __push_char(_M_value[0]);
       // POSIX doesn't allow '-' as a start-range char (say [a-z--0]),
       // except when the '-' is the first or last character in the bracket
       // expression ([--0]). ECMAScript treats all '-' after a range as a
@@ -472,55 +496,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Clang (3.5) always uses ECMAScript style even in its POSIX syntax.
       //
       // It turns out that no one reads BNFs ;)
-      else if (_M_try_char())
+      else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
        {
          if (!__last_char.first)
            {
-             __matcher._M_add_char(_M_value[0]);
-             if (_M_value[0] == '-'
-                 && !(_M_flags & regex_constants::ECMAScript))
+             if (!(_M_flags & regex_constants::ECMAScript))
                {
                  if (_M_match_token(_ScannerT::_S_token_bracket_end))
-                   return false;
+                   {
+                     __push_char('-');
+                     return false;
+                   }
                  __throw_regex_error(
                    regex_constants::error_range,
                    "Unexpected dash in bracket expression. For POSIX syntax, "
                    "a dash is not treated literally only when it is at "
                    "beginning or end.");
                }
-             __last_char.first = true;
-             __last_char.second = _M_value[0];
+             __push_char('-');
            }
          else
            {
-             if (_M_value[0] == '-')
+             if (_M_try_char())
                {
-                 if (_M_try_char())
-                   {
-                     __matcher._M_make_range(__last_char.second , _M_value[0]);
-                     __last_char.first = false;
-                   }
-                 else
-                   {
-                     if (_M_scanner._M_get_token()
-                         != _ScannerT::_S_token_bracket_end)
-                       __throw_regex_error(
-                         regex_constants::error_range,
-                         "Unexpected end of bracket expression.");
-                     __matcher._M_add_char(_M_value[0]);
-                   }
+                 __matcher._M_make_range(__last_char.second, _M_value[0]);
+                 __last_char.first = false;
+               }
+             else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
+               {
+                 __matcher._M_make_range(__last_char.second, '-');
+                 __last_char.first = false;
                }
              else
                {
-                 __matcher._M_add_char(_M_value[0]);
-                 __last_char.second = _M_value[0];
+                 if (_M_scanner._M_get_token()
+                     != _ScannerT::_S_token_bracket_end)
+                   __throw_regex_error(
+                     regex_constants::error_range,
+                     "Character is expected after a dash.");
+                 __push_char(_M_value[0]);
                }
            }
        }
       else if (_M_match_token(_ScannerT::_S_token_quoted_class))
-       __matcher._M_add_character_class(_M_value,
-                                        _M_ctype.is(_CtypeT::upper,
-                                                    _M_value[0]));
+       {
+         __last_char.first = false;
+         __matcher._M_add_character_class(_M_value,
+                                          _M_ctype.is(_CtypeT::upper,
+                                                      _M_value[0]));
+       }
       else
        __throw_regex_error(regex_constants::error_brack,
                            "Unexpected character in bracket expression.");
diff --git a/libstdc++-v3/include/bits/regex_scanner.h 
b/libstdc++-v3/include/bits/regex_scanner.h
index 37dea84..2a83d1c 100644
--- a/libstdc++-v3/include/bits/regex_scanner.h
+++ b/libstdc++-v3/include/bits/regex_scanner.h
@@ -73,6 +73,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _S_token_comma,
       _S_token_dup_count,
       _S_token_eof,
+      _S_token_bracket_dash,
       _S_token_unknown
     };
 
diff --git a/libstdc++-v3/include/bits/regex_scanner.tcc 
b/libstdc++-v3/include/bits/regex_scanner.tcc
index fedba09..a734bb1 100644
--- a/libstdc++-v3/include/bits/regex_scanner.tcc
+++ b/libstdc++-v3/include/bits/regex_scanner.tcc
@@ -210,7 +210,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       auto __c = *_M_current++;
 
-      if (__c == '[')
+      if (__c == '-')
+       _M_token = _S_token_bracket_dash;
+      else if (__c == '[')
        {
          if (_M_current == _M_end)
            __throw_regex_error(regex_constants::error_brack,
diff --git a/libstdc++-v3/testsuite/28_regex/regression.cc 
b/libstdc++-v3/testsuite/28_regex/regression.cc
index d367c8b..0896a74 100644
--- a/libstdc++-v3/testsuite/28_regex/regression.cc
+++ b/libstdc++-v3/testsuite/28_regex/regression.cc
@@ -61,12 +61,23 @@ test03()
   VERIFY(!regex_search_debug("a", regex(R"(\b$)"), 
regex_constants::match_not_eow));
 }
 
+// PR libstdc++/77356
+void
+test04()
+{
+  bool test __attribute__((unused)) = true;
+  static const char* kNumericAnchor ="(\\$|usd)(usd|\\$|to|and|up 
to|[0-9,\\.\\-\\sk])+";
+  const std::regex re(kNumericAnchor);
+  (void)re;
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
   return 0;
 }
 

Reply via email to