Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fmt::format_to + FMT_STRING with char16_t/char32_t characters fails to compile #4198

Closed
XZiar opened this issue Oct 13, 2024 · 2 comments
Closed
Labels

Comments

@XZiar
Copy link
Contributor

XZiar commented Oct 13, 2024

It's failing when using char16_t or char32_t with FMT_STRING in fmt 11.x, but it was working in fmt 10.x.

    // Using a char32_t buffer fails to compile:
    std::u32string u32buf;
    fmt::format_to(std::back_inserter(u32buf), FMT_STRING(U"{}"), 2);

Similar to #3925, PR #3931 only fixed wchar_t.

godbolt repro:
https://godbolt.org/z/q4vqbTEc5

godbolt success for fmt 10.x:
https://godbolt.org/z/sT6aKjfjj

@vitaut
Copy link
Contributor

vitaut commented Oct 19, 2024

Thanks for reporting but compile-time checks are only supported for char and wchar_t strings and there are no current plans to implement them for other code unit types. We could make legacy FMT_STRING be a noop for these but it's probably better to just remove them from your code.

@puetzk
Copy link
Contributor

puetzk commented Nov 20, 2024

We also hit this while upgrading from 10.2.1 to 11.x.

We try pretty hard to use only char{8,16}_t in our data structures, avoiding things with unspecified/non-portable encoding like std::string and std::wstring, since we build in really interesting environments like winelib (where wchar_t might be libstdc++'s ucs-4, but there's still lots of windows WCHAR running around that is utf-16 like wchar_t is on MSVC.

compile-time checks are only supported for char and wchar_t strings and there are no current plans to implement them for other code unit types

Interesting. I do see that even where it compiled in fmt 10.x the compile-time check was not actually performed. I.e. a totally incorrect usage like

#include <fmt/format.h>
#include <fmt/xchar.h>

int main() {
    (void)fmt::format(FMT_STRING(u8"hello {:x}"),u8"world");
}

compiles just fine in fmt 10.2.x, but crashes at runtime with

terminate called after throwing an instance of 'fmt::v10::format_error'
what(): invalid format specifier

whereas changing it to wchar_t detects the problem at compile time

int main() {
    (void)fmt::format(FMT_STRING(L"hello {:x}"),L"world");
}

/opt/compiler-explorer/libs/fmt/10.2.1/include/fmt/core.h:2340:27: error: call to non-'constexpr' function 'void fmt::v10::detail::throw_format_error(const char*)'
throw_format_error("invalid format specifier");

Interestingly, these did work with char16_t when we first introduced the use of FMT_STRING back with fmt 7.1.2

So, just to make the change somewhat more searchable:

  • In fmt 8.1.1 and below, FMT_STRING seems to have actually worked to get compile-time checks with char16_t, including in c++14 mode. But you did need the macro even in c++20 mode - only char (not even wchar_t) seems to get compile-time checking automatically.
  • In fmt 9.0-10.2.1, char and wchar_t both get compile time checking even without FMT_STRING. FMT_STRING with other types (like char16_t) still compiles, but quietly became a no-op. Wrong format string/argument pairing for other char types is detected only at runtime.
    Seemingly this was intentional, and the functionality to check other kinds of format strings was removed on purpose (might be good documentation update to least mention that in the release notes for 9.0?).
  • In fmt 11.0+, FMT_STRING no longer compiles except with char or wchar_t (where it actually works, but is unnecessary since you get that by default in c++20 mode anyway).

https://godbolt.org/z/38hfK9o4r

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants