[v2] libstdc++: Export explicit instantiations for C++20 members of std::string

Message ID 20260404162445.14896-1-tkaminsk@redhat.com
State New
Headers
Series [v2] libstdc++: Export explicit instantiations for C++20 members of std::string |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Test failed

Commit Message

Tomasz Kaminski April 4, 2026, 4:22 p.m. UTC
  The C++20 standard added new starts_with and ends_with members to
std::basic_string, which were not previously instantiated in the library.
This meant that the extern template declarations had to be disabled for
C++20 mode. With this patch the new members are instantiated in the
library and so the explicit instantiation declarations can be used for
C++20.

Furthermore, basic_string default constructor is now constrained with
is_default_constructible_v<_Alloc> constrains, that is included in
mangled name, so we also need to instantiate and export it.

The new members added by C++23 are still not exported, and so the
explicit instantiation declarations are still disabled for C++23.

libstdc++-v3/ChangeLog:

	* config/abi/pre/gnu.ver (GLIBCXX_3.4): Make string exports
	less greedy.
	(GLIBCXX_3.4.26): Export basic_string default constructor and
	starts_with and ends_with members.
	* include/bits/basic_string.h: Update __cpluplus checks for C++20.
	* include/bits/cow_string.h: Likewise.
	* include/bits/basic_string.tcc: Declare explicit instantiations
	for C++20 as well as earlier dialects.
	* src/c++20/Makefile.am: Add cow-string-inst.cc and
	string-inst.cc source files.
	* src/c++20/Makefile.in: Regenerate.
	* src/c++20/string-inst.cc: New file defining explicit
	instantiations for basic_string default constructor and starts_with,
	ends_with methods added in C++20
	* src/c++20/cow-string-inst.cc: Version of above for cow-stings.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
---
v2 updates the years in copyright and standard reference,
as suggested.

Tested after Jakub's fix for PR124754 on x86_64-linux,
and all test passed. Same for test -O0.
OK for trunk?

 libstdc++-v3/config/abi/pre/gnu.ver        | 31 ++++++++++--
 libstdc++-v3/include/bits/basic_string.h   |  2 +-
 libstdc++-v3/include/bits/basic_string.tcc | 17 ++++---
 libstdc++-v3/include/bits/cow_string.h     |  4 +-
 libstdc++-v3/src/c++20/Makefile.am         | 16 +++++-
 libstdc++-v3/src/c++20/Makefile.in         | 15 ++++--
 libstdc++-v3/src/c++20/cow-string-inst.cc  | 34 +++++++++++++
 libstdc++-v3/src/c++20/string-inst.cc      | 59 ++++++++++++++++++++++
 8 files changed, 158 insertions(+), 20 deletions(-)
 create mode 100644 libstdc++-v3/src/c++20/cow-string-inst.cc
 create mode 100644 libstdc++-v3/src/c++20/string-inst.cc
  

Comments

Jonathan Wakely April 7, 2026, 3:44 p.m. UTC | #1
On Sat, 4 Apr 2026, 17:26 Tomasz Kamiński, <tkaminsk@redhat.com> wrote:

> The C++20 standard added new starts_with and ends_with members to
> std::basic_string, which were not previously instantiated in the library.
> This meant that the extern template declarations had to be disabled for
> C++20 mode. With this patch the new members are instantiated in the
> library and so the explicit instantiation declarations can be used for
> C++20.
>
> Furthermore, basic_string default constructor is now constrained with
> is_default_constructible_v<_Alloc> constrains, that is included in
> mangled name, so we also need to instantiate and export it.
>
> The new members added by C++23 are still not exported, and so the
> explicit instantiation declarations are still disabled for C++23.
>
> libstdc++-v3/ChangeLog:
>
>         * config/abi/pre/gnu.ver (GLIBCXX_3.4): Make string exports
>         less greedy.
>         (GLIBCXX_3.4.26): Export basic_string default constructor and
>         starts_with and ends_with members.
>         * include/bits/basic_string.h: Update __cpluplus checks for C++20.
>         * include/bits/cow_string.h: Likewise.
>         * include/bits/basic_string.tcc: Declare explicit instantiations
>         for C++20 as well as earlier dialects.
>         * src/c++20/Makefile.am: Add cow-string-inst.cc and
>         string-inst.cc source files.
>         * src/c++20/Makefile.in: Regenerate.
>         * src/c++20/string-inst.cc: New file defining explicit
>         instantiations for basic_string default constructor and
> starts_with,
>         ends_with methods added in C++20
>         * src/c++20/cow-string-inst.cc: Version of above for cow-stings.
>
> Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
> ---
> v2 updates the years in copyright and standard reference,
> as suggested.
>
> Tested after Jakub's fix for PR124754 on x86_64-linux,
> and all test passed. Same for test -O0.
> OK for trunk?
>

OK, thanks



