Skip to content

Check format strings at compile time in the mh::format family#23

Open
pr-minder[bot] wants to merge 2 commits into
masterfrom
claude/format-strings
Open

Check format strings at compile time in the mh::format family#23
pr-minder[bot] wants to merge 2 commits into
masterfrom
claude/format-strings

Conversation

@pr-minder

@pr-minder pr-minder Bot commented Jul 21, 2026

Copy link
Copy Markdown

Before: an invalid format string passed to mh::format and friends compiled fine and threw mh::format_error at runtime. After: it fails the build. A format string only known at runtime opts in explicitly by wrapping it in mh::runtime() — or by using mh::vformat/mh::try_format, which remain runtime-checked by design.

How: mh::format/format_to/format_to_container/format_to_n now take a typed format-string parameter per backend (fmt::format_string under fmtlib, std::format_string under the STL backend) whose consteval constructor checks literal format strings against the argument types; MH_FORMATTER_NONE builds are unaffected. Call sites that assemble format strings at runtime (the source_location and enum formatters, mh::fmtstr) now wrap them in mh::runtime(). A CMake configure-time negative-compile check asserts that a format string referencing a missing argument fails to build, with a valid-string positive control so a broken harness cannot fake a pass; it runs only when the fmt backend is active.

mh::format, mh::format_to, mh::format_to_container, and mh::format_to_n
now take a typed, backend-checked format string parameter (narrow and
wide overloads) instead of laundering every string through the backend's
runtime() escape. Literal format strings are validated against the
argument types at compile time; a format string only known at runtime
must be explicitly wrapped in the new mh::runtime escape hatch:
mh::format(mh::runtime(str), args...). vformat, try_format, and
try_vformat keep their runtime-checked contracts, with try_format
rerouted through mh::runtime internally.

Call sites that assemble format strings at runtime (the source_location
and enum_fmt formatters, base_format_string::fmt, and the format_string
constructor SFINAE) now wrap them in mh::runtime, and the
runtime-format-string test is updated to document the new contract.

The wide format_to/format_to_n overloads delegate through the backend's
vformat* layer because the shape of the typed wide overloads varies
across supported fmt versions; the compile-time check already happened
while constructing the wformat_string_t parameter. Under the (disabled)
STL backend the typed aliases map to std::format_string, fixing a
latent reference to the nonexistent std runtime().

Co-Authored-By: Claude <noreply@anthropic.com>
@pr-minder pr-minder Bot changed the title claude/format-strings Add compile-time format string checking, require mh::runtime() Jul 21, 2026
…trings

Configure-time try_compile gate (fmt backend only): a format string
referencing a missing argument must fail to compile, with a valid-string
positive control so a broken harness cannot fake a pass. try_compile
ignores non-imported targets in LINK_LIBRARIES, so the TUs use the include
directory directly plus the imported fmt::fmt target. Also add runtime
tests that the typed, mh::runtime, and vformat paths agree, and update the
README for compile-time checking (under MH_FORMATTER_NONE the format
family is absent, not a built-in fallback).

Co-Authored-By: Claude <noreply@anthropic.com>
@PazerOP PazerOP changed the title Add compile-time format string checking, require mh::runtime() Check format strings at compile time in the mh::format family Jul 21, 2026
@PazerOP
PazerOP marked this pull request as draft July 21, 2026 20:02
@PazerOP
PazerOP marked this pull request as ready for review July 21, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant