Commit Graph

14 Commits

Author SHA1 Message Date
Jonathan Wakely
fe3ed885cd libstdc++: Limit new basic_string(nullptr_t) constructor to C++23 [PR104099]
The new deleted constructors added by P2166R1 are a breaking change,
making previously valid code ill-formed in C++23. As a result, they
should only be defined for C++23 and not for C++11 and up.

libstdc++-v3/ChangeLog:

	PR libstdc++/104099
	* include/bits/basic_string.h (basic_string(nullptr_t)): Only
	define for C++23.
	(operator=(nullptr_t)): Likewise.
	* include/bits/cow_string.h: Likewise.
	* include/std/string_view (basic_string_view(nullptr_t)):
	Likewise.
	* testsuite/21_strings/basic_string/cons/char/nullptr.cc: Adjust
	expected error. Add examples that become ill-formed in C++23.
	* testsuite/21_strings/basic_string_view/cons/char/nonnull.cc:
	Adjust expected errors.
	* testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc:
	Likewise.
2022-01-18 20:41:46 +00:00
Jonathan Wakely
6aa0859afa libstdc++: Fix overconstrained std::string constructor [PR103919]
The C++17 basic_string(const T&, size_t, size_t) constructor is
overconstrained, so it can't be used for a NTBS and a temporary string
gets constructed (potentially allocating memory). There is no
corresponding constructor taking an NTBS, so no need to disambiguate
from it. Accepting an NTBS avoids the temporary (and potential
allocation) and is what the standard requires.

libstdc++-v3/ChangeLog:

	PR libstdc++/103919
	* include/bits/basic_string.h (basic_string(const T&, size_t, size_t)):
	Relax constraints on string_view parameter.
	* include/bits/cow_string.h (basic_string(const T&, size_t, size_t)):
	Likewise.
	* testsuite/21_strings/basic_string/cons/char/103919.cc: New test.
2022-01-05 15:31:04 +00:00
Jakub Jelinek
7adcbafe45 Update copyright years. 2022-01-03 10:42:10 +01:00
Jonathan Wakely
fb9875ebf1 libstdc++: Do not leak empty COW strings
When non-const references, pointers or iterators are obtained to the
contents of a COW std::basic_string, the implementation has to assume it
could result in a write to the contents. If the string was previously
shared, it does the "copy-on-write" step of creating a new copy of the
data that is not shared by another object.  It also marks the string as
"leaked", so that no future copies of it will share ownership either.

However, if the string is empty then the only character in the sequence
is the terminating null, and modifying that is undefined behaviour. This
means that non-const references/pointers/iterators to an empty string
are effectively const. Since no direct modification is possible, there
is no need to "leak" the string, it can be safely shared with other
objects. This avoids unnecessary allocations to create new copies of
empty strings that can't be modified anyway.

We already did this optimization for strings that share ownership of the
static _S_empty_rep() object, but not for strings that have non-zero
capacity, and not for fully-dynamic-strings (where the _S_empty_rep()
object is never used).

With this change we avoid two allocations in the return statement:

  std::string s;
  s.reserve(1);       // allocate
  std::string s2 = s;
  std::string s3 = s;
  return s[0] + s2[0] + s3[0]; // leak+allocate twice

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h (basic_string::_M_leak_hard): Do not
	reallocate an empty string.
2021-12-09 22:51:06 +00:00
Jonathan Wakely
b5a568683f libstdc++: Restore unconditional atomic load in COW std::string
The relaxed load is already optimal, checking the __single_threaded
global before doing a non-atomic load isn't an optimization.

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h (basic_string::_M_is_leaked()):
	Revert change to check __is_single_threaded() before using
	atomic load.
2021-12-02 16:46:28 +00:00
Jonathan Wakely
74d14778e7 libstdc++: Define std::__is_constant_evaluated() for internal use
This adds std::__is_constant_evaluated() as a C++11 wrapper for
__builtin_is_constant_evaluated, but just returning false if the
built-in isn't supported by the compiler. This allows us to use it
throughout the library without checking __has_builtin every time.

Some uses in std::vector and std::string can only be constexpr when the
std::is_constant_evaluated() function actually works, so we might as
well guard them with a relevant macro and call that function directly,
rather than the built-in or std::__is_constant_evaluated().

The remaining checks of the __cpp_lib_is_constant_evaluated macro could
now be replaced by checking __cplusplus >= 202002 instead, but there's
no practical difference. We still need some kind of preprocessor check
there anyway.

