[libcxx-commits] [libcxx] [libcxx] Undefine all supported C math functions (PR #94533)

Roland McGrath via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 11 17:53:47 PDT 2024


frobtech wrote:

> I think I agree with @philnik777 's comments about this being needed for every C library function.
> 
> Basically, we have to choose whether libc++ works on top of a conforming C Standard Library per the C Standard, or whether we require C++ friendliness in a C Standard Library for it to be usable with libc++.
> 
> If we support an arbitrary conforming C Standard Library, then per 7.1.4 it does seem like they are allowed to define functions as macros, which is extremely unfriendly to C++ due to namespaces amongst other things. I've come across this issue (with `memcpy` for example) several times when porting libc++ to new platforms.
> 
> So far, what I've always done was to ask the underlying C library to stop using macros because that is C++-unfriendly. However, it might be reasonable for libc++ to support that.
> 
> Doing this correctly in the general case is going to be non-trivial, though, since it basically means that we can't blindly reuse names from the C Standard Library anymore. For example, `strxfrm` isn't defined anywhere by libc++, we just reuse it from the C stdlib:
> 
> ```c++
> // <cstring>
> namespace std {
>   using ::strxfrm;
> }
> ```
> 
> If we wanted to work in spite of ยง7.1.4, we'd basically have to `#undef strxfrm` and then define it ourselves as a function. I believe the logical conclusion here is that we basically can't reuse anything from the C Standard Library, we'd have to implement everything ourselves.
> 
> This makes me wonder whether that is a viable approach. Thoughts?

You're right that you need `#undef strxfrm`.  You're not right that this means you need to define it yourself.  The requirement of the C standard is that any standard library function may *also* be defined as a macro.  It's also valid to `#undef strxfrm` and then call `strxfrm`. There has to be a proper extern function declaration before the `#define` in the standard C header.  The C standard allows any function to have a macro defined.  It specifies precisely which APIs are macros per se and thus both *must* be macros (users can use `#ifdef` as a conformance check on the implementation) and *must be used* as macros (`#undef` by a user is a violation of the standard).  The "may be defined as macro" rule applies to all standard library functions that are specified as functions: it must be the case that using that macro has the semantics the standard specifies for that function, and it must also be the case that `#undef foo` (or `(foo)(args)` or other means of avoiding using the macro) does not change the semantics of using that function.

So it's entirely sufficient and entirely conforms with the C standard to write `#undef foo` before each and every use of `foo` in a libc++ header.  That might not be the most fun way to maintain things, but it would be perfectly fine semantically and avoids error-prone complexities of getting a single `#undef foo` in exactly after `#include <foo.h>` (for some standard C function `foo` specified to be declared in standard C header `<foo.h>`).

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


More information about the libcxx-commits mailing list