[libcxx-commits] [libcxx] [libc++] Fix C++23 standard modules when using with `clang-cl` on Windows (PR #148992)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jul 19 19:14:25 PDT 2025


https://github.com/siradam7th updated https://github.com/llvm/llvm-project/pull/148992

>From ed2c4e4947d9f703675acdc0dad3c380fb0a390a Mon Sep 17 00:00:00 2001
From: siradam7th <siradam7th at users.noreply.github.com>
Date: Wed, 16 Jul 2025 00:35:50 +0100
Subject: [PATCH 1/4] fix libc++ std modules compilation on Windows using
 clang-cl

---
 libcxx/include/__new/new_handler.h  | 5 +++++
 libcxx/modules/std.compat/ctime.inc | 6 ++++--
 libcxx/modules/std.cppm.in          | 3 +++
 libcxx/modules/std/ctime.inc        | 6 ++++--
 4 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__new/new_handler.h b/libcxx/include/__new/new_handler.h
index 05f4e846c3ef9..2350f9ae9bc19 100644
--- a/libcxx/include/__new/new_handler.h
+++ b/libcxx/include/__new/new_handler.h
@@ -17,6 +17,11 @@
 
 #if defined(_LIBCPP_ABI_VCRUNTIME)
 #  include <new.h>
+// <new.h> does not define 'get_new_handler'
+// which makes the 'std' module build fail, this fixes it
+namespace std {
+_LIBCPP_EXPORTED_FROM_ABI new_handler get_new_handler() _NOEXCEPT;
+}
 #else
 _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
 typedef void (*new_handler)();
diff --git a/libcxx/modules/std.compat/ctime.inc b/libcxx/modules/std.compat/ctime.inc
index eba8234a08969..7547b055b6807 100644
--- a/libcxx/modules/std.compat/ctime.inc
+++ b/libcxx/modules/std.compat/ctime.inc
@@ -14,15 +14,17 @@ export {
 
   using ::timespec _LIBCPP_USING_IF_EXISTS;
   using ::tm _LIBCPP_USING_IF_EXISTS;
-
   using ::asctime _LIBCPP_USING_IF_EXISTS;
   using ::clock _LIBCPP_USING_IF_EXISTS;
+  using ::strftime _LIBCPP_USING_IF_EXISTS;
+
+#ifndef _LIBCPP_ABI_VCRUNTIME
   using ::ctime _LIBCPP_USING_IF_EXISTS;
   using ::difftime _LIBCPP_USING_IF_EXISTS;
   using ::gmtime _LIBCPP_USING_IF_EXISTS;
   using ::localtime _LIBCPP_USING_IF_EXISTS;
   using ::mktime _LIBCPP_USING_IF_EXISTS;
-  using ::strftime _LIBCPP_USING_IF_EXISTS;
   using ::time _LIBCPP_USING_IF_EXISTS;
   using ::timespec_get _LIBCPP_USING_IF_EXISTS;
+#endif
 } // export
diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in
index 984b18321923c..f19dc07169fda 100644
--- a/libcxx/modules/std.cppm.in
+++ b/libcxx/modules/std.cppm.in
@@ -51,6 +51,9 @@ module;
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#ifdef _LIBCPP_ABI_VCRUNTIME
+#define _BUILD_STD_MODULE
+#endif
 #include <ctime>
 #include <cuchar>
 #include <cwchar>
diff --git a/libcxx/modules/std/ctime.inc b/libcxx/modules/std/ctime.inc
index 5bfa61917e5f2..e9f8ecb6ec63e 100644
--- a/libcxx/modules/std/ctime.inc
+++ b/libcxx/modules/std/ctime.inc
@@ -14,15 +14,17 @@ export namespace std {
 
   using std::timespec _LIBCPP_USING_IF_EXISTS;
   using std::tm _LIBCPP_USING_IF_EXISTS;
-
   using std::asctime _LIBCPP_USING_IF_EXISTS;
   using std::clock _LIBCPP_USING_IF_EXISTS;
+  using std::strftime _LIBCPP_USING_IF_EXISTS;
+
+#ifndef _LIBCPP_ABI_VCRUNTIME
   using std::ctime _LIBCPP_USING_IF_EXISTS;
   using std::difftime _LIBCPP_USING_IF_EXISTS;
   using std::gmtime _LIBCPP_USING_IF_EXISTS;
   using std::localtime _LIBCPP_USING_IF_EXISTS;
   using std::mktime _LIBCPP_USING_IF_EXISTS;
-  using std::strftime _LIBCPP_USING_IF_EXISTS;
   using std::time _LIBCPP_USING_IF_EXISTS;
   using std::timespec_get _LIBCPP_USING_IF_EXISTS;
+#endif
 } // namespace std

>From b6bf097211fc8755f233a8c81d7248910da03529 Mon Sep 17 00:00:00 2001
From: siradam7th <siradam7th at users.noreply.github.com>
Date: Sun, 20 Jul 2025 02:49:00 +0100
Subject: [PATCH 2/4] fix python file encoding error on Windows

---
 libcxx/utils/generate_libcxx_cppm_in.py | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/libcxx/utils/generate_libcxx_cppm_in.py b/libcxx/utils/generate_libcxx_cppm_in.py
index 39076a61b55b8..4e0d39289f33e 100644
--- a/libcxx/utils/generate_libcxx_cppm_in.py
+++ b/libcxx/utils/generate_libcxx_cppm_in.py
@@ -9,11 +9,19 @@
 import os.path
 import sys
 
-from libcxx.header_information import module_c_headers, module_headers, header_restrictions, headers_not_available, libcxx_root
+from libcxx.header_information import (
+    module_c_headers,
+    module_headers,
+    header_restrictions,
+    headers_not_available,
+    libcxx_root,
+)
 
 
 def write_file(module):
-    with open(libcxx_root / "modules" / f"{module}.cppm.in", "w") as module_cpp_in:
+    with open(
+        libcxx_root / "modules" / f"{module}.cppm.in", "w", encoding="utf-8"
+    ) as module_cpp_in:
         module_cpp_in.write(
             """\
 // -*- C++ -*-
@@ -25,6 +33,7 @@ def write_file(module):
 //
 //===----------------------------------------------------------------------===//
 
+
 // WARNING, this entire header is generated by
 // utils/generate_libcxx_cppm_in.py
 // DO NOT MODIFY!

>From 4e7a4c990be91e342baff24742d343c868d7970f Mon Sep 17 00:00:00 2001
From: siradam7th <siradam7th at users.noreply.github.com>
Date: Sun, 20 Jul 2025 02:58:17 +0100
Subject: [PATCH 3/4] add missing functions defined as inline, remove
 '_BUILD_STD_MODULE'

---
 libcxx/modules/std.compat/ctime.inc | 40 ++++++++++++++++++++++++++++
 libcxx/modules/std.cppm.in          |  3 ---
 libcxx/modules/std/ctime.inc        | 41 +++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/libcxx/modules/std.compat/ctime.inc b/libcxx/modules/std.compat/ctime.inc
index 7547b055b6807..dbaf76fe6363d 100644
--- a/libcxx/modules/std.compat/ctime.inc
+++ b/libcxx/modules/std.compat/ctime.inc
@@ -27,4 +27,44 @@ export {
   using ::time _LIBCPP_USING_IF_EXISTS;
   using ::timespec_get _LIBCPP_USING_IF_EXISTS;
 #endif
+
+// A workaround for UCRT because it defines these functions
+// as static and that causes the error "internal linkage cannot be exported"
+#ifdef _LIBCPP_ABI_VCRUNTIME
+
+  template <int = 0>
+  inline char* __CRTDECL ctime(_In_ time_t const* const _Time) noexcept {
+    return _ctime64(_Time);
+  }
+
+  template <int = 0>
+  inline double __CRTDECL difftime(_In_ time_t const _Time1, _In_ time_t const _Time2) noexcept {
+    return _difftime64(_Time1, _Time2);
+  }
+
+  template <int = 0>
+  inline tm* __CRTDECL gmtime(_In_ time_t const* const _Time) noexcept {
+    return _gmtime64(_Time);
+  }
+
+  template <int = 0>
+  inline tm* __CRTDECL localtime(_In_ time_t const* const _Time) noexcept {
+    return _localtime64(_Time);
+  }
+
+  template <int = 0>
+  inline time_t __CRTDECL mktime(_Inout_ tm* const _Tm) noexcept {
+    return _mktime64(_Tm);
+  }
+
+  template <int = 0>
+  inline time_t __CRTDECL time(_Out_opt_ time_t* const _Time) noexcept {
+    return _time64(_Time);
+  }
+
+  template <int = 0>
+  inline int __CRTDECL timespec_get(_Out_ timespec* const _Ts, _In_ int const _Base) noexcept {
+    return _timespec64_get(reinterpret_cast<_timespec64*>(_Ts), _Base);
+  }
+#endif
 } // export
diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in
index f19dc07169fda..984b18321923c 100644
--- a/libcxx/modules/std.cppm.in
+++ b/libcxx/modules/std.cppm.in
@@ -51,9 +51,6 @@ module;
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#ifdef _LIBCPP_ABI_VCRUNTIME
-#define _BUILD_STD_MODULE
-#endif
 #include <ctime>
 #include <cuchar>
 #include <cwchar>
diff --git a/libcxx/modules/std/ctime.inc b/libcxx/modules/std/ctime.inc
index e9f8ecb6ec63e..4caa9d3e33d36 100644
--- a/libcxx/modules/std/ctime.inc
+++ b/libcxx/modules/std/ctime.inc
@@ -14,6 +14,7 @@ export namespace std {
 
   using std::timespec _LIBCPP_USING_IF_EXISTS;
   using std::tm _LIBCPP_USING_IF_EXISTS;
+
   using std::asctime _LIBCPP_USING_IF_EXISTS;
   using std::clock _LIBCPP_USING_IF_EXISTS;
   using std::strftime _LIBCPP_USING_IF_EXISTS;
@@ -27,4 +28,44 @@ export namespace std {
   using std::time _LIBCPP_USING_IF_EXISTS;
   using std::timespec_get _LIBCPP_USING_IF_EXISTS;
 #endif
+
+// A workaround for UCRT because it defines these functions
+// as static and that causes the error "internal linkage cannot be exported"
+#ifdef _LIBCPP_ABI_VCRUNTIME
+
+  template <int = 0>
+  inline char* __CRTDECL ctime(_In_ time_t const* const _Time) noexcept {
+    return _ctime64(_Time);
+  }
+
+  template <int = 0>
+  inline double __CRTDECL difftime(_In_ time_t const _Time1, _In_ time_t const _Time2) noexcept {
+    return _difftime64(_Time1, _Time2);
+  }
+
+  template <int = 0>
+  inline tm* __CRTDECL gmtime(_In_ time_t const* const _Time) noexcept {
+    return _gmtime64(_Time);
+  }
+
+  template <int = 0>
+  inline tm* __CRTDECL localtime(_In_ time_t const* const _Time) noexcept {
+    return _localtime64(_Time);
+  }
+
+  template <int = 0>
+  inline time_t __CRTDECL mktime(_Inout_ tm* const _Tm) noexcept {
+    return _mktime64(_Tm);
+  }
+
+  template <int = 0>
+  inline time_t __CRTDECL time(_Out_opt_ time_t* const _Time) noexcept {
+    return _time64(_Time);
+  }
+
+  template <int = 0>
+  inline int __CRTDECL timespec_get(_Out_ timespec* const _Ts, _In_ int const _Base) noexcept {
+    return _timespec64_get(reinterpret_cast<_timespec64*>(_Ts), _Base);
+  }
+#endif
 } // namespace std

>From bf7ca141d4366bdef2cca482e89624fddf5362ce Mon Sep 17 00:00:00 2001
From: siradam7th <siradam7th at users.noreply.github.com>
Date: Sun, 20 Jul 2025 03:12:45 +0100
Subject: [PATCH 4/4] remove 'FIXME' for 'get_new_handler()' test

---
 .../alloc.errors/set.new.handler/get_new_handler.pass.cpp   | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/libcxx/test/std/language.support/support.dynamic/alloc.errors/set.new.handler/get_new_handler.pass.cpp b/libcxx/test/std/language.support/support.dynamic/alloc.errors/set.new.handler/get_new_handler.pass.cpp
index c5725bde6e6c3..2c0081703760e 100644
--- a/libcxx/test/std/language.support/support.dynamic/alloc.errors/set.new.handler/get_new_handler.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/alloc.errors/set.new.handler/get_new_handler.pass.cpp
@@ -8,12 +8,6 @@
 
 // test get_new_handler
 
-// FIXME: When libc++ is linked against vcruntime (i.e. the default config in
-// MSVC mode), the declarations of std::set_new_handler and std::get_new_handler
-// are provided by vcruntime/UCRT's new.h. However, that header actually only
-// declares set_new_handler - it's missing a declaration of get_new_handler.
-
-// XFAIL: msvc && stdlib=libc++
 
 #include <new>
 #include <cassert>



More information about the libcxx-commits mailing list