diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -614,6 +614,7 @@ __ranges/views.h __ranges/zip_view.h __split_buffer + __std_mbstate_t.h __string/char_traits.h __string/constexpr_c_functions.h __string/extern_template_lists.h diff --git a/libcxx/include/__locale b/libcxx/include/__locale --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -25,6 +25,8 @@ #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # include +#else +# include <__std_mbstate_t.h> #endif #if defined(_LIBCPP_MSVCRT_LIKE) diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h --- a/libcxx/include/__mbstate_t.h +++ b/libcxx/include/__mbstate_t.h @@ -16,29 +16,27 @@ # pragma GCC system_header #endif -// TODO(ldionne): -// The goal of this header is to provide mbstate_t without having to pull in -// or . This is necessary because we need that type even -// when we don't have (or try to provide) support for wchar_t, because several -// types like std::fpos are defined in terms of mbstate_t. +// The goal of this header is to provide mbstate_t without requiring all of +// or . It's also used by the libc++ versions of +// and to get mbstate_t when the C library doesn't provide +// or , hence the #include_next of those headers instead of #include. +// (e.g. if isn't present in the C library, the libc++ +// will include this header. This header needs to not turn around and cyclically +// include , but fall through to .) // -// This is a gruesome hack, but I don't know how to make it cleaner for -// the time being. +// This does not define std::mbstate_t -- this only brings in the declaration +// in the global namespace. -#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS -# include // for mbstate_t -#elif __has_include() +#if __has_include() # include // works on most Unixes #elif __has_include() # include // works on Darwin +#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next() +# include_next // fall back to the C standard provider of mbstate_t +#elif __has_include_next() +# include_next // is also required to make mbstate_t visible #else -# error "The library was configured without support for wide-characters, but we don't know how to get the definition of mbstate_t without on your platform." +# error "We don't know how to get the definition of mbstate_t without on your platform." #endif -_LIBCPP_BEGIN_NAMESPACE_STD - -using ::mbstate_t _LIBCPP_USING_IF_EXISTS; - -_LIBCPP_END_NAMESPACE_STD - #endif // _LIBCPP___MBSTATE_T_H diff --git a/libcxx/include/__std_mbstate_t.h b/libcxx/include/__std_mbstate_t.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__std_mbstate_t.h @@ -0,0 +1,29 @@ +// -*- 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> +#include <__mbstate_t.h> + +#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 or . + +_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/iosfwd b/libcxx/include/iosfwd --- a/libcxx/include/iosfwd +++ b/libcxx/include/iosfwd @@ -103,7 +103,7 @@ #include <__fwd/sstream.h> #include <__fwd/streambuf.h> #include <__fwd/string.h> -#include <__mbstate_t.h> +#include <__std_mbstate_t.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1735,6 +1735,7 @@ module __mbstate_t { private header "__mbstate_t.h" export * } module __node_handle { private header "__node_handle" export * } module __split_buffer { private header "__split_buffer" export * } + module __std_mbstate_t { private header "__std_mbstate_t.h" export * } module __threading_support { header "__threading_support" export * } module __tree { header "__tree" export * } module __undef_macros { header "__undef_macros" export * } diff --git a/libcxx/include/uchar.h b/libcxx/include/uchar.h --- a/libcxx/include/uchar.h +++ b/libcxx/include/uchar.h @@ -42,10 +42,12 @@ // Some platforms don't implement and we don't want to give a hard // error on those platforms. When the platform doesn't provide , at -// least include so we get the declaration for size_t. +// least include so we get the declaration for size_t, and try to +// get the declaration of mbstate_t too. #if __has_include_next() # include_next #else +# include <__mbstate_t.h> # include #endif diff --git a/libcxx/include/wchar.h b/libcxx/include/wchar.h --- a/libcxx/include/wchar.h +++ b/libcxx/include/wchar.h @@ -122,6 +122,8 @@ # if __has_include_next() # include_next +# else +# include <__mbstate_t.h> // make sure we have mbstate_t regardless of the existence of # endif // Determine whether we have const-correct overloads for wcschr and friends. diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -614,6 +614,7 @@ #include <__ranges/views.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/views.h'}} #include <__ranges/zip_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/zip_view.h'}} #include <__split_buffer> // expected-error@*:* {{use of private header from outside its module: '__split_buffer'}} +#include <__std_mbstate_t.h> // expected-error@*:* {{use of private header from outside its module: '__std_mbstate_t.h'}} #include <__string/char_traits.h> // expected-error@*:* {{use of private header from outside its module: '__string/char_traits.h'}} #include <__string/constexpr_c_functions.h> // expected-error@*:* {{use of private header from outside its module: '__string/constexpr_c_functions.h'}} #include <__string/extern_template_lists.h> // expected-error@*:* {{use of private header from outside its module: '__string/extern_template_lists.h'}} diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py --- a/libcxx/utils/generate_iwyu_mapping.py +++ b/libcxx/utils/generate_iwyu_mapping.py @@ -56,11 +56,12 @@ elif i == '__pstl_memory': continue elif i == '__pstl_numeric': continue elif i == '__split_buffer': public = ['deque', 'vector'] + elif i == '__std_mbstate_t.h': continue elif i == '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread'] elif i == '__tree': public = ['map', 'set'] elif i == '__undef_macros': continue elif i == '__verbose_abort': continue - else: panic() + else: panic(i) for p in public: result.append(f'{generate(f"<{i}>", p)},')