Skip to content

Commit 9a2205e

Browse files
committed
Fix ambiguous calls to std::min in basic_string
1 parent f4db142 commit 9a2205e

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
@@ -1112,7 +1112,7 @@ public:
11121112
size_type __str_sz = __str.size();
11131113
if (__pos > __str_sz)
11141114
this->__throw_out_of_range();
1115-
__init(__str.data() + __pos, std::min(__n, __str_sz - __pos));
1115+
__init(__str.data() + __pos, std::min<size_type>(__n, __str_sz - __pos));
11161116
}
11171117

11181118
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -1391,7 +1391,7 @@ public:
13911391
size_type __sz = __sv.size();
13921392
if (__pos > __sz)
13931393
__throw_out_of_range();
1394-
return append(__sv.data() + __pos, std::min(__n, __sz - __pos));
1394+
return append(__sv.data() + __pos, std::min<size_type>(__n, __sz - __pos));
13951395
}
13961396

13971397
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s, size_type __n);
@@ -1518,7 +1518,7 @@ public:
15181518
size_type __sz = __sv.size();
15191519
if (__pos > __sz)
15201520
__throw_out_of_range();
1521-
return assign(__sv.data() + __pos, std::min(__n, __sz - __pos));
1521+
return assign(__sv.data() + __pos, std::min<size_type>(__n, __sz - __pos));
15221522
}
15231523

15241524
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const value_type* __s, size_type __n);
@@ -1588,7 +1588,7 @@ public:
15881588
size_type __str_sz = __sv.size();
15891589
if (__pos2 > __str_sz)
15901590
__throw_out_of_range();
1591-
return insert(__pos1, __sv.data() + __pos2, std::min(__n, __str_sz - __pos2));
1591+
return insert(__pos1, __sv.data() + __pos2, std::min<size_type>(__n, __str_sz - __pos2));
15921592
}
15931593

15941594
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
@@ -1669,7 +1669,7 @@ public:
16691669
size_type __str_sz = __sv.size();
16701670
if (__pos2 > __str_sz)
16711671
__throw_out_of_range();
1672-
return replace(__pos1, __n1, __sv.data() + __pos2, std::min(__n2, __str_sz - __pos2));
1672+
return replace(__pos1, __n1, __sv.data() + __pos2, std::min<size_type>(__n2, __str_sz - __pos2));
16731673
}
16741674

16751675
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
@@ -2982,7 +2982,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const basic_string& __str, siz
29822982
size_type __sz = __str.size();
29832983
if (__pos > __sz)
29842984
this->__throw_out_of_range();
2985-
return assign(__str.data() + __pos, std::min(__n, __sz - __pos));
2985+
return assign(__str.data() + __pos, std::min<size_type>(__n, __sz - __pos));
29862986
}
29872987

29882988
template <class _CharT, class _Traits, class _Allocator>
@@ -3090,7 +3090,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const basic_string& __str, siz
30903090
size_type __sz = __str.size();
30913091
if (__pos > __sz)
30923092
this->__throw_out_of_range();
3093-
return append(__str.data() + __pos, std::min(__n, __sz - __pos));
3093+
return append(__str.data() + __pos, std::min<size_type>(__n, __sz - __pos));
30943094
}
30953095

30963096
template <class _CharT, class _Traits, class _Allocator>
@@ -3181,7 +3181,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(
31813181
size_type __str_sz = __str.size();
31823182
if (__pos2 > __str_sz)
31833183
this->__throw_out_of_range();
3184-
return insert(__pos1, __str.data() + __pos2, std::min(__n, __str_sz - __pos2));
3184+
return insert(__pos1, __str.data() + __pos2, std::min<size_type>(__n, __str_sz - __pos2));
31853185
}
31863186

31873187
template <class _CharT, class _Traits, class _Allocator>
@@ -3225,7 +3225,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(
32253225
size_type __sz = size();
32263226
if (__pos > __sz)
32273227
this->__throw_out_of_range();
3228-
__n1 = std::min(__n1, __sz - __pos);
3228+
__n1 = std::min<size_type>(__n1, __sz - __pos);
32293229
size_type __cap = capacity();
32303230
if (__cap - __sz + __n1 >= __n2) {
32313231
value_type* __p = std::__to_address(__get_pointer());
@@ -3267,7 +3267,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
32673267
size_type __sz = size();
32683268
if (__pos > __sz)
32693269
this->__throw_out_of_range();
3270-
__n1 = std::min(__n1, __sz - __pos);
3270+
__n1 = std::min<size_type>(__n1, __sz - __pos);
32713271
size_type __cap = capacity();
32723272
value_type* __p;
32733273
if (__cap - __sz + __n1 >= __n2) {
@@ -3294,7 +3294,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(
32943294
size_type __str_sz = __str.size();
32953295
if (__pos2 > __str_sz)
32963296
this->__throw_out_of_range();
3297-
return replace(__pos1, __n1, __str.data() + __pos2, std::min(__n2, __str_sz - __pos2));
3297+
return replace(__pos1, __n1, __str.data() + __pos2, std::min<size_type>(__n2, __str_sz - __pos2));
32983298
}
32993299

33003300
template <class _CharT, class _Traits, class _Allocator>
@@ -3314,7 +3314,7 @@ basic_string<_CharT, _Traits, _Allocator>::__erase_external_with_move(size_type
33143314
if (__n) {
33153315
size_type __sz = size();
33163316
value_type* __p = std::__to_address(__get_pointer());
3317-
__n = std::min(__n, __sz - __pos);
3317+
__n = std::min<size_type>(__n, __sz - __pos);
33183318
size_type __n_move = __sz - __pos - __n;
33193319
if (__n_move != 0)
33203320
traits_type::move(__p + __pos, __p + __pos + __n, __n_move);
@@ -3488,7 +3488,7 @@ basic_string<_CharT, _Traits, _Allocator>::copy(value_type* __s, size_type __n,
34883488
size_type __sz = size();
34893489
if (__pos > __sz)
34903490
this->__throw_out_of_range();
3491-
size_type __rlen = std::min(__n, __sz - __pos);
3491+
size_type __rlen = std::min<size_type>(__n, __sz - __pos);
34923492
traits_type::copy(__s, data() + __pos, __rlen);
34933493
return __rlen;
34943494
}
@@ -3526,7 +3526,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 int basic_string<_CharT, _Traits, _Allocato
35263526
size_type __sz = size();
35273527
if (__pos1 > __sz || __n2 == npos)
35283528
this->__throw_out_of_range();
3529-
size_type __rlen = std::min(__n1, __sz - __pos1);
3529+
size_type __rlen = std::min<size_type>(__n1, __sz - __pos1);
35303530
int __r = traits_type::compare(data() + __pos1, __s, std::min(__rlen, __n2));
35313531
if (__r == 0) {
35323532
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)