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 14:54:40 +0100
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:
> >>> wt., 3 mar 2026 o 11:41 Jonathan Grant <jg_at_[hidden]> napisał(a):
> >>>>
> >>>>
> >>>>> On Sun, 22 Feb 2026, 11:26 Marcin Jaczewski via Std-Proposals, <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>> wrote:
> >>>>>
> >>>> <....>>
> >>>>> Beside preconditions are visible on both sides of function call even if not
> >>>>> inlined, this means you do not need to rely on opimalzier to do this job
> >>>>> as you put enough preconditions to make all checks local.
> >>>>
> >>>> Martin may I ask, re inlining, if a function has an attribute [[gnu::noinline]] in my tests I found the constant is not propagated, so the Optimizer fails to identify the constraint is met. Is there any solution?
> >>>>
> >>>> [[gnu::noinline]]
> >>>> int get_int() { return 10; }
> >>>>
> >>>> int x = get_int();
> >>>> compile_assert(x < 15, "x must be < 15");
> >>>>
> >>>> If I changed the compile_assert() to call a [[deprecated]] function, the obj file would be produced, but it would then rely upon the linker removing the compile_assert() still there.
> >>>>
> >>>> There may be some places where it's difficult to place a compile_assert().
> >>>>
> >>>
> >>> I mean THE C++ preconditions like:
> >>>
> >>> ```
> >>> size_t foo(size_t x) pre(x < 10) post(z: z < x);
> >>> ```
> >>>
> >>> 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 .

> Kind regards
> Jonathan
>
>

Received on 2026-03-05 13:54:58