Skip to content

Commit b791541

Browse files
committed
[libc++][test] Fixes constexpr nasty_char_traits.
This was discovered by @StephanTLavavej who provided the solution they use in MSVC STL. This solution is based on that example. The same issue affects the constexpr_char_traits which was discovered in #88389. This uses the same fix. Fixes: #74221
1 parent a06c1fe commit b791541

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

libcxx/test/support/constexpr_char_traits.h

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@
1616

1717
#include "test_macros.h"
1818

19+
// Tests whether the range [p1, p1 + n) overlaps with the range [p2, p2 + n).
20+
//
21+
// precondition The ranges [p1, p1 + n) and [p2, p2 + n) are valid ranges.
22+
//
23+
// Typically the pointers are compared with less than. This is not allowed when
24+
// the pointers belong to different ranges. This is UB. Typically, this is
25+
// benign at run-time, however since UB is not allowed during constant
26+
// evaluation this does not compile. This function does the validation without
27+
// UB.
28+
//
29+
// When the ranges overlap the ranges can be copied from the beginning to the
30+
// end. Otherwise they need to be copied from the end to the beginning.
31+
template <class Traits>
32+
TEST_CONSTEXPR_CXX14 bool is_overlapping_range(Traits* p1, const Traits* p2, std::size_t n) {
33+
if (p1 == p2) // Needed when n == 0
34+
return true;
35+
36+
for (; n; --n, ++p1)
37+
if (p1 == p2)
38+
return true;
39+
40+
return false;
41+
}
42+
1943
template <class CharT>
2044
struct constexpr_char_traits
2145
{
@@ -98,23 +122,21 @@ constexpr_char_traits<CharT>::find(const char_type* s, std::size_t n, const char
98122
}
99123

100124
template <class CharT>
101-
TEST_CONSTEXPR_CXX14 CharT*
102-
constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n)
103-
{
104-
char_type* r = s1;
105-
if (s1 < s2)
106-
{
107-
for (; n; --n, ++s1, ++s2)
108-
assign(*s1, *s2);
109-
}
110-
else if (s2 < s1)
111-
{
112-
s1 += n;
113-
s2 += n;
114-
for (; n; --n)
115-
assign(*--s1, *--s2);
116-
}
117-
return r;
125+
TEST_CONSTEXPR_CXX14 CharT* constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n) {
126+
if (s1 == s2)
127+
return s1;
128+
129+
char_type* r = s1;
130+
if (is_overlapping_range(s1, s2, n)) {
131+
for (; n; --n)
132+
assign(*s1++, *s2++);
133+
} else {
134+
s1 += n;
135+
s2 += n;
136+
for (; n; --n)
137+
assign(*--s1, *--s2);
138+
}
139+
return r;
118140
}
119141

120142
template <class CharT>

libcxx/test/support/nasty_string.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "make_string.h"
1818
#include "test_macros.h"
19+
#include "constexpr_char_traits.h" // is_nonoverlapping_range
1920

2021
// This defines a nasty_string similar to nasty_containers. This string's
2122
// value_type does operator hijacking, which allows us to ensure that the
@@ -118,11 +119,14 @@ constexpr const nasty_char* nasty_char_traits::find(const nasty_char* s, std::si
118119
}
119120

120121
constexpr nasty_char* nasty_char_traits::move(nasty_char* s1, const nasty_char* s2, std::size_t n) {
122+
if (s1 == s2)
123+
return s1;
124+
121125
nasty_char* r = s1;
122-
if (s1 < s2) {
123-
for (; n; --n, ++s1, ++s2)
124-
assign(*s1, *s2);
125-
} else if (s2 < s1) {
126+
if (is_overlapping_range(s1, s2, n)) {
127+
for (; n; --n)
128+
assign(*s1++, *s2++);
129+
} else {
126130
s1 += n;
127131
s2 += n;
128132
for (; n; --n)

0 commit comments

Comments
 (0)