From 73d178af9482a53d024d922732d08b58d7e1df37 Mon Sep 17 00:00:00 2001 From: Lucas Chollet Date: Sun, 23 Aug 2026 19:33:26 +0200 Subject: [PATCH] LibC: Make wcschr and friends compatible with the C++ standard The C++ standard defines wcschr, wcsrchr, wcspbrk, wcsstr and wmemchr differently than POSIX. To be conformant, we need to provide a different signature when __cplusplus is defined. By defining the `__WCHAR_FORCE_C_DECLARATION` macro, users of `wchar.h` can force the header to provide the C declaration even if __cplusplus is defined. This escape hatch is needed to properly implement the C function in LibC. This makes us pass 3 more libcxx tests. --- Tests/LibC/TestWchar.cpp | 3 +++ Userland/Libraries/LibC/wchar.cpp | 2 ++ Userland/Libraries/LibC/wchar.h | 25 +++++++++++++++++++------ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Tests/LibC/TestWchar.cpp b/Tests/LibC/TestWchar.cpp index fdd9e2f2e82..26f4291fb39 100644 --- a/Tests/LibC/TestWchar.cpp +++ b/Tests/LibC/TestWchar.cpp @@ -10,6 +10,9 @@ #include #include #include + +// This is testing LibC, so let's use the C declaration. +#define __WCHAR_FORCE_C_DECLARATION #include TEST_CASE(wcspbrk) diff --git a/Userland/Libraries/LibC/wchar.cpp b/Userland/Libraries/LibC/wchar.cpp index e389a2f19c7..1e51862ff41 100644 --- a/Userland/Libraries/LibC/wchar.cpp +++ b/Userland/Libraries/LibC/wchar.cpp @@ -12,6 +12,8 @@ #include #include #include + +#define __WCHAR_FORCE_C_DECLARATION #include static unsigned int mbstate_expected_bytes(mbstate_t* state) diff --git a/Userland/Libraries/LibC/wchar.h b/Userland/Libraries/LibC/wchar.h index 090f340c436..60f30f5d381 100644 --- a/Userland/Libraries/LibC/wchar.h +++ b/Userland/Libraries/LibC/wchar.h @@ -26,8 +26,10 @@ __BEGIN_DECLS # define WEOF (0xffffffffu) #endif +// Let libcxx and libstdc++ know that we provide the C++ version of wcschr and friends. #ifdef __cplusplus -# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS +# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1 +# define __CORRECT_ISO_CPP_WCHAR_H_PROTO #endif typedef __WINT_TYPE__ wint_t; @@ -41,6 +43,15 @@ typedef struct { struct tm; +#if defined(__cplusplus) && !defined(__WCHAR_FORCE_C_DECLARATION) +# define __MAKE_C_OR_CPP_DECLARATION(name, ...) \ + extern "C++" wchar_t const* name(wchar_t const*, __VA_ARGS__) asm(#name); \ + extern "C++" wchar_t* name(wchar_t*, __VA_ARGS__) asm(#name) +#else +# define __MAKE_C_OR_CPP_DECLARATION(name, ...) \ + wchar_t* name(wchar_t const*, __VA_ARGS__) +#endif + size_t wcslen(wchar_t const*); wchar_t* wcscpy(wchar_t*, wchar_t const*); wchar_t* wcsdup(wchar_t const*); @@ -48,8 +59,8 @@ wchar_t* wcsncpy(wchar_t*, wchar_t const*, size_t); __attribute__((warn_unused_result)) size_t wcslcpy(wchar_t*, wchar_t const*, size_t); int wcscmp(wchar_t const*, wchar_t const*); int wcsncmp(wchar_t const*, wchar_t const*, size_t); -wchar_t* wcschr(wchar_t const*, int); -wchar_t* wcsrchr(wchar_t const*, wchar_t); +__MAKE_C_OR_CPP_DECLARATION(wcschr, int); +__MAKE_C_OR_CPP_DECLARATION(wcsrchr, wchar_t); wchar_t* wcscat(wchar_t*, wchar_t const*); wchar_t* wcsncat(wchar_t*, wchar_t const*, size_t); wchar_t* wcstok(wchar_t*, wchar_t const*, wchar_t**); @@ -63,9 +74,9 @@ int wcscoll(wchar_t const*, wchar_t const*); size_t wcsxfrm(wchar_t*, wchar_t const*, size_t); int wctob(wint_t); int mbsinit(mbstate_t const*); -wchar_t* wcspbrk(wchar_t const*, wchar_t const*); -wchar_t* wcsstr(wchar_t const*, wchar_t const*); -wchar_t* wmemchr(wchar_t const*, wchar_t, size_t); +__MAKE_C_OR_CPP_DECLARATION(wcspbrk, wchar_t const*); +__MAKE_C_OR_CPP_DECLARATION(wcsstr, wchar_t const*); +__MAKE_C_OR_CPP_DECLARATION(wmemchr, wchar_t, size_t); wchar_t* wmemcpy(wchar_t*, wchar_t const*, size_t); wchar_t* wmemset(wchar_t*, wchar_t, size_t); wchar_t* wmemmove(wchar_t*, wchar_t const*, size_t); @@ -112,3 +123,5 @@ int vwscanf(wchar_t const* __restrict format, va_list arg); size_t wcsftime(wchar_t* __restrict wcs, size_t maxsize, wchar_t const* __restrict format, const struct tm* __restrict timeptr); __END_DECLS + +#undef __MAKE_C_OR_CPP_DECLARATION