These compare overloads throw when the pos index is out of range, not
only when the const T& parameter throws on conversion to string_view.

Remove the incorrect conditional noexcept-specifier from the two
overloads that can throw.

libstdc++-v3/ChangeLog:

        PR libstdc++/123991
        * include/bits/basic_string.h (compare(size_type, size_type, T)):
        Remove noexcept-specifier.
        (compare(size_type, size_type, T, size_type, size_type)):
        Likewise.
        * include/bits/cow_string.h (compare(size_type, size_type, T)):
        Remove noexcept-specifier.
        (compare(size_type, size_type, T, size_type, size_type)):
        Likewise.
        * testsuite/21_strings/basic_string/operations/compare/char/123991.cc:
        New test.
        * 
testsuite/21_strings/basic_string/operations/compare/wchar_t/123991.cc:
        New test.
---

Tested x86_64-linux.

This is a regression, so backports are needed to all branches.

 libstdc++-v3/include/bits/basic_string.h      |  2 -
 libstdc++-v3/include/bits/cow_string.h        |  2 -
 .../operations/compare/char/123991.cc         | 56 +++++++++++++++++++
 .../operations/compare/wchar_t/123991.cc      | 56 +++++++++++++++++++
 4 files changed, 112 insertions(+), 4 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/char/123991.cc
 create mode 100644 
libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/wchar_t/123991.cc

diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index 0602b0dcac88..cd6f312f1bd2 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -3524,7 +3524,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
        _If_sv<_Tp, int>
        compare(size_type __pos, size_type __n, const _Tp& __svt) const
-       noexcept(is_same<_Tp, __sv_type>::value)
        {
          __sv_type __sv = __svt;
          return __sv_type(*this).substr(__pos, __n).compare(__sv);
@@ -3545,7 +3544,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        _If_sv<_Tp, int>
        compare(size_type __pos1, size_type __n1, const _Tp& __svt,
                size_type __pos2, size_type __n2 = npos) const
-       noexcept(is_same<_Tp, __sv_type>::value)
        {
          __sv_type __sv = __svt;
          return __sv_type(*this)
diff --git a/libstdc++-v3/include/bits/cow_string.h 
b/libstdc++-v3/include/bits/cow_string.h
index 36c19fabfc5b..6cf002243729 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -2998,7 +2998,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Tp>
        _If_sv<_Tp, int>
        compare(size_type __pos, size_type __n, const _Tp& __svt) const
-       noexcept(is_same<_Tp, __sv_type>::value)
        {
          __sv_type __sv = __svt;
          return __sv_type(*this).substr(__pos, __n).compare(__sv);
@@ -3018,7 +3017,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _If_sv<_Tp, int>
        compare(size_type __pos1, size_type __n1, const _Tp& __svt,
                size_type __pos2, size_type __n2 = npos) const
-       noexcept(is_same<_Tp, __sv_type>::value)
        {
          __sv_type __sv = __svt;
          return __sv_type(*this)
diff --git 
a/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/char/123991.cc
 
b/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/char/123991.cc
new file mode 100644
index 000000000000..53ef2d4606c6
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/char/123991.cc
@@ -0,0 +1,56 @@
+// { dg-do run { target c++17 } }
+
+// Bug 123991 - std::string::compare crashes instead of throwing
+
+#include <string>
+#include <string_view>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+void
+test_compare_3arg()
+{
+  std::string_view sv;
+  std::string s;
+  static_assert( ! noexcept(s.compare(0, 0, sv)) );
+#ifdef __cpp_exceptions
+  try
+  {
+    (void) s.compare(1, 0, sv);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+#endif
+}
+
+void
+test_compare_5arg()
+{
+  std::string_view sv;
+  std::string s;
+  static_assert( ! noexcept(s.compare(0, 0, sv, 0, 0)) );
+#ifdef __cpp_exceptions
+  try
+  {
+    (void) s.compare(1, 0, sv, 0, 0);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+
+  try
+  {
+    (void) s.compare(0, 0, sv, 1, 0);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+#endif
+}
+
+int main()
+{
+  test_compare_3arg();
+  test_compare_5arg();
+}
diff --git 
a/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/wchar_t/123991.cc
 
b/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/wchar_t/123991.cc
new file mode 100644
index 000000000000..c4188bbff8b2
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/21_strings/basic_string/operations/compare/wchar_t/123991.cc
@@ -0,0 +1,56 @@
+// { dg-do run { target c++17 } }
+
+// Bug 123991 - std::string::compare crashes instead of throwing
+
+#include <string>
+#include <string_view>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+void
+test_compare_3arg()
+{
+  std::wstring_view sv;
+  std::wstring s;
+  static_assert( ! noexcept(s.compare(0, 0, sv)) );
+#ifdef __cpp_exceptions
+  try
+  {
+    (void) s.compare(1, 0, sv);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+#endif
+}
+
+void
+test_compare_5arg()
+{
+  std::wstring_view sv;
+  std::wstring s;
+  static_assert( ! noexcept(s.compare(0, 0, sv, 0, 0)) );
+#ifdef __cpp_exceptions
+  try
+  {
+    (void) s.compare(1, 0, sv, 0, 0);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+
+  try
+  {
+    (void) s.compare(0, 0, sv, 1, 0);
+    VERIFY(false);
+  }
+  catch (const std::out_of_range&)
+  { }
+#endif
+}
+
+int main()
+{
+  test_compare_3arg();
+  test_compare_5arg();
+}
-- 
2.52.0

Reply via email to