Skip to content

[libc++] Fix regex_search to match $ alone with match_default flag #78845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2024

Conversation

SanjayMarreddi
Copy link
Contributor

Using regex_search with the regex_constant match_default and a simple regex pattern $ is expected to match general strings such as "a", "ab", "abc"... at [last, last) positions. But, the current implementation fails to do so.

Fixes #75042

@SanjayMarreddi SanjayMarreddi requested a review from a team as a code owner January 20, 2024 13:09
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jan 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 20, 2024

@llvm/pr-subscribers-libcxx

Author: Sanjay Marreddi (SanjayMarreddi)

Changes

Using regex_search with the regex_constant match_default and a simple regex pattern $ is expected to match general strings such as "a", "ab", "abc"... at [last, last) positions. But, the current implementation fails to do so.

Fixes #75042


Full diff: https://github.com/llvm/llvm-project/pull/78845.diff

2 Files Affected:

  • (modified) libcxx/include/regex (+8)
  • (modified) libcxx/test/std/re/re.const/re.matchflag/match_not_eol.pass.cpp (+28)
diff --git a/libcxx/include/regex b/libcxx/include/regex
index b575a267583b5f..48af5b8b57fd64 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -5124,6 +5124,14 @@ bool basic_regex<_CharT, _Traits>::__search(
       }
       __m.__matches_.assign(__m.size(), __m.__unmatched_);
     }
+    __m.__matches_.assign(__m.size(), __m.__unmatched_);
+    if (__match_at_start(__first, __last, __m, __flags, false)) {
+      __m.__prefix_.second  = __m[0].first;
+      __m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
+      __m.__suffix_.first   = __m[0].second;
+      __m.__suffix_.matched = __m.__suffix_.first != __m.__suffix_.second;
+      return true;
+    }
   }
   __m.__matches_.clear();
   return false;
diff --git a/libcxx/test/std/re/re.const/re.matchflag/match_not_eol.pass.cpp b/libcxx/test/std/re/re.const/re.matchflag/match_not_eol.pass.cpp
index edeea517d2537a..a696d815dda5a8 100644
--- a/libcxx/test/std/re/re.const/re.matchflag/match_not_eol.pass.cpp
+++ b/libcxx/test/std/re/re.const/re.matchflag/match_not_eol.pass.cpp
@@ -47,5 +47,33 @@ int main(int, char**)
     assert( std::regex_search(target, re, std::regex_constants::match_not_eol));
     }
 
+    {
+      std::string target = "foo";
+      std::regex re("$");
+      assert(std::regex_search(target, re));
+      assert(!std::regex_search(target, re, std::regex_constants::match_not_eol));
+
+      std::smatch match;
+      assert(std::regex_search(target, match, re));
+      assert(match.position(0) == 3);
+      assert(match.length(0) == 0);
+      assert(!std::regex_search(target, match, re, std::regex_constants::match_not_eol));
+      assert(match.length(0) == 0);
+    }
+
+    {
+      std::string target = "foo";
+      std::regex re("$");
+      assert(!std::regex_match(target, re));
+      assert(!std::regex_match(target, re, std::regex_constants::match_not_eol));
+    }
+
+    {
+      std::string target = "a";
+      std::regex re{"^b*$"};
+      assert(!std::regex_search(target, re));
+      assert(!std::regex_search(target, re, std::regex_constants::match_not_eol));
+    }
+
   return 0;
 }

@SanjayMarreddi
Copy link
Contributor Author

SanjayMarreddi commented Jan 20, 2024

  • I can see that std/re/re.const/re.matchflag/match_not_eol.pass.cpp is failing in generic-cxx03.
  • However locally, when I ran the tests using sudo libcxx/utils/libcxx-lit build/ -sv libcxx/test/std/re/re.const, the test passed.
  • How do I replicate the above behaviour locally to fix the failing tests on CI? Thanks!


{
std::string target = "a";
std::regex re{"^b*$"};
Copy link
Contributor

@H-G-Hristov H-G-Hristov Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::regex re{"^b*$"};
std::regex re("^b*$");

Did you test in C++03 mode?

https://libcxx.llvm.org/TestingLibcxx.html#usage

sudo libcxx/utils/libcxx-lit build/ -sv libcxx/test/std/re/re.const --param=c++03

It is interesting, this test doesn't have // UNSUPPORTED: c++03. Regex is a C++11 feature. Maybe it is supported as an extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Updated the test.
  • Yeah, I tested in the C++03 mode using the above command specifying the param. The tests are passing locally.

@SanjayMarreddi SanjayMarreddi force-pushed the fix_regex_search branch 2 times, most recently from b8e8e5f to 717b118 Compare January 20, 2024 17:25
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM -- I checked and this should fix all reported regressions around this.

@ldionne ldionne merged commit d83a3ea into llvm:main Jan 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc++] std::regex $ alone with match_default doesn't match [last, last)
4 participants