libstdc++-v3/ChangeLog:

	* doc/doxygen/user.cfg.in (PREDEFINED): Change macro name.
	* include/bits/allocator.h (allocate, deallocate): Use
	std::__is_constant_evaluated() unconditionally, instead of
	checking whether std::is_constant_evaluated() (or the built-in)
	can be used.
	* include/bits/basic_string.h: Check new macro. call
	std::is_constant_evaluated() directly in C++20-only code that is
	guarded by a suitable macro.
	* include/bits/basic_string.tcc: Likewise.
	* include/bits/c++config (__is_constant_evaluated): Define.
	(_GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED): Replace with ...
	(_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED): New macro.
	* include/bits/char_traits.h (char_traits): Replace conditional
	calls to std::is_constant_evaluated with unconditional calls to
	std::__is_constant_evaluated.
	* include/bits/cow_string.h: Use new macro.
	* include/bits/ranges_algobase.h (__copy_or_move): Replace
	conditional calls to std::is_constant_evaluated with unconditional
	calls to std::__is_constant_evaluated.
	(__copy_or_move_backward, __fill_n_fn): Likewise.
	* include/bits/ranges_cmp.h (ranges::less): Likewise.
	* include/bits/stl_algobase.h (lexicographical_compare_three_way):
	Likewise.
	* include/bits/stl_bvector.h: Call std::is_constant_evaluated
	directly in C++20-only code that is guarded by a suitable macro.
	* include/bits/stl_construct.h (_Construct, _Destroy, _Destroy_n):
	Replace is_constant_evaluated with __is_constant_evaluated.
	* include/bits/stl_function.h (greater, less, greater_equal)
	(less_equal): Replace __builtin_is_constant_evaluated and
	__builtin_constant_p with __is_constant_evaluated.
	* include/bits/stl_vector.h: Call std::is_constant_evaluated()
	in C++20-only code.
	* include/debug/helper_functions.h (__check_singular): Use
	__is_constant_evaluated instead of built-in, or remove check
	entirely.
	* include/std/array (operator<=>): Use __is_constant_evaluated
	unconditionally.
	* include/std/bit (__bit_ceil): Likewise.
	* include/std/type_traits (is_constant_evaluated): Define using
	'if consteval' if possible.
	* include/std/version: Use new macro.
	* libsupc++/compare: Use __is_constant_evaluated instead of
	__builtin_is_constant_evaluated.
	* testsuite/23_containers/array/tuple_interface/get_neg.cc:
	Adjust dg-error lines.
2021-12-01 15:00:33 +00:00
Jonathan Wakely
2b83bc6097 libstdc++: Optimize ref-count updates in COW std::string
Most ref-count updates in the COW string are done via the functions in
<ext/atomicity.h>, which will use non-atomic ops when the program is
known to be single-threaded. The _M_is_leaked() and _M_is_shared()
functions use __atomic_load_n directly, because <ext/atomicity.h>
doesn't provide a load operation. Those functions can check the
__is_single_threaded() predicate to avoid using __atomic_load_n when not
needed.

The move constructor for the fully-dynamic-string increments the
ref-count by either 2 or 1, for leaked or non-leaked strings
respectively. That can be changed to use a non-atomic store of 1 for all
non-shared strings. It can be non-atomic because even if the program is
multi-threaded, conflicting access to the rvalue object while it's being
moved from would be data race anyway. It can store 1 directly for all
non-shared strings because it doesn't matter whether the initial
refcount was -1 or 0, it should be 1 after the move constructor creates
a second owner.

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h (basic_string::_M_is_leaked): Use
	non-atomic load when __is_single_threaded() is true.
	(basic_string::_M_is_shared): Likewise.
	(basic_string::(basic_string&&)) [_GLIBCXX_FULLY_DYNAMIC_STRING]:
	Use non-atomic store when rvalue is not shared.
2021-12-01 15:00:33 +00:00
Jonathan Wakely
675afa2124 libstdc++: Fix fully-dynamic-string build
My last change to the fully-dynamic-string actually broke it. This fixes
the move constructor so it builds, and simplifies it slightly so that
more code is common between the fully-dynamic enabled/disabled cases.

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h (basic_string(basic_string&&)): Fix
	mem-initializer for _GLIBCXX_FULLY_DYNAMIC_STRING==0 case.
	* testsuite/21_strings/basic_string/cons/char/noexcept_move_construct.cc:
	Remove outdated comment.
	* testsuite/21_strings/basic_string/cons/wchar_t/noexcept_move_construct.cc:
	Likewise.
