On Fri, 11 Apr 2025 at 12:21, Tomasz Kaminski <tkami...@redhat.com> wrote:
>
>
>
> On Fri, Apr 11, 2025 at 12:52 PM Jonathan Wakely <jwak...@redhat.com> wrote:
>>
>> On 11/04/25 09:49 +0200, Tomasz Kaminski wrote:
>> >On Thu, Apr 10, 2025 at 6:29 PM Jonathan Wakely <jwak...@redhat.com> wrote:
>> >
>> >> For C++11 and later we can remvoe four overloads of _S_copy_chars and
>> >> use constexpr-if in the generic _S_copy_chars. This simplifies overload
>> >> resolution for _S_copy_chars, and also means that we optimize for other
>> >> iterators such as std::vector<char>::iterator.
>> >>
>> >> We still need all the _S_copy_chars overloads to be part of the explicit
>> >> instantiation definition, so make them depend on the macro that is
>> >> defined by src/c++11/string-inst.cc for that purpose.
>> >>
>> >> libstdc++-v3/ChangeLog:
>> >>
>> >>         * include/bits/basic_string.h (_S_copy_chars): Replace overloads
>> >>         with constexpr-if and extend optimization to all contiguous
>> >>         iterators.
>> >>         * src/c++11/string-inst.cc: Extend comment.
>> >> ---
>> >>
>> >> Tested x86_64-linux.
>> >>
>> >LGTM with one clarification question.
>> >
>> >>
>> >>  libstdc++-v3/include/bits/basic_string.h | 31 ++++++++++++++++++------
>> >>  libstdc++-v3/src/c++11/string-inst.cc    |  3 ++-
>> >>  2 files changed, 25 insertions(+), 9 deletions(-)
>> >>
>> >> diff --git a/libstdc++-v3/include/bits/basic_string.h
>> >> b/libstdc++-v3/include/bits/basic_string.h
>> >> index 886e7e6b19e..067c7915c76 100644
>> >> --- a/libstdc++-v3/include/bits/basic_string.h
>> >> +++ b/libstdc++-v3/include/bits/basic_string.h
>> >> @@ -468,6 +468,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>> >>           traits_type::assign(__d, __n, __c);
>> >>        }
>> >>
>> >> +#pragma GCC diagnostic push
>> >> +#pragma GCC diagnostic ignored "-Wc++17-extensions"
>> >>        // _S_copy_chars is a separate template to permit specialization
>> >>        // to optimize for the common case of pointers as iterators.
>> >>        template<class _Iterator>
>> >> @@ -475,31 +477,44 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>> >>          static void
>> >>          _S_copy_chars(_CharT* __p, _Iterator __k1, _Iterator __k2)
>> >>          {
>> >> +#if __cplusplus >= 201103L
>> >> +         using _IterBase = decltype(std::__niter_base(__k1));
>> >> +         if constexpr (__or_<is_same<_IterBase, _CharT*>,
>> >> +                             is_same<_IterBase, const _CharT*>>::value)
>> >> +           _S_copy(__p, std::__niter_base(__k1), __k2 - __k1);
>> >> +#if __cpp_lib_concepts
>> >> +         else if constexpr (contiguous_iterator<_Iterator>
>> >> +                              && is_same_v<iter_value_t<_Iterator>,
>> >> _CharT>)
>> >> +           {
>> >> +             const auto __d = __k2 - __k1;
>> >> +             (void) (__k1 + __d); // See P3349R1
>> >> +             _S_copy(__p, std::to_address(__k1),
>> >> static_cast<size_type>(__d));
>> >> +           }
>> >> +#endif
>> >> +         else
>> >> +#endif
>> >>           for (; __k1 != __k2; ++__k1, (void)++__p)
>> >>             traits_type::assign(*__p, *__k1); // These types are off.
>> >>         }
>> >> +#pragma GCC diagnostic pop
>> >>
>> >> -      _GLIBCXX20_CONSTEXPR
>> >> +#if __cplusplus < 201103L || defined
>> >> _GLIBCXX_DEFINING_STRING_INSTANTIATIONS
>> >>        static void
>> >> -      _S_copy_chars(_CharT* __p, iterator __k1, iterator __k2)
>> >> _GLIBCXX_NOEXCEPT
>> >>
>> >The  `_GLIBCXX_DEFINING_STRING_INSTANTIATIONS` seem to be used for
>> >c++11/string-inst.cc, in
>> >which case the noexcept was meaningful.
>>
>> Is it?
>
> I meant in a sense that `_GLIBCXX_NOEXCEPT` expanded to something. Nothing 
> beyond that.