>  libstdc++-v3/config/abi/pre/gnu.ver        | 31 ++++++++++--
>  libstdc++-v3/include/bits/basic_string.h   |  2 +-
>  libstdc++-v3/include/bits/basic_string.tcc | 17 ++++---
>  libstdc++-v3/include/bits/cow_string.h     |  4 +-
>  libstdc++-v3/src/c++20/Makefile.am         | 16 +++++-
>  libstdc++-v3/src/c++20/Makefile.in         | 15 ++++--
>  libstdc++-v3/src/c++20/cow-string-inst.cc  | 34 +++++++++++++
>  libstdc++-v3/src/c++20/string-inst.cc      | 59 ++++++++++++++++++++++
>  8 files changed, 158 insertions(+), 20 deletions(-)
>  create mode 100644 libstdc++-v3/src/c++20/cow-string-inst.cc
>  create mode 100644 libstdc++-v3/src/c++20/string-inst.cc
>
> diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
> b/libstdc++-v3/config/abi/pre/gnu.ver
> index fb968e122d8..2ff2aa02383 100644
> --- a/libstdc++-v3/config/abi/pre/gnu.ver
> +++ b/libstdc++-v3/config/abi/pre/gnu.ver
> @@ -268,9 +268,11 @@ GLIBCXX_3.4 {
>      _ZNSspLE[PRc]*;
>      _ZNKSs[0-3][a-b]*;
>      _ZNKSs[5-9][a-b]*;
> -    _ZNKSs[0-9][d-e]*;
> +    _ZNKSs[0-8][d-e]*;
>      _ZNKSs[0-9][g-z]*;
> -    _ZNKSs[0-9][0-9][a-z]*;
> +    _ZNKSs11_[MS]_*;
> +    _ZNKSs1[2-8][a-z]*;
> +    _ZNKSs[2-9][0-9][a-z]*;
>      _ZNKSs4find*;
>      _ZNKSs[abd-z]*;
>      _ZNKSs4_Rep12_M_is_leakedEv;
> @@ -339,9 +341,11 @@ GLIBCXX_3.4 {
>      _ZNSbIwSt11char_traitsIwESaIwEEpLE[PRw]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-3][a-b]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[5-9][a-b]*;
> -    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][d-e]*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE[0-8][d-e]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][g-z]*;
> -    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][0-9][a-z]*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[abd-z]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE4find*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE4_Rep12_M_is_leakedEv;
> @@ -1811,7 +1815,9 @@ GLIBCXX_3.4.21 {
>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
>
>  _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]I[PN]*;
>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[Daip]*;
> -    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[1-9]*;
> +
> _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11_[MS]_*;
> +
> _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE1[2-9]*;
> +    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[2-8]*;
>
>  _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEixE[jmy];
>
>      # operator+ for ABI-tagged std::basic_string
> @@ -2587,6 +2593,21 @@ GLIBCXX_3.4.35 {
>      _ZNSt12__cow_stringaSEOS_;
>      _ZNKSt12__cow_string5c_strEv;
>
> +    # basic_string::starts_with
> +    _ZNKSs11starts_with*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE11starts_with*;
> +
> _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11starts_with*;
> +
> +    # basic_string::ends_with
> +    _ZNKSs9ends_with*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE9ends_with*;
> +
> _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE9ends_with*;
> +
> +    # basic_string::basic_string() noexcept
> is_default_constructible<Allocator>;
> +    _ZNSsC[12]EvQ26is_default_constructible_vIT1_E;
> +
> _ZNSbIwSt11char_traitsIwESaIwEEC[12]EvQ26is_default_constructible_vIT1_E;
> +
> _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[1-2]EvQ26is_default_constructible_vIT1_E;
> +
>  #if defined (_WIN32) && !defined (__CYGWIN__)
>      _ZSt19__get_once_callablev;
>      _ZSt15__get_once_callv;
> diff --git a/libstdc++-v3/include/bits/basic_string.h
> b/libstdc++-v3/include/bits/basic_string.h
> index 202a911f9ef..af4e5d9486f 100644
> --- a/libstdc++-v3/include/bits/basic_string.h
> +++ b/libstdc++-v3/include/bits/basic_string.h
> @@ -1331,7 +1331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>        /**
>         *  Equivalent to shrink_to_fit().
>         */
> -#if __cplusplus > 201703L
> +#if __cplusplus >= 202002L
>        [[deprecated("use shrink_to_fit() instead")]]
>  #endif
>        _GLIBCXX20_CONSTEXPR
> diff --git a/libstdc++-v3/include/bits/basic_string.tcc
> b/libstdc++-v3/include/bits/basic_string.tcc
> index a223edf67ac..b00dd550237 100644
> --- a/libstdc++-v3/include/bits/basic_string.tcc
> +++ b/libstdc++-v3/include/bits/basic_string.tcc
> @@ -1031,12 +1031,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    // Inhibit implicit instantiations for required instantiations,
>    // which are defined via explicit instantiations elsewhere.
>  #if _GLIBCXX_EXTERN_TEMPLATE
> -  // The explicit instantiation definitions in src/c++11/string-inst.cc
> and
> -  // src/c++17/string-inst.cc only instantiate the members required for
> C++17
> -  // and earlier standards (so not C++20's starts_with and ends_with).
> -  // Suppress the explicit instantiation declarations for C++20, so C++20
> +  // The explicit instantiation definitions in src/c++11/string-inst.cc,
> +  // src/c++17/string-inst.cc and src/c++20/string-inst.cc only
> instantiate
> +  // the members required for C++20 and earlier standards (so not C++23's
> +  // contains).
> +  // Suppress the explicit instantiation declarations for C++23, so C++23
>    // code will implicitly instantiate std::string and std::wstring as
> needed.
> -# if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0
> +# if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0
>    extern template class basic_string<char>;
>  # elif ! _GLIBCXX_USE_CXX11_ABI
>    // Still need to prevent implicit instantiation of the COW empty rep,
> @@ -1044,7 +1045,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    extern template basic_string<char>::size_type
>      basic_string<char>::_Rep::_S_empty_rep_storage[];
>  # elif _GLIBCXX_EXTERN_TEMPLATE > 0
> -  // Export _M_replace_cold even for C++20.
> +  // Export _M_replace_cold even for C++23.
>    extern template void
>      basic_string<char>::_M_replace_cold(char *, size_type, const char*,
>                                         const size_type, const size_type);
> @@ -1064,13 +1065,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      getline(basic_istream<char>&, string&);
>
>  #ifdef _GLIBCXX_USE_WCHAR_T
> -# if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0
> +# if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0
>    extern template class basic_string<wchar_t>;
>  # elif ! _GLIBCXX_USE_CXX11_ABI
>    extern template basic_string<wchar_t>::size_type
>      basic_string<wchar_t>::_Rep::_S_empty_rep_storage[];
>  # elif _GLIBCXX_EXTERN_TEMPLATE > 0
> -  // Export _M_replace_cold even for C++20.
> +  // Export _M_replace_cold even for C++23.
>    extern template void
>      basic_string<wchar_t>::_M_replace_cold(wchar_t*, size_type, const
> wchar_t*,
>                                            const size_type, const
> size_type);
> diff --git a/libstdc++-v3/include/bits/cow_string.h
> b/libstdc++-v3/include/bits/cow_string.h
> index df71185e556..7c945f6b998 100644
> --- a/libstdc++-v3/include/bits/cow_string.h
> +++ b/libstdc++-v3/include/bits/cow_string.h
> @@ -1080,7 +1080,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        reserve(size_type __res_arg);
>
>        /// Equivalent to shrink_to_fit().
> -#if __cplusplus > 201703L
> +#if __cplusplus >= 202002L
>        [[deprecated("use shrink_to_fit() instead")]]
>  #endif
>        void
> @@ -3194,7 +3194,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         return __r;
>        }
>
> -#if __cplusplus > 201703L
> +#if __cplusplus >= 202002L
>        bool
>        starts_with(basic_string_view<_CharT, _Traits> __x) const noexcept
>        { return __sv_type(this->data(), this->size()).starts_with(__x); }
> diff --git a/libstdc++-v3/src/c++20/Makefile.am
> b/libstdc++-v3/src/c++20/Makefile.am
> index 0061678dc0f..af5d2fa4057 100644
> --- a/libstdc++-v3/src/c++20/Makefile.am
> +++ b/libstdc++-v3/src/c++20/Makefile.am
> @@ -27,10 +27,19 @@ noinst_LTLIBRARIES = libc++20convenience.la
>
>  headers =
>
> +if ENABLE_DUAL_ABI
> +extra_string_inst_sources = cow-string-inst.cc
> +else
> +extra_string_inst_sources =
> +endif
> +
> +
>  if ENABLE_EXTERN_TEMPLATE
>  # XTEMPLATE_FLAGS = -fno-implicit-templates
>  inst_sources = \
> -       sstream-inst.cc
> +       sstream-inst.cc \
> +       string-inst.cc \
> +       $(extra_string_inst_sources)
>  else
>  # XTEMPLATE_FLAGS =
>  inst_sources =
> @@ -40,6 +49,11 @@ sources = tzdb.cc format.cc atomic.cc clock.cc
> syncbuf.cc
>
>  vpath % $(top_srcdir)/src/c++20
>
> +if ENABLE_DUAL_ABI
> +# These files should be rebuilt if the .cc prerequisite changes.
> +cow-string-inst.lo cow-string-inst.o: string-inst.cc
> +endif
> +
>  if USE_STATIC_TZDATA
>  tzdata.zi.h: $(top_srcdir)/src/c++20/tzdata.zi
>         echo 'static const char tzdata_chars[] = R"__libstdcxx__(' > $@.tmp
> diff --git a/libstdc++-v3/src/c++20/Makefile.in
> b/libstdc++-v3/src/c++20/Makefile.in
> index f481ad08edb..a2386ec7ee0 100644
> --- a/libstdc++-v3/src/c++20/Makefile.in
> +++ b/libstdc++-v3/src/c++20/Makefile.in
> @@ -124,9 +124,11 @@ CONFIG_CLEAN_VPATH_FILES =
>  LTLIBRARIES = $(noinst_LTLIBRARIES)
>  libc__20convenience_la_LIBADD =
>  am__objects_1 = tzdb.lo format.lo atomic.lo clock.lo syncbuf.lo
> -@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo
> +@ENABLE_DUAL_ABI_TRUE@am__objects_2 = cow-string-inst.lo
> +@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_3 = sstream-inst.lo \
> +@ENABLE_EXTERN_TEMPLATE_TRUE@  string-inst.lo $(am__objects_2)
>  @GLIBCXX_HOSTED_TRUE@am_libc__20convenience_la_OBJECTS =  \
> -@GLIBCXX_HOSTED_TRUE@  $(am__objects_1) $(am__objects_2)
> +@GLIBCXX_HOSTED_TRUE@  $(am__objects_1) $(am__objects_3)
>  libc__20convenience_la_OBJECTS = $(am_libc__20convenience_la_OBJECTS)
>  AM_V_lt = $(am__v_lt_@AM_V@)
>  am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
> @@ -428,12 +430,16 @@ AM_CPPFLAGS = $(GLIBCXX_INCLUDES) $(CPPFLAGS)
>  # Convenience library for C++20 runtime.
>  noinst_LTLIBRARIES = libc++20convenience.la
>  headers =
> +@ENABLE_DUAL_ABI_FALSE@extra_string_inst_sources =
> +@ENABLE_DUAL_ABI_TRUE@extra_string_inst_sources = cow-string-inst.cc
>  # XTEMPLATE_FLAGS =
>  @ENABLE_EXTERN_TEMPLATE_FALSE@inst_sources =
>
>  # XTEMPLATE_FLAGS = -fno-implicit-templates
>  @ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = \
> -@ENABLE_EXTERN_TEMPLATE_TRUE@  sstream-inst.cc
> +@ENABLE_EXTERN_TEMPLATE_TRUE@  sstream-inst.cc \
> +@ENABLE_EXTERN_TEMPLATE_TRUE@  string-inst.cc \
> +@ENABLE_EXTERN_TEMPLATE_TRUE@  $(extra_string_inst_sources)
>
>  sources = tzdb.cc format.cc atomic.cc clock.cc syncbuf.cc
>  @GLIBCXX_HOSTED_FALSE@libc__20convenience_la_SOURCES =
> @@ -747,6 +753,9 @@ uninstall-am:
>
>  vpath % $(top_srcdir)/src/c++20
>
> +# These files should be rebuilt if the .cc prerequisite changes.
> +@ENABLE_DUAL_ABI_TRUE@cow-string-inst.lo cow-string-inst.o:
> string-inst.cc
> +
>  @USE_STATIC_TZDATA_TRUE@tzdata.zi.h: $(top_srcdir)/src/c++20/tzdata.zi
>  @USE_STATIC_TZDATA_TRUE@       echo 'static const char tzdata_chars[] =
> R"__libstdcxx__(' > $@.tmp
>  @USE_STATIC_TZDATA_TRUE@       cat $^ >> $@.tmp
> diff --git a/libstdc++-v3/src/c++20/cow-string-inst.cc
> b/libstdc++-v3/src/c++20/cow-string-inst.cc
> new file mode 100644
> index 00000000000..f3f411f5d0a
> --- /dev/null
> +++ b/libstdc++-v3/src/c++20/cow-string-inst.cc
> @@ -0,0 +1,34 @@
> +// Reference-counted COW string instantiations for C++20 -*- C++ -*-
> +
> +// Copyright (C) 2026 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// Under Section 7 of GPL version 3, you are granted additional
> +// permissions described in the GCC Runtime Library Exception, version
> +// 3.1, as published by the Free Software Foundation.
> +
> +// You should have received a copy of the GNU General Public License and
> +// a copy of the GCC Runtime Library Exception along with this program;
> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +
> +//
> +// ISO C++ 14882:2020 21  Strings library
> +//
> +
> +#define _GLIBCXX_USE_CXX11_ABI 0
> +#include "string-inst.cc"
> +
> +#if ! _GLIBCXX_USE_DUAL_ABI
> +# error This file should not be compiled for this configuration.
> +#endif
> diff --git a/libstdc++-v3/src/c++20/string-inst.cc
> b/libstdc++-v3/src/c++20/string-inst.cc
> new file mode 100644
> index 00000000000..2bdd77c78a4
> --- /dev/null
> +++ b/libstdc++-v3/src/c++20/string-inst.cc
> @@ -0,0 +1,59 @@
> +// string instantiations for C++20 -*- C++ -*-
> +
> +// Copyright (C) 2026 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// Under Section 7 of GPL version 3, you are granted additional
> +// permissions described in the GCC Runtime Library Exception, version
> +// 3.1, as published by the Free Software Foundation.
> +
> +// You should have received a copy of the GNU General Public License and
> +// a copy of the GCC Runtime Library Exception along with this program;
> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +
> +//
> +// ISO C++ 14882:2020 21  Strings library
> +//
> +
> +#ifndef _GLIBCXX_USE_CXX11_ABI
> +// Instantiations in this file use the new SSO std::string ABI unless
> included
> +// by another file which defines _GLIBCXX_USE_CXX11_ABI=0.
> +# define _GLIBCXX_USE_CXX11_ABI 1
> +#endif
> +
> +#include <string>
> +
> +namespace std _GLIBCXX_VISIBILITY(default)
> +{
> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
> +template basic_string<char>::basic_string() noexcept;
> +template bool basic_string<char>::starts_with(string_view) const noexcept;
> +template bool basic_string<char>::starts_with(char) const noexcept;
> +template bool basic_string<char>::starts_with(const char*) const noexcept;
> +template bool basic_string<char>::ends_with(string_view) const noexcept;
> +template bool basic_string<char>::ends_with(char) const noexcept;
> +template bool basic_string<char>::ends_with(const char*) const noexcept;
> +
> +#ifdef _GLIBCXX_USE_WCHAR_T
> +template basic_string<wchar_t>::basic_string() noexcept;
> +template bool basic_string<wchar_t>::starts_with(wstring_view) const
> noexcept;
> +template bool basic_string<wchar_t>::starts_with(wchar_t) const noexcept;
> +template bool basic_string<wchar_t>::starts_with(const wchar_t*) const
> noexcept;
> +template bool basic_string<wchar_t>::ends_with(wstring_view) const
> noexcept;
> +template bool basic_string<wchar_t>::ends_with(wchar_t) const noexcept;
> +template bool basic_string<wchar_t>::ends_with(const wchar_t*) const
> noexcept;
> +#endif
> +
> +_GLIBCXX_END_NAMESPACE_VERSION
> +} // namespace std
> --
> 2.53.0
>
>
  