2021-11-30 23:10:03 +00:00
Michael de Lang
b96e2ff9d8 libstdc++: Implement constexpr std::basic_string for C++20
This is only supported for the cxx11 ABI, not for COW strings.

libstdc++-v3/ChangeLog:

	* include/bits/basic_string.h (basic_string, operator""s): Add
	constexpr for C++20.
	(basic_string::basic_string(basic_string&&)): Only copy
	initialized portion of the buffer.
	(basic_string::basic_string(basic_string&&, const Alloc&)):
	Likewise.
	* include/bits/basic_string.tcc (basic_string): Add constexpr
	for C++20.
	(basic_string::swap(basic_string&)): Only copy initialized
	portions of the buffers.
	(basic_string::_M_replace): Add constexpr implementation that
	doesn't depend on pointer comparisons.
	* include/bits/cow_string.h: Adjust comment.
	* include/ext/type_traits.h (__is_null_pointer): Add constexpr.
	* include/std/string (erase, erase_if): Add constexpr.
	* include/std/version (__cpp_lib_constexpr_string): Update
	value.
	* testsuite/21_strings/basic_string/cons/char/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/literals/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/modifiers/constexpr.cc: New test.
	* testsuite/21_strings/basic_string/modifiers/swap/char/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/modifiers/swap/wchar_t/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/version.cc: New test.
2021-11-16 16:43:20 +00:00
Jonathan Wakely
cf876562c5 libstdc++: Disable std::string{,_view} construction from nullptr (P2166R1)
Implement this C++23 feature. Because construction from a null pointer
is undefined, we can implement it for C++11 and up, turning undefined
behaviour into a compilation error.

libstdc++-v3/ChangeLog:

	* include/bits/basic_string.h (basic_string(nullptr_t)): Define
	as deleted.
	(operator=(nullptr_t)): Likewise.
	* include/bits/cow_string.h (basic_string(nullptr_t)): Likewise.
	(operator=(nullptr_t)): Likewise.
	* include/std/string_view (basic_string_view(nullptr_t)):
	Likewise.
	* testsuite/21_strings/basic_string/cons/char/nullptr.cc: New test.
	* testsuite/21_strings/basic_string_view/cons/char/nonnull.cc:
	Change dg-warning to dg-error.
	* testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc:
	Likewise.
2021-10-04 15:23:28 +01:00
Jonathan Wakely
10b6d89bad libstdc++: Make move ctor noexcept for fully-dynamic string
The move constructor for the "fully-dynamic" COW string is not noexcept,
because it allocates a new empty string rep for the moved-from string.
However, there is no need to do that, because the moved-from string does
not have to be left empty. Instead, implement move construction for the
fully-dynamic case as a reference count increment, so the string is
shared.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h [_GLIBCXX_FULLY_DYNAMIC_STRING]
	(basic_string(basic_string&&)): Add noexcept and avoid
	allocation, by sharing rep with the rvalue string.
2021-10-01 20:34:47 +01:00
Jonathan Wakely
3b3f2f7c26 libstdc++: Only define basic_string::contains for C++23
The new contains member of the COW string is defined for non-strict
gnu++20 mode as well as for C++23 modes. I think that was left in the
committed patch unintentionally. It is inconsistent with the SSO string,
and doesn't actually compile because it uses the
basic_string_view::contains member which only defined for C++23.

This makes it only defined for C++23.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h (basic_string::contains): Do not
	define for -std=gnu++20.
2021-08-17 14:22:50 +01:00
Jonathan Wakely
7ffba77d01 libstdc++: Adjust whitespace in <bits/cow_string.h>
libstdc++-v3/ChangeLog:

	* include/bits/cow_string.h: Consistently use tab for
	indentation.
2021-07-27 12:13:42 +01:00
Jonathan Wakely
7b527614dd libstdc++: Move COW string definitions to separate header
This moves the definitions of the COW string to a separate file, so that
they don't need to be preprocessed for the common case. We could also
move the SSO string definitions to a new file, so that they don't need
to be preprocessed for the old ABI case, but that would require more
shovel work because there are some parts of <bits/basic_string.h> and
<bits/basic_string.tcc> that are common to both definitions.

libstdc++-v3/ChangeLog:

	* include/Makefile.am: Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/basic_string.h [!_GLIBCXX_USE_CXX11_ABI]
	(basic_string): Move definition of Copy-on-Write string to
	new file.
	* include/bits/basic_string.tcc: Likewise.
	* include/bits/cow_string.h: New file.
2021-07-27 12:04:18 +01:00