C++ Logo

std-proposals

Advanced search

[std-proposals] Additional assert functionality and the Hatchling Platform

From: Adrian Johnston <adrian3_at_[hidden]>
Date: Sun, 24 Aug 2025 13:14:56 -0700
Hello all,

I recently wrote my own freestanding replacement for the C++ standard
library. I'm one of those people who started writing out C++ on a 44Mhz
processor and never was allowed to use the standard template library
because it was too bloated. In many ways this code is the exact opposite of
Boost in terms of its design. I'd like to share a few details with this
list because I think it is interesting to talk about what could be done to
improve the developer experience of the standard library. Please be warned,
I have a lot of opinions about C++ and they are nonconformist.

In this email I would like to talk about asserts. I'd like to see a lot
more features available than with pre/post/contract_assert.

I would argue there has to be support by default for making the debugger
stop on the exact line where the assert fired. There is just no excuse for
having a software engineer do unnecessary manual labour every time an
assertion fires. And students shouldn't be asked to write this themselves
when learning a new language. Currently only clang (and not gcc) can be
configured to support this perfectly.

There are also uses for having different "levels" of severity when it comes
to asserts. When I am cross compiling to an embedded target I am not going
to be able to afford all the same assertions with all the same strings
being added to the string table. At minimum that entails "debug asserts"
and "release asserts" to differentiate between the two use cases. The code
I am sharing also uses compile time string hashing in order to identify
filenames when compiled for release. (This didn't work reliably with
constexpr and you have to check the generated assembly to find that out.)
Having these kinds of build levels is also common enough that CMake has it
built in.

(As a slight aside, it would be nice to have support for string hashing in
the elf file format. That way strings could be replaced by integers in the
generated assembly and then the debugger could look up those strings in an
optional string table. There is no reason to have a huge list of human
readable names embedded in a stripped executable's string table when you
are testing code on a 16-bit processor.)

Next is the issue of formatting assert messages. It turns out to be really
handy to have debug asserts that take C-style variadic arguments and
perform printf formatting. There is an issue here with having untested
format strings and that does need to be resolved. However, by leveraging
gcc's ability to check a printf format string against its arguments I was
able to avoid any issues in my own work. This approach avoids making an
unnecessary local function call or allocating memory after an assertion
fails.

With that out of the way, let me show you some code. This is a debug
assert that implements the above:

#define hxassertmsg(x_, ...) (void)((bool)(x_) \

|| (hxloghandler(hxloglevel_assert, __VA_ARGS__), hxasserthandler(__FILE__,
__LINE__)) \

|| hxbreakpoint())

The assert handler returns true when it wants a breakpoint set.

Next is a macro that implements a release assert at a higher release level.
(hxstring_literal_hash uses some horrifying macros.)

#define hxassertrelease(x_, ...) (void)((bool)(x_) \

        || (hxasserthandler(hxstring_literal_hash(__FILE__), __LINE__), 0))

The result is adding one function call with two integer parameters to the
executable. This macro is also capable of printing formatted messages and
setting breakpoints at lower release levels. This particular version uses a
handler that is also marked noreturn.

There are more pieces of functionality needed. Any C++ library implementing
asserts is going to want the compiler to know that the release mode assert
handler or log handler cannot throw an exception. However, there is
overhead associated with "noexcept" and it is just impossible to add that
overhead everywhere an assert is used. This is something that still
requires compiler intrinsics.

The standard library also has explicit language allowing for its asserts to
operate in a manifestly const environment. It would be nice for others to
be able to access that functionality without mucking up the callstack for
every assert in the codebase.

If you made it this far, thank you. Here are some links if you want to know
more. This is the main header file for the Hatchling Platform which has
been my test bed and includes this code:

https://github.com/whatchamacallem/hatchlingplatform/blob/master/include/hx/hatchling.h

Here is the whole project and it has some overview docs. Please be kind,
this is a solo effort that is just being released to the world and I am not
trying to go head to head with the standard library over all the possible
things.

https://github.com/whatchamacallem/hatchlingplatform/

Stay tuned and I'll put something else together about developer experience
and micro-optimization. I am happy to write a formal proposal if anything
resonates with the list.

Regards,

Adrian Johnston

Received on 2025-08-24 20:15:09