# How `parse_format_specs` Validates Format Strings in fmtlib/fmt

> Learn how fmtlib/fmt uses parse_format_specs to validate format strings with a state machine, ensuring type-specific constraints and preventing format_error exceptions.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: internals
- Published: 2026-09-09

---

**The `parse_format_specs` function is a constexpr parser in `fmt::detail` that validates format specifiers appearing after the colon character, using an eight-stage state machine to enforce type-specific constraints and throwing `fmt::format_error` when specifications violate argument type rules.**

The `parse_format_specs` function serves as the core validation engine for the {fmt} library, interpreting the portion of format strings that follows the colon (`:`) and transforming raw specifier text into structured `format_specs` objects. Implemented in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) at line 1457, this constexpr function ensures that formatting options are semantically legal for the specific argument types provided, operating during both compile-time and runtime contexts.

## State Machine Architecture

Located within the `fmt::detail` namespace, `parse_format_specs` implements a linear state machine that tracks progression through eight distinct stages: `start`, `align`, `sign`, `hash`, `zero`, `width`, `precision`, and `locale`. An internal `enter_state` lambda manages transitions between these stages, verifying that each new state occurs later in the sequence than the current one and that the transition is semantically valid for the argument type.

### Fill Character and Alignment Detection

The parser first examines the initial character to determine whether it represents a fill character or a specifier token. If the look-ahead character matches an alignment token (`<`, `>`, `^`), the current character becomes the fill character; otherwise, the parser treats it directly as a format specifier. The fill character must not be `{`, and alignment tokens trigger `parse_align` to set the alignment property in the `format_specs` object.

### Sign, Alternate Form, and Zero Padding Validation

As the state machine progresses, it encounters optional sign indicators and formatting flags. The `+` character and space set `sign::plus` or `sign::space` respectively, while `-` indicates left alignment—these sign specifiers are restricted to arguments belonging to `sint_set` or `float_set`. The alternate form flag `#`, which invokes `specs.set_alt()`, and the zero-padding flag `0` are permitted only when `is_arithmetic_type(arg_type)` returns true, ensuring that these numeric formatting options apply exclusively to arithmetic types.

### Width and Precision Parsing

Width specification handles numeric literals, dynamic width via `{}`, or positional width via `{id}`. The implementation delegates to `parse_width`, which internally calls `parse_dynamic_spec` to resolve runtime values from the argument list. Precision, triggered by a `.` character followed by a number or dynamic reference, undergoes stricter validation: it is legal only for types in `float_set`, `string_set`, or `cstring_set`, preventing precision specifications on incompatible integral types.

### Locale and Presentation Type Enforcement

The `L` character enables locale-specific formatting but requires an arithmetic argument type. Presentation type characters—including `d`, `x`, `X`, `o`, `b`, `B`, `e`, `E`, `f`, `F`, `g`, `G`, `a`, `A`, `c`, `s`, `p`, and `?`—map to specific `presentation_type` enum values. Each mapping validates that the argument type belongs to an appropriate type set; for example, integer presentations require `integral_set` membership, while string presentations require `string_set` or `cstring_set` membership.

## Error Handling and Type Safety

When validation rules are violated, `parse_format_specs` invokes `report_error("invalid format specifier")`, which throws a `fmt::format_error` exception. This mechanism operates during both compile-time and runtime evaluation, ensuring that malformed specifiers trigger immediate failure rather than producing undefined behavior. The function returns only after successfully populating a `format_specs` object with fully validated parameters.

## Practical Implementation Examples

The following examples demonstrate how `parse_format_specs` interprets various format specifications according to the validation rules:

```cpp
#include <fmt/core.h>
#include <fmt/format.h>

int main() {
    // Integer with hexadecimal presentation and zero-padding
    fmt::print("{:08x}\n", 255);          // → 000000ff
    
    // Floating-point with locale-aware formatting and precision
    fmt::print("{:L.2f}\n", 1234.5);      // → 1,234.50 (locale-dependent)
    
    // String with custom fill and center alignment
    fmt::print("{:*^10}\n", "hi");        // → ***hi****
    
    // Dynamic width specification
    fmt::print("{:{}}", 42, 5);           // →    42
}

```

These calls exercise the parser's handling of alignment flags, type-restricted specifiers, and dynamic argument resolution.

## Summary

- **`parse_format_specs`** is a constexpr function in `fmt::detail` located in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) (line 1457) that parses the colon-separated portion of format strings
- It implements an eight-stage state machine (`start` → `align` → `sign` → `hash` → `zero` → `width` → `precision` → `locale`) via an `enter_state` lambda to enforce ordering constraints
- Type validation restricts sign specifiers to numeric types (`sint_set`, `float_set`), precision to floats and strings (`float_set`, `string_set`, `cstring_set`), and alternate form to arithmetic types
- Errors trigger `fmt::format_error` through the `report_error` mechanism, providing early failure for malformed input
- The function supports both compile-time and runtime format string validation, enabling static analysis of format correctness

## Frequently Asked Questions

### What triggers a format_error in parse_format_specs?

Invalid state transitions, type mismatches (such as specifying precision on an integer), malformed dynamic width/precision syntax, or unrecognized presentation types invoke `report_error`, which throws `fmt::format_error` to halt formatting immediately before producing output.

### Can parse_format_specs evaluate format strings at compile time?

Yes. The function is declared `constexpr`, enabling compile-time validation of format specifiers when used with `FMT_STRING` or other compile-time string contexts, allowing the compiler to catch format errors during compilation rather than at runtime.

### Which types support precision specifiers according to parse_format_specs?

The function permits precision only for floating-point types (members of `float_set`), standard strings (`string_set`), and C-strings (`cstring_set`), explicitly rejecting precision for integral types, pointers, and other non-applicable argument categories.

### How does parse_format_specs differentiate between fill characters and specifiers?

The parser performs look-ahead analysis: if the character following the potential fill character is an alignment token (`<`, `>`, or `^`), the first character is treated as a custom fill character; otherwise, the parser assumes the first character is itself a format specifier or alignment flag.