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.

>
> >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