Improve compile-time checks

This commit is contained in:
Victor Zverovich 2024-09-01 07:49:35 -07:00
parent f4dad85c3a
commit 66920feeee

View File

@ -2841,24 +2841,23 @@ FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
return true; return true;
} }
template <typename T, typename ParseContext> template <typename T, typename Char>
FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769).
FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) FMT_CONSTEXPR auto parse_format_specs(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) { -> decltype(ctx.begin()) {
using char_type = typename ParseContext::char_type; using context = buffered_context<Char>;
using context = buffered_context<char_type>;
using mapped_type = using mapped_type =
remove_cvref_t<decltype(arg_mapper<context>().map(std::declval<T&>()))>; remove_cvref_t<decltype(arg_mapper<context>().map(std::declval<T&>()))>;
#if defined(__cpp_if_constexpr) #if defined(__cpp_if_constexpr)
if constexpr (std::is_default_constructible< if constexpr (std::is_default_constructible<
formatter<mapped_type, char_type>>::value) { formatter<mapped_type, Char>>::value) {
return formatter<mapped_type, char_type>().parse(ctx); return formatter<mapped_type, Char>().parse(ctx);
} else { } else {
type_is_unformattable_for<T, char_type> _; type_is_unformattable_for<T, Char> _;
return ctx.begin(); return ctx.begin();
} }
#else #else
return formatter<mapped_type, char_type>().parse(ctx); return formatter<mapped_type, Char>().parse(ctx);
#endif #endif
} }
@ -2867,32 +2866,26 @@ template <typename... T> struct arg_pack {};
template <typename Char, int NUM_ARGS, int NUM_NAMED_ARGS, bool DYNAMIC_NAMES> template <typename Char, int NUM_ARGS, int NUM_NAMED_ARGS, bool DYNAMIC_NAMES>
class format_string_checker { class format_string_checker {
private: private:
using parse_context_type = compile_parse_context<Char>;
// Format specifiers parsing function.
// In the future basic_format_parse_context will replace compile_parse_context
// here and will use is_constant_evaluated and downcasting to access the data
// needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1.
using parse_func = const Char* (*)(parse_context_type&);
type types_[NUM_ARGS > 0 ? NUM_ARGS : 1]; type types_[NUM_ARGS > 0 ? NUM_ARGS : 1];
parse_context_type context_;
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1];
named_arg_info<Char> named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1]; named_arg_info<Char> named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1];
compile_parse_context<Char> context_;
using parse_func = const Char* (*)(basic_format_parse_context<Char>&);
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1];
public: public:
template <typename... T> template <typename... T>
explicit FMT_CONSTEXPR format_string_checker(basic_string_view<Char> fmt, explicit FMT_CONSTEXPR format_string_checker(basic_string_view<Char> fmt,
arg_pack<T...>) arg_pack<T...>)
: types_{mapped_type_constant<T, buffered_context<Char>>::value...}, : types_{mapped_type_constant<T, buffered_context<Char>>::value...},
named_args_{},
context_(fmt, NUM_ARGS, types_), context_(fmt, NUM_ARGS, types_),
parse_funcs_{&parse_format_specs<T, parse_context_type>...}, parse_funcs_{&parse_format_specs<T, Char>...} {
named_args_{} { using ignore = int[];
using dummy = int[];
int arg_index = 0, named_arg_index = 0; int arg_index = 0, named_arg_index = 0;
(void)dummy{0, (init_statically_named_arg<T>(named_args_, arg_index, (void)ignore{0, (init_statically_named_arg<T>(named_args_, arg_index,
named_arg_index), named_arg_index),
0)...}; 0)...};
ignore_unused(arg_index, named_arg_index); ignore_unused(arg_index, named_arg_index);
} }