[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