Supported C++ Feature Matrix
cppbolt implements a defined, correctness-oriented subset of C++17. Every supported feature is covered by automated corpus tests and pinned by cryptographic golden hashes. Features outside the subset are either explicitly rejected with clear diagnostics or tracked as planned future extensions.
The baseline test status is tracked in tests/PASSING.txt. Run the test runner to verify status locally:
cargo run --bin cppbolt-testrunner -- target/release/cppbolt-cli
Feature Matrix
| Feature | Status | Notes | Test |
|---|---|---|---|
Scalar Types (int, long long, short, char, float, double, bool) | Done | ILP32 32-bit data model; unsigned overflow wrapping; binary literals (0b), octal, and single-quote digit separators (') | tests/c_basics/types/arithmetic.cpp, tests/c_basics/types/numeric_literals.cpp, tests/c_basics/types/long_long.cpp, tests/c_basics/types/floats.cpp |
| Pointers & Conversions | Done | 32-bit Wasm i32 addresses; array decay; nullptr (std::nullptr_t); C++17 null pointer constants (0, 0u); multi-level const qualification rules; implicit object pointer to void*; explicit static_cast for void* to typed pointer | tests/c_basics/pointers_arrays/pointers_arrays.cpp, tests/c_basics/types/pointer_conversions.cpp |
| String Literals | Done | Typed as const char[N] with trailing null terminator (sizeof("hello") == 6); decay to const char*; immutable (rejected for char*) | tests/c_basics/types/pointer_conversions.cpp |
| Function Pointers | Done | Indirect calls via WebAssembly function table; comparator callbacks | tests/classes_oop/methods/function_pointer_comparator.cpp |
| Multi-Dimensional Arrays | Done | Nested dimensions wrap inside-out; contiguous row-major layout; pointer-to-array decay | tests/c_basics/pointers_arrays/multidim_arrays.cpp, tests/c_basics/pointers_arrays/multidim_pointer_deref.cpp |
Lvalue References (T&) | Done | Reference binding, parameters, reference return values | tests/classes_oop/statics_namespaces/references.cpp, tests/classes_oop/methods/member_reference_return.cpp |
const Qualifiers | Done | const variables, const pointers, const member methods | tests/c_basics/types/const_qualifiers.cpp, tests/classes_oop/methods/const_methods.cpp |
auto Type Deduction | Done | Local variable and reference type deduction | tests/c_basics/types/auto_type.cpp |
Type Aliases (typedef, using) | Done | Standard typedef and C++11 using Alias = Type; | tests/c_basics/types/auto_type.cpp |
| Multi-Declarator Declarations | Done | Comma-separated declarators sharing base specifiers (int *p, q = 2;) | tests/c_basics/misc/multi_declarator.cpp |
| Array Function Parameters | Done | Parameter adjustment decaying int arr[] and int arr[N] to int* arr | tests/c_basics/pointers_arrays/array_parameter_decay.cpp |
| Enums | Done | Scoped (enum class) with qualified lookup (Scope::Val) and unscoped enum | tests/c_basics/enums/enums.cpp, tests/c_basics/enums/scoped_enums.cpp |
Control Flow (if, switch, loops) | Done | if/else, ternary ?:, while, for, do-while, switch/case/default (with enum & const-expr case labels) | tests/c_basics/control_flow/control_if_else.cpp, tests/c_basics/control_flow/control_loops.cpp, tests/c_basics/control_flow/switch_enum_case.cpp |
| Functions & Overloading | Done | Exact match > reference binding > promotion > conversion; default arguments; global init reachability | tests/c_basics/functions/functions_call.cpp, tests/c_basics/functions/constexpr_global_init_call.cpp, tests/c_basics/functions/overload_resolution.cpp |
| Static Variables | Done | Function-local statics with arguments; class static members | tests/classes_oop/statics_namespaces/function_local_statics.cpp, tests/classes_oop/statics_namespaces/static_members.cpp |
| Structs & Classes | Done | Aggregate init, member variables/methods, access control | tests/classes_oop/structs/struct_basic.cpp, tests/classes_oop/structs/initializer_lists.cpp |
| Constructors & Destructors | Done | Default, parameterized, copy, delegating (C() : C(x) {}); initializer list ordering; implicit synthesis for trivial/empty classes and prvalues (Value().get()); global parenthesized construction | tests/classes_oop/constructors_destructors/copy_semantics.cpp, tests/classes_oop/constructors_destructors/delegating_constructor.cpp, tests/classes_oop/constructors_destructors/prvalue_default_constructor.cpp, tests/classes_oop/statics_namespaces/global_constructor_args.cpp |
| Conversion Operators | Done | User-defined conversion operators operator T() const with explicit qualification checks; disambiguated from copy constructors | tests/classes_oop/operators/conversion_operator.cpp, tests/classes_oop/operators/regress_user_conversion_param.cpp, tests/classes_oop/operators/regress_byval_param_conversion.cpp |
| Ref-Qualified Methods | Done | Lvalue and rvalue ref-qualified member functions (get() &, get() &&) with receiver value-category dispatch | tests/classes_oop/methods/ref_qualified_methods.cpp |
| Structured Bindings | Done | Aggregate decomposition (auto [a, b] = p;, auto&, const auto&) | tests/classes_oop/structs/structured_bindings.cpp |
| RAII Lifecycle & Scope Cleanups | Done | Cleanups on scope exit, early return, break, continue, statement temporaries | tests/classes_oop/memory_raii/class_raii.cpp, tests/classes_oop/memory_raii/raii_early_return.cpp, tests/classes_oop/memory_raii/raii_temporaries.cpp |
| C++17 Copy Elision | Done | Prvalue construction in place (direct init and function return) | tests/classes_oop/memory_raii/prvalue_elision.cpp, tests/classes_oop/memory_raii/direct_initialization_elision.cpp |
Dynamic Memory (new / delete) | Done | Single object and array new[]/delete[]; placement new | tests/classes_oop/memory_raii/new_delete.cpp, tests/classes_oop/memory_raii/new_delete_object_arrays.cpp, tests/classes_oop/memory_raii/placement_new.cpp |
| Single & Linear Inheritance | Done | Base subobjects, slicing, constructor/destructor chains | tests/classes_oop/inheritance/single_inheritance.cpp, tests/classes_oop/inheritance/multi_level_inheritance.cpp |
| Virtual Functions & Polymorphism | Done | Vtable dispatch, virtual destructors, pure virtual (= 0) | tests/classes_oop/inheritance/virtual_functions.cpp, tests/classes_oop/inheritance/virtual_destructor.cpp, tests/classes_oop/inheritance/pure_virtual.cpp |
| Namespaces | Done | Nested namespaces, using namespace, qualified lookups | tests/classes_oop/statics_namespaces/namespaces_comprehensive.cpp |
| Operator Overloading (Binary & Compound) | Done | +, -, *, /, %, ==, !=, <, <=, >, >=, <<, >>, &, ^, |, =, +=, -=, *= | tests/templates_operators/op_overload_binary.cpp, tests/classes_oop/operators/chained_compound_assign.cpp |
| Operator Overloading (Prefix & Subscript) | Done | Unary +, -, !, ~, prefix ++/--, subscript [], operator bool() | tests/templates_operators/op_overload_unary.cpp, tests/templates_operators/op_overload_subscript.cpp, tests/classes_oop/operators/contextual_bool_comprehensive.cpp |
| Preprocessor | Done | #define (function/object, #, raw ##), #undef, #include, #if/#elif, #error, #warning, \ | tests/c_basics/preprocessor/preprocessor.cpp, tests/c_basics/preprocessor/macro_rescan.cpp, tests/c_basics/preprocessor/macro_token_paste_raw.cpp, tests/c_basics/preprocessor/warning_directive.cpp |
C Standard I/O (<cstdio>) | Done | printf (all conversions %d, %i, %u, %o, %x, %X, %c, %s, %e, %E, %f, %g, %G), sprintf, snprintf, puts | tests/c_basics/io_printf/printf_conversions.cpp, tests/c_basics/io_printf/printf_table.cpp, tests/mini_stl/cstdio_basic.cpp |
C++ Streams (<iostream>) | Done | std::cout, std::cin, std::getline, custom stream operators | tests/mini_stl/iostream_basic.cpp, tests/mini_stl/iostream_cin.cpp, tests/mini_stl/stream_operator_overload.cpp |
Standard String (<string>) | Done | std::string, .c_str(), .length(), .append(), concatenation | tests/mini_stl/string_basic.cpp, tests/mini_stl/string_comprehensive.cpp |
Math & Formatting (<cmath>, <iomanip>) | Done | Math intrinsics, std::abs integer overloads for long and long long, std::setprecision, std::fixed, std::setw | tests/mini_stl/cmath_basic.cpp, tests/c_basics/functions/std_abs_long.cpp, tests/mini_stl/iostream_precision_after_fixed.cpp |
Templates & Member Templates (template <typename T>) | Done | Class templates, out-of-class member method definitions, member function templates, dependent member type aliases, lazy method instantiation, multi-arity function overloads, and deduction for callables and pointers | tests/templates_operators/template_class_basic.cpp, tests/templates_operators/template_class_methods.cpp, tests/templates_operators/template_func_basic.cpp, tests/templates_operators/template_multi_param.cpp, tests/templates_operators/template_pair.cpp, tests/mini_stl/pair_basic.cpp |
Containers: Vector & Utility (<vector>, <utility>) | Done | std::vector (dynamic growth, capacity doubling, element access, iterators, brace initialization, push_back self-aliasing protection, RAII lifecycle cleanup), std::pair and std::make_pair | tests/mini_stl/vector_basic.cpp, tests/mini_stl/vector_brace_init.cpp, tests/mini_stl/vector_objects.cpp, tests/mini_stl/vector_aliasing.cpp, tests/mini_stl/iterators_range_for.cpp, tests/mini_stl/combined_integration.cpp |
Algorithms (<algorithm>) | Done | std::sort (default comparator and custom functor), std::reverse, std::min, std::max, std::swap | tests/mini_stl/algorithm_basic.cpp, tests/mini_stl/algorithm_sort.cpp, tests/mini_stl/sort_comparator.cpp |
Associative Containers (<map>, <set>) | Done | Balanced binary search tree (detail::AVLTree), bidirectional iterators, insertion, lookup, range traversal, deletion, and differential fuzzing | tests/mini_stl/map_basic.cpp, tests/mini_stl/set_basic.cpp, tests/mini_stl/differential_fuzz.cpp |
| Nested Classes & Structs | Done | Member classes in non-template and template classes, access control validation, fixed-point dependent type alias resolution, and scoped member registration | tests/classes_oop/structs/nested_classes.cpp, tests/classes_oop/structs/nested_classes_scopes.cpp, tests/templates_operators/template_nested_classes.cpp, tests/templates_operators/template_nested_alias_chain.cpp |
Dependent Types (typename) | Done | Disambiguation of dependent member types (typename T::Type), rejection of unqualified typename | tests/templates_operators/typename_dependent_syntax.cpp, tests/negative/typename_unqualified.cpp |
Range-Based for Loops | Done | C++11 for (decl : range) over fixed-size arrays (1D and multi-dimensional) and classes with .begin()/.end(); supports auto, const auto, auto&, const auto& | tests/c_basics/pointers_arrays/range_for_array.cpp, tests/mini_stl/range_for_string.cpp |
Overloaded Postfix ++ / -- | Done | Overloaded operator++(int) and operator--(int) distinguish postfix from prefix via dummy int parameter | tests/classes_oop/operators/operator_postfix_incdec.cpp |
Overloaded ->, *(), () | Done | Smart-pointer and functor operators: operator-> (recursive chaining with cycle detection), dereference operator*(), and function call operator() | tests/classes_oop/operators/operator_smart_pointer.cpp, tests/classes_oop/operators/operator_arrow_chaining.cpp, tests/classes_oop/operators/operator_call_functor.cpp |
| Lambda Expressions (C++17) | Done | [], [x], [&x], [=], [&], mutable, trailing return type (-> T), return type deduction, auto storage, direct invocation, unary + decay, and implicit conversion of captureless lambdas to C function pointers (R (*)(P...)) including return targets | tests/classes_oop/lambdas/lambda_basic.cpp, tests/classes_oop/lambdas/lambda_default_captures.cpp, tests/classes_oop/lambdas/lambda_function_pointer.cpp, tests/classes_oop/lambdas/lambda_return_fn_ptr.cpp, tests/classes_oop/lambdas/lambda_range_for_capture.cpp, tests/classes_oop/lambdas/lambda_unary_plus.cpp |
| List Initialization & Aggregates | Done | Direct-list (T x{...}), copy-list (T x = {...}), empty brace value initialization ({}), namespace-scope (global) brace initialization, aggregate base subobjects, brace elision, narrowing conversion checks ([dcl.init.list] p7), dynamic allocation (new T{...}, new T[n]{...}), typed temporaries (Type{...}.get()), and explicit constructor enforcement | tests/classes_oop/structs/brace_init_scalars.cpp, tests/classes_oop/structs/brace_init_classes.cpp, tests/classes_oop/structs/brace_init_aggregates.cpp, tests/classes_oop/structs/brace_init_brace_elision.cpp, tests/classes_oop/structs/brace_init_temporaries.cpp, tests/classes_oop/structs/brace_init_dynamic_new.cpp |
std::initializer_list | Done | Compiler-created contiguous backing arrays, begin()/end()/size(), constructor preference for braced containers (ranked by exact, promotion, and standard conversions), empty-brace fallback to an initializer-list constructor, nested brace lists, namespace-scope lists, auto deduction, homogeneity checks, narrowing diagnostics, and parenthesized braced arguments | tests/mini_stl/initializer_list_basic.cpp, tests/mini_stl/vector_brace_init.cpp, tests/mini_stl/initializer_list_ctor_ranking.cpp, tests/mini_stl/initializer_list_nested.cpp, tests/mini_stl/initializer_list_global.cpp, tests/negative/initializer_list_narrowing.cpp, tests/negative/initializer_list_mismatched_types.cpp |
Const-Ref Method Overloading (T m() const &) | Planned | const methods supported; const & method ref-qualifiers are rejected with const overloading is not supported | tests/negative/const_overload_unsupported.cpp |
Namespace Aliases (namespace A = B;) | Done | C++17 namespace alias declarations at namespace, file, and block scope with chained and qualified resolution | tests/classes_oop/statics_namespaces/namespace_aliases.cpp, tests/negative/namespace_alias.cpp |
Extended Casts (reinterpret_cast) | Done | C++17 reinterpret_cast<T>(expr) across scalar integers, pointers, and reference types within the ILP32 data model; bit-preserving conversions between integers and pointers, pointer conversions without adjusting offsets, and byte inspection; disallows scalar float conversions | tests/c_basics/types/reinterpret_cast.cpp |
| Functional Casts & Value Initialization | Done | Value initialization of scalars and typedef aliases (T(), zero-initialized) and explicit functional conversions (Type(val)) | tests/c_basics/types/value_init_scalar.cpp |
| Scalar Pseudo-Destructors | Done | No-op pseudo-destructor calls on scalar types (p->~T(), x.~T()), preserving receiver evaluation and side effects | tests/c_basics/types/pseudo_destructor_scalar.cpp |
| Destructors via Typedef Aliases | Done | Explicit destructor calls resolved through typedef aliases (sp->~ClassT()), verifying target class identity | tests/classes_oop/constructors_destructors/destructor_via_typedef.cpp |
| Multiple & Virtual Inheritance | Out of Scope | Single/linear inheritance supported; multiple and virtual base specifiers are rejected | tests/negative/multiple_inheritance.cpp, tests/negative/virtual_inheritance.cpp |
Exceptions (throw) | Diagnosed | throw keyword recognized and rejected with explicit target diagnostic (C++ exception handling ('throw') is not supported on this WebAssembly target) | tests/negative/throw_unsupported.cpp |
Known Limitations & Design Rules
1. Language Semantics & Edge Cases
- Copy Elision: Prvalue initialization is elided as guaranteed by C++17 (
T x = T(1);). However, return of named local variables requires running the copy constructor. - Null Pointer Constants & Pointer Conversions:
- Integer literal zeroes (
0,0u) andnullptr(std::nullptr_t,decltype(nullptr)) qualify as null pointer constants. Zero-valued variables, non-zero integers, andfalseare rejected. - Qualification conversions require every subsequent indirection level to be
constwhen addingconstto an intermediate level (int**converts toconst int* const*, but notconst int**). - Object pointers convert implicitly to
void*; convertingvoid*to a typed pointer requiresstatic_cast<T*>.
- Integer literal zeroes (
- String Literal Semantics: String literals have type
const char[N]with a null terminator (sizeof("hello") == 6). They decay toconst char*for call arguments and pointer assignments, and cannot bind tochar*. - Multiple and Virtual Inheritance: Explicitly rejected at parse time:
- Second base specifier yields:
multiple inheritance is not supported virtualbase specifier yields:virtual inheritance is not supported
- Second base specifier yields:
- Operator Overloading Boundaries: User-defined operator overloads for arithmetic, relational, bitwise, assignment, subscript
[], smart-pointer->, dereference*(), functor(), postfix++/--, and conversion operatorsoperator T()are supported. Method ref-qualifier overloading with const-lvalue references (const &) is explicitly rejected withconst overloading is not supported. - Chained
operator->& Cycle Detection: In accordance with C++17, member access via->recursively resolves through chainedoperator->()overloads returning class objects or references until a raw struct pointer is reached. Cycle detection prevents compile-time recursion loops (circular operator-> delegation on '<class>'), and recursion depth is budgeted to 128 hops. - C++17 Lambda Expressions: Lambdas desugar into anonymous closure structs (
__lambda_N) holding captured state as either by-value copies or references. The synthesizedoperator()isconst-qualified unless markedmutable, enforcing immutability on by-value captures. Return types can be explicitly annotated with trailing return syntax (-> T) or automatically deduced fromreturnstatements. Captureless lambdas ([]) synthesize a static__invoketrampoline enabling implicit conversion to standard C function pointers (R (*)(P...)), including as return statement targets and via unary+decay (+[](){}). Default captures (=,&) must strictly appear first in the capture list, and free-variable discovery traversesRangeFor,StructuredBinding, and nestedLambda/Newconstructs. - List Initialization & Aggregates: Braced initializer lists (
{...}) work across variable declarations, namespace-scope (global) variables, constructor member initializers (: member{val}), returns, call arguments, assignments, typed temporaries (Type{args...}.member()), and heap allocations (new T{...},new T[n]{...}).- Direct-list initialization allows selecting
explicitconstructors; copy-list initialization rejects them. Empty braces ({}) value-initialize scalars and enums to zero, clear aggregate fields, or call default constructors. - Under C++17 aggregate rules, classes qualify as aggregates when they have no user-declared constructors, no private or protected non-static data members, no virtual functions, and no virtual or private base classes. Public non-virtual bases initialize as initial subobjects, either with nested braces (
Derived{{base_args}, derived_args}) or flattened across the outer list. - Narrowing conversion checks follow C++17 [dcl.init.list] p7, rejecting conversions from floating-point to integer,
doubletofloat(unless an exact constant literal), and between integer types with sign changes or smaller ranges. Compile-time constant expressions, including negative integer literals, are accepted when the value fits the destination type. - Single-object
new T{...}direct-initializes the heap object. Arraynew T[n]{...}initializes explicit elements and runs a WebAssembly loop to value-initialize omitted trailing elements up ton. - Initializer-list constructors taking
std::initializer_list<T>receive a frame-backed pointer-and-size view. The backing array stays live through the full expression; elements of local initializer-list variables are destroyed at scope exit. - Multiple viable initializer-list constructors are ranked by element conversions: exact matches beat integral promotions, which beat other standard conversions. A narrowing candidate is discarded, and its diagnostic is reported only when no viable candidate remains. Empty braces use the initializer-list constructor when the class has no default constructor.
- Nested brace lists such as
std::vector<std::vector<int>> v{{1, 2}, {3, 4}}are resolved against the chosen element type after constructor selection. - Namespace-scope lists and braced containers are initialized before
mainruns. The backing array of a namespace-scopestd::initializer_listis placed inmain's frame, which outlives every use of the list.
- Direct-list initialization allows selecting
- Extended Casts (
reinterpret_cast): Supports C++17reinterpret_cast<T>(expr)between pointer types, pointer and integer types (matching the 32-bit ILP32 pointer width), and reference types (reinterpret_cast<T&>(v)). Does not invoke user-defined conversion operators or constructors. Scalar floating-point reinterpretations by value are rejected; bit patterns of floats can be inspected via pointer or reference reinterpretation (e.g.*reinterpret_cast<uint32_t*>(&f)). - Template Core:
- Class templates and function templates support type parameters (
template <typename T>). Non-type parameters, template template parameters, variadic templates, and explicit specializations (template <>) are rejected with explicit diagnostics. - Instantiation follows a single-phase lookup model (ADR 0010). The parser preserves template declarations in the AST (
TemplateDecl), and semantic analysis resolves names and types during concrete specialization. - Type resolution recursively unwraps pointers, references, const qualifiers, and arrays, generating concrete struct layouts before calculating member access offsets.
- Non-template structs compute layouts after resolving template fields, giving fields valid offsets and sizes. Non-template functions accept and return template instance types.
- Class template member methods instantiate lazily on first call, address-of reference, or operator overload lookup (
operator[], unary operators). Unused member methods are neither typechecked nor emitted into WebAssembly. - Non-virtual class template destructors instantiate eagerly alongside virtual methods so synthesized cleanup logic can drop values on scope exit. Dynamically instantiated template classes containing fields with non-trivial destructors synthesize cleanup methods and copy operations.
- Function template overload resolution deduces type arguments from values, references, const references, top-level const pointers, and template instance arguments. Candidate registration tracks overloads sharing identical parameter counts by signature. Explicit template arguments (
func<int>(val),func<Inner<int>>(val)) override deduction and parse nested template types. Default argument expressions fill omitted trailing parameters for both free and member template functions. Exact non-template function overloads take precedence over template specializations. - Out-of-class method definitions match class template and concrete struct declarations by parameter types and const qualification, including across multi-part namespace paths (
Outer::Inner::Class::Class()). - Member template parameters shadow outer class template parameters with identical names during class instantiation.
- Expression calls on struct instances dispatch to
operator()only when an explicit call operator or member templateoperator()exists. - Nested class declarations inside class templates clone and specialize on outer template instantiation, generating qualified types (such as
Container<int>::Node), computing distinct field layouts, and registering member methods. - Nested class type specifiers (
Outer::Inner) enforce access control during type resolution. Private nested types can only be referenced from within the enclosing class, its member methods, or template specializations parameterized with the nested type. Referencing private nested types externally triggers a compile diagnostic (tests/negative/nested_type_private_access.cpp). Nested class short names remain scoped to the outer struct and do not pollute the global namespace (tests/negative/nested_class_unqualified_leak.cpp). - Chained dependent type aliases resolve iteratively to a fixed point during template specialization, supporting arbitrary alias chains without fixed loop bounds (
tests/templates_operators/template_nested_alias_chain.cpp). Member type aliases in thestdnamespace are restricted to templates actually defined withinstd. - Dependent member type specifiers require the
typenameprefix (typename Container<T>::iterator). Unqualifiedtypenameor non-type usage is rejected at parse time. - Instantiation recursion is limited to 500 levels (
template instantiation depth exceeded (limit: 500)).
- Class templates and function templates support type parameters (
2. Nesting Limits per Construct
To protect WebAssembly engine shadow stacks from exhaustion when compiling deep programs in Web Workers, the compiler enforces per-construct nesting budgets (src/depth.rs). One construct cannot exhaust the budget of another:
| Construct | Limit | Deepest Accepted Input (Native & Wasm) |
|---|---|---|
| Expressions | 4,000 | Parenthesized conditional costs 2 levels |
| Parentheses | 1,600 | 1,600 nested parentheses |
| Call Argument Lists | 1,500 | 1,500 nested calls |
| Statements | 1,600 | 1,599 nested if statements |
| Compound Blocks | 1,600 | 1,599 nested {} blocks |
| Declarations | 1,600 | 1,600 nested declarations |
| Type Expressions | 1,600 | 1,600 nested type qualifiers |
| Preprocessor Conditions | 1,600 | 1,600 nested #if conditions |
| Include Depth | 128 | 128 nested #include directives (129 is rejected) |
These limits are verified by tests/nesting.rs and tests/wasm_stack_safety.rs.
Wide left-associative expressions (sums of 20,000 terms), string concatenations (4,000 terms), and else-if chains (5,000 branches) are flattened iteratively and do not consume recursion depth.
3. Printf Runtime Specifications
The embedded printf engine (src/runtime/format.rs) supports:
- Specifiers:
%d,%i,%u,%o,%x,%X,%c,%s,%e,%E,%f,%g,%G. - Modifiers:
h,hh,l,ll, andz. - Flags:
0(zero-pad),-(left-align),+(sign),(space sign),#(alternate form). - Dynamic precision:
.*is supported. (Dynamic width*is not implemented). - Unsupported conversions:
%pand%n. - NaN and Infinities: Zero padding falls back to spaces; sign of NaN is implementation-defined.