On Wed, 01 Jul 2026 at 23:11 +0800, Yuao Ma wrote:
On second thoughts, I think we can actually just remove the check
altogether. It delegates to the string_view overload, which ultimately
calls the overload without __pos anyway.
On Wed, Jul 1, 2026 at 11:08 PM Jonathan Wakely <[email protected]> wrote:
On Wed, 1 Jul 2026 at 15:47, Tomasz Kaminski <[email protected]> wrote:
>
> Are the following checks correct? I think we need string of at least length
__pos + __len.
The macro is defined as:
# define __glibcxx_requires_string_len(_String,_Len) \
_GLIBCXX_DEBUG_PEDASSERT(_String != 0 || _Len == 0)
So it says we can't have a null pointer unless n==0 is true. I think
that's the right check here.
> __glibcxx_requires_string_len(__s, __n);
>
>
>
>
> On Wed, Jul 1, 2026 at 4:41 PM Yuao Ma <[email protected]> wrote:
>>
>> Hi!
>>
>> This patch implements LWG3662 for C++11 ABI and COW ABI of strings.
>>
>> Tested on x86_64 linux, ok for trunk?
>>
>> Thanks,
>> Yuao
From abae92d920dcb27beab2720ac079f1e852fafb66 Mon Sep 17 00:00:00 2001
From: Yuao Ma <[email protected]>
Date: Wed, 1 Jul 2026 23:09:35 +0800
Subject: [PATCH] libstdc++: implement LWG3662
basic_string::append/assign(NTBS, pos, n) suboptimal
This patch implements LWG3662 for both ABIs of std::string.
libstdc++-v3/ChangeLog:
* include/bits/basic_string.h: Add new append/assign API.
Please follow the documented form for the ChangeLog and name the
functions being added:
* include/bits/basic_string.h (append, assign): Add new
overloads.
* include/bits/cow_string.h: Ditto.
* testsuite/21_strings/basic_string/modifiers/append/char/2.cc: Test
new API.
Please break this line and the next three lines after the colon.
'git log' indents the commit log by 4 spaces, which means the
ChangeLog entry is indended by 12 spaces, so if your ChangeLog entry
already uses 85 lines it's going to be much too long.
* testsuite/21_strings/basic_string/modifiers/append/wchar_t/2.cc:
Ditto.
* testsuite/21_strings/basic_string/modifiers/assign/char/3.cc: Ditto.
* testsuite/21_strings/basic_string/modifiers/assign/wchar_t/3.cc:
Ditto.
---
libstdc++-v3/include/bits/basic_string.h | 28 +++++++++++++++++++
libstdc++-v3/include/bits/cow_string.h | 26 +++++++++++++++++
.../basic_string/modifiers/append/char/2.cc | 4 +++
.../modifiers/append/wchar_t/2.cc | 4 +++
.../basic_string/modifiers/assign/char/3.cc | 4 +++
.../modifiers/assign/wchar_t/3.cc | 4 +++
6 files changed, 70 insertions(+)
diff --git a/libstdc++-v3/include/bits/basic_string.h
b/libstdc++-v3/include/bits/basic_string.h
index 65d92ebfbcf..4f07b1c14f1 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1639,6 +1639,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return _M_append(__s, __n);
}
Please add a _GLIBCXX_RESOLVE_LIB_DEFECTS comment:
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3662. basic_string::append/assign(NTBS, pos, n) suboptimal
+ /**
+ * @brief Append a C substring.
+ * @param __s The C string to append.
+ * @param __pos The position in the C string to append from.
+ * @param __n The number of characters to append.
+ * @return Reference to this string.
+ */
+ _GLIBCXX20_CONSTEXPR
+ basic_string&
+ append(const _CharT* __s, size_type __pos, size_type __n)
+ {
+ return append(__sv_type(__s).substr(__pos, __n));
+ }
This should be one line:
{ return append(__sv_type(__s).substr(__pos, __n)); }
+
/**
* @brief Append multiple characters.
* @param __n The number of characters to append.
@@ -1902,6 +1916,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
traits_type::length(__s));
}
_GLIBCXX_RESOLVE_LIB_DEFECTS comment.
+ /**
+ * @brief Set value to a C substring.
+ * @param __s The C string to use.
+ * @param __pos The position in the C string to assign from.
+ * @param __n Number of characters to use.
+ * @return Reference to this string.
+ */
+ _GLIBCXX20_CONSTEXPR
+ basic_string&
+ assign(const _CharT* __s, size_type __pos, size_type __n)
+ {
+ return assign(__sv_type(__s).substr(__pos, __n));
+ }
Just one line.
+
/**
* @brief Set value to multiple characters.
* @param __n Length of the resulting string.
diff --git a/libstdc++-v3/include/bits/cow_string.h
b/libstdc++-v3/include/bits/cow_string.h
index 7c945f6b998..7708c2474ba 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -1345,6 +1345,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return this->append(__s, traits_type::length(__s));
}
_GLIBCXX_RESOLVE_LIB_DEFECTS comment.
+ /**
+ * @brief Append a C substring.
+ * @param __s The C string to append.
+ * @param __pos The position in the C string to append from.
+ * @param __n The number of characters to append.
+ * @return Reference to this string.
+ */
+ basic_string&
+ append(const _CharT* __s, size_type __pos, size_type __n)
+ {
+ return append(__sv_type(__s).substr(__pos, __n));
+ }
One line.
+
/**
* @brief Append multiple characters.
* @param __n The number of characters to append.
@@ -1517,6 +1530,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return this->assign(__s, traits_type::length(__s));
}
_GLIBCXX_RESOLVE_LIB_DEFECTS comment.
+ /**
+ * @brief Set value to a C substring.
+ * @param __s The C string to use.
+ * @param __pos The position in the C string to assign from.
+ * @param __n Number of characters to use.
+ * @return Reference to this string.
+ */
+ basic_string&
+ assign(const _CharT* __s, size_type __pos, size_type __n)
+ {
+ return assign(__sv_type(__s).substr(__pos, __n));
+ }
One line.
+
/**
* @brief Set value to multiple characters.
* @param __n Length of the resulting string.
diff --git
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/char/2.cc
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/char/2.cc
index d70fc190b45..5dd39347574 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/char/2.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/char/2.cc
@@ -24,6 +24,7 @@
// append(const _CharT* __s, size_type __n)
// append(const _CharT* __s)
+// append(const _CharT* __s, size_type __pos, size_type __n)
void
test02()
{
@@ -55,6 +56,9 @@ test02()
two.append(two.c_str(), 3);
VERIFY( two == "Written in your eyeseyesWri" );
+
+ two.append(two.c_str(), 8, 2);
+ VERIFY( two == "Written in your eyeseyesWriin" );
}
Do we have a test for the s.append("a\0b", 2, 1) example I gave, which
should throw std::out_of_range? I think that would be good to have.
int main()
diff --git
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/wchar_t/2.cc
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/wchar_t/2.cc
index 1922874de7f..fcc1ef54f28 100644
---
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/wchar_t/2.cc
+++
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/wchar_t/2.cc
@@ -24,6 +24,7 @@
// append(const _CharT* __s, size_type __n)
// append(const _CharT* __s)
+// append(const _CharT* __s, size_type __pos, size_type __n)
void
test02()
{
@@ -55,6 +56,9 @@ test02()
two.append(two.c_str(), 3);
VERIFY( two == L"Written in your eyeseyesWri" );
+
+ two.append(two.c_str(), 8, 2);
+ VERIFY( two == L"Written in your eyeseyesWriin" );
}
int main()
diff --git
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/3.cc
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/3.cc
index 1bd3deb30f4..a742c1ed3df 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/3.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/3.cc
@@ -24,6 +24,7 @@
// assign(const _CharT* __s, size_type __n)
// assign(const _CharT* __s)
+// assign(const _CharT* __s, size_type __pos, size_type __n)
void
test03()
{
@@ -47,6 +48,9 @@ test03()
one.assign(one.c_str() + 8, 6);
VERIFY( one == "by the" );
+
+ one.assign(one.c_str(), 3, 3);
+ VERIFY( one == "the" );
}
int main()
diff --git
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/3.cc
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/3.cc
index e7fcb231dff..37ff7e1ca2b 100644
---
a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/3.cc
+++
b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/3.cc
@@ -24,6 +24,7 @@
// assign(const _CharT* __s, size_type __n)
// assign(const _CharT* __s)
+// assign(const _CharT* __s, size_type __pos, size_type __n)
void
test03()
{
@@ -47,6 +48,9 @@ test03()
one.assign(one.c_str() + 8, 6);
VERIFY( one == L"by the" );
+
+ one.assign(one.c_str(), 3, 3);
+ VERIFY( one == L"the" );
}
int main()
--
2.54.0