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   //assert_is_formattable<std::chrono::zoned_time, CharT>();
192 #  endif // !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB)
193 
194 #endif // TEST_HAS_NO_LOCALIZATION
195 }
196 
197 // Tests for P1636 Formatters for library types
198 //
199 // The paper hasn't been voted in so currently all formatters are disabled.
200 // Note the paper has been abandoned, the types are kept since other papers may
201 // introduce these formatters.
202 template <class CharT>
203 void test_P1636() {
204   assert_is_not_formattable<std::basic_streambuf<CharT>, CharT>();
205   assert_is_not_formattable<std::bitset<42>, CharT>();
206   assert_is_not_formattable<std::complex<double>, CharT>();
207   assert_is_not_formattable<std::error_code, CharT>();
208   assert_is_not_formattable<std::filesystem::path, CharT>();
209   assert_is_not_formattable<std::shared_ptr<int>, CharT>();
210 #ifndef TEST_HAS_NO_LOCALIZATION
211   if constexpr (!std::same_as<CharT, int>) // sub_match only works with proper character types
212     assert_is_not_formattable<std::sub_match<CharT*>, CharT>();
213 #endif
214 #ifndef TEST_HAS_NO_THREADS
215   assert_is_formattable<std::thread::id, CharT>();
216 #endif
217   assert_is_not_formattable<std::unique_ptr<int>, CharT>();
218 }
219 
220 template <class CharT, class Vector>
221 void test_P2286_vector_bool() {
222   assert_is_formattable<Vector, CharT>();
223   assert_is_formattable<typename Vector::reference, CharT>();
224 
225   // The const_reference shall be a bool.
226   // However libc++ uses a __bit_const_reference<vector> when
227   // _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL is defined.
228   assert_is_formattable<const Vector&, CharT>();
229   assert_is_formattable<typename Vector::const_reference, CharT>();
230 }
231 
232 // Tests for P2286 Formatting ranges
233 template <class CharT>
234 void test_P2286() {
235   assert_is_formattable<std::array<int, 42>, CharT>();
236   assert_is_formattable<std::vector<int>, CharT>();
237   assert_is_formattable<std::deque<int>, CharT>();
238   assert_is_formattable<std::forward_list<int>, CharT>();
239   assert_is_formattable<std::list<int>, CharT>();
240 
241   assert_is_formattable<std::set<int>, CharT>();
242   assert_is_formattable<std::map<int, int>, CharT>();
243   assert_is_formattable<std::multiset<int>, CharT>();
244   assert_is_formattable<std::multimap<int, int>, CharT>();
245 
246 #if TEST_STD_VER >= 23
247   // assert_is_formattable<std::flat_set<int>, CharT>();
248   assert_is_formattable<std::flat_map<int, int>, CharT>();
249   // assert_is_formattable<std::flat_multiset<int>, CharT>();
250   assert_is_formattable<std::flat_multimap<int, int>, CharT>();
251 #endif // TEST_STD_VER >= 2
252 
253   assert_is_formattable<std::unordered_set<int>, CharT>();
254   assert_is_formattable<std::unordered_map<int, int>, CharT>();
255   assert_is_formattable<std::unordered_multiset<int>, CharT>();
256   assert_is_formattable<std::unordered_multimap<int, int>, CharT>();
257 
258   assert_is_formattable<std::stack<int>, CharT>();
259   assert_is_formattable<std::queue<int>, CharT>();
260   assert_is_formattable<std::priority_queue<int>, CharT>();
261 
262   assert_is_formattable<std::span<int>, CharT>();
263 
264   assert_is_formattable<std::valarray<int>, CharT>();
265 
266   assert_is_formattable<std::pair<int, int>, CharT>();
267   assert_is_formattable<std::tuple<int>, CharT>();
268 
269   test_P2286_vector_bool<CharT, std::vector<bool>>();
270   test_P2286_vector_bool<CharT, std::vector<bool, std::allocator<bool>>>();
271   test_P2286_vector_bool<CharT, std::vector<bool, min_allocator<bool>>>();
272 }
273 
274 // Tests volatile qualified objects are no longer formattable.
275 template <class CharT>
276 void test_LWG3631() {
277   assert_is_not_formattable<volatile CharT, CharT>();
278 
279   assert_is_not_formattable<volatile bool, CharT>();
280 
281   assert_is_not_formattable<volatile signed int, CharT>();
282   assert_is_not_formattable<volatile unsigned int, CharT>();
283 
284   assert_is_not_formattable<volatile std::chrono::microseconds, CharT>();
285   assert_is_not_formattable<volatile std::chrono::sys_time<std::chrono::microseconds>, CharT>();
286   assert_is_not_formattable<volatile std::chrono::day, CharT>();
287 
288   assert_is_not_formattable<std::array<volatile int, 42>, CharT>();
289 
290   assert_is_not_formattable<std::pair<volatile int, int>, CharT>();
291   assert_is_not_formattable<std::pair<int, volatile int>, CharT>();
292   assert_is_not_formattable<std::pair<volatile int, volatile int>, CharT>();
293 }
294 
295 class c {
296   void f();
297   void fc() const;
298   static void sf();
299 };
300 enum e { a };
301 enum class ec { a };
302 template <class CharT>
303 void test_disabled() {
304 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
305   assert_is_not_formattable<const char*, wchar_t>();
306 #endif
307   assert_is_not_formattable<const char*, char8_t>();
308   assert_is_not_formattable<const char*, char16_t>();
309   assert_is_not_formattable<const char*, char32_t>();
310 
311   assert_is_not_formattable<c, CharT>();
312   assert_is_not_formattable<const c, CharT>();
313   assert_is_not_formattable<volatile c, CharT>();
314   assert_is_not_formattable<const volatile c, CharT>();
315 
316   assert_is_not_formattable<e, CharT>();
317   assert_is_not_formattable<const e, CharT>();
318   assert_is_not_formattable<volatile e, CharT>();
319   assert_is_not_formattable<const volatile e, CharT>();
320 
321   assert_is_not_formattable<ec, CharT>();
322   assert_is_not_formattable<const ec, CharT>();
323   assert_is_not_formattable<volatile ec, CharT>();
324   assert_is_not_formattable<const volatile ec, CharT>();
325 
326   assert_is_not_formattable<int*, CharT>();
327   assert_is_not_formattable<const int*, CharT>();
328   assert_is_not_formattable<volatile int*, CharT>();
329   assert_is_not_formattable<const volatile int*, CharT>();
330 
331   assert_is_not_formattable<c*, CharT>();
332   assert_is_not_formattable<const c*, CharT>();
333   assert_is_not_formattable<volatile c*, CharT>();
334   assert_is_not_formattable<const volatile c*, CharT>();
335 
336   assert_is_not_formattable<e*, CharT>();
337   assert_is_not_formattable<const e*, CharT>();
338   assert_is_not_formattable<volatile e*, CharT>();
339   assert_is_not_formattable<const volatile e*, CharT>();
340 
341   assert_is_not_formattable<ec*, CharT>();
342   assert_is_not_formattable<const ec*, CharT>();
343   assert_is_not_formattable<volatile ec*, CharT>();
344   assert_is_not_formattable<const volatile ec*, CharT>();
345 
346   assert_is_not_formattable<void (*)(), CharT>();
347   assert_is_not_formattable<void (c::*)(), CharT>();
348   assert_is_not_formattable<void (c::*)() const, CharT>();
349 
350   assert_is_not_formattable<std::optional<int>, CharT>();
351   assert_is_not_formattable<std::variant<int>, CharT>();
352 
353   assert_is_not_formattable<std::shared_ptr<c>, CharT>();
354   assert_is_not_formattable<std::unique_ptr<c>, CharT>();
355 
356   assert_is_not_formattable<std::array<c, 42>, CharT>();
357   assert_is_not_formattable<std::vector<c>, CharT>();
358   assert_is_not_formattable<std::deque<c>, CharT>();
359   assert_is_not_formattable<std::forward_list<c>, CharT>();
360   assert_is_not_formattable<std::list<c>, CharT>();
361 
362   assert_is_not_formattable<std::set<c>, CharT>();
363   assert_is_not_formattable<std::map<c, int>, CharT>();
364   assert_is_not_formattable<std::multiset<c>, CharT>();
365   assert_is_not_formattable<std::multimap<c, int>, CharT>();
366 
367   assert_is_not_formattable<std::unordered_set<c>, CharT>();
368   assert_is_not_formattable<std::unordered_map<c, int>, CharT>();
369   assert_is_not_formattable<std::unordered_multiset<c>, CharT>();
370   assert_is_not_formattable<std::unordered_multimap<c, int>, CharT>();
371 
372   assert_is_not_formattable<std::stack<c>, CharT>();
373   assert_is_not_formattable<std::queue<c>, CharT>();
374   assert_is_not_formattable<std::priority_queue<c>, CharT>();
375 
376   assert_is_not_formattable<std::span<c>, CharT>();
377 
378   assert_is_not_formattable<std::valarray<c>, CharT>();
379 
380   assert_is_not_formattable<std::pair<c, int>, CharT>();
381   assert_is_not_formattable<std::tuple<c>, CharT>();
382 
383   assert_is_not_formattable<std::optional<c>, CharT>();
384   assert_is_not_formattable<std::variant<c>, CharT>();
385 }
386 
387 struct abstract {
388   virtual ~abstract() = 0;
389 };
390 
391 template <class CharT>
392   requires std::same_as<CharT, char>
393 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
394         || std::same_as<CharT, wchar_t>
395 #endif
396 struct std::formatter<abstract, CharT> {
397   template <class ParseContext>
398   constexpr typename ParseContext::iterator parse(ParseContext& parse_ctx) {
399     return parse_ctx.begin();
400   }
401 
402   template <class FormatContext>
403   typename FormatContext::iterator format(const abstract&, FormatContext& ctx) const {
404     return ctx.out();
405   }
406 };
407 
408 template <class CharT>
409 void test_abstract_class() {
410   assert_is_formattable<abstract, CharT>();
411 }
412 
413 template <class CharT>
414 void test() {
415   test_P0645<CharT>();
416   test_P1361<CharT>();
417   test_P1636<CharT>();
418   test_P2286<CharT>();
419   test_LWG3631<CharT>();
420   test_abstract_class<CharT>();
421   test_disabled<CharT>();
422 }
423 
424 void test() {
425   test<char>();
426 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
427   test<wchar_t>();
428 #endif
429   test<char8_t>();
430   test<char16_t>();
431   test<char32_t>();
432 }
433