1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
15 // template<class charT, class traits, class Allocator>
16 // constexpr basic_string<charT, traits, Allocator>
17 // operator+(const basic_string<charT, traits, Allocator>& lhs,
18 // type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
19 // template<class charT, class traits, class Allocator>
20 // constexpr basic_string<charT, traits, Allocator>
21 // operator+(basic_string<charT, traits, Allocator>&& lhs,
22 // type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
23 // template<class charT, class traits, class Allocator>
24 // constexpr basic_string<charT, traits, Allocator>
25 // operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
26 // const basic_string<charT, traits, Allocator>& rhs); // Since C++26
27 // template<class charT, class traits, class Allocator>
28 // constexpr basic_string<charT, traits, Allocator>
29 // operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
30 // basic_string<charT, traits, Allocator>&& rhs); // Since C++26
37 #include "asan_testing.h"
38 #include "constexpr_char_traits.h"
39 #include "make_string.h"
40 #include "min_allocator.h"
41 #include "test_allocator.h"
42 #include "test_macros.h"
44 template <typename CharT
, class TraitsT
= std::char_traits
<CharT
>>
45 class ConvertibleToStringView
{
47 constexpr explicit ConvertibleToStringView(const CharT
* cs
) : cs_
{cs
} {}
49 constexpr operator std::basic_string_view
<CharT
, TraitsT
>() { return std::basic_string_view
<CharT
, TraitsT
>(cs_
); }
50 constexpr operator std::basic_string_view
<CharT
, TraitsT
>() const {
51 return std::basic_string_view
<CharT
, TraitsT
>(cs_
);
58 static_assert(std::constructible_from
<std::basic_string_view
<char>, const ConvertibleToStringView
<char>>);
59 static_assert(std::convertible_to
<const ConvertibleToStringView
<char>, std::basic_string_view
<char>>);
61 static_assert(std::constructible_from
<std::basic_string_view
<char>, ConvertibleToStringView
<char>>);
62 static_assert(std::convertible_to
<ConvertibleToStringView
<char>, std::basic_string_view
<char>>);
64 #define CS(S) MAKE_CSTRING(CharT, S)
66 template <template <typename
, typename
> typename StringViewT
, typename CharT
, typename TraitsT
, typename AllocT
>
67 constexpr void test(const CharT
* x
, const CharT
* y
, const CharT
* expected
) {
70 // string& + string_view
72 std::basic_string
<CharT
, TraitsT
, AllocT
> st
{x
, allocator
};
73 StringViewT
<CharT
, TraitsT
> sv
{y
};
75 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= st
+ sv
;
76 assert(result
== expected
);
77 assert(result
.get_allocator() == allocator
);
78 LIBCPP_ASSERT(is_string_asan_correct(st
+ sv
));
80 // const string& + string_view
82 const std::basic_string
<CharT
, TraitsT
, AllocT
> st
{x
, allocator
};
83 StringViewT
<CharT
, TraitsT
> sv
{y
};
85 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= st
+ sv
;
86 assert(result
== expected
);
87 assert(result
.get_allocator() == allocator
);
88 LIBCPP_ASSERT(is_string_asan_correct(st
+ sv
));
90 // string&& + string_view
92 std::basic_string
<CharT
, TraitsT
, AllocT
> st
{x
, allocator
};
93 StringViewT
<CharT
, TraitsT
> sv
{y
};
95 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= std::move(st
) + sv
;
96 assert(result
== expected
);
97 assert(result
.get_allocator() == allocator
);
98 LIBCPP_ASSERT(is_string_asan_correct(std::move(st
) + sv
));
100 // string_view + string&
102 StringViewT
<CharT
, TraitsT
> sv
{x
};
103 std::basic_string
<CharT
, TraitsT
, AllocT
> st
{y
, allocator
};
105 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= sv
+ st
;
106 assert(result
== expected
);
107 assert(result
.get_allocator() == allocator
);
108 LIBCPP_ASSERT(is_string_asan_correct(sv
+ st
));
110 // string_view + const string&
112 StringViewT
<CharT
, TraitsT
> sv
{x
};
113 const std::basic_string
<CharT
, TraitsT
, AllocT
> st
{y
, allocator
};
115 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= sv
+ st
;
116 assert(result
== expected
);
117 assert(result
.get_allocator() == allocator
);
118 LIBCPP_ASSERT(is_string_asan_correct(sv
+ st
));
120 // string_view + string&&
122 // TODO: Remove workaround once https://github.com/llvm/llvm-project/issues/92382 is fixed.
123 // Create a `basic_string` to workaround clang bug:
124 // https://github.com/llvm/llvm-project/issues/92382
125 // Comparison between pointers to a string literal and some other object results in constant evaluation failure.
126 if constexpr (std::same_as
<StringViewT
<CharT
, TraitsT
>, std::basic_string_view
<CharT
, TraitsT
>>) {
127 std::basic_string
<CharT
, TraitsT
, AllocT
> st_
{x
, allocator
};
128 StringViewT
<CharT
, TraitsT
> sv
{st_
};
129 std::basic_string
<CharT
, TraitsT
, AllocT
> st
{y
, allocator
};
131 std::same_as
<std::basic_string
<CharT
, TraitsT
, AllocT
>> decltype(auto) result
= sv
+ std::move(st
);
132 assert(result
== expected
);
133 assert(result
.get_allocator() == allocator
);
134 LIBCPP_ASSERT(is_string_asan_correct(sv
+ std::move(st
)));
139 template <template <typename
, typename
> typename StringViewT
,
142 typename AllocT
= std::allocator
<CharT
>>
143 constexpr void test() {
144 // Concatenate with an empty `string`/`string_view`
145 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS(""), CS(""), CS(""));
146 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS(""), CS("short"), CS("short"));
147 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS(""), CS("not so short"), CS("not so short"));
148 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(
149 CS(""), CS("this is a much longer string"), CS("this is a much longer string"));
151 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS(""), CS(""), CS(""));
152 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS("short"), CS(""), CS("short"));
153 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS("not so short"), CS(""), CS("not so short"));
154 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(
155 CS("this is a much longer string"), CS(""), CS("this is a much longer string"));
158 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS("B"), CS("D"), CS("BD"));
159 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS("zmt94"), CS("+hkt82"), CS("zmt94+hkt82"));
160 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(CS("not so short"), CS("+is not bad"), CS("not so short+is not bad"));
161 test
<StringViewT
, CharT
, TraitsT
, AllocT
>(
162 CS("this is a much longer string"),
163 CS("+which is so much better"),
164 CS("this is a much longer string+which is so much better"));
167 template <template <typename
, typename
> typename StringViewT
, typename CharT
>
168 constexpr bool test() {
169 test
<StringViewT
, CharT
, std::char_traits
<CharT
>>();
170 test
<StringViewT
, CharT
, std::char_traits
<CharT
>, min_allocator
<CharT
>>();
171 test
<StringViewT
, CharT
, std::char_traits
<CharT
>, safe_allocator
<CharT
>>();
172 test
<StringViewT
, CharT
, std::char_traits
<CharT
>, test_allocator
<CharT
>>();
174 test
<StringViewT
, CharT
, constexpr_char_traits
<CharT
>>();
175 test
<StringViewT
, CharT
, constexpr_char_traits
<CharT
>, min_allocator
<CharT
>>();
176 test
<StringViewT
, CharT
, constexpr_char_traits
<CharT
>, safe_allocator
<CharT
>>();
177 test
<StringViewT
, CharT
, constexpr_char_traits
<CharT
>, test_allocator
<CharT
>>();
182 int main(int, char**) {
183 // std::basic_string_view
184 test
<std::basic_string_view
, char>();
185 static_assert(test
<std::basic_string_view
, char>());
186 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
187 test
<std::basic_string_view
, wchar_t>();
188 static_assert(test
<std::basic_string_view
, wchar_t>());
190 #ifndef TEST_HAS_NO_CHAR8_T
191 test
<std::basic_string_view
, char8_t
>();
192 static_assert(test
<std::basic_string_view
, char8_t
>());
194 test
<std::basic_string_view
, char16_t
>();
195 static_assert(test
<std::basic_string_view
, char16_t
>());
196 test
<std::basic_string_view
, char32_t
>();
197 static_assert(test
<std::basic_string_view
, char32_t
>());
199 // ConvertibleToStringView
200 test
<ConvertibleToStringView
, char>();
201 static_assert(test
<ConvertibleToStringView
, char>());
202 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
203 test
<ConvertibleToStringView
, wchar_t>();
204 static_assert(test
<ConvertibleToStringView
, wchar_t>());
206 #ifndef TEST_HAS_NO_CHAR8_T
207 test
<ConvertibleToStringView
, char8_t
>();
208 static_assert(test
<ConvertibleToStringView
, char8_t
>());
210 test
<ConvertibleToStringView
, char16_t
>();
211 static_assert(test
<ConvertibleToStringView
, char16_t
>());
212 test
<ConvertibleToStringView
, char32_t
>();
213 static_assert(test
<ConvertibleToStringView
, char32_t
>());