Rainer Orth April 8, 2026, 5:40 p.m. UTC | #2
Hi Jonathan,

> On Sat, 4 Apr 2026, 17:26 Tomasz Kamiński, <tkaminsk@redhat.com> wrote:
>
>> The C++20 standard added new starts_with and ends_with members to
>> std::basic_string, which were not previously instantiated in the library.
>> This meant that the extern template declarations had to be disabled for
>> C++20 mode. With this patch the new members are instantiated in the
>> library and so the explicit instantiation declarations can be used for
>> C++20.
>>
>> Furthermore, basic_string default constructor is now constrained with
>> is_default_constructible_v<_Alloc> constrains, that is included in
>> mangled name, so we also need to instantiate and export it.
>>
>> The new members added by C++23 are still not exported, and so the
>> explicit instantiation declarations are still disabled for C++23.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * config/abi/pre/gnu.ver (GLIBCXX_3.4): Make string exports
>>         less greedy.
>>         (GLIBCXX_3.4.26): Export basic_string default constructor and
>>         starts_with and ends_with members.
>>         * include/bits/basic_string.h: Update __cpluplus checks for C++20.
>>         * include/bits/cow_string.h: Likewise.
>>         * include/bits/basic_string.tcc: Declare explicit instantiations
>>         for C++20 as well as earlier dialects.
>>         * src/c++20/Makefile.am: Add cow-string-inst.cc and
>>         string-inst.cc source files.
>>         * src/c++20/Makefile.in: Regenerate.
>>         * src/c++20/string-inst.cc: New file defining explicit
>>         instantiations for basic_string default constructor and
>> starts_with,
>>         ends_with methods added in C++20
>>         * src/c++20/cow-string-inst.cc: Version of above for cow-stings.
>>
>> Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
>> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
>> ---
>> v2 updates the years in copyright and standard reference,
>> as suggested.
>>
>> Tested after Jakub's fix for PR124754 on x86_64-linux,
>> and all test passed. Same for test -O0.
>> OK for trunk?
>>
>
> OK, thanks

this patch broke Solaris bootstrap:

ld: fatal: libstdc++-symbols.ver-sun: 3753: symbol '_ZNKSs11_M_disjunctEPKc': symbol version conflict
ld: fatal: libstdc++-symbols.ver-sun: 3765: symbol '_ZNKSbIwSt11char_traitsIwESaIwEE11_M_disjunctEPKw': symbol version conflict

Both symbols now match GLIBCXX_3.4 and GLIBCXX_3.4.5.

	Rainer
  
Tomasz Kaminski April 8, 2026, 6:02 p.m. UTC | #3
I think I made an mistake splitting the pattern:
-    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][0-9][a-z]*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
Note that for 11 I am now matching _M_disjunt. Looking at
the baseline_symbols.txt file,
this seem to be only name with 11 characters, so the pattern seem
unnecessary.

Could you check if the following patch fixes it for you?
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
b/libstdc++-v3/config/abi/pre/gnu.ver
index 2ff2aa02383..433b36af965 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -270,7 +270,6 @@ GLIBCXX_3.4 {
     _ZNKSs[5-9][a-b]*;
     _ZNKSs[0-8][d-e]*;
     _ZNKSs[0-9][g-z]*;
-    _ZNKSs11_[MS]_*;
     _ZNKSs1[2-8][a-z]*;
     _ZNKSs[2-9][0-9][a-z]*;
     _ZNKSs4find*;
@@ -343,7 +342,6 @@ GLIBCXX_3.4 {
     _ZNKSbIwSt11char_traitsIwESaIwEE[5-9][a-b]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[0-8][d-e]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][g-z]*;
-    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
     _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[abd-z]*;
@@ -1815,7 +1813,6 @@ GLIBCXX_3.4.21 {
     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;

 _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]I[PN]*;
     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[Daip]*;
-
 _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11_[MS]_*;
     _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE1[2-9]*;
     _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[2-8]*;

 _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEixE[jmy];




On Wed, Apr 8, 2026 at 7:41 PM Rainer Orth <ro@cebitec.uni-bielefeld.de>
wrote:

> Hi Jonathan,
>
> > On Sat, 4 Apr 2026, 17:26 Tomasz Kamiński, <tkaminsk@redhat.com> wrote:
> >
> >> The C++20 standard added new starts_with and ends_with members to
> >> std::basic_string, which were not previously instantiated in the
> library.
> >> This meant that the extern template declarations had to be disabled for
> >> C++20 mode. With this patch the new members are instantiated in the
> >> library and so the explicit instantiation declarations can be used for
> >> C++20.
> >>
> >> Furthermore, basic_string default constructor is now constrained with
> >> is_default_constructible_v<_Alloc> constrains, that is included in
> >> mangled name, so we also need to instantiate and export it.
> >>
> >> The new members added by C++23 are still not exported, and so the
> >> explicit instantiation declarations are still disabled for C++23.
> >>
> >> libstdc++-v3/ChangeLog:
> >>
> >>         * config/abi/pre/gnu.ver (GLIBCXX_3.4): Make string exports
> >>         less greedy.
> >>         (GLIBCXX_3.4.26): Export basic_string default constructor and
> >>         starts_with and ends_with members.
> >>         * include/bits/basic_string.h: Update __cpluplus checks for
> C++20.
> >>         * include/bits/cow_string.h: Likewise.
> >>         * include/bits/basic_string.tcc: Declare explicit instantiations
> >>         for C++20 as well as earlier dialects.
> >>         * src/c++20/Makefile.am: Add cow-string-inst.cc and
> >>         string-inst.cc source files.
> >>         * src/c++20/Makefile.in: Regenerate.
> >>         * src/c++20/string-inst.cc: New file defining explicit
> >>         instantiations for basic_string default constructor and
> >> starts_with,
> >>         ends_with methods added in C++20
> >>         * src/c++20/cow-string-inst.cc: Version of above for cow-stings.
> >>
> >> Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
> >> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
> >> ---
> >> v2 updates the years in copyright and standard reference,
> >> as suggested.
> >>
> >> Tested after Jakub's fix for PR124754 on x86_64-linux,
> >> and all test passed. Same for test -O0.
> >> OK for trunk?
> >>
> >
> > OK, thanks
>
> this patch broke Solaris bootstrap:
>
> ld: fatal: libstdc++-symbols.ver-sun: 3753: symbol
> '_ZNKSs11_M_disjunctEPKc': symbol version conflict
> ld: fatal: libstdc++-symbols.ver-sun: 3765: symbol
> '_ZNKSbIwSt11char_traitsIwESaIwEE11_M_disjunctEPKw': symbol version conflict
>
> Both symbols now match GLIBCXX_3.4 and GLIBCXX_3.4.5.
>
>         Rainer
>
> --
>
> -----------------------------------------------------------------------------
> Rainer Orth, Center for Biotechnology, Bielefeld University
>
>
  
Tomasz Kaminski April 8, 2026, 6:07 p.m. UTC | #4
On Wed, Apr 8, 2026 at 8:02 PM Tomasz Kaminski <tkaminsk@redhat.com> wrote:

> I think I made an mistake splitting the pattern:
> -    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][0-9][a-z]*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
> +    _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
> Note that for 11 I am now matching _M_disjunt. Looking at
> the baseline_symbols.txt file,
> this seem to be only name with 11 characters, so the pattern seem
> unnecessary.
>
> Could you check if the following patch fixes it for you?
> diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
> b/libstdc++-v3/config/abi/pre/gnu.ver
> index 2ff2aa02383..433b36af965 100644
> --- a/libstdc++-v3/config/abi/pre/gnu.ver
> +++ b/libstdc++-v3/config/abi/pre/gnu.ver
> @@ -270,7 +270,6 @@ GLIBCXX_3.4 {
>      _ZNKSs[5-9][a-b]*;
>      _ZNKSs[0-8][d-e]*;
>      _ZNKSs[0-9][g-z]*;
> -    _ZNKSs11_[MS]_*;
>      _ZNKSs1[2-8][a-z]*;
>      _ZNKSs[2-9][0-9][a-z]*;
>      _ZNKSs4find*;
> @@ -343,7 +342,6 @@ GLIBCXX_3.4 {
>      _ZNKSbIwSt11char_traitsIwESaIwEE[5-9][a-b]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-8][d-e]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][g-z]*;
> -    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
>      _ZNKSbIwSt11char_traitsIwESaIwEE[abd-z]*;
> @@ -1815,7 +1813,6 @@ GLIBCXX_3.4.21 {
>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
>
>  _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]I[PN]*;
>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[Daip]*;
> -
>  _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11_[MS]_*;
>
Please ignore this last change, and test only the two above.

>
>  _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE1[2-9]*;
>      _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[2-8]*;
>
>  _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEixE[jmy];
>
>
>
>
> On Wed, Apr 8, 2026 at 7:41 PM Rainer Orth <ro@cebitec.uni-bielefeld.de>
> wrote:
>
>> Hi Jonathan,
>>
>> > On Sat, 4 Apr 2026, 17:26 Tomasz Kamiński, <tkaminsk@redhat.com> wrote:
>> >
>> >> The C++20 standard added new starts_with and ends_with members to
>> >> std::basic_string, which were not previously instantiated in the
>> library.
>> >> This meant that the extern template declarations had to be disabled for
>> >> C++20 mode. With this patch the new members are instantiated in the
>> >> library and so the explicit instantiation declarations can be used for
>> >> C++20.
>> >>
>> >> Furthermore, basic_string default constructor is now constrained with
>> >> is_default_constructible_v<_Alloc> constrains, that is included in
>> >> mangled name, so we also need to instantiate and export it.
>> >>
>> >> The new members added by C++23 are still not exported, and so the
>> >> explicit instantiation declarations are still disabled for C++23.
>> >>
>> >> libstdc++-v3/ChangeLog:
>> >>
>> >>         * config/abi/pre/gnu.ver (GLIBCXX_3.4): Make string exports
>> >>         less greedy.
>> >>         (GLIBCXX_3.4.26): Export basic_string default constructor and
>> >>         starts_with and ends_with members.
>> >>         * include/bits/basic_string.h: Update __cpluplus checks for
>> C++20.
>> >>         * include/bits/cow_string.h: Likewise.
>> >>         * include/bits/basic_string.tcc: Declare explicit
>> instantiations
>> >>         for C++20 as well as earlier dialects.
>> >>         * src/c++20/Makefile.am: Add cow-string-inst.cc and
>> >>         string-inst.cc source files.
>> >>         * src/c++20/Makefile.in: Regenerate.
>> >>         * src/c++20/string-inst.cc: New file defining explicit
>> >>         instantiations for basic_string default constructor and
>> >> starts_with,
>> >>         ends_with methods added in C++20
>> >>         * src/c++20/cow-string-inst.cc: Version of above for
>> cow-stings.
>> >>
>> >> Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
>> >> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
>> >> ---
>> >> v2 updates the years in copyright and standard reference,
>> >> as suggested.
>> >>
>> >> Tested after Jakub's fix for PR124754 on x86_64-linux,
>> >> and all test passed. Same for test -O0.
>> >> OK for trunk?
>> >>
>> >
>> > OK, thanks
>>
>> this patch broke Solaris bootstrap:
>>
>> ld: fatal: libstdc++-symbols.ver-sun: 3753: symbol
>> '_ZNKSs11_M_disjunctEPKc': symbol version conflict
>> ld: fatal: libstdc++-symbols.ver-sun: 3765: symbol
>> '_ZNKSbIwSt11char_traitsIwESaIwEE11_M_disjunctEPKw': symbol version conflict
>>
>> Both symbols now match GLIBCXX_3.4 and GLIBCXX_3.4.5.
>>
>>         Rainer
>>
>> --
>>
>> -----------------------------------------------------------------------------
>> Rainer Orth, Center for Biotechnology, Bielefeld University
>>
>>
  
Rainer Orth April 8, 2026, 7:27 p.m. UTC | #5
Hi Tomasz,

> On Wed, Apr 8, 2026 at 8:02 PM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>> I think I made an mistake splitting the pattern:
>> -    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][0-9][a-z]*;
>> +    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
>> +    _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
>> +    _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
>> Note that for 11 I am now matching _M_disjunt. Looking at
>> the baseline_symbols.txt file,
>> this seem to be only name with 11 characters, so the pattern seem
>> unnecessary.
>>
>> Could you check if the following patch fixes it for you?
>> diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
>> b/libstdc++-v3/config/abi/pre/gnu.ver
>> index 2ff2aa02383..433b36af965 100644
>> --- a/libstdc++-v3/config/abi/pre/gnu.ver
>> +++ b/libstdc++-v3/config/abi/pre/gnu.ver
>> @@ -270,7 +270,6 @@ GLIBCXX_3.4 {
>>      _ZNKSs[5-9][a-b]*;
>>      _ZNKSs[0-8][d-e]*;
>>      _ZNKSs[0-9][g-z]*;
>> -    _ZNKSs11_[MS]_*;
>>      _ZNKSs1[2-8][a-z]*;
>>      _ZNKSs[2-9][0-9][a-z]*;
>>      _ZNKSs4find*;
>> @@ -343,7 +342,6 @@ GLIBCXX_3.4 {
>>      _ZNKSbIwSt11char_traitsIwESaIwEE[5-9][a-b]*;
>>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-8][d-e]*;
>>      _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][g-z]*;
>> -    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
>>      _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
>>      _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
>>      _ZNKSbIwSt11char_traitsIwESaIwEE[abd-z]*;
>> @@ -1815,7 +1813,6 @@ GLIBCXX_3.4.21 {
>>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
>>
>>  _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]I[PN]*;
>>      _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[Daip]*;
>> -
>>  _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11_[MS]_*;
>>
> Please ignore this last change, and test only the two above.

looks good: builds are in stage 2 now.

Thanks.
	Rainer
  
Rainer Orth April 9, 2026, 1:51 a.m. UTC | #6
Hi Tomasz,

>> Please ignore this last change, and test only the two above.
>
> looks good: builds are in stage 2 now.

while there were not Solaris-specific regressions, the original patch
caused this regression

+FAIL: g++.dg/lto/20091022-2 cp_lto_20091022-2_0.o assemble, -O3 -flto -Winline
+FAIL: g++.dg/lto/20091022-2 cp_lto_20091022-2_0.o-cp_lto_20091022-2_0.o link, -O3 -flto -Winline

In file included from i386-pc-solaris2.11/libstdc++-v3/include/string:58,
                 from /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/lto/20091022-2_0.C:5:
In member function 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()',
    inlined from 'main' at /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/lto/20091022-2_0.C:12:1:
i386-pc-solaris2.11/libstdc++-v3/include/bits/basic_string.h:295:7: warning: inlining failed in call to 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose()': call is unlikely and code size would grow [-Winline]
i386-pc-solaris2.11/libstdc++-v3/include/bits/basic_string.h:920:19: note: called from here

apparently everywhere: seen on i386-pc-solaris2.11,
sparc-sun-solaris2.11, x86_64-pc-linux-gnu, and i686-pc-linux-gnu.

	Rainer
  
Tomasz Kaminski April 9, 2026, 6:10 a.m. UTC | #7
On Thu, Apr 9, 2026 at 3:51 AM Rainer Orth <ro@cebitec.uni-bielefeld.de>
wrote:

> Hi Tomasz,
>
> >> Please ignore this last change, and test only the two above.
> >
> > looks good: builds are in stage 2 now.
>
> while there were not Solaris-specific regressions, the original patch
> caused this regression
>
> +FAIL: g++.dg/lto/20091022-2 cp_lto_20091022-2_0.o assemble, -O3 -flto
> -Winline
> +FAIL: g++.dg/lto/20091022-2 cp_lto_20091022-2_0.o-cp_lto_20091022-2_0.o
> link, -O3 -flto -Winline
>
> In file included from i386-pc-solaris2.11/libstdc++-v3/include/string:58,
>                  from
> /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/lto/20091022-2_0.C:5:
> In member function 'std::__cxx11::basic_string<char,
> std::char_traits<char>, std::allocator<char> >::~basic_string()',
>     inlined from 'main' at
> /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/lto/20091022-2_0.C:12:1:
> i386-pc-solaris2.11/libstdc++-v3/include/bits/basic_string.h:295:7:
> warning: inlining failed in call to 'std::__cxx11::basic_string<char,
> std::char_traits<char>, std::allocator<char> >::_M_dispose()': call is
> unlikely and code size would grow [-Winline]
> i386-pc-solaris2.11/libstdc++-v3/include/bits/basic_string.h:920:19: note:
> called from here

 I have created a bugzilla ticket for it
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124828.

>
> apparently everywhere: seen on i386-pc-solaris2.11,
> sparc-sun-solaris2.11, x86_64-pc-linux-gnu, and i686-pc-linux-gnu.
>
>         Rainer
>
> --
>
> -----------------------------------------------------------------------------
> Rainer Orth, Center for Biotechnology, Bielefeld University
>
>
  

