From 6348bd64d2d66c67a63ccd9a751c71918eb05a30 Mon Sep 17 00:00:00 2001 From: Kenneth Weiss Date: Tue, 10 Jan 2023 18:17:19 -0800 Subject: [PATCH] Adds a factory function for `arg_formatter` w/ default `locale_ref` Use this within printf_arg_formatter constructor as workaround for XL compiler bug that optimizes away base class initializer. Also: Reverts conversion of internal `specs` variable back to a const ref Per PR suggestion. --- include/fmt/format.h | 11 ++++++++--- include/fmt/printf.h | 20 +++++++------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 0d42bd9aaefd6..70764bff4e770 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3580,18 +3580,23 @@ template struct arg_formatter { using context = buffer_context; iterator out; - const format_specs* specs; + const format_specs& specs; locale_ref locale; template FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { - return detail::write(out, value, *specs, locale); + return detail::write(out, value, specs, locale); } auto operator()(typename basic_format_arg::handle) -> iterator { // User-defined types are handled separately because they require access // to the parse context. return out; } + + static auto make_arg_formatter(iterator iter, format_specs& s) + -> arg_formatter { + return {iter, s, locale_ref()}; + } }; template struct custom_formatter { @@ -4213,7 +4218,7 @@ void vformat_to(buffer& buf, basic_string_view fmt, specs.precision, specs.precision_ref, context); if (begin == end || *begin != '}') on_error("missing '}' in format string"); - auto f = arg_formatter{context.out(), &specs, context.locale()}; + auto f = arg_formatter{context.out(), specs, context.locale()}; context.advance_to(visit_format_arg(f, arg)); return begin; } diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 8eecf0b44c5f6..40ebede416d78 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -228,20 +228,14 @@ class printf_arg_formatter : public arg_formatter { context_type& context_; OutputIt write_null_pointer(bool is_string = false) { - auto s = *this->specs; + auto s = this->specs; s.type = presentation_type::none; return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); } public: - printf_arg_formatter(OutputIt iter, format_specs* s, context_type& ctx) - : base{iter, s, locale_ref()}, context_(ctx) { -#if defined(__ibmxl__) - // Bugfix: XL compiler optimizes out initializer for base - this->out = iter; - this->specs = s; -#endif - } + printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx) + : base(base::make_arg_formatter(iter, s)), context_(ctx) {} OutputIt operator()(monostate value) { return base::operator()(value); } @@ -250,7 +244,7 @@ class printf_arg_formatter : public arg_formatter { // MSVC2013 fails to compile separate overloads for bool and Char so use // std::is_same instead. if (std::is_same::value) { - format_specs fmt_specs = *this->specs; + format_specs fmt_specs = this->specs; if (fmt_specs.type != presentation_type::none && fmt_specs.type != presentation_type::chr) { return (*this)(static_cast(value)); @@ -275,13 +269,13 @@ class printf_arg_formatter : public arg_formatter { /** Formats a null-terminated C string. */ OutputIt operator()(const char* value) { if (value) return base::operator()(value); - return write_null_pointer(this->specs->type != presentation_type::pointer); + return write_null_pointer(this->specs.type != presentation_type::pointer); } /** Formats a null-terminated wide C string. */ OutputIt operator()(const wchar_t* value) { if (value) return base::operator()(value); - return write_null_pointer(this->specs->type != presentation_type::pointer); + return write_null_pointer(this->specs.type != presentation_type::pointer); } OutputIt operator()(basic_string_view value) { @@ -551,7 +545,7 @@ void vprintf(buffer& buf, basic_string_view format, // Format argument. out = visit_format_arg( - printf_arg_formatter(out, &specs, context), arg); + printf_arg_formatter(out, specs, context), arg); } write(out, basic_string_view(start, to_unsigned(it - start))); }