Hi,
here is updated patch.
I am not ceratin if:
const size_t __diffmax
= __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_CharT);
really needs "/ sizeof (_CharT)". I think we only need to be able to
compute the difference between two entries in multiplies of sizeof(_CharT)?
However it is consistent with what std::vector does. Do we really need
to be also able to represent differences in number of bytes?
I was also thinking about API change implication. I hope that indeed
real code does not need knowing max size and it is mostly needed to let
GCC to VRP optimize the memory allocations.
I also noticed that this patch trigger empty-loop.C failure which I
originaly attributed to different change. I filled PR117764 on that.
We are no longer able to eliminate empty loops early, but we still
optimize them late.
I also changed empty() to do the test directly (as done by std::vector
and friends) instead of computing size. I do not think having
__builtin_unreachable range check is useful there, so this should save
some compile-time effort.
Bootstrapped/regtested x86_64-linux, OK?
libstdc++-v3/ChangeLog:
* include/bits/basic_string.h (basic_string::size(),
basic_string::length(), basic_string::capacity()): Add
__builtin_unreachable to declare value ranges.
(basic_string::empty): Inline test.
(basic_string::max_size()): Account correctly the terminating 0
and limits implied by ptrdiff_t.
gcc/testsuite/ChangeLog:
* g++.dg/tree-ssa/empty-loop.C: xfail optimization at cddce2 and check
it happens at cddce3.
* g++.dg/tree-ssa/string-1.C: New test.
diff --git a/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C
b/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C
index ed4a603bf5b..b7e7e27cc04 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C
@@ -30,5 +30,8 @@ int foo (vector<string> &v, list<string> &l, set<string> &s,
map<int, string> &m
return 0;
}
-/* { dg-final { scan-tree-dump-not "if" "cddce2"} } */
+/* Adding __builtin_unreachable to std::string::size() prevents cddce2 from
+ eliminating the loop early, see PR117764. */
+/* { dg-final { scan-tree-dump-not "if" "cddce2" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-not "if" "cddce3"} } */
diff --git a/gcc/testsuite/g++.dg/tree-ssa/string-1.C
b/gcc/testsuite/g++.dg/tree-ssa/string-1.C
new file mode 100644
index 00000000000..d38c23a7628
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/string-1.C
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c++20 -fdump-tree-optimized" } */
+#include <string>
+std::string
+test (std::string &a)
+{
+ return a;
+}
+/* { dg-final { scan-tree-dump-not "throw" "optimized" } } */
diff --git a/libstdc++-v3/include/bits/basic_string.h
b/libstdc++-v3/include/bits/basic_string.h
index f5b320099b1..17b973c8b45 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1079,20 +1079,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
size_type
size() const _GLIBCXX_NOEXCEPT
- { return _M_string_length; }
+ {
+ size_type __sz = _M_string_length;
+ if (__sz > max_size ())
+ __builtin_unreachable ();
+ return __sz;
+ }
/// Returns the number of characters in the string, not including any
/// null-termination.
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
size_type
length() const _GLIBCXX_NOEXCEPT
- { return _M_string_length; }
+ { return size(); }
/// Returns the size() of the largest possible %string.
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
size_type
max_size() const _GLIBCXX_NOEXCEPT
- { return (_Alloc_traits::max_size(_M_get_allocator()) - 1) / 2; }
+ {
+ const size_t __diffmax
+ = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_CharT);
+ const size_t __allocmax = _Alloc_traits::max_size(_M_get_allocator());
+ return (std::min)(__diffmax, __allocmax) - 1;
+ }
/**
* @brief Resizes the %string to the specified number of characters.
@@ -1184,8 +1194,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
size_type
capacity() const _GLIBCXX_NOEXCEPT
{
- return _M_is_local() ? size_type(_S_local_capacity)
- : _M_allocated_capacity;
+ size_t __sz = _M_is_local() ? size_type(_S_local_capacity)
+ : _M_allocated_capacity;
+ if (__sz < _S_local_capacity || __sz > max_size ())
+ __builtin_unreachable ();
+ return __sz;
}
/**
@@ -1234,7 +1247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
bool
empty() const _GLIBCXX_NOEXCEPT
- { return this->size() == 0; }
+ { return _M_string_length == 0; }
// Element access:
/**