Fix regex bug with ^\W. Thanks to Tim Shen for the patch. Reviewed as https://reviews.llvm.org/D37955

llvm-svn: 316095
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 77623cb511968bf5741f861b10a447f38ee843a6
diff --git a/include/regex b/include/regex
index dfc97c5..bd72012 100644
--- a/include/regex
+++ b/include/regex
@@ -2409,17 +2409,28 @@
                 goto __exit;
             }
         }
-        if (!__neg_chars_.empty())
+        // set of "__found" chars =
+        //   union(complement(union(__neg_chars_, __neg_mask_)),
+        //         other cases...)
+        //
+        // __neg_chars_ and __neg_mask_'d better be handled together, as there
+        // are no short circuit opportunities.
+        //
+        // In addition, when __neg_mask_/__neg_chars_ is empty, they should be
+        // treated as all ones/all chars.
         {
-            for (size_t __i = 0; __i < __neg_chars_.size(); ++__i)
-            {
-                if (__ch == __neg_chars_[__i])
-                    goto __is_neg_char;
-            }
+          const bool __in_neg_mask = (__neg_mask_ == 0) ||
+              __traits_.isctype(__ch, __neg_mask_);
+          const bool __in_neg_chars =
+              __neg_chars_.empty() ||
+              std::find(__neg_chars_.begin(), __neg_chars_.end(), __ch) !=
+              __neg_chars_.end();
+          if (!(__in_neg_mask || __in_neg_chars))
+          {
             __found = true;
             goto __exit;
+          }
         }
-__is_neg_char:
         if (!__ranges_.empty())
         {
             string_type __s2 = __collate_ ?
@@ -2451,11 +2462,6 @@
             __found = true;
             goto __exit;
         }
-        if (__neg_mask_ && !__traits_.isctype(__ch, __neg_mask_))
-        {
-            __found = true;
-            goto __exit;
-        }
     }
     else
         __found = __negate_;  // force reject