C++ Logo

std-proposals

Advanced search

Re: [std-proposals] P4021 compile_assert draft proposal for feedback

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Thu, 5 Mar 2026 15:41:05 +0100
czw., 5 mar 2026 o 15:26 Jonathan Grant <jg_at_[hidden]> napisał(a):
>
>
>
> On 05/03/2026 13:54, Marcin Jaczewski wrote:
> > czw., 5 mar 2026 o 13:41 Jonathan Grant <jg_at_[hidden]> napisał(a):
> >>
> >>
> >>
> >> On 03/03/2026 12:10, Marcin Jaczewski wrote:> wt., 3 mar 2026 o 12:57 Jonathan Grant <jg_at_[hidden]> napisał(a):
> >>>>
> >>>>
> >>>>
> >>>> On 03/03/2026 11:19, Marcin Jaczewski wrote:
> >>>>>
> >>>>> <<....>>
> >>>>>
> >>>>> as you see no function body posted there but you know that result will
> >>>>> be less than given x.
> >>>>> We could ask the compiler to solve them statically and the programmer
> >>>>> can add more constatians
> >>>>> to make it possible for dumb compiler. No need for optimization levels
> >>>>> only constexpr calcations.
> >>>>
> >>>> Hi Marcin
> >>>>
> >>>> Ok I see, so the caller() call fail with a compile error if static analysis finds it's x is >= 10 before the call to foo(x)?
> >>>> then caller() can also static analysis check return z < x. These would force both functions to put checks that their values are within bounds and handle it safely I expect?
> >>>>
> >>>
> >>> Close, right now it's only runtime checks but it can have enough
> >>> information that some compile checks
> >>> can be done.
> >>
> >> My concern would be that a pre() I expect to run at at compile time may silently degrade to be be a runtime assert().
> >> I like having a separate name compile_assert(), maybe it could be an attribute eg
> >> [[compiler]] pre();
> >> [[runtime]] pre();
> >>
> >> Although that starts to look complicated.
> >>
> >>>> I wrote out below, where I show the lines the programmer needed to add:
> >>>>
> >>>> size_t foo(size_t x)
> >>>> {
> >>>> size_t result = get_network(x);
> >>>>
> >>>> // this line added to satisfy build constraint.
> >>>> if(result >= x) throw std::runtime_error;
> >>>> return result;
> >>>> }
> >>>>
> >>>> void caller()
> >>>> {
> >>>> size_t x = get_val();
> >>>>
> >>>> // this line added to pass constraint.
> >>>> if(x >= 10) throw std::runtime_error;
> >>>>
> >>>> size_t z = foo(x);
> >>>>
> >>>> std::cout << z;
> >>>> }
> >>>>
> >>>
> >>> Yes, we could require that the programmer have explicit checks for
> >>> this too, but `get_val` has some
> >>> constraints on its return value that would make this check not needed,
> >>> but if the function has
> >>> changed (like return bigger range) then the compiler could fail to compile it.
> >>>
> >>> I think we could require the compiler to do basic folding like `x <
> >>> 10` and `z < x` and conclude that
> >>> `z < 10`.
> >>
> >> My thought was static analysis is more about proving the program is correct and safe. The optimizer does constant propagation.
> >> I know I hijacked the optimizer to find risky branches, and put a function call in the unsafe branch location, so I get a build error when the function is missing or [[gnu:error]].
> >>
> >> How would these pre(), post() differ from the proposed compile_assert() reliance upon the Optimizer? I think static analysis would also require a control-flow-graph, and many compilers don't have a static analyser. I recall David Malcolm added some GCC. I noticed eg nonnull attribute doesn't get propagated fully yet.
> >>
> >
> > Because they do not need an optimizer and inlining? Only thing is
> > constexpr calculation that is always required for any C++ compiler in
> > any mode past C++11.
> > If we stick to only basic operations like `<,>,!=,==` compiler can
> > change `pre(x < 10)` to `temp_x = MAX_INT; temp_x = std::min(temp_x,
> > 10 - 1);` and then put this
> > `temp_x` to the next precondition. And all this can be done locally
> > and do not need to know the external part of the codebase.
> > And at some point put this `temp_x` to `static_assert` to check if the
> > result still makes sense and not something like `temp_x < temp_x`.
> > All compilers should have the same output but if users do not provide
> > enough data (or format that compiler can recognize) then we will have
> > compiler error in every compiler.
> > We can start with very basic operations like comparing with fixed
> > values but in further standard we could expand to more complex cases
> > like we did with constexpr .
>
> That sounds good. Would it need to do some sort of control flow analysis, rather like the inlining the optimizer does?

Probably not in the initial version, this is more "calcaution" than
"analysis", if code has `if` or loops that
alter `x` then the user would need to add inline constraints that
would inform the compiler what the final result will be.
Like:

```
const auto t = x;
foo(&x);
while (process(&x)) { } //Turing complete...

contract_assert(x < t * 20);
```

>
> Kind regards
> Jonathan
>

Received on 2026-03-05 14:41:19