[clang] [Headers] Don't declare unreachable() from stddef.h in C++ (PR #86748)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 28 12:49:04 PDT 2024


AaronBallman wrote:

> Thanks for the explanation, @AaronBallman . I think I am generally deeply confused about what should be provided by the compiler and what should be provided by the C Standard Library on any given platform. From your reply, it looks like there's no clear rule and Clang basically provides anything that seems "easy enough" to provide. I still don't understand how that works in case you do end up including a header from the platform that (re)defines `unreachable`, for example.

For C17 and earlier, the rule was that we provided everything required for freestanding by the standard, and anything else the user wanted had to come from a library the user supplied. For C23, which we're still in the process of implementing, the situation is different and we've not documented what the expectations are yet. I suspect we're going to end up requiring the user to provide their own freestanding library implementation and the compiler will provide only the bits that the compiler has to provide (things like `limits.h`).

The `unreachable` macro is interesting in that it could be provided by either a CRT implementation or the compiler. The whole point to the macro is "if the expansion is reached, you have undefined behavior", which fits naturally with `__builtin_unreachable()` which the backend knows how to do optimizations around. However, a CRT implementation could decide the macro expands to `*(int *)nullptr` or the likes, which also triggers undefined behavior.

> The same problem also applies today to e.g. `size_t` and anything else provided by the Clang builtin headers. If a platform decides to define `size_t` differently than what the Clang builtin headers define it to, I guess we run into issues? I assume it's not something that happens often because it's pretty unambiguous what these typedefs should be, but still.

If the platform defines `size_t` to be different from the Clang builtin headers define it to, there are Serious Problems™ because `sizeof()` suddenly returns strange things, interfaces like `printf` will find ABI issues with `%z`, etc.

> Anyway, this might turn out to be nothing more than a documentation issue, but in any case I think it would be valuable to write down how this is intended to work somewhere (even if only in a comment), since I suspect it's not clear to most people. I work on the C++ Standard Library and I don't understand how this works in our own implementation :-)

Definitely agreed that we need to document this, but we need to figure out what we want to document in the first place -- some of this is new-ish territory because of the additional interfaces. `unreachable` is morally similar to `offsetof` in that it's a macro interface where the implementation can give better results by expanding to a builtin than a library is likely to be able to give via a naive implementation, but the interfaces *can* be provided by a CRT. So which one *should* win? Today, if something else defined `offsetof` or `unreachable` before including `stddef.h`, Clang's headers won't bother re-defining the macro.

I think we may need to look at what existing freestanding CRTs and hosted CRTs expect to help give us a path forward?

https://github.com/llvm/llvm-project/pull/86748


More information about the cfe-commits mailing list