[libcxx-commits] [libcxx] a595b93 - [libc++] cuchar redeclares ::mbstate_t when it's in its own clang module
Ian Anderson via libcxx-commits
libcxx-commits at lists.llvm.org
Mon May 1 11:48:26 PDT 2023
Author: Ian Anderson
Date: 2023-05-01T13:48:20-05:00
New Revision: a595b931f1f91897317a4257df313bddfeb029a6
URL: https://github.com/llvm/llvm-project/commit/a595b931f1f91897317a4257df313bddfeb029a6
DIFF: https://github.com/llvm/llvm-project/commit/a595b931f1f91897317a4257df313bddfeb029a6.diff
LOG: [libc++] cuchar redeclares ::mbstate_t when it's in its own clang module
When cuchar is compiled independently on platforms that don't have <uchar.h>, it doesn't get a declaration of mbstate_t, and so makes an empty declaration for ::mbstate_t. That conflicts with the declarations in __mbstate_t.h and cwchar since both of those headers do get mbstate_t before making ::mbstate_t.
Change `__mbstate_t.h` to just get the underlying declaration for mbstate_t and not make a declaration for ::mbstate_t. Include __mbstate_t.h in uchar.h and wchar.h when their next headers aren't available so that at least mbstate_t gets defined.
Add __std_mbstate_t.h to declare ::mbstate_t for headers that need that when cuchar or cwchar aren't available (because either _LIBCPP_HAS_NO_WIDE_CHARACTERS or _LIBCPP_CXX03_LANG).
Reviewed By: ldionne, Mordante, #libc, philnik
Differential Revision: https://reviews.llvm.org/D148542
Added:
libcxx/include/__std_mbstate_t.h
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__locale
libcxx/include/__mbstate_t.h
libcxx/include/iosfwd
libcxx/include/module.modulemap.in
libcxx/include/uchar.h
libcxx/include/wchar.h
libcxx/test/libcxx/private_headers.verify.cpp
libcxx/utils/generate_iwyu_mapping.py
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fa64cec327e6c..356af6db8f6c0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -614,6 +614,7 @@ set(files
__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
index 994613083cdff..a812427acba4e 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -25,6 +25,8 @@
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# include <cwchar>
+#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
index 487a6d092c715..d793787fa0cd6 100644
--- 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
-// <wchar.h> or <uchar.h>. 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
+// <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 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 <wchar.h> // for mbstate_t
-#elif __has_include(<bits/types/mbstate_t.h>)
+#if __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 "The library was configured without support for wide-characters, but we don't know how to get the definition of mbstate_t without <wchar.h> on your platform."
+# 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___MBSTATE_T_H
diff --git a/libcxx/include/__std_mbstate_t.h b/libcxx/include/__std_mbstate_t.h
new file mode 100644
index 0000000000000..e79cc789fddf9
--- /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 <cuchar> or <cwchar>.
+
+_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
index 0af7df30d8fd7..e3cd9faa70b7b 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -103,7 +103,7 @@ using u32streampos = fpos<char_traits<char32_t>::state_type>;
#include <__fwd/sstream.h>
#include <__fwd/streambuf.h>
#include <__fwd/string.h>
-#include <__mbstate_t.h>
+#include <__std_mbstate_t.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 01f763d764e62..99907787132b8 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1735,6 +1735,7 @@ module std [system] {
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
index 3a51bb7a9f61f..546113f7eab46 100644
--- a/libcxx/include/uchar.h
+++ b/libcxx/include/uchar.h
@@ -42,10 +42,12 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
// Some platforms don't implement <uchar.h> and we don't want to give a hard
// error on those platforms. When the platform doesn't provide <uchar.h>, at
-// least include <stddef.h> so we get the declaration for size_t.
+// least include <stddef.h> so we get the declaration for size_t, and try to
+// 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
diff --git a/libcxx/include/wchar.h b/libcxx/include/wchar.h
index c684508dc2ccd..db624cea2bee3 100644
--- a/libcxx/include/wchar.h
+++ b/libcxx/include/wchar.h
@@ -122,6 +122,8 @@ 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 <__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/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 48b9a7f8c5745..0720e1f72a77f 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -614,6 +614,7 @@ END-SCRIPT
#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
index cb27d46773955..f8377a976f08e 100644
--- a/libcxx/utils/generate_iwyu_mapping.py
+++ b/libcxx/utils/generate_iwyu_mapping.py
@@ -56,11 +56,12 @@ def generate_map(include):
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)},')
More information about the libcxx-commits
mailing list