Skip to content
Snippets Groups Projects
Commit c62e9454 authored by Jonathan Wakely's avatar Jonathan Wakely
Browse files

libstdc++: Enforce value_type consistency in strings and streams

P1463R1 made it ill-formed for allocator-aware containers (including
std::basic_string) to use an allocator that has a different value_type
from the container itself. We already enforce that for other containers
(since r8-4828-g866e4d3853ccc0), but not for std::basic_string. We
traditionally accepted it as an extension and rebound the allocator, so
this change only adds the enforcement for C++20 and later.

Similarly, P1148R0 made it ill-formed for strings and streams to use a
traits type that has an incorrect char_type. We already enforce that for
std::basic_string_view, so we just need to add it to std::basic_ios and
std::basic_string.

The assertion for the allocator's value_type caused some testsuite
regressions:
FAIL: 21_strings/basic_string/cons/char/deduction.cc (test for excess errors)
FAIL: 21_strings/basic_string/cons/wchar_t/deduction.cc (test for excess errors)
FAIL: 21_strings/basic_string/requirements/explicit_instantiation/debug.cc (test for excess errors)
FAIL: 21_strings/basic_string/requirements/explicit_instantiation/int.cc (test for excess errors)

The last two are testing the traditional extension that rebinds the
allocator, so need to be disabled for C++20.

The first two are similar to LWG 3076 where an incorrect constructor is
considered for CTAD. In this case, determining that it's not viable
requires instantiating std::basic_string<Iter, char_traits<Iter>, Alloc>
which then fails the new assertion, because Alloc::value_type is not the
same as Iter. This is only a problem because the size_type parameter of
the non-viable constructor is an alias for
_Alloc_traits_impl<A>::size_type which is a nested type, and so the
enclosing basic_string specialization needs to be instantiated. If we
remove the _Alloc_traits_impl wrapper that was added in
r12-5413-g2d76292bd6719d, then the definition of size_type no longer
depends on basic_string, and we don't instantiate an invalid
specialization and don't fail the assertion. The work done by
_Alloc_traits_impl::allocate can be done in a _S_allocate function
instead, which is probably more efficient to compile anyway.

libstdc++-v3/ChangeLog:

	* config/abi/pre/gnu.ver: Export basic_string::_S_allocate.
	* include/bits/basic_ios.h: Add static assertion checking
	traits_type::value_type.
	* include/bits/basic_string.h: Likewise. Do not rebind
	allocator, and add static assertion checking its value_type.
	(basic_string::_Alloc_traits_impl): Remove class template.
	(basic_string::_S_allocate): New static member function.
	(basic_string::assign): Use _S_allocate.
	* include/bits/basic_string.tcc (basic_string::_M_create)
	(basic_string::reserve, basic_string::_M_replace): Likewise.
	* testsuite/21_strings/basic_string/requirements/explicit_instantiation/debug.cc:
	Disable for C++20 and later.
	* testsuite/21_strings/basic_string/requirements/explicit_instantiation/int.cc:
	Likweise.
parent c4638cc4
No related branches found
No related tags found
No related merge requests found
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment