https://gcc.gnu.org/g:395e5cef29d935052e5ebcab77f068f3596aa1a6

commit r16-8510-g395e5cef29d935052e5ebcab77f068f3596aa1a6
Author: Tomasz Kamiński <[email protected]>
Date:   Wed Apr 1 14:32:21 2026 +0200

    libstdc++: Export explicit instantiations for C++20 members of std::string
    
    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.35): 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 <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>

Diff:
---
 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(-)

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver 
b/libstdc++-v3/config/abi/pre/gnu.ver
index fb968e122d8a..2ff2aa02383b 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 202a911f9ef3..af4e5d9486fb 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 a223edf67acc..b00dd550237b 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 df71185e556d..7c945f6b9983 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 0061678dc0f8..af5d2fa4057b 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__(' > [email protected]
diff --git a/libstdc++-v3/src/c++20/Makefile.in 
b/libstdc++-v3/src/c++20/Makefile.in
index f481ad08edbe..a2386ec7ee0c 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.
+@[email protected] cow-string-inst.o: string-inst.cc
+
 @[email protected]: $(top_srcdir)/src/c++20/tzdata.zi
 @USE_STATIC_TZDATA_TRUE@       echo 'static const char tzdata_chars[] = 
R"__libstdcxx__(' > [email protected]
 @USE_STATIC_TZDATA_TRUE@       cat $^ >> [email protected]
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 000000000000..f3f411f5d0af
--- /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 000000000000..2bdd77c78a4f
--- /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

Reply via email to