Ah OK :-)

Yes, it is a difference in the tokens compiled in string-inst.cc, but
I don't think it matters.

>>
>>
>> >The macro is not used in
>> >c++17/string-inst.cc file, so noexcept
>>
>> The src/c++17/string-inst.cc file only instantiates a handful of
>> member functions, and none of them uses _S_copy_chars. So I don't
>> think it matters for src/c++17/string-inst.cc at all.
>>
>> >would be part of the function signature, so I do not think we change
>> >emitted symbols. Is this the reason
>> >why did you remove it?
>>
>> I removed it because those overloads of _S_copy_chars are only visible
>> in the header for C++98, where _GLIBCXX_NOEXCEPT expands to nothing.
>>
>> You're correct that in src/c++11/string-inst.cc those overloads are
>> instantiated for C++11 (using -std=gnu++11), where it would expand to
>> 'noexcept'. But I don't think it's meaningful whether it's present or
>> not.
>>
>> In C++11 the noexcept isn't part of the type, and it never affects the
>> mangled name even in C++17. For these _S_copy_chars overloads, the
>> compiler can easily see that they don't throw, as they only call
>> std::char_traits<char>::assign or std::char_traits<char>::copy (or the
>> wchar_t equivalents) and those are noexcept. So for the explicit
>> instantiation definitions, the compiler knows they can't throw, and so
>> it never needs to use a noexcept landing pad to terminate if an
>> exception happens. So noexcept on the definition does nothing. Those
>> functions can't throw, and we don't need (or want) extra code emitted
>> to enforce the noexcept by terminating.
>>
>> So the noexcept is only meaningful at the call site, so that callers
>> can see that those functions don't throw (and don't need their own
>> exception handling code). The call sites in string-inst.cc should be
>> able to see that they don't throw (they're compiled with -O2, and I
>> checked on x86_64 and there are no calls to _S_copy_chars left in the
>> assembly code). The call sites in user code can only see those
>> overloads for C++98, where _GLIBCXX_NOEXCEPT expands to nothing.
>>
>> So I don't think the 'noexcept' is ever meaningful.
>>
>>
>> >> +      _S_copy_chars(_CharT* __p, iterator __k1, iterator __k2)
>> >>        { _S_copy_chars(__p, __k1.base(), __k2.base()); }
>> >>
>> >> -      _GLIBCXX20_CONSTEXPR
>> >>        static void
>> >>        _S_copy_chars(_CharT* __p, const_iterator __k1, const_iterator 
>> >> __k2)
>> >> -      _GLIBCXX_NOEXCEPT
>> >>        { _S_copy_chars(__p, __k1.base(), __k2.base()); }
>> >>
>> >> -      _GLIBCXX20_CONSTEXPR
>> >>        static void
>> >> -      _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2)
>> >> _GLIBCXX_NOEXCEPT
>> >> +      _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2)
>> >>        { _S_copy(__p, __k1, __k2 - __k1); }
>> >>
>> >> -      _GLIBCXX20_CONSTEXPR
>> >>        static void
>> >>        _S_copy_chars(_CharT* __p, const _CharT* __k1, const _CharT* __k2)
>> >> -      _GLIBCXX_NOEXCEPT
>> >>        { _S_copy(__p, __k1, __k2 - __k1); }
>> >> +#endif
>> >>
>> >>        _GLIBCXX20_CONSTEXPR
>> >>        static int
>> >> diff --git a/libstdc++-v3/src/c++11/string-inst.cc
>> >> b/libstdc++-v3/src/c++11/string-inst.cc
>> >> index c4864794d40..34df909b31a 100644
>> >> --- a/libstdc++-v3/src/c++11/string-inst.cc
>> >> +++ b/libstdc++-v3/src/c++11/string-inst.cc
>> >> @@ -40,7 +40,8 @@
>> >>  // replaced by constrained function templates, so that we instantiate the
>> >>  // pre-C++17 definitions.
>> >>  // This also causes the instantiation of the non-standard C++0x-era
>> >> -// insert(iterator, initializer_list<C>) overload, see PR libstdc++/83328
>> >> +// insert(iterator, initializer_list<C>) overload, see PR 
>> >> libstdc++/83328,
>> >> +// and overloads of _S_copy_chars for string iterators and pointers.
>> >>  #define _GLIBCXX_DEFINING_STRING_INSTANTIATIONS 1
>> >>
>> >>  #include <string>
>> >> --
>> >> 2.49.0
>> >>
>> >>
>>

Reply via email to