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 <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
Tomasz Kamiński
2026-04-01 14:32:21 +02:00
parent a9a1ed3499
commit 395e5cef29
8 changed files with 158 additions and 20 deletions

View File

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

View File

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

View File

@@ -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);

View File

@@ -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); }

View File

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

View File

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

View File

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

View File

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