Skip to content

Commit a595b93

Browse files
[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
1 parent 7f3b0e5 commit a595b93

File tree

10 files changed

+57
-20
lines changed

10 files changed

+57
-20
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ set(files
614614
__ranges/views.h
615615
__ranges/zip_view.h
616616
__split_buffer
617+
__std_mbstate_t.h
617618
__string/char_traits.h
618619
__string/constexpr_c_functions.h
619620
__string/extern_template_lists.h

libcxx/include/__locale

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2727
# include <cwchar>
28+
#else
29+
# include <__std_mbstate_t.h>
2830
#endif
2931

3032
#if defined(_LIBCPP_MSVCRT_LIKE)

libcxx/include/__mbstate_t.h

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,27 @@
1616
# pragma GCC system_header
1717
#endif
1818

19-
// TODO(ldionne):
20-
// The goal of this header is to provide mbstate_t without having to pull in
21-
// <wchar.h> or <uchar.h>. This is necessary because we need that type even
22-
// when we don't have (or try to provide) support for wchar_t, because several
23-
// types like std::fpos are defined in terms of mbstate_t.
19+
// The goal of this header is to provide mbstate_t without requiring all of
20+
// <uchar.h> or <wchar.h>. It's also used by the libc++ versions of <uchar.h>
21+
// and <wchar.h> to get mbstate_t when the C library doesn't provide <uchar.h>
22+
// or <wchar.h>, hence the #include_next of those headers instead of #include.
23+
// (e.g. if <wchar.h> isn't present in the C library, the libc++ <wchar.h>
24+
// will include this header. This header needs to not turn around and cyclically
25+
// include <wchar.h>, but fall through to <uchar.h>.)
2426
//
25-
// This is a gruesome hack, but I don't know how to make it cleaner for
26-
// the time being.
27+
// This does not define std::mbstate_t -- this only brings in the declaration
28+
// in the global namespace.
2729

28-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
29-
# include <wchar.h> // for mbstate_t
30-
#elif __has_include(<bits/types/mbstate_t.h>)
30+
#if __has_include(<bits/types/mbstate_t.h>)
3131
# include <bits/types/mbstate_t.h> // works on most Unixes
3232
#elif __has_include(<sys/_types/_mbstate_t.h>)
3333
# include <sys/_types/_mbstate_t.h> // works on Darwin
34+
#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next(<wchar.h>)
35+
# include_next <wchar.h> // fall back to the C standard provider of mbstate_t
36+
#elif __has_include_next(<uchar.h>)
37+
# include_next <uchar.h> // <uchar.h> is also required to make mbstate_t visible
3438
#else
35-
# 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."
39+
# error "We don't know how to get the definition of mbstate_t without <wchar.h> on your platform."
3640
#endif
3741

38-
_LIBCPP_BEGIN_NAMESPACE_STD
39-
40-
using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
41-
42-
_LIBCPP_END_NAMESPACE_STD
43-
4442
#endif // _LIBCPP___MBSTATE_T_H

libcxx/include/__std_mbstate_t.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___STD_MBSTATE_T_H
11+
#define _LIBCPP___STD_MBSTATE_T_H
12+
13+
#include <__config>
14+
#include <__mbstate_t.h>
15+
16+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
17+
# pragma GCC system_header
18+
#endif
19+
20+
// The goal of this header is to provide std::mbstate_t without requiring all
21+
// of <cuchar> or <cwchar>.
22+
23+
_LIBCPP_BEGIN_NAMESPACE_STD
24+
25+
using ::mbstate_t _LIBCPP_USING_IF_EXISTS;
26+
27+
_LIBCPP_END_NAMESPACE_STD
28+
29+
#endif // _LIBCPP___STD_MBSTATE_T_H

libcxx/include/iosfwd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ using u32streampos = fpos<char_traits<char32_t>::state_type>;
103103
#include <__fwd/sstream.h>
104104
#include <__fwd/streambuf.h>
105105
#include <__fwd/string.h>
106-
#include <__mbstate_t.h>
106+
#include <__std_mbstate_t.h>
107107
#include <version>
108108

109109
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,7 @@ module std [system] {
17351735
module __mbstate_t { private header "__mbstate_t.h" export * }
17361736
module __node_handle { private header "__node_handle" export * }
17371737
module __split_buffer { private header "__split_buffer" export * }
1738+
module __std_mbstate_t { private header "__std_mbstate_t.h" export * }
17381739
module __threading_support { header "__threading_support" export * }
17391740
module __tree { header "__tree" export * }
17401741
module __undef_macros { header "__undef_macros" export * }

libcxx/include/uchar.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
4242

4343
// Some platforms don't implement <uchar.h> and we don't want to give a hard
4444
// error on those platforms. When the platform doesn't provide <uchar.h>, at
45-
// least include <stddef.h> so we get the declaration for size_t.
45+
// least include <stddef.h> so we get the declaration for size_t, and try to
46+
// get the declaration of mbstate_t too.
4647
#if __has_include_next(<uchar.h>)
4748
# include_next <uchar.h>
4849
#else
50+
# include <__mbstate_t.h>
4951
# include <stddef.h>
5052
#endif
5153

libcxx/include/wchar.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
122122

123123
# if __has_include_next(<wchar.h>)
124124
# include_next <wchar.h>
125+
# else
126+
# include <__mbstate_t.h> // make sure we have mbstate_t regardless of the existence of <wchar.h>
125127
# endif
126128

127129
// Determine whether we have const-correct overloads for wcschr and friends.

libcxx/test/libcxx/private_headers.verify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ END-SCRIPT
614614
#include <__ranges/views.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/views.h'}}
615615
#include <__ranges/zip_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/zip_view.h'}}
616616
#include <__split_buffer> // expected-error@*:* {{use of private header from outside its module: '__split_buffer'}}
617+
#include <__std_mbstate_t.h> // expected-error@*:* {{use of private header from outside its module: '__std_mbstate_t.h'}}
617618
#include <__string/char_traits.h> // expected-error@*:* {{use of private header from outside its module: '__string/char_traits.h'}}
618619
#include <__string/constexpr_c_functions.h> // expected-error@*:* {{use of private header from outside its module: '__string/constexpr_c_functions.h'}}
619620
#include <__string/extern_template_lists.h> // expected-error@*:* {{use of private header from outside its module: '__string/extern_template_lists.h'}}

libcxx/utils/generate_iwyu_mapping.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ def generate_map(include):
5656
elif i == '__pstl_memory': continue
5757
elif i == '__pstl_numeric': continue
5858
elif i == '__split_buffer': public = ['deque', 'vector']
59+
elif i == '__std_mbstate_t.h': continue
5960
elif i == '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread']
6061
elif i == '__tree': public = ['map', 'set']
6162
elif i == '__undef_macros': continue
6263
elif i == '__verbose_abort': continue
63-
else: panic()
64+
else: panic(i)
6465

6566
for p in public:
6667
result.append(f'{generate(f"<{i}>", p)},')

0 commit comments

Comments
 (0)