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