Skip to content

Commit 8f2a90f

Browse files
committed
Fix ambiguous calls to std::min in basic_string
1 parent 896df5c commit 8f2a90f

File tree

2 files changed

+259
-14
lines changed

2 files changed

+259
-14
lines changed

libcxx/include/string

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ public:
11011101
size_type __str_sz = __str.size();
11021102
if (__pos > __str_sz)
11031103
this->__throw_out_of_range();
1104-
__init(__str.data() + __pos, std::min(__n, __str_sz - __pos));
1104+
__init(__str.data() + __pos, std::min<size_type>(__n, __str_sz - __pos));
11051105
}
11061106

11071107
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -2943,7 +2943,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const basic_string& __str, siz
29432943
size_type __sz = __str.size();
29442944
if (__pos > __sz)
29452945
this->__throw_out_of_range();
2946-
return assign(__str.data() + __pos, std::min(__n, __sz - __pos));
2946+
return assign(__str.data() + __pos, std::min<size_type>(__n, __sz - __pos));
29472947
}
29482948

29492949
template <class _CharT, class _Traits, class _Allocator>
@@ -2957,7 +2957,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const _Tp& __t, size_type __po
29572957
size_type __sz = __sv.size();
29582958
if (__pos > __sz)
29592959
this->__throw_out_of_range();
2960-
return assign(__sv.data() + __pos, std::min(__n, __sz - __pos));
2960+
return assign(__sv.data() + __pos, std::min<size_type>(__n, __sz - __pos));
29612961
}
29622962

29632963
template <class _CharT, class _Traits, class _Allocator>
@@ -3088,7 +3088,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const basic_string& __str, siz
30883088
size_type __sz = __str.size();
30893089
if (__pos > __sz)
30903090
this->__throw_out_of_range();
3091-
return append(__str.data() + __pos, std::min(__n, __sz - __pos));
3091+
return append(__str.data() + __pos, std::min<size_type>(__n, __sz - __pos));
30923092
}
30933093

30943094
template <class _CharT, class _Traits, class _Allocator>
@@ -3102,7 +3102,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const _Tp& __t, size_type __po
31023102
size_type __sz = __sv.size();
31033103
if (__pos > __sz)
31043104
this->__throw_out_of_range();
3105-
return append(__sv.data() + __pos, std::min(__n, __sz - __pos));
3105+
return append(__sv.data() + __pos, std::min<size_type>(__n, __sz - __pos));
31063106
}
31073107

31083108
template <class _CharT, class _Traits, class _Allocator>
@@ -3210,7 +3210,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(
32103210
size_type __str_sz = __str.size();
32113211
if (__pos2 > __str_sz)
32123212
this->__throw_out_of_range();
3213-
return insert(__pos1, __str.data() + __pos2, std::min(__n, __str_sz - __pos2));
3213+
return insert(__pos1, __str.data() + __pos2, std::min<size_type>(__n, __str_sz - __pos2));
32143214
}
32153215

32163216
template <class _CharT, class _Traits, class _Allocator>
@@ -3224,7 +3224,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos1, const _Tp& _
32243224
size_type __str_sz = __sv.size();
32253225
if (__pos2 > __str_sz)
32263226
this->__throw_out_of_range();
3227-
return insert(__pos1, __sv.data() + __pos2, std::min(__n, __str_sz - __pos2));
3227+
return insert(__pos1, __sv.data() + __pos2, std::min<size_type>(__n, __str_sz - __pos2));
32283228
}
32293229