Patch

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index fb968e122d8..2ff2aa02383 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -268,9 +268,11 @@  GLIBCXX_3.4 {
     _ZNSspLE[PRc]*;
     _ZNKSs[0-3][a-b]*;
     _ZNKSs[5-9][a-b]*;
-    _ZNKSs[0-9][d-e]*;
+    _ZNKSs[0-8][d-e]*;
     _ZNKSs[0-9][g-z]*;
-    _ZNKSs[0-9][0-9][a-z]*;
+    _ZNKSs11_[MS]_*;
+    _ZNKSs1[2-8][a-z]*;
+    _ZNKSs[2-9][0-9][a-z]*;
     _ZNKSs4find*;
     _ZNKSs[abd-z]*;
     _ZNKSs4_Rep12_M_is_leakedEv;
@@ -339,9 +341,11 @@  GLIBCXX_3.4 {
     _ZNSbIwSt11char_traitsIwESaIwEEpLE[PRw]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[0-3][a-b]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[5-9][a-b]*;
-    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][d-e]*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE[0-8][d-e]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][g-z]*;
-    _ZNKSbIwSt11char_traitsIwESaIwEE[0-9][0-9][a-z]*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE11_[MS]_*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE1[2-8][a-z]*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE[2-9][0-9][a-z]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE[abd-z]*;
     _ZNKSbIwSt11char_traitsIwESaIwEE4find*;
     _ZNKSbIwSt11char_traitsIwESaIwEE4_Rep12_M_is_leakedEv;
@@ -1811,7 +1815,9 @@  GLIBCXX_3.4.21 {
     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]Ev;
     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[12]I[PN]*;
     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[Daip]*;
-    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[1-9]*;
+    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11_[MS]_*;
+    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE1[2-9]*;
+    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE[2-8]*;
     _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEixE[jmy];
 
     # operator+ for ABI-tagged std::basic_string
@@ -2587,6 +2593,21 @@  GLIBCXX_3.4.35 {
     _ZNSt12__cow_stringaSEOS_;
     _ZNKSt12__cow_string5c_strEv;
 
+    # basic_string::starts_with
+    _ZNKSs11starts_with*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE11starts_with*;
+    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE11starts_with*;
+
+    # basic_string::ends_with
+    _ZNKSs9ends_with*;
+    _ZNKSbIwSt11char_traitsIwESaIwEE9ends_with*;
+    _ZNKSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE9ends_with*;
+
+    # basic_string::basic_string() noexcept is_default_constructible<Allocator>;
+    _ZNSsC[12]EvQ26is_default_constructible_vIT1_E;
+    _ZNSbIwSt11char_traitsIwESaIwEEC[12]EvQ26is_default_constructible_vIT1_E;
+    _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[1-2]EvQ26is_default_constructible_vIT1_E;
+
 #if defined (_WIN32) && !defined (__CYGWIN__)
     _ZSt19__get_once_callablev;
     _ZSt15__get_once_callv;
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index 202a911f9ef..af4e5d9486f 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1331,7 +1331,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
       /**
        *  Equivalent to shrink_to_fit().
        */
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
       [[deprecated("use shrink_to_fit() instead")]]
 #endif
       _GLIBCXX20_CONSTEXPR
diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc
index a223edf67ac..b00dd550237 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -1031,12 +1031,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Inhibit implicit instantiations for required instantiations,
   // which are defined via explicit instantiations elsewhere.
 #if _GLIBCXX_EXTERN_TEMPLATE
-  // The explicit instantiation definitions in src/c++11/string-inst.cc and
-  // src/c++17/string-inst.cc only instantiate the members required for C++17
-  // and earlier standards (so not C++20's starts_with and ends_with).
-  // Suppress the explicit instantiation declarations for C++20, so C++20
+  // The explicit instantiation definitions in src/c++11/string-inst.cc,
+  // src/c++17/string-inst.cc and src/c++20/string-inst.cc only instantiate
+  // the members required for C++20 and earlier standards (so not C++23's
+  // contains).
+  // Suppress the explicit instantiation declarations for C++23, so C++23
   // code will implicitly instantiate std::string and std::wstring as needed.
-# if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0
+# if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0
   extern template class basic_string<char>;
 # elif ! _GLIBCXX_USE_CXX11_ABI
   // Still need to prevent implicit instantiation of the COW empty rep,
@@ -1044,7 +1045,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   extern template basic_string<char>::size_type
     basic_string<char>::_Rep::_S_empty_rep_storage[];
 # elif _GLIBCXX_EXTERN_TEMPLATE > 0
-  // Export _M_replace_cold even for C++20.
+  // Export _M_replace_cold even for C++23.
   extern template void
     basic_string<char>::_M_replace_cold(char *, size_type, const char*,
 					const size_type, const size_type);
@@ -1064,13 +1065,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     getline(basic_istream<char>&, string&);
 
 #ifdef _GLIBCXX_USE_WCHAR_T
-# if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0
+# if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0
   extern template class basic_string<wchar_t>;
 # elif ! _GLIBCXX_USE_CXX11_ABI
   extern template basic_string<wchar_t>::size_type
     basic_string<wchar_t>::_Rep::_S_empty_rep_storage[];
 # elif _GLIBCXX_EXTERN_TEMPLATE > 0
-  // Export _M_replace_cold even for C++20.
+  // Export _M_replace_cold even for C++23.
   extern template void
     basic_string<wchar_t>::_M_replace_cold(wchar_t*, size_type, const wchar_t*,
 					   const size_type, const size_type);
diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h
index df71185e556..7c945f6b998 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -1080,7 +1080,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       reserve(size_type __res_arg);
 
       /// Equivalent to shrink_to_fit().
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
       [[deprecated("use shrink_to_fit() instead")]]
 #endif
       void
@@ -3194,7 +3194,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __r;
       }
 
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
       bool
       starts_with(basic_string_view<_CharT, _Traits> __x) const noexcept
       { return __sv_type(this->data(), this->size()).starts_with(__x); }
diff --git a/libstdc++-v3/src/c++20/Makefile.am b/libstdc++-v3/src/c++20/Makefile.am
index 0061678dc0f..af5d2fa4057 100644
--- a/libstdc++-v3/src/c++20/Makefile.am
+++ b/libstdc++-v3/src/c++20/Makefile.am
@@ -27,10 +27,19 @@  noinst_LTLIBRARIES = libc++20convenience.la
 
 headers =
 
