[PATCH] Decorate COW string methods with std::_RequireInputIte

François Dumont frs.dumont@gmail.com
Tue Jul 28 17:00:54 GMT 2026


Sorry for previous patch, I was too focus on _GLIBCXX_DEBUG mode and 
tend to forget that template methods can be exported.

Let's try with this less enthusiast version then.

I've split the patch, so the subject change. The small _GLIBCXX_DEBUG 
parts left will come in a future patch, not implying new symbols thought.

For now I think just adding _RequireInputIte and remove in C++11 useless 
methods is fine.

     libstdc++: Decorate COW string methods with std::_RequireInputIte

     Add the std::_RequireInputIter constraints on members taking template
     iterator range to avoid the "do the right thing" ambiguity.

     Thanks to this requirement remove, in post-C++11, associated 
dispatch methods.

     libstdc++v3/ChangeLog:

             * include/bits/cow_string.h
             (basic_string(_InputIterator, _InputIterator, const _Alloc&):
             Add std::_RequireInputIter constraint and
             __glibcxx_requires_valid_constructor_range check.
             (basic_string::append(_InputIte, _InputIte): Add 
std::_RequireInputIter
             constraint.
             (basic_string::assign(_InputIte, _InputIte): Likewise.
             (basic_string::insert(iterator, _InputIte, _InputIte)): 
Likewise.
             (basic_string::replace(iterator, iterator, _InputIte, 
_InputIte)): Likewise.
             [__cplusplus < 201103L](basic_string::_M_replace_dispatch
             (iterator, iterator, _Integer, _Integer, __true_type)): Remove.
             [__cplusplus < 201103L](basic_string::_S_construct_aux): 
Remove.
             [__cplusplus < 201103L](basic_string::_S_construct_aux_2): 
Remove.
             (basic_string::_S_construct): Adapt.

Tested under Linux x86_64 testsuite/21_strings/* C++98 & C++23 including 
abi check.

Ok to commit ?

François


On 7/21/26 13:19, Jonathan Wakely wrote:
> On Tue, 21 Jul 2026 at 07:43, Jonathan Wakely<jwakely@redhat.com> wrote:
>> On Tue, 21 Jul 2026 at 05:57, François Dumont<frs.dumont@gmail.com> wrote:
>>> Here is the new commit message:
>>>
>>>       libstdc++: [_GLIBCXX_DEBUG] Improve COW basic_string checks
>>>
>>>       Put the __glibcxx_requires_valid_range checks at public member level
>>>       so that diagnostics are giving directly the culprit member name.
>>>
>>>       Add thestd::_RequireInputIter constraints on members taking template
>>>       iterator range to avoid the "do the right thing" ambiguity.
>>>
>>>       libstdc++v3/ChangeLog:
>>>
>>>               * include/bits/cow_string.h
>>>               (basic_string::_M_replace): New.
>>>               (basic_string(_InputIterator, _InputIterator, const _Alloc&):
>>>               Addstd::_RequireInputIter constraint and
>>>               __glibcxx_requires_valid_constructor_range check.
>>>               (basic_string::append(_InputIte, _InputIte): Add
>>> std::_RequireInputIter
>>>               constraint and __glibcxx_requires_valid_range check. Call
>>> _M_replace.
>>>               (basic_string::assign(_InputIte, _InputIte): Likewise.
>>>               (basic_string::insert(iterator, _InputIte, _InputIte)):
>>> Likewise.
>>>               (basic_string::replace(iterator, iterator, _InputIte,
>>> _InputIte)): Likewise.
>>>               [__cplusplus >= 201103L](basic_string::_S_construct): New.
>>>               (basic_string::_M_replace_dispatch(iterator, iterator,
>>> _InputIte, _InputIte,
>>>               __false_type)): Remove __glibcxx_requires_valid_range check.
>>>               * include/debug/debug.h
>>> (__glibcxx_requires_valid_constructor_range): New.
>>>
>>> On 7/6/26 22:42, Jonathan Wakely wrote:
>>>> On Mon, 15 Jun 2026 at 07:07 +0200, François Dumont wrote:
>>>>> Hi
>>>>>
>>>>>     libstdc++: [_GLIBCXX_DEBUG] Improve COW basic_string checks
>>>>>
>>>>>      Put the __glibcxx_requires_valid_range checks at public member level
>>>>>      so that diagnostics are giving directly the invoked member name.
>>>>>
>>>>>      Add thestd::_RequireInputIter constraints on members taking
>>>>> template
>>>>>      iterator range to avoid the "do the right thing" ambiguity
>>>>> without the help of __is_integer.
>>>>>
>>>>>      libstdc++v3/ChangeLog:
>>>>>
>>>>>              * include/bits/cow_string.h
>>>>>              (basic_string::_M_replace): New.
>>>>>              (basic_string(_InputIterator, _InputIterator, const
>>>>> _Alloc&): Add
>>>>>              std::_RequireInputIter constraint and
>>>>> __glibcxx_requires_valid_constructor_range
>>>> Please fix the line-wrapping here. Try to keep the lines to < 72
>>>> characters so that when indented by 'git log' they fit below 80.
>>>>
>>>>>              check.
>>>>>              (basic_string::append(_InputIte, _InputIte): Add
>>>>> std::_RequireInputIter
>>>>>              constraint and __glibcxx_requires_valid_range check. Call
>>>>> _M_replace.
>>>>>              (basic_string::assign(_InputIte, _InputIte): Likewise.
>>>>>              (basic_string::insert(iterator, _InputIte, _InputIte)):
>>>>> Likewise.
>>>>>              (basic_string::replace(iterator, iterator, _InputIte,
>>>>> _InputIte)): Likewise.
>>>>>              [__cplusplus >= 201103L](basic_string::_S_construct): New.
>>>>>              (basic_string::_M_replace_dispatch(iterator, iterator,
>>>>> _InputIte, _InputIte,
>>>>>              __false_type)): Remove __glibcxx_requires_valid_range check.
>>>>>              * include/debug/debug.h
>>>>> (__glibcxx_requires_valid_constructor_range): New.
>>>>>
>>>>> Tested under Linux x86_64 with _GLIBCXX_USE_CXX11_ABI=0 and
>>>>> _GLIBCXX_DEBUG.
>>>> Did you test C++98 as well as the default -std modes?
>>> I hadn't but now did, ex:
>>>
>>> In function:
>>>       std::basic_string<_CharT, _Traits, _Alloc>&std::basic_string<_CharT,
>>>       _Traits, _Alloc>::append(_InputIterator, _InputIterator) [with
>>>       _InputIterator = gnu_debug::_Safe_iterator<gnu_cxx::
>>>       normal_iterator<char*,std::vector<char,std::allocator<char> > >,
>>> std::
>>>       debug::vector<char>,std::random_access_iterator_tag>; _CharT = char;
>>>       _Traits =std::char_traits<char>; _Alloc =std::allocator<char>]
>>>
>>> Error: function requires a valid iterator range [first, last).
>>>
>>> Objects involved in the operation:
>>>       iterator "first" @ 0x7ffc9027e5a0 {
>>>         type = gnu_cxx::normal_iterator<char*,std::vector<char,
>>> std::allocator<char> > > (mutable iterator);
>>>         state = dereferenceable;
>>>         references sequence with type 'std::debug::vector<char,
>>> std::allocator<char> >' @ 0x7ffc9027e750
>>>       }
>>>       iterator "last" @ 0x7ffc9027e600 {
>>>         type = gnu_cxx::normal_iterator<char*,std::vector<char,
>>> std::allocator<char> > > (mutable iterator);
>>>         state = dereferenceable;
>>>         references sequence with type 'std::debug::vector<char,
>>> std::allocator<char> >' @ 0x7ffc9027e750
>>>       }
>>> XFAIL: 21_strings/basic_string/debug/append_neg.cc  -std=gnu++98
>>> execution test
>>>
>>>> Doesn't this require new symbols to be exported by the linker script?
>>>>
>>> I don't think so. Maybe you had in mind the
>>> __gnu_debug::__check_valid_range but that's a template function
>>> implemented inline.
>> You've added a new member function, basic_string::_M_replace. Why
>> doesn't that need to be exported from the shared library?
>>
>> Why don't the changes to the signature of basic_string::assign and
>> basic_string::append change the exported symbols?
> As expected, 'make check-abi' fails:
>
> Running /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/libstdc++-abi/abi.exp
> ...
> FAIL: libstdc++-abi/abi_check
>
>                 === libstdc++ Summary ===
>
> # of unexpected failures        1
>
>
>>> Ok to commit ?
> Definitely not.
>
-------------- next part --------------
diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h
index 0f1a2e082d0..a3f9195c098 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -721,7 +721,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @param  __end  End of range.
        *  @param  __a  Allocator to use (default is default allocator).
        */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string(_InputIterator __beg, _InputIterator __end,
 		     const _Alloc& __a = _Alloc())
 	: _M_dataplus(_S_construct(__beg, __end, __a), __a)
@@ -1391,7 +1396,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Appends characters in the range [__first,__last) to this string.
        */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	append(_InputIterator __first, _InputIterator __last)
 	{ return this->replace(_M_iend(), _M_iend(), __first, __last); }
@@ -1551,7 +1561,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Sets value of string to characters in the range [__first,__last).
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	assign(_InputIterator __first, _InputIterator __last)
 	{ return this->replace(_M_ibegin(), _M_iend(), __first, __last); }
@@ -1657,7 +1672,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  length_error is thrown.  The value of the string doesn't
        *  change if an error is thrown.
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	void
 	insert(iterator __p, _InputIterator __beg, _InputIterator __end)
 	{ this->replace(__p, __p, __beg, __end); }
@@ -2143,14 +2163,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  The value of the string doesn't change if an error is
        *  thrown.
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	replace(iterator __i1, iterator __i2,
 		_InputIterator __k1, _InputIterator __k2)
 	{
 	  _GLIBCXX_DEBUG_PEDASSERT(_M_ibegin() <= __i1 && __i1 <= __i2
 				   && __i2 <= _M_iend());
+#if __cplusplus >= 201103L
+	  typedef std::__false_type _Integral;
+#else
 	  typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+#endif
 	  return _M_replace_dispatch(__i1, __i2, __k1, __k2, _Integral());
 	}
 
@@ -2295,11 +2324,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // C++17
 
     private:
+#if __cplusplus < 201103L
       template<class _Integer>
 	basic_string&
 	_M_replace_dispatch(iterator __i1, iterator __i2, _Integer __n,
 			    _Integer __val, __true_type)
 	{ return _M_replace_aux(__i1 - _M_ibegin(), __i2 - __i1, __n, __val); }
+#endif
 
       template<class _InputIterator>
 	basic_string&
@@ -2314,6 +2345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_replace_safe(size_type __pos1, size_type __n1, const _CharT* __s,
 		      size_type __n2);
 
+#if __cplusplus < 201103L
       // _S_construct_aux is used to implement the 21.3.1 para 15 which
       // requires special behaviour if _InIter is an integral type
       template<class _InIterator>
@@ -2337,13 +2369,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static _CharT*
       _S_construct_aux_2(size_type __req, _CharT __c, const _Alloc& __a)
       { return _S_construct(__req, __c, __a); }
+#endif
 
       template<class _InIterator>
 	static _CharT*
 	_S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a)
 	{
+#if __cplusplus < 201103L
 	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
 	  return _S_construct_aux(__beg, __end, __a, _Integral());
+#else
+	  return _S_construct(__beg, __end, __a,
+			      std::__iterator_category(__beg));
+#endif
 	}
 
       // For Input Iterators, used in istreambuf_iterators, etc.


More information about the Libstdc++ mailing list