|
16 | 16 |
|
17 | 17 | #include <__concepts/arithmetic.h> |
18 | 18 | #include <__concepts/same_as.h> |
| 19 | +#include <__concepts/semiregular.h> |
19 | 20 | #include <__config> |
20 | 21 | #include <__format/concepts.h> |
21 | 22 | #include <__format/format_arg.h> |
| 23 | +#include <__format/format_parse_context.h> |
22 | 24 | #include <__type_traits/conditional.h> |
23 | 25 | #include <__type_traits/extent.h> |
| 26 | +#include <__type_traits/is_assignable.h> |
| 27 | +#include <__type_traits/is_constructible.h> |
24 | 28 | #include <__type_traits/remove_const.h> |
25 | 29 | #include <cstdint> |
26 | 30 | #include <string> |
@@ -161,12 +165,11 @@ consteval __arg_t __determine_arg_t() { |
161 | 165 | // |
162 | 166 | // Modeled after template<class T> explicit basic_format_arg(T& v) noexcept; |
163 | 167 | // [format.arg]/4-6 |
164 | | -template <class _Context, class _Tp> |
| 168 | +template <class _Context, __formattable_with<_Context> _Tp> |
165 | 169 | _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __value) noexcept { |
166 | 170 | using _Dp = remove_const_t<_Tp>; |
167 | 171 | constexpr __arg_t __arg = __format::__determine_arg_t<_Context, _Dp>(); |
168 | 172 | static_assert(__arg != __arg_t::__none, "the supplied type is not formattable"); |
169 | | - static_assert(__formattable_with<_Tp, _Context>); |
170 | 173 |
|
171 | 174 | // Not all types can be used to directly initialize the |
172 | 175 | // __basic_format_arg_value. First handle all types needing adjustment, the |
@@ -205,6 +208,149 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu |
205 | 208 | return basic_format_arg<_Context>{__arg, __value}; |
206 | 209 | } |
207 | 210 |
|
| 211 | +// Helper function that issues a diagnostic when __formattable_with<_Tp, _Context> is false. |
| 212 | +// |
| 213 | +// Since it's quite easy to make a mistake writing a formatter specialization |
| 214 | +// this function tries to give a better explanation. This should improve the |
| 215 | +// diagnostics when trying to format type that has no properly specialized |
| 216 | +// formatter. |
| 217 | +template <class _Context, class _Tp> |
| 218 | +[[noreturn]] _LIBCPP_HIDE_FROM_ABI constexpr void __diagnose_invalid_formatter() { |
| 219 | + using _Formatter = typename _Context::template formatter_type<remove_const_t<_Tp>>; |
| 220 | + constexpr bool __is_disabled = |
| 221 | + !is_default_constructible_v<_Formatter> && !is_copy_constructible_v<_Formatter> && |
| 222 | + !is_move_constructible_v<_Formatter> && !is_copy_assignable_v<_Formatter> && !is_move_assignable_v<_Formatter>; |
| 223 | + constexpr bool __is_semiregular = semiregular<_Formatter>; |
| 224 | + |
| 225 | + constexpr bool __has_parse_function = |
| 226 | + requires(_Formatter& __f, basic_format_parse_context<typename _Context::char_type> __pc) { |
| 227 | + { __f.parse(__pc) }; |
| 228 | + }; |
| 229 | + constexpr bool __correct_parse_function_return_type = |
| 230 | + requires(_Formatter& __f, basic_format_parse_context<typename _Context::char_type> __pc) { |
| 231 | + { __f.parse(__pc) } -> same_as<typename decltype(__pc)::iterator>; |
| 232 | + }; |
| 233 | + |
| 234 | + // The reason these static_asserts are placed in an if-constexpr-chain is to |
| 235 | + // only show one error. For example, when the formatter is not specialized it |
| 236 | + // would show all static_assert messages. With this chain the compiler only |
| 237 | + // evaluates one static_assert. |
| 238 | + |
| 239 | + if constexpr (__is_disabled) |
| 240 | + |
| 241 | + static_assert( |
| 242 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 243 | + sizeof(_Tp) == 0 |
| 244 | +# else |
| 245 | + false |
| 246 | +# endif |
| 247 | + , |
| 248 | + "The required formatter specialization has not been provided."); |
| 249 | + else if constexpr (!__is_semiregular) |
| 250 | + static_assert( |
| 251 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 252 | + sizeof(_Tp) == 0 |
| 253 | +# else |
| 254 | + false |
| 255 | +# endif |
| 256 | + , |
| 257 | + "The required formatter specialization is not semiregular."); |
| 258 | + |
| 259 | + else if constexpr (!__has_parse_function) |
| 260 | + static_assert( |
| 261 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 262 | + sizeof(_Tp) == 0 |
| 263 | +# else |
| 264 | + false |
| 265 | +# endif |
| 266 | + , |
| 267 | + "The required formatter specialization does not have a parse function taking the proper arguments."); |
| 268 | + else if constexpr (!__correct_parse_function_return_type) |
| 269 | + static_assert( |
| 270 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 271 | + sizeof(_Tp) == 0 |
| 272 | +# else |
| 273 | + false |
| 274 | +# endif |
| 275 | + , |
| 276 | + "The required formatter specialization's parse function does not return the required type."); |
| 277 | + |
| 278 | + else { |
| 279 | + // During constant evaluation this function is called, but the format |
| 280 | + // member function has not been evaluated. This means these functions |
| 281 | + // can't be evaluated at that time. |
| 282 | + // |
| 283 | + // Note this else branch should never been taken during constant |
| 284 | + // eveluation, the static_asserts in one of the branches above should |
| 285 | + // trigger. |
| 286 | + constexpr bool __has_format_function = requires(_Formatter& __f, _Tp&& __t, _Context __fc) { |
| 287 | + { __f.format(__t, __fc) }; |
| 288 | + }; |
| 289 | + constexpr bool __is_format_function_const_qualified = requires(const _Formatter& __cf, _Tp&& __t, _Context __fc) { |
| 290 | + { __cf.format(__t, __fc) }; |
| 291 | + }; |
| 292 | + constexpr bool __correct_format_function_return_type = requires(_Formatter& __f, _Tp&& __t, _Context __fc) { |
| 293 | + { __f.format(__t, __fc)->template same_as<typename _Context::iterator> }; |
| 294 | + }; |
| 295 | + |
| 296 | + if constexpr (!__has_format_function) |
| 297 | + static_assert( |
| 298 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 299 | + sizeof(_Tp) == 0 |
| 300 | +# else |
| 301 | + false |
| 302 | +# endif |
| 303 | + , |
| 304 | + "The required formatter specialization does not have a format function taking the proper arguments."); |
| 305 | + else if constexpr (!__is_format_function_const_qualified) |
| 306 | + static_assert( |
| 307 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 308 | + sizeof(_Tp) == 0 |
| 309 | +# else |
| 310 | + false |
| 311 | +# endif |
| 312 | + , |
| 313 | + "The required formatter specialization's format function is not const qualified."); |
| 314 | + else if constexpr (!__correct_format_function_return_type) |
| 315 | + static_assert( |
| 316 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 317 | + sizeof(_Tp) == 0 |
| 318 | +# else |
| 319 | + false |
| 320 | +# endif |
| 321 | + , |
| 322 | + "The required formatter specialization's format function does not return the required type."); |
| 323 | + |
| 324 | + else |
| 325 | + // This should not happen; it makes sure the code is ill-formed. |
| 326 | + static_assert( |
| 327 | +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 |
| 328 | + sizeof(_Tp) == 0 |
| 329 | +# else |
| 330 | + false |
| 331 | +# endif |
| 332 | + , |
| 333 | + "The required formatter specialization is not formattable with its context."); |
| 334 | + } |
| 335 | +} |
| 336 | + |
| 337 | +// The Psuedo constructor is constrained per [format.arg]/4. |
| 338 | +// The only way for a user to call __create_format_arg is from std::make_format_args. |
| 339 | +// Per [format.arg.store]/3 |
| 340 | +// template<class Context = format_context, class... Args> |
| 341 | +// format-arg-store<Context, Args...> make_format_args(Args&... fmt_args); |
| 342 | +// |
| 343 | +// Preconditions: The type typename Context::template formatter_type<remove_const_t<Ti>> |
| 344 | +// meets the BasicFormatter requirements ([formatter.requirements]) for each Ti in Args. |
| 345 | +// |
| 346 | +// This function is only called when the precondition is violated. |
| 347 | +// Without this function the compilation would fail since the overload is |
| 348 | +// SFINAE'ed away. This function is used to provide better diagnostics. |
| 349 | +template <class _Context, class _Tp> |
| 350 | +_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp&) noexcept { |
| 351 | + __format::__diagnose_invalid_formatter<_Context, _Tp>(); |
| 352 | +} |
| 353 | + |
208 | 354 | template <class _Context, class... _Args> |
209 | 355 | _LIBCPP_HIDE_FROM_ABI void |
210 | 356 | __create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept { |
|
0 commit comments