[libcxx-commits] [libcxx] [libc++] Prevent cycle from including __mbstate_t.h within wchar.h (PR #200940)

Zibi Sarbinowski via libcxx-commits libcxx-commits at lists.llvm.org
Sat Aug 22 10:20:05 PDT 2026


https://github.com/zibi2 updated https://github.com/llvm/llvm-project/pull/200940

>From adaee84ead8c3a2d69bf1d572e86fdc7da99b255 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Mon, 17 Aug 2026 09:38:06 -0400
Subject: [PATCH 1/4] [libc++] Remove __mbstate_t.h and inline platform logic
 into __std_mbstate_t.h

Remove __mbstate_t.h and __cxx03/__mbstate_t.h entirely. The only
legitimate need for mbstate_t outside of <wchar.h>/<uchar.h> is in
__std_mbstate_t.h (used by iosfwd, char_traits, locale, etc. to get
std::mbstate_t). Inline the platform-detection logic directly into
__std_mbstate_t.h instead of indirecting through __mbstate_t.h.

Also remove the unconditional fallback includes of <__mbstate_t.h> and
<stddef.h> from wchar.h, uchar.h and __cxx03/wchar.h. On platforms
that provide a system <wchar.h> (including z/OS), mbstate_t comes from
the system header via include_next. On platforms without it, libc++ is
not responsible for providing mbstate_t.

This eliminates the circular inclusion that caused module build failures
(redefinition of wchar.h shims like __libcpp_wcschr) when __mbstate_t.h
fell through to include_next <wchar.h> inside the module system, which
re-entered libc++'s wchar.h without the _LIBCPP_WCHAR_H guard being set.

Removes the std_private_mbstate_t and cxx03_std_private_mbstate_t
module map entries and the file list entries in CMakeLists.txt.
---
 libcxx/include/CMakeLists.txt            |  2 -
 libcxx/include/__cxx03/__mbstate_t.h     | 54 ----------------------
 libcxx/include/__cxx03/__std_mbstate_t.h | 27 ++++++++++-
 libcxx/include/__cxx03/module.modulemap  |  4 --
 libcxx/include/__cxx03/wchar.h           |  2 -
 libcxx/include/__mbstate_t.h             | 58 ------------------------
 libcxx/include/__std_mbstate_t.h         | 29 +++++++++++-
 libcxx/include/module.modulemap.in       |  5 --
 libcxx/include/uchar.h                   |  3 --
 libcxx/include/wchar.h                   |  3 --
 10 files changed, 54 insertions(+), 133 deletions(-)
 delete mode 100644 libcxx/include/__cxx03/__mbstate_t.h
 delete mode 100644 libcxx/include/__mbstate_t.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index a1d6a09aa6b20..3de0bef7dccf6 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -590,7 +590,6 @@ set(files
   __math/rounding_functions.h
   __math/traits.h
   __math/trigonometric_functions.h
-  __mbstate_t.h
   __mdspan/aligned_accessor.h
   __mdspan/default_accessor.h
   __mdspan/extents.h
@@ -1368,7 +1367,6 @@ set(files
   __cxx03/__math/rounding_functions.h
   __cxx03/__math/traits.h
   __cxx03/__math/trigonometric_functions.h
-  __cxx03/__mbstate_t.h
   __cxx03/__memory/addressof.h
   __cxx03/__memory/align.h
   __cxx03/__memory/aligned_alloc.h
diff --git a/libcxx/include/__cxx03/__mbstate_t.h b/libcxx/include/__cxx03/__mbstate_t.h
deleted file mode 100644
index 6c7cfaaa8fe5b..0000000000000
--- a/libcxx/include/__cxx03/__mbstate_t.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___CXX03___MBSTATE_T_H
-#define _LIBCPP___CXX03___MBSTATE_T_H
-
-#include <__cxx03/__config>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-// The goal of this header is to provide mbstate_t without requiring all of
-// <uchar.h> or <wchar.h>. It's also used by the libc++ versions of <uchar.h>
-// and <wchar.h> to get mbstate_t when the C library doesn't provide <uchar.h>
-// or <wchar.h>, hence the #include_next of those headers instead of #include.
-// (e.g. if <wchar.h> isn't present in the C library, the libc++ <wchar.h>
-// will include this header. This header needs to not turn around and cyclically
-// include <__cxx03/wchar.h>, but fall through to <uchar.h>.)
-//
-// This does not define std::mbstate_t -- this only brings in the declaration
-// in the global namespace.
-
-// We define this here to support older versions of glibc <wchar.h> that do
-// not define this for clang. This is also set in libc++'s <wchar.h> header,
-// and we need to do so here too to avoid a different function signature given
-// a different include order.
-#ifdef __cplusplus
-#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
-#endif
-
-#if defined(_LIBCPP_HAS_MUSL_LIBC)
-#  define __NEED_mbstate_t
-#  include <bits/alltypes.h>
-#  undef __NEED_mbstate_t
-#elif __has_include(<bits/types/mbstate_t.h>)
-#  include <bits/types/mbstate_t.h> // works on most Unixes
-#elif __has_include(<sys/_types/_mbstate_t.h>)
-#  include <sys/_types/_mbstate_t.h> // works on Darwin
-#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next(<wchar.h>)
-#  include_next <wchar.h> // fall back to the C standard provider of mbstate_t
-#elif __has_include_next(<uchar.h>)
-#  include_next <uchar.h> // <uchar.h> is also required to make mbstate_t visible
-#else
-#  error "We don't know how to get the definition of mbstate_t without <wchar.h> on your platform."
-#endif
-
-#endif // _LIBCPP___CXX03___MBSTATE_T_H
diff --git a/libcxx/include/__cxx03/__std_mbstate_t.h b/libcxx/include/__cxx03/__std_mbstate_t.h
index 7a81d1bd024ae..1595d845cc9e1 100644
--- a/libcxx/include/__cxx03/__std_mbstate_t.h
+++ b/libcxx/include/__cxx03/__std_mbstate_t.h
@@ -11,7 +11,6 @@
 #define _LIBCPP___CXX03___STD_MBSTATE_T_H
 
 #include <__cxx03/__config>
-#include <__cxx03/__mbstate_t.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -20,6 +19,32 @@
 // The goal of this header is to provide std::mbstate_t without requiring all
 // of <cuchar> or <cwchar>.
 
+// We define this here to support older versions of glibc <wchar.h> that do
+// not define this for clang. This is also set in libc++'s <wchar.h> header,
+// and we need to do so here too to avoid a different function signature given
+// a different include order.
+#ifdef __cplusplus
+#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
+#endif
+
+#if defined(_LIBCPP_HAS_MUSL_LIBC)
+#  define __NEED_mbstate_t
+#  include <bits/alltypes.h>
+#  undef __NEED_mbstate_t
+#elif __has_include(<bits/types/mbstate_t.h>)
+#  include <bits/types/mbstate_t.h> // works on most Unixes
+#elif __has_include(<sys/_types/_mbstate_t.h>)
+#  include <sys/_types/_mbstate_t.h> // works on Darwin
+#elif __has_include(<bits/mbstate_t.h>)
+#  include <bits/mbstate_t.h> // works for Android
+#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next(<wchar.h>)
+#  include_next <wchar.h> // fall back to the C standard provider of mbstate_t
+#elif __has_include_next(<uchar.h>)
+#  include_next <uchar.h> // <uchar.h> is also required to make mbstate_t visible
+#else
+#  error "We don't know how to get the definition of mbstate_t without <wchar.h> on your platform."
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
diff --git a/libcxx/include/__cxx03/module.modulemap b/libcxx/include/__cxx03/module.modulemap
index 717926a46a55d..fa6b55e5c0532 100644
--- a/libcxx/include/__cxx03/module.modulemap
+++ b/libcxx/include/__cxx03/module.modulemap
@@ -590,10 +590,6 @@ module cxx03_std_private_locale            [system] {
   header "__locale"
   export *
 }
-module cxx03_std_private_mbstate_t         [system] {
-  header "__mbstate_t.h"
-  export *
-}
 module cxx03_std_private_node_handle       [system] {
   header "__node_handle"
   export *
diff --git a/libcxx/include/__cxx03/wchar.h b/libcxx/include/__cxx03/wchar.h
index f30b18df9c9f7..0da6b276b176e 100644
--- a/libcxx/include/__cxx03/wchar.h
+++ b/libcxx/include/__cxx03/wchar.h
@@ -125,8 +125,6 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
 
 #  if __has_include_next(<wchar.h>)
 #    include_next <wchar.h>
-#  else
-#    include <__cxx03/__mbstate_t.h> // make sure we have mbstate_t regardless of the existence of <wchar.h>
 #  endif
 
 // Determine whether we have const-correct overloads for wcschr and friends.
diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h
deleted file mode 100644
index 1ce5f0cd6da1d..0000000000000
--- a/libcxx/include/__mbstate_t.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___MBSTATE_T_H
-#define _LIBCPP___MBSTATE_T_H
-
-#include <__config>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-// The goal of this header is to provide mbstate_t without requiring all of
-// <uchar.h> or <wchar.h>. It's also used by the libc++ versions of <uchar.h>
-// and <wchar.h> to get mbstate_t when the C library doesn't provide <uchar.h>
-// or <wchar.h>, hence the #include_next of those headers instead of #include.
-// (e.g. if <wchar.h> isn't present in the C library, the libc++ <wchar.h>
-// will include this header. This header needs to not turn around and cyclically
-// include <wchar.h>, but fall through to <uchar.h>.)
-//
-// This does not define std::mbstate_t -- this only brings in the declaration
-// in the global namespace.
-
-// We define this here to support older versions of glibc <wchar.h> that do
-// not define this for clang. This is also set in libc++'s <wchar.h> header,
-// and we need to do so here too to avoid a different function signature given
-// a different include order.
-#ifdef __cplusplus
-#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
-#endif
-
-#if _LIBCPP_HAS_MUSL_LIBC
-#  define __NEED_mbstate_t
-#  include <bits/alltypes.h>
-#  undef __NEED_mbstate_t
-#elif _LIBCPP_LIBC_LLVM_LIBC
-#  include <llvm-libc-types/mbstate_t.h>
-#elif __has_include(<bits/types/mbstate_t.h>)
-#  include <bits/types/mbstate_t.h> // works on most Unixes
-#elif __has_include(<sys/_types/_mbstate_t.h>)
-#  include <sys/_types/_mbstate_t.h> // works on Darwin
-#elif __has_include(<bits/mbstate_t.h>)
-#  include <bits/mbstate_t.h> // works for Android
-#elif __has_include_next(<wchar.h>)
-#  include_next <wchar.h> // use the C standard provider of mbstate_t if present
-#elif __has_include_next(<uchar.h>)
-#  include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
-#else
-#  error "We don't know how to get the definition of mbstate_t on your platform."
-#endif
-
-#endif // _LIBCPP___MBSTATE_T_H
diff --git a/libcxx/include/__std_mbstate_t.h b/libcxx/include/__std_mbstate_t.h
index e79cc789fddf9..7990328312f35 100644
--- a/libcxx/include/__std_mbstate_t.h
+++ b/libcxx/include/__std_mbstate_t.h
@@ -11,7 +11,6 @@
 #define _LIBCPP___STD_MBSTATE_T_H
 
 #include <__config>
-#include <__mbstate_t.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -20,6 +19,34 @@
 // The goal of this header is to provide std::mbstate_t without requiring all
 // of <cuchar> or <cwchar>.
 
+// We define this here to support older versions of glibc <wchar.h> that do
+// not define this for clang. This is also set in libc++'s <wchar.h> header,
+// and we need to do so here too to avoid a different function signature given
+// a different include order.
+#ifdef __cplusplus
+#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
+#endif
+
+#if _LIBCPP_HAS_MUSL_LIBC
+#  define __NEED_mbstate_t
+#  include <bits/alltypes.h>
+#  undef __NEED_mbstate_t
+#elif _LIBCPP_LIBC_LLVM_LIBC
+#  include <llvm-libc-types/mbstate_t.h>
+#elif __has_include(<bits/types/mbstate_t.h>)
+#  include <bits/types/mbstate_t.h> // works on most Unixes
+#elif __has_include(<sys/_types/_mbstate_t.h>)
+#  include <sys/_types/_mbstate_t.h> // works on Darwin
+#elif __has_include(<bits/mbstate_t.h>)
+#  include <bits/mbstate_t.h> // works for Android
+#elif __has_include_next(<wchar.h>)
+#  include_next <wchar.h> // use the C standard provider of mbstate_t if present
+#elif __has_include_next(<uchar.h>)
+#  include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
+#else
+#  error "We don't know how to get the definition of mbstate_t on your platform."
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4512cc71153ca..f8228bbb59779 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2566,8 +2566,3 @@ module std_wctype_h {
   export *
 }
 
-// This header is used by other C compatibility headers so it needs to be in its own module.
-module std_private_mbstate_t {
-  header "__mbstate_t.h"
-  export *
-}
diff --git a/libcxx/include/uchar.h b/libcxx/include/uchar.h
index 01e1d57db7454..00a57dfdb640b 100644
--- a/libcxx/include/uchar.h
+++ b/libcxx/include/uchar.h
@@ -49,9 +49,6 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
 // get the declaration of mbstate_t too.
 #    if __has_include_next(<uchar.h>)
 #      include_next <uchar.h>
-#    else
-#      include <__mbstate_t.h>
-#      include <stddef.h>
 #    endif
 
 #  endif // _LIBCPP_CXX03_LANG
diff --git a/libcxx/include/wchar.h b/libcxx/include/wchar.h
index e5844249bdf7e..25c4c236529b5 100644
--- a/libcxx/include/wchar.h
+++ b/libcxx/include/wchar.h
@@ -119,9 +119,6 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
 #  ifndef _LIBCPP_WCHAR_H
 #    define _LIBCPP_WCHAR_H
 
-#    include <__mbstate_t.h> // provide mbstate_t
-#    include <stddef.h>      // provide size_t
-
 // Determine whether we have const-correct overloads for wcschr and friends.
 #    if defined(_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_)
 #      define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1

>From cf20f43ca745d6af33deb8972365ff8ee72c2193 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Tue, 18 Aug 2026 12:11:31 -0400
Subject: [PATCH 2/4] [libc++] Remove __std_mbstate_t.h and replace with direct
 wchar.h includes

Remove __std_mbstate_t.h and __cxx03/__std_mbstate_t.h. All includers
are updated to use <wchar.h> directly, which provides mbstate_t on all
supported platforms via the platform-detection chain already present
in libc++'s wchar.h.

This is a follow-up to the removal of __mbstate_t.h: since the platform
detection logic was already inlined into __std_mbstate_t.h in the
previous commit, and since wchar.h on all supported platforms (including
z/OS) provides mbstate_t, there is no longer any need for the
intermediate __std_mbstate_t.h indirection.

Files updated:
- iosfwd, __locale, __string/char_traits.h
- __locale_dir/support/{aix,bsd_like,linux,newlib,openbsd,no_locale/conversions}.h
- __cxx03/__locale, __cxx03/iosfwd
- module.modulemap.in, __cxx03/module.modulemap, CMakeLists.txt
---
 libcxx/include/CMakeLists.txt                 |  2 -
 libcxx/include/__cxx03/__locale               |  2 +-
 libcxx/include/__cxx03/__std_mbstate_t.h      | 54 ------------------
 libcxx/include/__cxx03/iosfwd                 |  2 +-
 libcxx/include/__cxx03/module.modulemap       |  4 --
 libcxx/include/__locale_dir/codecvt.h         |  2 +-
 libcxx/include/__locale_dir/support/aix.h     |  2 +-
 .../include/__locale_dir/support/bsd_like.h   |  2 +-
 libcxx/include/__locale_dir/support/linux.h   |  2 +-
 libcxx/include/__locale_dir/support/newlib.h  |  2 +-
 .../support/no_locale/conversions.h           |  2 +-
 libcxx/include/__locale_dir/support/openbsd.h |  2 +-
 .../include/__locale_dir/utf8_conversions.h   |  2 +-
 libcxx/include/__std_mbstate_t.h              | 56 -------------------
 libcxx/include/__string/char_traits.h         |  2 +-
 libcxx/include/iosfwd                         |  2 +-
 libcxx/include/module.modulemap.in            |  4 --
 17 files changed, 12 insertions(+), 132 deletions(-)
 delete mode 100644 libcxx/include/__cxx03/__std_mbstate_t.h
 delete mode 100644 libcxx/include/__std_mbstate_t.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3de0bef7dccf6..026dcdcc513af 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -794,7 +794,6 @@ set(files
   __ranges/zip_transform_view.h
   __ranges/zip_view.h
   __split_buffer
-  __std_mbstate_t.h
   __stop_token/atomic_unique_lock.h
   __stop_token/intrusive_list_view.h
   __stop_token/intrusive_shared_ptr.h
@@ -1441,7 +1440,6 @@ set(files
   __cxx03/__random/weibull_distribution.h
   __cxx03/__split_buffer
   __cxx03/__std_clang_module
-  __cxx03/__std_mbstate_t.h
   __cxx03/__string/char_traits.h
   __cxx03/__string/constexpr_c_functions.h
   __cxx03/__string/extern_template_lists.h
diff --git a/libcxx/include/__cxx03/__locale b/libcxx/include/__cxx03/__locale
index e9cbc1f2d7683..92f3edd80c354 100644
--- a/libcxx/include/__cxx03/__locale
+++ b/libcxx/include/__cxx03/__locale
@@ -30,7 +30,7 @@
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 #  include <__cxx03/cwchar>
 #else
-#  include <__cxx03/__std_mbstate_t.h>
+#  include <wchar.h>
 #endif
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__cxx03/__std_mbstate_t.h b/libcxx/include/__cxx03/__std_mbstate_t.h
deleted file mode 100644
index 1595d845cc9e1..0000000000000
--- a/libcxx/include/__cxx03/__std_mbstate_t.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___CXX03___STD_MBSTATE_T_H
-#define _LIBCPP___CXX03___STD_MBSTATE_T_H
-
-#include <__cxx03/__config>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-// The goal of this header is to provide std::mbstate_t without requiring all
-// of <cuchar> or <cwchar>.
-
-// We define this here to support older versions of glibc <wchar.h> that do
-// not define this for clang. This is also set in libc++'s <wchar.h> header,
-// and we need to do so here too to avoid a different function signature given
-// a different include order.
-#ifdef __cplusplus
-#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
-#endif
-
-#if defined(_LIBCPP_HAS_MUSL_LIBC)
-#  define __NEED_mbstate_t
-#  include <bits/alltypes.h>
-#  undef __NEED_mbstate_t
-#elif __has_include(<bits/types/mbstate_t.h>)
-#  include <bits/types/mbstate_t.h> // works on most Unixes
-#elif __has_include(<sys/_types/_mbstate_t.h>)
-#  include <sys/_types/_mbstate_t.h> // works on Darwin
-#elif __has_include(<bits/mbstate_t.h>)
-#  include <bits/mbstate_t.h> // works for Android
-#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next(<wchar.h>)
-#  include_next <wchar.h> // fall back to the C standard provider of mbstate_t
-#elif __has_include_next(<uchar.h>)
-#  include_next <uchar.h> // <uchar.h> is also required to make mbstate_t visible
-#else
-#  error "We don't know how to get the definition of mbstate_t without <wchar.h> on your platform."
-#endif
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP___CXX03___STD_MBSTATE_T_H
diff --git a/libcxx/include/__cxx03/iosfwd b/libcxx/include/__cxx03/iosfwd
index 674e901c30650..7f7d3999ae843 100644
--- a/libcxx/include/__cxx03/iosfwd
+++ b/libcxx/include/__cxx03/iosfwd
@@ -114,7 +114,7 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #include <__cxx03/__fwd/sstream.h>
 #include <__cxx03/__fwd/streambuf.h>
 #include <__cxx03/__fwd/string.h>
-#include <__cxx03/__std_mbstate_t.h>
+#include <wchar.h>
 #include <__cxx03/version>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__cxx03/module.modulemap b/libcxx/include/__cxx03/module.modulemap
index fa6b55e5c0532..ba88846cc230b 100644
--- a/libcxx/include/__cxx03/module.modulemap
+++ b/libcxx/include/__cxx03/module.modulemap
@@ -598,10 +598,6 @@ module cxx03_std_private_split_buffer      [system] {
   header "__split_buffer"
   export *
 }
-module cxx03_std_private_std_mbstate_t     [system] {
-  header "__std_mbstate_t.h"
-  export *
-}
 module cxx03_std_private_tree              [system] {
   header "__tree"
   export *
diff --git a/libcxx/include/__locale_dir/codecvt.h b/libcxx/include/__locale_dir/codecvt.h
index c601a6ee62cd2..a404c03dc246c 100644
--- a/libcxx/include/__locale_dir/codecvt.h
+++ b/libcxx/include/__locale_dir/codecvt.h
@@ -21,7 +21,7 @@
 #  if _LIBCPP_HAS_WIDE_CHARACTERS
 #    include <cwchar>
 #  else
-#    include <__std_mbstate_t.h>
+#    include <wchar.h>
 #  endif
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__locale_dir/support/aix.h b/libcxx/include/__locale_dir/support/aix.h
index 4ab52793ae3c1..c14e62aa904bf 100644
--- a/libcxx/include/__locale_dir/support/aix.h
+++ b/libcxx/include/__locale_dir/support/aix.h
@@ -11,7 +11,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <cstdio>
diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h
index 6632ca51e1eaa..891e476522653 100644
--- a/libcxx/include/__locale_dir/support/bsd_like.h
+++ b/libcxx/include/__locale_dir/support/bsd_like.h
@@ -11,7 +11,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <ctype.h>
diff --git a/libcxx/include/__locale_dir/support/linux.h b/libcxx/include/__locale_dir/support/linux.h
index 6a91a001c239c..816cca1b702e5 100644
--- a/libcxx/include/__locale_dir/support/linux.h
+++ b/libcxx/include/__locale_dir/support/linux.h
@@ -11,7 +11,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <cstdio>
diff --git a/libcxx/include/__locale_dir/support/newlib.h b/libcxx/include/__locale_dir/support/newlib.h
index 7fe48572b4587..2c887b40f2c06 100644
--- a/libcxx/include/__locale_dir/support/newlib.h
+++ b/libcxx/include/__locale_dir/support/newlib.h
@@ -11,7 +11,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <clocale> // std::lconv
 #include <cstdio>
 #include <cstdlib>
diff --git a/libcxx/include/__locale_dir/support/no_locale/conversions.h b/libcxx/include/__locale_dir/support/no_locale/conversions.h
index bb501515c4d4e..a9495e2b8b1ec 100644
--- a/libcxx/include/__locale_dir/support/no_locale/conversions.h
+++ b/libcxx/include/__locale_dir/support/no_locale/conversions.h
@@ -11,7 +11,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <cstdlib>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar>
diff --git a/libcxx/include/__locale_dir/support/openbsd.h b/libcxx/include/__locale_dir/support/openbsd.h
index 0ec5b12f2ebdd..157c230b767cb 100644
--- a/libcxx/include/__locale_dir/support/openbsd.h
+++ b/libcxx/include/__locale_dir/support/openbsd.h
@@ -12,7 +12,7 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <ctype.h>
diff --git a/libcxx/include/__locale_dir/utf8_conversions.h b/libcxx/include/__locale_dir/utf8_conversions.h
index a4a32700a8ad7..68d435488f64d 100644
--- a/libcxx/include/__locale_dir/utf8_conversions.h
+++ b/libcxx/include/__locale_dir/utf8_conversions.h
@@ -15,7 +15,7 @@
 
 #  include <__cstddef/size_t.h>
 #  include <__locale_dir/codecvt.h>
-#  include <__std_mbstate_t.h>
+#  include <wchar.h>
 #  include <stdexcept>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__std_mbstate_t.h b/libcxx/include/__std_mbstate_t.h
deleted file mode 100644
index 7990328312f35..0000000000000
--- a/libcxx/include/__std_mbstate_t.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___STD_MBSTATE_T_H
-#define _LIBCPP___STD_MBSTATE_T_H
-
-#include <__config>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-// The goal of this header is to provide std::mbstate_t without requiring all
-// of <cuchar> or <cwchar>.
-
-// We define this here to support older versions of glibc <wchar.h> that do
-// not define this for clang. This is also set in libc++'s <wchar.h> header,
-// and we need to do so here too to avoid a different function signature given
-// a different include order.
-#ifdef __cplusplus
-#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
-#endif
-
-#if _LIBCPP_HAS_MUSL_LIBC
-#  define __NEED_mbstate_t
-#  include <bits/alltypes.h>
-#  undef __NEED_mbstate_t
-#elif _LIBCPP_LIBC_LLVM_LIBC
-#  include <llvm-libc-types/mbstate_t.h>
-#elif __has_include(<bits/types/mbstate_t.h>)
-#  include <bits/types/mbstate_t.h> // works on most Unixes
-#elif __has_include(<sys/_types/_mbstate_t.h>)
-#  include <sys/_types/_mbstate_t.h> // works on Darwin
-#elif __has_include(<bits/mbstate_t.h>)
-#  include <bits/mbstate_t.h> // works for Android
-#elif __has_include_next(<wchar.h>)
-#  include_next <wchar.h> // use the C standard provider of mbstate_t if present
-#elif __has_include_next(<uchar.h>)
-#  include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
-#else
-#  error "We don't know how to get the definition of mbstate_t on your platform."
-#endif
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP___STD_MBSTATE_T_H
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index d98595030e6a5..927d89cc5ce90 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -21,7 +21,7 @@
 #include <__functional/hash.h>
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
-#include <__std_mbstate_t.h>
+#include <wchar.h>
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/is_constant_evaluated.h>
 #include <__utility/is_pointer_in_range.h>
diff --git a/libcxx/include/iosfwd b/libcxx/include/iosfwd
index 7f7c9417d3e70..492c5a478770c 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -117,7 +117,7 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #  include <__fwd/sstream.h>
 #  include <__fwd/streambuf.h>
 #  include <__fwd/string.h>
-#  include <__std_mbstate_t.h>
+#  include <wchar.h>
 #  include <version>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index f8228bbb59779..46b45cf75ccdb 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2473,10 +2473,6 @@ module std {
     header "__tree"
     export std.memory.unique_ptr
   }
-  module std_mbstate_t {
-    header "__std_mbstate_t.h"
-    export *
-  }
   module log_hardening_failure {
     header "__log_hardening_failure"
   }

>From 0dd5e87e4df3313a4804dddb5a5d262821edc9a5 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Thu, 20 Aug 2026 10:12:51 -0400
Subject: [PATCH 3/4] [libc++] Fix include order for <wchar.h> after removal of
 __std_mbstate_t.h

The previous commit replaced <__std_mbstate_t.h> (an __-prefixed internal
header) with <wchar.h> in several files, but placed <wchar.h> before other
__-prefixed headers, violating the llvm-include-order clang-tidy rule which
requires all <__...> internal headers to precede system headers.

Move <wchar.h> to after the last <__...> include in each affected file:
- __locale_dir/support/aix.h
- __locale_dir/support/bsd_like.h
- __locale_dir/support/linux.h
- __locale_dir/support/openbsd.h
- __string/char_traits.h
- iosfwd
- __cxx03/iosfwd
---
 libcxx/include/__cxx03/iosfwd                               | 2 +-
 libcxx/include/__locale_dir/support/aix.h                   | 2 +-
 libcxx/include/__locale_dir/support/bsd_like.h              | 2 +-
 libcxx/include/__locale_dir/support/linux.h                 | 2 +-
 libcxx/include/__locale_dir/support/newlib.h                | 2 +-
 libcxx/include/__locale_dir/support/no_locale/conversions.h | 2 +-
 libcxx/include/__locale_dir/support/openbsd.h               | 2 +-
 libcxx/include/__locale_dir/utf8_conversions.h              | 2 +-
 libcxx/include/__string/char_traits.h                       | 2 +-
 libcxx/include/iosfwd                                       | 2 +-
 10 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__cxx03/iosfwd b/libcxx/include/__cxx03/iosfwd
index 7f7d3999ae843..32c1e15a0f31c 100644
--- a/libcxx/include/__cxx03/iosfwd
+++ b/libcxx/include/__cxx03/iosfwd
@@ -114,8 +114,8 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #include <__cxx03/__fwd/sstream.h>
 #include <__cxx03/__fwd/streambuf.h>
 #include <__cxx03/__fwd/string.h>
-#include <wchar.h>
 #include <__cxx03/version>
+#include <wchar.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__locale_dir/support/aix.h b/libcxx/include/__locale_dir/support/aix.h
index c14e62aa904bf..43664ce78d85c 100644
--- a/libcxx/include/__locale_dir/support/aix.h
+++ b/libcxx/include/__locale_dir/support/aix.h
@@ -11,7 +11,6 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <cstdio>
@@ -20,6 +19,7 @@
 #include <langinfo.h>
 #include <string.h>
 #include <time.h>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar>
 #  include <wctype.h>
diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h
index 891e476522653..64ce5453a962b 100644
--- a/libcxx/include/__locale_dir/support/bsd_like.h
+++ b/libcxx/include/__locale_dir/support/bsd_like.h
@@ -11,7 +11,6 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <ctype.h>
@@ -20,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <wchar.h>
 #  include <wctype.h>
diff --git a/libcxx/include/__locale_dir/support/linux.h b/libcxx/include/__locale_dir/support/linux.h
index 816cca1b702e5..bd2bc19d39f04 100644
--- a/libcxx/include/__locale_dir/support/linux.h
+++ b/libcxx/include/__locale_dir/support/linux.h
@@ -11,7 +11,6 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <cstdio>
@@ -21,6 +20,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <time.h>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar>
 #  include <wctype.h>
diff --git a/libcxx/include/__locale_dir/support/newlib.h b/libcxx/include/__locale_dir/support/newlib.h
index 2c887b40f2c06..5dc2aa066f7bb 100644
--- a/libcxx/include/__locale_dir/support/newlib.h
+++ b/libcxx/include/__locale_dir/support/newlib.h
@@ -11,7 +11,6 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <clocale> // std::lconv
 #include <cstdio>
 #include <cstdlib>
@@ -20,6 +19,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <time.h>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar>
 #  include <wctype.h>
diff --git a/libcxx/include/__locale_dir/support/no_locale/conversions.h b/libcxx/include/__locale_dir/support/no_locale/conversions.h
index a9495e2b8b1ec..ec3fd48d1b45c 100644
--- a/libcxx/include/__locale_dir/support/no_locale/conversions.h
+++ b/libcxx/include/__locale_dir/support/no_locale/conversions.h
@@ -11,8 +11,8 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <cstdlib>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar>
 #endif
diff --git a/libcxx/include/__locale_dir/support/openbsd.h b/libcxx/include/__locale_dir/support/openbsd.h
index 157c230b767cb..6fa2062f6967b 100644
--- a/libcxx/include/__locale_dir/support/openbsd.h
+++ b/libcxx/include/__locale_dir/support/openbsd.h
@@ -12,7 +12,6 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
-#include <wchar.h>
 #include <__utility/forward.h>
 #include <clocale> // std::lconv
 #include <ctype.h>
@@ -20,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <wchar.h>
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <wchar.h>
 #  include <wctype.h>
diff --git a/libcxx/include/__locale_dir/utf8_conversions.h b/libcxx/include/__locale_dir/utf8_conversions.h
index 68d435488f64d..563a46f5e3b58 100644
--- a/libcxx/include/__locale_dir/utf8_conversions.h
+++ b/libcxx/include/__locale_dir/utf8_conversions.h
@@ -15,8 +15,8 @@
 
 #  include <__cstddef/size_t.h>
 #  include <__locale_dir/codecvt.h>
-#  include <wchar.h>
 #  include <stdexcept>
+#  include <wchar.h>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #    pragma GCC system_header
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 927d89cc5ce90..714a0193731a6 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -21,13 +21,13 @@
 #include <__functional/hash.h>
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
-#include <wchar.h>
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/is_constant_evaluated.h>
 #include <__utility/is_pointer_in_range.h>
 #include <cstdint>
 #include <cstdio>
 #include <iosfwd>
+#include <wchar.h>
 
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar> // for wmemcpy
diff --git a/libcxx/include/iosfwd b/libcxx/include/iosfwd
index 492c5a478770c..11241afd68e53 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -117,8 +117,8 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #  include <__fwd/sstream.h>
 #  include <__fwd/streambuf.h>
 #  include <__fwd/string.h>
-#  include <wchar.h>
 #  include <version>
+#  include <wchar.h>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #    pragma GCC system_header

>From 6aa8c85c4bd22391ddcf6b15ed95d39b59118d72 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Thu, 20 Aug 2026 13:48:37 -0400
Subject: [PATCH 4/4] [libc++] Add __fwd/mbstate_t.h to fix mbstate_t
 visibility in modules build

The previous commit replaced <__std_mbstate_t.h> (which had its own module
entry) with direct <wchar.h> includes. Since <wchar.h> is declared as a
textual header in module.modulemap.in, mbstate_t was no longer visible
through the module system, causing a failure in the generic-modules build:

  declaration of 'mbstate_t' must be imported from module 'std.cuchar'
  before it is required

Fix by introducing __fwd/mbstate_t.h, a proper modularized header that
includes <wchar.h> and pulls ::mbstate_t into namespace std, mirroring
the pattern of other __fwd/ headers. Register it as a submodule of iosfwd
in module.modulemap.in and list it in CMakeLists.txt.

Use <__fwd/mbstate_t.h> in iosfwd and __string/char_traits.h (the two
headers reachable from the modules build path) in place of <wchar.h>.
---
 libcxx/include/CMakeLists.txt         |  1 +
 libcxx/include/__fwd/mbstate_t.h      | 56 +++++++++++++++++++++++++++
 libcxx/include/__string/char_traits.h |  2 +-
 libcxx/include/cuchar                 |  1 -
 libcxx/include/cwchar                 |  1 -
 libcxx/include/iosfwd                 |  2 +-
 libcxx/include/module.modulemap.in    |  5 +++
 libcxx/utils/generate_iwyu_mapping.py |  4 +-
 8 files changed, 67 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/include/__fwd/mbstate_t.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 026dcdcc513af..9e80857f6df3a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -471,6 +471,7 @@ set(files
   __fwd/get.h
   __fwd/ios.h
   __fwd/istream.h
+  __fwd/mbstate_t.h
   __fwd/mdspan.h
   __fwd/memory.h
   __fwd/memory_resource.h
diff --git a/libcxx/include/__fwd/mbstate_t.h b/libcxx/include/__fwd/mbstate_t.h
new file mode 100644
index 0000000000000..c85213b36eb7b
--- /dev/null
+++ b/libcxx/include/__fwd/mbstate_t.h
@@ -0,0 +1,56 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FWD_MBSTATE_T_H
+#define _LIBCPP___FWD_MBSTATE_T_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+// The goal of this header is to provide std::mbstate_t without requiring all
+// of <cuchar> or <cwchar>.
+
+// We define this here to support older versions of glibc <wchar.h> that do
+// not define this for clang. This is also set in libc++'s <wchar.h> header,
+// and we need to do so here too to avoid a different function signature given
+// a different include order.
+#ifdef __cplusplus
+#  define __CORRECT_ISO_CPP_WCHAR_H_PROTO
+#endif
+
+#if _LIBCPP_HAS_MUSL_LIBC
+#  define __NEED_mbstate_t
+#  include <bits/alltypes.h>
+#  undef __NEED_mbstate_t
+#elif _LIBCPP_LIBC_LLVM_LIBC
+#  include <llvm-libc-types/mbstate_t.h>
+#elif __has_include(<bits/types/mbstate_t.h>)
+#  include <bits/types/mbstate_t.h> // works on most Unixes
+#elif __has_include(<sys/_types/_mbstate_t.h>)
+#  include <sys/_types/_mbstate_t.h> // works on Darwin
+#elif __has_include(<bits/mbstate_t.h>)
+#  include <bits/mbstate_t.h> // works for Android
+#elif __has_include_next(<wchar.h>)
+#  include_next <wchar.h> // use the C standard provider of mbstate_t if present
+#elif __has_include_next(<uchar.h>)
+#  include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
+#else
+#  error "We don't know how to get the definition of mbstate_t on your platform."
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FWD_MBSTATE_T_H
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 714a0193731a6..9568efd546d3f 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -20,6 +20,7 @@
 #include <__cstddef/ptrdiff_t.h>
 #include <__functional/hash.h>
 #include <__functional/identity.h>
+#include <__fwd/mbstate_t.h>
 #include <__iterator/iterator_traits.h>
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/is_constant_evaluated.h>
@@ -27,7 +28,6 @@
 #include <cstdint>
 #include <cstdio>
 #include <iosfwd>
-#include <wchar.h>
 
 #if _LIBCPP_HAS_WIDE_CHARACTERS
 #  include <cwchar> // for wmemcpy
diff --git a/libcxx/include/cuchar b/libcxx/include/cuchar
index 591f332c70dab..9ee40e10e85be 100644
--- a/libcxx/include/cuchar
+++ b/libcxx/include/cuchar
@@ -41,7 +41,6 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
 #else
 #  include <__config>
 #  include <__cstddef/size_t.h>
-
 #  include <uchar.h>
 
 #  ifndef _LIBCPP_UCHAR_H
diff --git a/libcxx/include/cwchar b/libcxx/include/cwchar
index 770b6f2a31d88..599f4f4c317f6 100644
--- a/libcxx/include/cwchar
+++ b/libcxx/include/cwchar
@@ -114,7 +114,6 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
 #  include <__type_traits/is_same.h>
 #  include <__type_traits/remove_cv.h>
 #  include <cwctype>
-
 #  include <wchar.h>
 
 #  ifndef _LIBCPP_WCHAR_H
diff --git a/libcxx/include/iosfwd b/libcxx/include/iosfwd
index 11241afd68e53..4d9f33143fde6 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -112,13 +112,13 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #  include <__fwd/fstream.h>
 #  include <__fwd/ios.h>
 #  include <__fwd/istream.h>
+#  include <__fwd/mbstate_t.h>
 #  include <__fwd/memory.h>
 #  include <__fwd/ostream.h>
 #  include <__fwd/sstream.h>
 #  include <__fwd/streambuf.h>
 #  include <__fwd/string.h>
 #  include <version>
-#  include <wchar.h>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #    pragma GCC system_header
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 46b45cf75ccdb..94abc50d2206b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1501,6 +1501,7 @@ module std {
   }
 
   module iosfwd {
+    module fwd { header "__fwd/mbstate_t.h" }
     header "iosfwd"
     export *
   }
@@ -2469,6 +2470,10 @@ module std {
   module hash_table           { header "__hash_table" }
   module node_handle          { header "__node_handle" }
   module split_buffer         { header "__split_buffer" }
+  module std_mbstate_t {
+    header "__fwd/mbstate_t.h"
+    export *
+  }
   module tree                 {
     header "__tree"
     export std.memory.unique_ptr
diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py
index d041cbcdd13d4..86962ba2e0c4c 100644
--- a/libcxx/utils/generate_iwyu_mapping.py
+++ b/libcxx/utils/generate_iwyu_mapping.py
@@ -45,7 +45,9 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
         return ["utility"]
     elif header == "__fwd/subrange.h":
         return ["ranges"]
-    elif re.match("__fwd/(fstream|ios|istream|ostream|sstream|streambuf)[.]h", header):
+    elif re.match(
+        "__fwd/(fstream|ios|istream|mbstate_t|ostream|sstream|streambuf)[.]h", header
+    ):
         return ["iosfwd"]
     # Handle remaining forward declaration headers
     elif re.match("__fwd/(.+)[.]h", header):



More information about the libcxx-commits mailing list