+if ENABLE_DUAL_ABI
+extra_string_inst_sources = cow-string-inst.cc
+else
+extra_string_inst_sources =
+endif
+
+
 if ENABLE_EXTERN_TEMPLATE
 # XTEMPLATE_FLAGS = -fno-implicit-templates
 inst_sources = \
-	sstream-inst.cc
+	sstream-inst.cc \
+	string-inst.cc \
+	$(extra_string_inst_sources)
 else
 # XTEMPLATE_FLAGS =
 inst_sources =
@@ -40,6 +49,11 @@  sources = tzdb.cc format.cc atomic.cc clock.cc syncbuf.cc
 
 vpath % $(top_srcdir)/src/c++20
 
+if ENABLE_DUAL_ABI
+# These files should be rebuilt if the .cc prerequisite changes.
+cow-string-inst.lo cow-string-inst.o: string-inst.cc
+endif
+
 if USE_STATIC_TZDATA
 tzdata.zi.h: $(top_srcdir)/src/c++20/tzdata.zi
 	echo 'static const char tzdata_chars[] = R"__libstdcxx__(' > $@.tmp
diff --git a/libstdc++-v3/src/c++20/Makefile.in b/libstdc++-v3/src/c++20/Makefile.in
index f481ad08edb..a2386ec7ee0 100644
--- a/libstdc++-v3/src/c++20/Makefile.in
+++ b/libstdc++-v3/src/c++20/Makefile.in
@@ -124,9 +124,11 @@  CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libc__20convenience_la_LIBADD =
 am__objects_1 = tzdb.lo format.lo atomic.lo clock.lo syncbuf.lo
-@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo
+@ENABLE_DUAL_ABI_TRUE@am__objects_2 = cow-string-inst.lo
+@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_3 = sstream-inst.lo \
+@ENABLE_EXTERN_TEMPLATE_TRUE@	string-inst.lo $(am__objects_2)
 @GLIBCXX_HOSTED_TRUE@am_libc__20convenience_la_OBJECTS =  \
-@GLIBCXX_HOSTED_TRUE@	$(am__objects_1) $(am__objects_2)
+@GLIBCXX_HOSTED_TRUE@	$(am__objects_1) $(am__objects_3)
 libc__20convenience_la_OBJECTS = $(am_libc__20convenience_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -428,12 +430,16 @@  AM_CPPFLAGS = $(GLIBCXX_INCLUDES) $(CPPFLAGS)
 # Convenience library for C++20 runtime.
 noinst_LTLIBRARIES = libc++20convenience.la
 headers = 
+@ENABLE_DUAL_ABI_FALSE@extra_string_inst_sources = 
+@ENABLE_DUAL_ABI_TRUE@extra_string_inst_sources = cow-string-inst.cc
 # XTEMPLATE_FLAGS =
 @ENABLE_EXTERN_TEMPLATE_FALSE@inst_sources = 
 
 # XTEMPLATE_FLAGS = -fno-implicit-templates
 @ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = \
-@ENABLE_EXTERN_TEMPLATE_TRUE@	sstream-inst.cc
+@ENABLE_EXTERN_TEMPLATE_TRUE@	sstream-inst.cc \
+@ENABLE_EXTERN_TEMPLATE_TRUE@	string-inst.cc \
+@ENABLE_EXTERN_TEMPLATE_TRUE@	$(extra_string_inst_sources)
 
 sources = tzdb.cc format.cc atomic.cc clock.cc syncbuf.cc
 @GLIBCXX_HOSTED_FALSE@libc__20convenience_la_SOURCES = 
@@ -747,6 +753,9 @@  uninstall-am:
 
 vpath % $(top_srcdir)/src/c++20
 
+# These files should be rebuilt if the .cc prerequisite changes.
+@ENABLE_DUAL_ABI_TRUE@cow-string-inst.lo cow-string-inst.o: string-inst.cc
+
 @USE_STATIC_TZDATA_TRUE@tzdata.zi.h: $(top_srcdir)/src/c++20/tzdata.zi
 @USE_STATIC_TZDATA_TRUE@	echo 'static const char tzdata_chars[] = R"__libstdcxx__(' > $@.tmp
 @USE_STATIC_TZDATA_TRUE@	cat $^ >> $@.tmp
diff --git a/libstdc++-v3/src/c++20/cow-string-inst.cc b/libstdc++-v3/src/c++20/cow-string-inst.cc
new file mode 100644
index 00000000000..f3f411f5d0a
--- /dev/null
+++ b/libstdc++-v3/src/c++20/cow-string-inst.cc
@@ -0,0 +1,34 @@ 
+// Reference-counted COW string instantiations for C++20 -*- C++ -*-
+
+// Copyright (C) 2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+//
+// ISO C++ 14882:2020 21  Strings library
+//
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "string-inst.cc"
+
+#if ! _GLIBCXX_USE_DUAL_ABI
+# error This file should not be compiled for this configuration.
+#endif
diff --git a/libstdc++-v3/src/c++20/string-inst.cc b/libstdc++-v3/src/c++20/string-inst.cc
new file mode 100644
index 00000000000..2bdd77c78a4
--- /dev/null
+++ b/libstdc++-v3/src/c++20/string-inst.cc
@@ -0,0 +1,59 @@ 
+// string instantiations for C++20 -*- C++ -*-
+
+// Copyright (C) 2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+//
+// ISO C++ 14882:2020 21  Strings library
+//
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+// Instantiations in this file use the new SSO std::string ABI unless included
+// by another file which defines _GLIBCXX_USE_CXX11_ABI=0.
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <string>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+template basic_string<char>::basic_string() noexcept;
+template bool basic_string<char>::starts_with(string_view) const noexcept;
+template bool basic_string<char>::starts_with(char) const noexcept;
+template bool basic_string<char>::starts_with(const char*) const noexcept;
+template bool basic_string<char>::ends_with(string_view) const noexcept;
+template bool basic_string<char>::ends_with(char) const noexcept;
+template bool basic_string<char>::ends_with(const char*) const noexcept;
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+template basic_string<wchar_t>::basic_string() noexcept;
+template bool basic_string<wchar_t>::starts_with(wstring_view) const noexcept;
+template bool basic_string<wchar_t>::starts_with(wchar_t) const noexcept;
+template bool basic_string<wchar_t>::starts_with(const wchar_t*) const noexcept;
+template bool basic_string<wchar_t>::ends_with(wstring_view) const noexcept;
+template bool basic_string<wchar_t>::ends_with(wchar_t) const noexcept;
+template bool basic_string<wchar_t>::ends_with(const wchar_t*) const noexcept;
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std