32303230
template <class _CharT, class _Traits, class _Allocator>
@@ -3268,7 +3268,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(
32683268
size_type __sz = size();
32693269
if (__pos > __sz)
32703270
this->__throw_out_of_range();
3271-
__n1 = std::min(__n1, __sz - __pos);
3271+
__n1 = std::min<size_type>(__n1, __sz - __pos);
32723272
size_type __cap = capacity();
32733273
if (__cap - __sz + __n1 >= __n2) {
32743274
value_type* __p = std::__to_address(__get_pointer());
@@ -3310,7 +3310,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
33103310
size_type __sz = size();
33113311
if (__pos > __sz)
33123312
this->__throw_out_of_range();
3313-
__n1 = std::min(__n1, __sz - __pos);
3313+
__n1 = std::min<size_type>(__n1, __sz - __pos);
33143314
size_type __cap = capacity();
33153315
value_type* __p;
33163316
if (__cap - __sz + __n1 >= __n2) {
@@ -3346,7 +3346,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(
33463346
size_type __str_sz = __str.size();
33473347
if (__pos2 > __str_sz)
33483348
this->__throw_out_of_range();
3349-
return replace(__pos1, __n1, __str.data() + __pos2, std::min(__n2, __str_sz - __pos2));
3349+
return replace(__pos1, __n1, __str.data() + __pos2, std::min<size_type>(__n2, __str_sz - __pos2));
33503350
}
33513351

33523352
template <class _CharT, class _Traits, class _Allocator>
@@ -3361,7 +3361,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(
33613361
size_type __str_sz = __sv.size();
33623362
if (__pos2 > __str_sz)
33633363
this->__throw_out_of_range();
3364-
return replace(__pos1, __n1, __sv.data() + __pos2, std::min(__n2, __str_sz - __pos2));
3364+
return replace(__pos1, __n1, __sv.data() + __pos2, std::min<size_type>(__n2, __str_sz - __pos2));
33653365
}
33663366

33673367
template <class _CharT, class _Traits, class _Allocator>
@@ -3381,7 +3381,7 @@ basic_string<_CharT, _Traits, _Allocator>::__erase_external_with_move(size_type
33813381
if (__n) {
33823382
size_type __sz = size();
33833383
value_type* __p = std::__to_address(__get_pointer());
3384-
__n = std::min(__n, __sz - __pos);
3384+
__n = std::min<size_type>(__n, __sz - __pos);
33853385
size_type __n_move = __sz - __pos - __n;
33863386
if (__n_move != 0)
33873387
traits_type::move(__p + __pos, __p + __pos + __n, __n_move);
@@ -3555,7 +3555,7 @@ basic_string<_CharT, _Traits, _Allocator>::copy(value_type* __s, size_type __n,
35553555
size_type __sz = size();
35563556
if (__pos > __sz)
35573557
this->__throw_out_of_range();
3558-
size_type __rlen = std::min(__n, __sz - __pos);
3558+
size_type __rlen = std::min<size_type>(__n, __sz - __pos);
35593559
traits_type::copy(__s, data() + __pos, __rlen);
35603560
return __rlen;
35613561
}
@@ -3609,7 +3609,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 int basic_string<_CharT, _Traits, _Allocato
36093609
size_type __sz = size();
36103610
if (__pos1 > __sz || __n2 == npos)
36113611
this->__throw_out_of_range();
3612-
size_type __rlen = std::min(__n1, __sz - __pos1);
3612+
size_type __rlen = std::min<size_type>(__n1, __sz - __pos1);
36133613
int __r = traits_type::compare(data() + __pos1, __s, std::min(__rlen, __n2));
36143614
if (__r == 0) {
36153615
if (__rlen < __n2)
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <string>
10+
11+
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
12+
13+
// Make sure basic_string constructors and functions operate properly for allocators with small `size_type`s.
14+
// Related issue: https://github.com/llvm/llvm-project/issues/125187
15+
16+
// constexpr basic_string(
17+
// basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // C++23
18+
// basic_string(const basic_string& str, size_type pos, size_type n,
19+
// const Allocator& a = Allocator()); // constexpr since C++20
20+
// basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // constexpr since C++20
21+
// template <class T>
22+
// basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20
23+
// basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // constexpr since C++20
24+
// template <class T>
25+
// basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20
26+
// basic_string& insert(size_type pos1, const basic_string& str,
27+
// size_type pos2, size_type n=npos); // constexpr since C++20
28+
// template <class T>
29+
// basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20
30+
// basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20
31+
// basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20
32+
// basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20
33+
// basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
34+
// size_type pos2, size_type n2=npos); // constexpr since C++20
35+
// template <class T>
36+
// basic_string& replace(size_type pos1, size_type n1, const T& t,
37+
// size_type pos2, size_type n2= npos); // C++17, constexpr since C++20
38+
// size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20
39+
// template <class T>
40+
// int compare(const T& t) const noexcept; // C++17, constexpr since C++20
41+
// int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20
42+
43+
#include <cassert>
44+
#include <cstdint>
45+
#include <string>
46+
#include <string_view>
47+
48+
#include "sized_allocator.h"
49+
#include "test_macros.h"
50+
51+
template <class SizeT, class DiffT, class CharT = char, class Traits = std::char_traits<CharT> >
52+
TEST_CONSTEXPR_CXX20 void test_with_custom_size_type() {
53+
using Alloc = sized_allocator<CharT, SizeT, DiffT>;
54+
using string = std::basic_string<CharT, Traits, Alloc>;
55+
string s = "hello world";
56+
57+
// The following tests validate all possible calls to std::min within <basic_string>
58+
{ // basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a = Allocator())
59+
assert(string(s, 0, 5) == "hello");
60+
assert(string(s, 0, 5, Alloc(3)) == "hello");
61+
assert(string(s, 6, 5) == "world");
62+
assert(string(s, 6, 5, Alloc(3)) == "world");
63+
assert(string(s, 6, 100) == "world");
64+
assert(string(s, 6, 100, Alloc(3)) == "world");
65+
}
66+
#if TEST_STD_VER >= 23
67+
{ // constexpr basic_string(basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator());
68+
assert(string(string(s), 0, 5) == "hello");
69+
assert(string(string(s), 0, 5, Alloc(3)) == "hello");
70+
assert(string(string(s), 6, 5) == "world");
71+
assert(string(string(s), 6, 5, Alloc(3)) == "world");
72+
assert(string(string(s), 6, 100) == "world");
73+
assert(string(string(s), 6, 100, Alloc(3)) == "world");
74+
}
75+
#endif
76+
{ // basic_string& assign(const basic_string& str, size_type pos, size_type n=npos)
77+
string s1 = s;
78+
string s2 = "cplusplus";
79+
s1.assign(s2, 0, 5);
80+
assert(s1 == "cplus");
81+
s1.assign(s2, 0, 9);
82+
assert(s1 == "cplusplus");
83+
s1.assign(s2, 5);
84+
assert(s1 == "plus");
85+
s1.assign(s2, 0, 100);
86+
assert(s1 == "cplusplus");
87+
s1.assign(s2, 4);
88+
assert(s1 == "splus");
89+
s1.assign(s2, 0);
90+
assert(s1 == "cplusplus");
91+
}
92+
#if TEST_STD_VER >= 17
93+
{ // template <class T> basic_string& assign(const T& t, size_type pos, size_type n=npos)
94+
std::string_view sv = "cplusplus";
95+
string s1 = s;
96+
s1.assign(sv, 0, 5);
97+
assert(s1 == "cplus");
98+
s1.assign(sv, 0, 9);
99+
assert(s1 == "cplusplus");
100+
s1.assign(sv, 5);
101+
assert(s1 == "plus");
102+
s1.assign(sv, 0, 100);
103+
assert(s1 == "cplusplus");
104+
s1.assign(sv, 4);
105+
assert(s1 == "splus");
106+
s1.assign(sv, 0);
107+
assert(s1 == "cplusplus");
108+
}
109+
#endif
110+
{ // basic_string& append(const basic_string& str, size_type pos, size_type n=npos)
111+
string s1 = s;
112+
string s2 = " of cplusplus";
113+
s1.append(s2, 0, 5);
114+
assert(s1 == "hello world of c");
115+
s1 = s;
116+
s1.append(s2, 0, 100);
117+
assert(s1 == "hello world of cplusplus");
118+
s1 = s;
119+
s1.append(s2, 0);
120+
assert(s1 == "hello world of cplusplus");
121+
}
122+
#if TEST_STD_VER >= 17
123+
{ // template <class T> basic_string& append(const T& t, size_type pos, size_type n=npos)
124+
string s1 = s;
125+
std::string_view sv = " of cplusplus";
126+
s1.append(sv, 0, 5);
127+
assert(s1 == "hello world of c");
128+
s1 = s;
129+
s1.append(sv, 0, 100);
130+
assert(s1 == "hello world of cplusplus");
131+
s1 = s;
132+
s1.append(sv, 0);
133+
assert(s1 == "hello world of cplusplus");
134+
}
135+
#endif
136+
{ // basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n=npos)
137+
string s1 = s;
138+
string s2 = " cplusplus";
139+
s1.insert(5, s2, 0, 2);
140+
assert(s1 == "hello c world");
141+
s1 = s;
142+
s1.insert(5, s2, 0, 100);
143+
assert(s1 == "hello cplusplus world");
144+
s1 = s;
145+
s1.insert(5, s2, 0);
146+
assert(s1 == "hello cplusplus world");
147+
}
148+
#if TEST_STD_VER >= 17
149+
{ // template <class T> basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos)
150+
string s1 = s;
151+
std::string_view sv = " cplusplus";
152+
s1.insert(5, sv, 0, 2);
153+
assert(s1 == "hello c world");
154+
s1 = s;
155+
s1.insert(5, sv, 0, 100);
156+
assert(s1 == "hello cplusplus world");
157+
s1 = s;
158+
s1.insert(5, sv, 0);
159+
assert(s1 == "hello cplusplus world");
160+
}
161+
#endif
162+
{ // basic_string& erase(size_type pos = 0, size_type n = npos)
163+
string s1 = s;
164+
assert(s1.erase(5, 100) == "hello");
165+
s1 = s;
166+
assert(s1.erase(5) == "hello");
167+
assert(s1.erase().empty());
168+
}
169+
{ // basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2)
170+
string s1 = s;
171+
const char* s2 = "cpluscplus";
172+
assert(s1.replace(6, 5, s2, 1) == "hello c");
173+
assert(s1.replace(6, 1, s2, 10) == "hello cpluscplus");
174+
}
175+
{ // basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c)
176+
string s1 = s;
177+
assert(s1.replace(5, 6, 2, 'o') == "hellooo");
178+
assert(s1.replace(5, 2, 0, 'o') == "hello");
179+
}
180+
{ // basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2=npos)
181+
string s1 = s;
182+
string s2 = "cplusplus";
183+
assert(s1.replace(6, 5, s2, 0, 1) == "hello c");
184+
assert(s1.replace(7, 0, s2, 1, 9) == "hello cplusplus");
185+
s1 = s;
186+
assert(s1.replace(6, 5, s2, 0, 100) == "hello cplusplus");
187+
s1 = s;
188+
assert(s1.replace(6, 5, s2, 0) == "hello cplusplus");
189+
}
190+
#if TEST_STD_VER >= 17
191+
{ // template <class T> basic_string& replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2= npos)
192+
string s1 = s;
193+
std::string_view sv = "cplusplus";
194+
assert(s1.replace(6, 5, sv, 0, 1) == "hello c");
195+
assert(s1.replace(7, 0, sv, 1, 9) == "hello cplusplus");
196+
s1 = s;
197+
assert(s1.replace(6, 5, sv, 0, 100) == "hello cplusplus");
198+
s1 = s;
199+
assert(s1.replace(6, 5, sv, 0) == "hello cplusplus");
200+
}
201+
#endif
202+
{ // size_type copy(value_type* s, size_type n, size_type pos = 0) const
203+
string s1 = s;
204+
char bar[100] = {};
205+
s1.copy(bar, s1.size());
206+
assert(s1 == bar);
207+
}
208+
{ // int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const
209+
string s1 = s;
210+
assert(s1.compare(0, 11, "hello world", 11) == 0);
211+
assert(s1.compare(0, 11, "hello", 11) > 0);
212+
assert(s1.compare(0, 11, "hello world C++", 100) < 0);
213+
}
214+
#if TEST_STD_VER >= 17
215+
{ // template <class T> int compare(const T& t) const noexcept;
216+
using std::operator""sv;
217+
string s1 = s;
218+
assert(s1.compare("hello world"sv) == 0);
219+
assert(s1.compare("hello"sv) > 0);
220+
assert(s1.compare("hello world C++"sv) < 0);
221+
}
222+
#endif
223+
}
224+
225+
TEST_CONSTEXPR_CXX20 bool test() {
226+
test_with_custom_size_type<std::uint8_t, std::int8_t>();
227+
test_with_custom_size_type<std::uint16_t, std::int16_t>();
228+
test_with_custom_size_type<std::uint32_t, std::int32_t>();
229+
test_with_custom_size_type<std::uint64_t, std::int64_t>();
230+
test_with_custom_size_type<std::size_t, std::ptrdiff_t>();
231+
test_with_custom_size_type<unsigned char, int>();
232+
test_with_custom_size_type<unsigned short, short>();
233+
test_with_custom_size_type<unsigned, int>();
234+
235+
return true;
236+
}
237+
238+
int main(int, char**) {
239+
test();
240+
#if TEST_STD_VER > 17
241+
static_assert(test());
242+
#endif
243+
244+
return 0;
245+
}

0 commit comments

Comments
 (0)