C++L is intended to become a genuine proof-aware C++ superset, not merely an annotation system around C++.
The roadmap therefore prioritizes semantic correctness before language breadth.
This document describes implementation order, not a reduction in the final language goal.
C++L V1 is complete when the language can demonstrate the entire core workflow:
formal Law
↓
C++L implementation
↓
proof obligations
↓
mechanically checked proof
↓
proof erasure
↓
ordinary C++
↓
Clang / LLVM
↓
native binary
V1 must demonstrate that this workflow is sound enough to build real software against.
Define the mathematical and language core before optimizing tooling.
Deliverables:
- core proposition syntax
- proof-term representation
- equality
- dependent function types
- universal quantification
- existential quantification
- case analysis over C++ types
- induction principles
- proof-only mathematical domains
- refinement propositions
- normalization semantics
- termination semantics
- explicit trusted assumptions
- proof erasure semantics
Required documents:
SPEC.mdFOUNDATIONS.mdTRUST.md
Exit criterion:
The core calculus can be described independently of the production compiler.
Implement the smallest useful proof checker.
Responsibilities:
- validate core types
- validate propositions
- validate proof terms
- validate equality
- validate substitution
- validate dependent application
- validate quantification
- validate induction
- validate refinements
- validate normalization evidence
Non-responsibilities:
- C++ parsing
- optimization
- AI integration
- IDE features
- full automation
- code generation
Exit criterion:
valid proof → accepted
invalid proof → rejected
malformed proof → rejected
with extensive adversarial tests.
Create a stable verification intermediate representation.
The VIR should separate:
C++ syntax
from
logical meaning
The VIR should model:
- values
- types
- propositions
- control flow
- state
- function contracts
- proof obligations
- trusted assumptions
- unsafe boundaries
Exit criterion:
Simple C++ functions can be represented as proof obligations without depending on surface syntax.
Integrate with Clang rather than reimplementing C++.
Required capabilities:
- source locations
- Clang AST access
- resolved C++ types
- overload resolution results
- template instantiation information
- constexpr results where soundly usable
- object lifetime information where available
- control-flow information
- diagnostics mapping
Exit criterion:
Ordinary supported C++ can be consumed using Clang semantics while C++L retains its own verification semantics.
Implement actual C++L syntax.
Initial constructs:
law
proves
proof
pure
verified
ghost
unsafe
trusted
where
expects
ensures
decreases
invariant
cases
inductioncases and induction are proof statements only. C++L adds no data-type declarations or runtime pattern matching.
Exit criterion:
C++L is syntactically a genuine C++ superset rather than an annotation convention.
Current sequence: single-return verified functions and verified-call contract
composition, conditionals with path obligations and integer comparisons, and
locals, assignments and their updates, unsigned machine arithmetic with
kernel-checked linear order reasoning, and while/for loops with explicit
invariants (partial correctness) are prototyped. The formal language is now
under way: explicit equality, universal quantification, implication, conjunction,
disjunction and equivalence are prototyped as propositions, and formal operands
compose through them. Refinement and indexed refinement types are prototyped: they
declare a verification-level type over an ordinary C++ base type, lower to the
alias the program keeps, make membership an obligation wherever a value enters one -
a declaration, an assignment, a verified call's argument, a return - and treat
crossing between two of them as the implication between their predicates. Next in
that core are existential quantification with its proof surface,
induction and termination. Scalar reference storage, void functions, alias
invalidation and verified call post-state are now prototyped together with their
refinement crossings. Signed arithmetic, division and integral conversions are
prototyped with their defined-behavior obligations (RFC 0019). General object
and pointer memory reasoning, and SMT remain incomplete. Trust propagation
is implemented within a translation unit: a proof may name a trusted law, is
checked relative to it, and the trust report lists every proven claim with the
trusted laws it rests on. Contracts, with that closure, now cross translation
units through verification interfaces (RFC 0017, SPEC.md Annex L.2.1), which
record what a unit proved without carrying evidence to re-check; transporting
evidence, and authenticating interfaces, come later. Trusted memory propositions
are not started. See STATUS.md for the supported fragment.
Implement:
- Laws
- preconditions
- postconditions
- proof declarations
- proof reuse
- dependency tracking
- trust propagation
Example:
law identity<T>(T x)
proves (id(x) == x);Exit criterion:
A failing implementation cannot compile as fully verified when it violates a Law.
Implement practical value-dependent typing.
Initial target:
Vector<T, n>
Fin<n>
type Percentage = int where self >= 0 && self <= 100;Required:
- introduction rules
- elimination rules
- conversion
- runtime validation boundaries
- erased dependent information where applicable
Exit criterion:
Value-dependent relationships participate in real type checking and proof checking.
Case analysis is implemented as a representation-independent engine over
decomposition providers (RFC 0013), and the formal value model that the
providers needed — abstract nominal values with checked component projection —
is implemented with it. Scoped enumerations, std::variant, std::optional,
std::expected, pointers and every product form (records, std::pair,
std::tuple, std::array, built-in arrays) each decompose, and nesting
composes across them generically. cases and decompose also split a verified
body's path over values that can change, with case facts bound to the version
they were read at, so the storage model's own versions invalidate them
(SPEC.md 20.7). STATUS.md records the details.
What decomposition still leaves at PROTOTYPE: omitted impossible cases and
impossible runtime paths. omit label by contradiction e; (GRAMMAR.md 5.7)
discharges a case through the ordinary proof system rather than letting a
provider guess it, and contradiction e; in a verified body claims a runtime
path cannot occur (VERIFIED-045). Each is an obligation of its own, under its
own origin (SPEC.md CASE-012), discharged by one mechanism. A contradiction
closes a goal of any shape, structured-value equalities included, by falsity
elimination.
The reach of a split grows with what verified bodies model, not with the case
engine: writing a std::optional or std::variant, reassigning a pointer local,
and reading a local aggregate as one value are storage-model work, and a split
over them follows as soon as they exist.
None of this delivers induction or recursive proof admission.
Implement, over ordinary C++ types:
- induction (
induction) for machine integers and well-founded C++ structures - impossible runtime paths beyond the
PROTOTYPEclaim (VERIFIED-045), such as a claim over values a path learns through a pointer - recursive proofs
- termination checking
- proof-only mathematical domains
@N,@Z,@Seq<T>,@Set<T>,@Map<K, V>, and explicit conversions into them from machine values
Example:
proof add_zero(unsigned x)
proves (add(x, 0u) == x)
{
induction x;
}Exit criterion:
C++L can prove universal properties of C++ values without enumeration and without redeclaring C++ types.
Add verification-condition generation for ordinary systems-style code.
Required:
- assignments
- branching
- loops
- function calls
- mutable state
- invariants
- pre/postconditions
- weakest-precondition or equivalent reasoning
Member functions: a statically bound member function is prototyped as a verified
callable over its implicit object's storage, with member writes, aliasing and
member calls on the common storage model (docs/rfcs/0018-verified-member-functions.md).
Next are old(...) over the implicit object, override substitutability for
virtual functions, constructors and destructors, member functions of class
templates, members of container type, and the disjointness of an object from a
reference argument where Clang resolves it, as between a local object and a
reference parameter's referent (tests/fixtures/cross_feature/client.cpp,
first_copied).
Exit criterion:
Useful imperative C++ can be verified without rewriting it as a purely functional language.
Implement correct reasoning for:
- fixed-width integers
- overflow
- shifts
- conversions
- signedness
- division
- bitvectors
Provide explicit semantics where useful:
Checked<T>
Wrapping<T>
Saturating<T>Current sequence: unsigned + - * as the ring modulo 2^width with linear
order reasoning (RFC 0006), and signed + - * and unary -, /, % and
integral conversions with their definedness obligations (RFC 0019), are
prototyped. Next are products of two bounded unknowns, which need a nonlinear
certificate step, then shifts and bitwise operators with their own obligations,
then Checked<T>, Wrapping<T> and Saturating<T>.
Exit criterion:
Mathematical proofs cannot silently assume arithmetic semantics different from runtime C++.
This is one of the most important systems milestones.
Storage generations (RFC 0020) are the first lifetime rule in verified bodies: a standard container's views and element references end where its storage may be reallocated, shrunk, replaced or moved from, a use after is refused, and a view is formed only over a container that outlives it.
Implement proof rules for:
- object lifetime
- references
- pointers
- nullability
- pointer provenance
- ownership
- borrowing or equivalent restrictions
- aliasing
- mutation
- moves
- destruction
- arrays
- bounds
Exit criterion:
Verified memory safety claims correspond to actual C++ object and memory behavior.
Create explicit obligations for relevant C++ undefined behavior.
At minimum:
- signed overflow
- invalid shifts
- division by zero
- null dereference
- bounds
- lifetime
- use-after-free
- invalid references
- uninitialized reads
- invalid pointer arithmetic
- invalid casts
- aliasing violations
Signed overflow, division by zero, the least value divided by -1 and unrepresentable conversions are obligations today, owed on the path that evaluates the operation (RFC 0019). So are bounds at every modeled subscript of an array, a capability region and a standard container (RFC 0014, RFC 0016, RFC 0020), and, for the container subset, the storage generation a view or an element reference was formed at (RFC 0020). The rest of the list is not started or belongs to the memory model.
Exit criterion:
Verified regions cannot silently depend on UB.
Add proof automation after the formal core is stable.
Potential automation:
proof auto;
proof simplify;
proof arithmetic;
proof rewrite theorem;
proof induction x;
proof contradiction;Integrations MAY include:
- cvc5
- Z3
- custom simplifier
- congruence closure
- arithmetic solvers
- bitvector solvers
Exit criterion:
Common proof obligations require minimal manual proof code without weakening the kernel model.
Reduce dependency on trusted automation.
Preferred direction:
solver
↓
proof/certificate
↓
independent checker
Exit criterion:
Solver trust is minimized and clearly reported.
Implement verified proof erasure.
Erase:
- proofs
- ghost state
- theorem-only values
- compile-time-only indices where runtime representation does not require them
Required properties:
- no change in observable runtime behavior
- no removed runtime validation
- no new UB
- stable ABI where promised
Exit criterion:
Verified C++L produces clean ordinary C++ suitable for normal Clang/LLVM optimization.
Current sequence: std::array, std::vector, std::string and
dynamic-extent std::span are prototyped as the verified sequence subset
(RFC 0020, SPEC.md J.17): a container is a length and element places at a
storage generation, its operations are trusted library summaries over that
length (TRUST.md 28.1), and every claim resting on one says so in the trust
report. Iterators, range-for, algorithms, std::string_view, subspan,
static-extent spans, the rest of each container's members and element types
beyond integers and bool are next; std::optional and std::variant read
through the case engine (Phase 7) but are not yet written.
Provide verified models for common abstractions.
Priority candidates:
- primitive integer types
std::arraystd::spanstd::optionalstd::variantstd::vector- strings
- smart pointers
- standard algorithms
Exit criterion:
Real applications can use common C++ facilities without dropping immediately into unverified code.
Define verified interface specifications for:
- C
- Objective-C++
- JNI
- N-API
- WASM
- operating-system APIs
Exit criterion:
Foreign calls have explicit proof/trust boundaries.
Only after the sequential memory model is solid.
Required design areas:
- threads
- atomics
- memory ordering
- synchronization
- race freedom
- ownership transfer
- concurrent invariants
Exit criterion:
C++L does not apply unsound sequential reasoning to concurrent C++.
Implement:
cppl build
cppl check
cppl prove
cppl explain
cppl trust-reportAlso:
- LSP semantic tokens for a range or as a delta, and interactive proof state
(incremental sync, diagnostics, formatting, code actions, hover, completion,
signature help, definition, declaration, type definition, implementation,
references and highlights, the document outline, folding and selection
ranges, inlay hints, navigation from proof statements to what they name,
verification status and each obligation's goal, background compiles, a
workspace index for workspace symbols and references in closed files, and
rename are implemented; see
STATUS.md) - IDE diagnostics
- proof goals
- counterexamples
- quick fixes
- theorem navigation
- proof dependency graph
Exit criterion:
Verification is practical during normal development.
Expose machine-readable proof obligations.
Required:
- structured goal representation
- structured diagnostics
- available theorem list
- assumptions
- proof state
- counterexamples
- safe patch loop
Conceptually:
AI writes implementation
↓
C++L returns proof obligations
↓
AI repairs implementation/proof
↓
kernel independently verifies
The AI itself is never trusted.
Optimize only after semantics are stable.
Targets:
- incremental verification
- content-addressed proof cache
- dependency-aware invalidation
- parallel obligation solving
- fast normalization
- reusable theorem artifacts
- minimal Clang reparsing
- deterministic caching
Verification performance must not change proof meaning.
V1 should not ship as "complete" unless all of the following core properties work together:
- real C++L syntax
- Laws
- mechanically checked proofs
- dependent or indexed relationships
- refinement types
- equality
- induction
- termination
- contracts
- explicit unsafe/trusted boundaries
- proof erasure
- C++ native output
- trust reporting
- enough C++ safety semantics to make demonstrated guarantees meaningful
Some advanced C++ constructs may initially remain outside verified regions.
That is acceptable if the boundary is explicit.
It is not acceptable to silently call them verified.
Implementation may be staged.
The semantic goal must not be weakened merely to make an intermediate milestone easier.
C++L should prefer:
small and sound
over:
broad and unsound
and then expand verified C++ coverage systematically.