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 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
10 | |
11 | // This test uses std::filesystem::path, which is not always available |
12 | // XFAIL: availability-filesystem-missing |
13 | |
14 | // <format> |
15 | |
16 | // template<class T, class charT> |
17 | // concept formattable = ... |
18 | |
19 | #include <array> |
20 | #include <bitset> |
21 | #include <bitset> |
22 | #include <chrono> |
23 | #include <complex> |
24 | #include <concepts> |
25 | #include <deque> |
26 | #include <filesystem> |
27 | #include <flat_map> |
28 | #include <format> |
29 | #include <forward_list> |
30 | #include <list> |
31 | #include <map> |
32 | #include <memory> |
33 | #include <optional> |
34 | #include <queue> |
35 | #include <set> |
36 | #include <span> |
37 | #include <stack> |
38 | #include <system_error> |
39 | #include <tuple> |
40 | #include <type_traits> |
41 | #include <unordered_map> |
42 | #include <unordered_set> |
43 | #include <valarray> |
44 | #include <variant> |
45 | |
46 | #include "test_macros.h" |
47 | #include "min_allocator.h" |
48 | |
49 | #ifndef TEST_HAS_NO_LOCALIZATION |
50 | # include <regex> |
51 | #endif |
52 | #ifndef TEST_HAS_NO_THREADS |
53 | # include <thread> |
54 | #endif |
55 | |
56 | template <class T, class CharT> |
57 | void assert_is_not_formattable() { |
58 | // clang-format off |
59 | static_assert(!std::formattable< T , CharT>); |
60 | static_assert(!std::formattable< T& , CharT>); |
61 | static_assert(!std::formattable< T&& , CharT>); |
62 | static_assert(!std::formattable<const T , CharT>); |
63 | static_assert(!std::formattable<const T& , CharT>); |
64 | static_assert(!std::formattable<const T&& , CharT>); |
65 | // clang-format on |
66 | } |
67 | |
68 | template <class T, class CharT> |
69 | void assert_is_formattable() { |
70 | // Only formatters for CharT == char || CharT == wchar_t are enabled for the |
71 | // standard formatters. When CharT is a different type the formatter should |
72 | // be disabled. |
73 | if constexpr (std::same_as<CharT, char> |
74 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
75 | || std::same_as<CharT, wchar_t> |
76 | #endif |
77 | ) { |
78 | // clang-format off |
79 | static_assert(std::formattable< T , CharT>); |
80 | static_assert(std::formattable< T& , CharT>); |
81 | static_assert(std::formattable< T&& , CharT>); |
82 | static_assert(std::formattable<const T , CharT>); |
83 | static_assert(std::formattable<const T& , CharT>); |
84 | static_assert(std::formattable<const T&& , CharT>); |
85 | // clang-format on |
86 | } else |
87 | assert_is_not_formattable<T, CharT>(); |
88 | } |
89 | |
90 | // Tests for P0645 Text Formatting |
91 | template <class CharT> |
92 | void test_P0645() { |
93 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
94 | // Tests the special formatter that converts a char to a wchar_t. |
95 | assert_is_formattable<char, wchar_t>(); |
96 | #endif |
97 | assert_is_formattable<CharT, CharT>(); |
98 | |
99 | assert_is_formattable<CharT*, CharT>(); |
100 | assert_is_formattable<const CharT*, CharT>(); |
101 | assert_is_formattable<CharT[42], CharT>(); |
102 | if constexpr (!std::same_as<CharT, int>) { // string and string_view only work with proper character types |
103 | assert_is_formattable<std::basic_string<CharT>, CharT>(); |
104 | assert_is_formattable<std::basic_string_view<CharT>, CharT>(); |
105 | } |
106 | |
107 | assert_is_formattable<bool, CharT>(); |
108 | |
109 | assert_is_formattable<signed char, CharT>(); |
110 | assert_is_formattable<signed short, CharT>(); |
111 | assert_is_formattable<signed int, CharT>(); |
112 | assert_is_formattable<signed long, CharT>(); |
113 | assert_is_formattable<signed long long, CharT>(); |
114 | #ifndef TEST_HAS_NO_INT128 |
115 | assert_is_formattable<__int128_t, CharT>(); |
116 | #endif |
117 | |
118 | assert_is_formattable<unsigned char, CharT>(); |
119 | assert_is_formattable<unsigned short, CharT>(); |
120 | assert_is_formattable<unsigned int, CharT>(); |
121 | assert_is_formattable<unsigned long, CharT>(); |
122 | assert_is_formattable<unsigned long long, CharT>(); |
123 | #ifndef TEST_HAS_NO_INT128 |
124 | assert_is_formattable<__uint128_t, CharT>(); |
125 | #endif |
126 | |
127 | // floating-point types are tested in concept.formattable.float.compile.pass.cpp |
128 | |
129 | assert_is_formattable<std::nullptr_t, CharT>(); |
130 | assert_is_formattable<void*, CharT>(); |
131 | assert_is_formattable<const void*, CharT>(); |
132 | } |
133 | |
134 | // Tests for P1361 Integration of chrono with text formatting |
135 | // |
136 | // Some tests are commented out since these types haven't been implemented in |
137 | // chrono yet. After P1361 has been implemented these formatters should be all |
138 | // enabled. |
139 | template <class CharT> |
140 | void test_P1361() { |
141 | // The chrono formatters require localization support. |
142 | // [time.format]/7 |
143 | // If the chrono-specs is omitted, the chrono object is formatted as if by |
144 | // streaming it to std::ostringstream os with the formatting |
145 | // locale imbued and copying os.str() through the output iterator of the |
146 | // context with additional padding and adjustments as specified by the format |
147 | // specifiers. |
148 | // In libc++ std:::ostringstream requires localization support. |
149 | #ifndef TEST_HAS_NO_LOCALIZATION |
150 | |
151 | assert_is_formattable<std::chrono::microseconds, CharT>(); |
152 | |
153 | assert_is_formattable<std::chrono::sys_time<std::chrono::microseconds>, CharT>(); |
154 | # if !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) && !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) && \ |
155 | !defined(TEST_HAS_NO_FILESYSTEM) |
156 | assert_is_formattable<std::chrono::utc_time<std::chrono::microseconds>, CharT>(); |
157 | assert_is_formattable<std::chrono::tai_time<std::chrono::microseconds>, CharT>(); |
158 | assert_is_formattable<std::chrono::gps_time<std::chrono::microseconds>, CharT>(); |
159 | |
160 | # endif // !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) && !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) && |
161 | // !defined(TEST_HAS_NO_FILESYSTEM) |
162 | |
163 | assert_is_formattable<std::chrono::file_time<std::chrono::microseconds>, CharT>(); |
164 | assert_is_formattable<std::chrono::local_time<std::chrono::microseconds>, CharT>(); |
165 | |
166 | assert_is_formattable<std::chrono::day, CharT>(); |
167 | assert_is_formattable<std::chrono::month, CharT>(); |
168 | assert_is_formattable<std::chrono::year, CharT>(); |
169 | |
170 | assert_is_formattable<std::chrono::weekday, CharT>(); |
171 | assert_is_formattable<std::chrono::weekday_indexed, CharT>(); |
172 | assert_is_formattable<std::chrono::weekday_last, CharT>(); |
173 | |
174 | assert_is_formattable<std::chrono::month_day, CharT>(); |
175 | assert_is_formattable<std::chrono::month_day_last, CharT>(); |
176 | assert_is_formattable<std::chrono::month_weekday, CharT>(); |
177 | assert_is_formattable<std::chrono::month_weekday_last, CharT>(); |
178 | |
179 | assert_is_formattable<std::chrono::year_month, CharT>(); |
180 | assert_is_formattable<std::chrono::year_month_day, CharT>(); |
181 | assert_is_formattable<std::chrono::year_month_day_last, CharT>(); |
182 | assert_is_formattable<std::chrono::year_month_weekday, CharT>(); |
183 | assert_is_formattable<std::chrono::year_month_weekday_last, CharT>(); |
184 | |
185 | assert_is_formattable<std::chrono::hh_mm_ss<std::chrono::microseconds>, CharT>(); |
186 | |
187 | # if !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) |
188 | assert_is_formattable<std::chrono::sys_info, CharT>(); |
189 | assert_is_formattable<std::chrono::local_info, CharT>(); |
190 | |
191 | # if !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) && !defined(TEST_HAS_NO_FILESYSTEM) |
192 | assert_is_formattable<std::chrono::zoned_time<std::chrono::microseconds>, CharT>(); |
193 | # endif // !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) && !defined(TEST_HAS_NO_FILESYSTEM) |
194 | # endif // !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) |
195 | |
196 | #endif // TEST_HAS_NO_LOCALIZATION |
197 | } |
198 | |
199 | // Tests for P1636 Formatters for library types |
200 | // |
201 | // The paper hasn't been voted in so currently all formatters are disabled. |
202 | // Note the paper has been abandoned, the types are kept since other papers may |
203 | // introduce these formatters. |
204 | template <class CharT> |
205 | void test_P1636() { |
206 | assert_is_not_formattable<std::basic_streambuf<CharT>, CharT>(); |
207 | assert_is_not_formattable<std::bitset<42>, CharT>(); |
208 | assert_is_not_formattable<std::complex<double>, CharT>(); |
209 | assert_is_not_formattable<std::error_code, CharT>(); |
210 | assert_is_not_formattable<std::filesystem::path, CharT>(); |
211 | assert_is_not_formattable<std::shared_ptr<int>, CharT>(); |
212 | #ifndef TEST_HAS_NO_LOCALIZATION |
213 | if constexpr (!std::same_as<CharT, int>) // sub_match only works with proper character types |
214 | assert_is_not_formattable<std::sub_match<CharT*>, CharT>(); |
215 | #endif |
216 | #ifndef TEST_HAS_NO_THREADS |
217 | assert_is_formattable<std::thread::id, CharT>(); |
218 | #endif |
219 | assert_is_not_formattable<std::unique_ptr<int>, CharT>(); |
220 | } |
221 | |
222 | template <class CharT, class Vector> |
223 | void test_P2286_vector_bool() { |
224 | assert_is_formattable<Vector, CharT>(); |
225 | assert_is_formattable<typename Vector::reference, CharT>(); |
226 | |
227 | // The const_reference shall be a bool. |
228 | // However libc++ uses a __bit_const_reference<vector> when |
229 | // _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL is defined. |
230 | assert_is_formattable<const Vector&, CharT>(); |
231 | assert_is_formattable<typename Vector::const_reference, CharT>(); |
232 | } |
233 | |
234 | // Tests for P2286 Formatting ranges |
235 | template <class CharT> |
236 | void test_P2286() { |
237 | assert_is_formattable<std::array<int, 42>, CharT>(); |
238 | assert_is_formattable<std::vector<int>, CharT>(); |
239 | assert_is_formattable<std::deque<int>, CharT>(); |
240 | assert_is_formattable<std::forward_list<int>, CharT>(); |
241 | assert_is_formattable<std::list<int>, CharT>(); |
242 | |
243 | assert_is_formattable<std::set<int>, CharT>(); |
244 | assert_is_formattable<std::map<int, int>, CharT>(); |
245 | assert_is_formattable<std::multiset<int>, CharT>(); |
246 | assert_is_formattable<std::multimap<int, int>, CharT>(); |
247 | |
248 | #if TEST_STD_VER >= 23 |
249 | // assert_is_formattable<std::flat_set<int>, CharT>(); |
250 | assert_is_formattable<std::flat_map<int, int>, CharT>(); |
251 | // assert_is_formattable<std::flat_multiset<int>, CharT>(); |
252 | assert_is_formattable<std::flat_multimap<int, int>, CharT>(); |
253 | #endif // TEST_STD_VER >= 2 |
254 | |
255 | assert_is_formattable<std::unordered_set<int>, CharT>(); |
256 | assert_is_formattable<std::unordered_map<int, int>, CharT>(); |
257 | assert_is_formattable<std::unordered_multiset<int>, CharT>(); |
258 | assert_is_formattable<std::unordered_multimap<int, int>, CharT>(); |
259 | |
260 | assert_is_formattable<std::stack<int>, CharT>(); |
261 | assert_is_formattable<std::queue<int>, CharT>(); |
262 | assert_is_formattable<std::priority_queue<int>, CharT>(); |
263 | |
264 | assert_is_formattable<std::span<int>, CharT>(); |
265 | |
266 | assert_is_formattable<std::valarray<int>, CharT>(); |
267 | |
268 | assert_is_formattable<std::pair<int, int>, CharT>(); |
269 | assert_is_formattable<std::tuple<int>, CharT>(); |
270 | |
271 | test_P2286_vector_bool<CharT, std::vector<bool>>(); |
272 | test_P2286_vector_bool<CharT, std::vector<bool, std::allocator<bool>>>(); |
273 | test_P2286_vector_bool<CharT, std::vector<bool, min_allocator<bool>>>(); |
274 | } |
275 | |
276 | // Tests volatile qualified objects are no longer formattable. |
277 | template <class CharT> |
278 | void test_LWG3631() { |
279 | assert_is_not_formattable<volatile CharT, CharT>(); |
280 | |
281 | assert_is_not_formattable<volatile bool, CharT>(); |
282 | |
283 | assert_is_not_formattable<volatile signed int, CharT>(); |
284 | assert_is_not_formattable<volatile unsigned int, CharT>(); |
285 | |
286 | assert_is_not_formattable<volatile std::chrono::microseconds, CharT>(); |
287 | assert_is_not_formattable<volatile std::chrono::sys_time<std::chrono::microseconds>, CharT>(); |
288 | assert_is_not_formattable<volatile std::chrono::day, CharT>(); |
289 | |
290 | assert_is_not_formattable<std::array<volatile int, 42>, CharT>(); |
291 | |
292 | assert_is_not_formattable<std::pair<volatile int, int>, CharT>(); |
293 | assert_is_not_formattable<std::pair<int, volatile int>, CharT>(); |
294 | assert_is_not_formattable<std::pair<volatile int, volatile int>, CharT>(); |
295 | } |
296 | |
297 | void test_LWG3944() { |
298 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
299 | assert_is_not_formattable<char*, wchar_t>(); |
300 | assert_is_not_formattable<const char*, wchar_t>(); |
301 | assert_is_not_formattable<char[42], wchar_t>(); |
302 | assert_is_not_formattable<std::string, wchar_t>(); |
303 | assert_is_not_formattable<std::string_view, wchar_t>(); |
304 | |
305 | assert_is_formattable<std::vector<char>, wchar_t>(); |
306 | assert_is_formattable<std::set<char>, wchar_t>(); |
307 | assert_is_formattable<std::map<char, char>, wchar_t>(); |
308 | assert_is_formattable<std::tuple<char>, wchar_t>(); |
309 | #endif |
310 | } |
311 | |
312 | class c { |
313 | void f(); |
314 | void fc() const; |
315 | static void sf(); |
316 | }; |
317 | enum e { a }; |
318 | enum class ec { a }; |
319 | template <class CharT> |
320 | void test_disabled() { |
321 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
322 | assert_is_not_formattable<const char*, wchar_t>(); |
323 | #endif |
324 | assert_is_not_formattable<const char*, char8_t>(); |
325 | assert_is_not_formattable<const char*, char16_t>(); |
326 | assert_is_not_formattable<const char*, char32_t>(); |
327 | |
328 | assert_is_not_formattable<c, CharT>(); |
329 | assert_is_not_formattable<const c, CharT>(); |
330 | assert_is_not_formattable<volatile c, CharT>(); |
331 | assert_is_not_formattable<const volatile c, CharT>(); |
332 | |
333 | assert_is_not_formattable<e, CharT>(); |
334 | assert_is_not_formattable<const e, CharT>(); |
335 | assert_is_not_formattable<volatile e, CharT>(); |
336 | assert_is_not_formattable<const volatile e, CharT>(); |
337 | |
338 | assert_is_not_formattable<ec, CharT>(); |
339 | assert_is_not_formattable<const ec, CharT>(); |
340 | assert_is_not_formattable<volatile ec, CharT>(); |
341 | assert_is_not_formattable<const volatile ec, CharT>(); |
342 | |
343 | assert_is_not_formattable<int*, CharT>(); |
344 | assert_is_not_formattable<const int*, CharT>(); |
345 | assert_is_not_formattable<volatile int*, CharT>(); |
346 | assert_is_not_formattable<const volatile int*, CharT>(); |
347 | |
348 | assert_is_not_formattable<c*, CharT>(); |
349 | assert_is_not_formattable<const c*, CharT>(); |
350 | assert_is_not_formattable<volatile c*, CharT>(); |
351 | assert_is_not_formattable<const volatile c*, CharT>(); |
352 | |
353 | assert_is_not_formattable<e*, CharT>(); |
354 | assert_is_not_formattable<const e*, CharT>(); |
355 | assert_is_not_formattable<volatile e*, CharT>(); |
356 | assert_is_not_formattable<const volatile e*, CharT>(); |
357 | |
358 | assert_is_not_formattable<ec*, CharT>(); |
359 | assert_is_not_formattable<const ec*, CharT>(); |
360 | assert_is_not_formattable<volatile ec*, CharT>(); |
361 | assert_is_not_formattable<const volatile ec*, CharT>(); |
362 | |
363 | assert_is_not_formattable<void (*)(), CharT>(); |
364 | assert_is_not_formattable<void (c::*)(), CharT>(); |
365 | assert_is_not_formattable<void (c::*)() const, CharT>(); |
366 | |
367 | assert_is_not_formattable<std::optional<int>, CharT>(); |
368 | assert_is_not_formattable<std::variant<int>, CharT>(); |
369 | |
370 | assert_is_not_formattable<std::shared_ptr<c>, CharT>(); |
371 | assert_is_not_formattable<std::unique_ptr<c>, CharT>(); |
372 | |
373 | assert_is_not_formattable<std::array<c, 42>, CharT>(); |
374 | assert_is_not_formattable<std::vector<c>, CharT>(); |
375 | assert_is_not_formattable<std::deque<c>, CharT>(); |
376 | assert_is_not_formattable<std::forward_list<c>, CharT>(); |
377 | assert_is_not_formattable<std::list<c>, CharT>(); |
378 | |
379 | assert_is_not_formattable<std::set<c>, CharT>(); |
380 | assert_is_not_formattable<std::map<c, int>, CharT>(); |
381 | assert_is_not_formattable<std::multiset<c>, CharT>(); |
382 | assert_is_not_formattable<std::multimap<c, int>, CharT>(); |
383 | |
384 | assert_is_not_formattable<std::unordered_set<c>, CharT>(); |
385 | assert_is_not_formattable<std::unordered_map<c, int>, CharT>(); |
386 | assert_is_not_formattable<std::unordered_multiset<c>, CharT>(); |
387 | assert_is_not_formattable<std::unordered_multimap<c, int>, CharT>(); |
388 | |
389 | assert_is_not_formattable<std::stack<c>, CharT>(); |
390 | assert_is_not_formattable<std::queue<c>, CharT>(); |
391 | assert_is_not_formattable<std::priority_queue<c>, CharT>(); |
392 | |
393 | assert_is_not_formattable<std::span<c>, CharT>(); |
394 | |
395 | assert_is_not_formattable<std::valarray<c>, CharT>(); |
396 | |
397 | assert_is_not_formattable<std::pair<c, int>, CharT>(); |
398 | assert_is_not_formattable<std::tuple<c>, CharT>(); |
399 | |
400 | assert_is_not_formattable<std::optional<c>, CharT>(); |
401 | assert_is_not_formattable<std::variant<c>, CharT>(); |
402 | } |
403 | |
404 | struct abstract { |
405 | virtual ~abstract() = 0; |
406 | }; |
407 | |
408 | template <class CharT> |
409 | requires std::same_as<CharT, char> |
410 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
411 | || std::same_as<CharT, wchar_t> |
412 | #endif |
413 | struct std::formatter<abstract, CharT> { |
414 | template <class ParseContext> |
415 | constexpr typename ParseContext::iterator parse(ParseContext& parse_ctx) { |
416 | return parse_ctx.begin(); |
417 | } |
418 | |
419 | template <class FormatContext> |
420 | typename FormatContext::iterator format(const abstract&, FormatContext& ctx) const { |
421 | return ctx.out(); |
422 | } |
423 | }; |
424 | |
425 | template <class CharT> |
426 | void test_abstract_class() { |
427 | assert_is_formattable<abstract, CharT>(); |
428 | } |
429 | |
430 | template <class CharT> |
431 | void test() { |
432 | test_P0645<CharT>(); |
433 | test_P1361<CharT>(); |
434 | test_P1636<CharT>(); |
435 | test_P2286<CharT>(); |
436 | test_LWG3631<CharT>(); |
437 | test_LWG3944(); |
438 | test_abstract_class<CharT>(); |
439 | test_disabled<CharT>(); |
440 | } |
441 | |
442 | void test() { |
443 | test<char>(); |
444 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
445 | test<wchar_t>(); |
446 | #endif |
447 | test<char8_t>(); |
448 | test<char16_t>(); |
449 | test<char32_t>(); |
450 | } |
451 | |