Skip to content

Commit 5407763

Browse files
committed
Fix wchar.h to work with modules.
Textual headers are guaranteed to be safe to include multiple times. Function definitions are not safe to be included multiple times. Although the function definitions are guarded by a header guard, header guards do not work properly with modules. Consider: module a: #include <wchar.h> module b: #include <wchar.h> module c: #include <a> #include <b> When precompling A, the AST now contains all function definitions in wchar.h. The same goes for B. When compiling C, both A and B provide definitions for these functions, resulting in ODR violations. When this occurs, you get an ODR violation while attempting to compile the module std. This is because function definitions cannot be textual. To solve this, we split the module into a textual and non-textual component.
1 parent a17f635 commit 5407763

File tree

4 files changed

+132
-87
lines changed

4 files changed

+132
-87
lines changed

libcxx/include/__mbstate_t.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@
4343
# include <bits/types/mbstate_t.h> // works on most Unixes
4444
#elif __has_include(<sys/_types/_mbstate_t.h>)
4545
# include <sys/_types/_mbstate_t.h> // works on Darwin
46+
// include_next works differently for module builders.
4647
#elif __has_include_next(<wchar.h>)
48+
# define _LIBCPP_INCLUDE_NEXT_WCHAR
4749
# include_next <wchar.h> // use the C standard provider of mbstate_t if present
50+
# undef _LIBCPP_INCLUDE_NEXT_WCHAR
51+
# ifdef _LIBCPP_WCHAR_NOT_FOUND
52+
# undef _LIBCPP_WCHAR_NOT_FOUND
53+
# include <uchar.h>
54+
# endif
4855
#elif __has_include_next(<uchar.h>)
4956
# include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
5057
#else

libcxx/include/__wchar.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
// Lack of header guards is intentional.
11+
// This file should only ever be included by wchar.h, which provides its own
12+
// header guard. This prevents macro hiding issues with modules where cwchar
13+
// complains that _LIBCPP_WCHAR_H isn't present.
14+
15+
#include <__config>
16+
#include <__mbstate_t.h> // provide mbstate_t
17+
#include <stddef.h> // provide size_t
18+
19+
// include_next doesn't work with modules.
20+
#if __has_include_next(<wchar.h>)
21+
# define _LIBCPP_INCLUDE_NEXT_WCHAR
22+
# include_next <wchar.h>
23+
# undef _LIBCPP_INCLUDE_NEXT_WCHAR
24+
#endif
25+
26+
// Determine whether we have const-correct overloads for wcschr and friends.
27+
#if defined(_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_)
28+
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
29+
#elif defined(__GLIBC_PREREQ)
30+
# if __GLIBC_PREREQ(2, 10)
31+
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
32+
# endif
33+
#elif defined(_LIBCPP_MSVCRT)
34+
# if defined(_CRT_CONST_CORRECT_OVERLOADS)
35+
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
36+
# endif
37+
#endif
38+
39+
#if _LIBCPP_HAS_WIDE_CHARACTERS
40+
# if defined(__cplusplus) && !defined(_LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS) && defined(_LIBCPP_PREFERRED_OVERLOAD)
41+
extern "C++" {
42+
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcschr(const wchar_t* __s, wchar_t __c) {
43+
return (wchar_t*)wcschr(__s, __c);
44+
}
45+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t* wcschr(const wchar_t* __s, wchar_t __c) {
46+
return __libcpp_wcschr(__s, __c);
47+
}
48+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcschr(wchar_t* __s, wchar_t __c) {
49+
return __libcpp_wcschr(__s, __c);
50+
}
51+
52+
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {
53+
return (wchar_t*)wcspbrk(__s1, __s2);
54+
}
55+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
56+
wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {
57+
return __libcpp_wcspbrk(__s1, __s2);
58+
}
59+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcspbrk(wchar_t* __s1, const wchar_t* __s2) {
60+
return __libcpp_wcspbrk(__s1, __s2);
61+
}
62+
63+
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcsrchr(const wchar_t* __s, wchar_t __c) {
64+
return (wchar_t*)wcsrchr(__s, __c);
65+
}
66+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t* wcsrchr(const wchar_t* __s, wchar_t __c) {
67+
return __libcpp_wcsrchr(__s, __c);
68+
}
69+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcsrchr(wchar_t* __s, wchar_t __c) {
70+
return __libcpp_wcsrchr(__s, __c);
71+
}
72+
73+
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcsstr(const wchar_t* __s1, const wchar_t* __s2) {
74+
return (wchar_t*)wcsstr(__s1, __s2);
75+
}
76+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
77+
wcsstr(const wchar_t* __s1, const wchar_t* __s2) {
78+
return __libcpp_wcsstr(__s1, __s2);
79+
}
80+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcsstr(wchar_t* __s1, const wchar_t* __s2) {
81+
return __libcpp_wcsstr(__s1, __s2);
82+
}
83+
84+
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wmemchr(const wchar_t* __s, wchar_t __c, size_t __n) {
85+
return (wchar_t*)wmemchr(__s, __c, __n);
86+
}
87+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
88+
wmemchr(const wchar_t* __s, wchar_t __c, size_t __n) {
89+
return __libcpp_wmemchr(__s, __c, __n);
90+
}
91+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wmemchr(wchar_t* __s, wchar_t __c, size_t __n) {
92+
return __libcpp_wmemchr(__s, __c, __n);
93+
}
94+
}
95+
# endif
96+
97+
# if defined(__cplusplus) && (defined(_LIBCPP_MSVCRT_LIKE) || defined(__MVS__))
98+
extern "C" {
99+
size_t mbsnrtowcs(
100+
wchar_t* __restrict __dst, const char** __restrict __src, size_t __nmc, size_t __len, mbstate_t* __restrict __ps);
101+
size_t wcsnrtombs(
102+
char* __restrict __dst, const wchar_t** __restrict __src, size_t __nwc, size_t __len, mbstate_t* __restrict __ps);
103+
} // extern "C"
104+
# endif // __cplusplus && (_LIBCPP_MSVCRT || __MVS__)
105+
#endif // _LIBCPP_HAS_WIDE_CHARACTERS

libcxx/include/module.modulemap.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,6 +2420,9 @@ module std_uchar_h [system] {
24202420
module std_wchar_h [system] {
24212421
// <wchar.h> supports being included multiple times with different pre-defined macros
24222422
textual header "wchar.h"
2423+
// Parts of wchar.h contain function definitions, so cannot be included
2424+
// multiple times.
2425+
header "__wchar.h"
24232426
}
24242427
module std_wctype_h [system] {
24252428
header "wctype.h"

libcxx/include/wchar.h

Lines changed: 17 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,17 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
9494
9595
*/
9696

97-
#if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
97+
// #include_next has different semantics for module builds.
98+
// include_next<wchar.h> only works if the current filename is wchar.h,
99+
// otherwise it just does a regular #include.
100+
// To solve this, if _LIBCPP_INCLUDE_NEXT_WCHAR is defined, fake an include_next.
101+
#ifdef _LIBCPP_INCLUDE_NEXT_WCHAR
102+
# if __has_include_next(<wchar.h>)
103+
# include_next <wchar.h>
104+
# elif defined(_LIBCPP_INCLUDE_NEXT_WCHAR)
105+
# define _LIBCPP_WCHAR_NOT_FOUND
106+
# endif
107+
#elif defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
98108
# include <__cxx03/wchar.h>
99109
#else
100110
# include <__config>
@@ -116,92 +126,12 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
116126
# include_next <wchar.h>
117127
# endif
118128

119-
# ifndef _LIBCPP_WCHAR_H
129+
// Place the header guard here to make it visible to cwchar.
130+
# if !defined(_LIBCPP_WCHAR_H)
120131
# define _LIBCPP_WCHAR_H
121-
122-
# include <__mbstate_t.h> // provide mbstate_t
123-
# include <stddef.h> // provide size_t
124-
125-
// Determine whether we have const-correct overloads for wcschr and friends.
126-
# if defined(_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_)
127-
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
128-
# elif defined(__GLIBC_PREREQ)
129-
# if __GLIBC_PREREQ(2, 10)
130-
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
131-
# endif
132-
# elif defined(_LIBCPP_MSVCRT)
133-
# if defined(_CRT_CONST_CORRECT_OVERLOADS)
134-
# define _LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS 1
135-
# endif
136-
# endif
137-
138-
# if _LIBCPP_HAS_WIDE_CHARACTERS
139-
# if defined(__cplusplus) && !defined(_LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS) && defined(_LIBCPP_PREFERRED_OVERLOAD)
140-
extern "C++" {
141-
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcschr(const wchar_t* __s, wchar_t __c) {
142-
return (wchar_t*)wcschr(__s, __c);
143-
}
144-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t* wcschr(const wchar_t* __s, wchar_t __c) {
145-
return __libcpp_wcschr(__s, __c);
146-
}
147-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcschr(wchar_t* __s, wchar_t __c) {
148-
return __libcpp_wcschr(__s, __c);
149-
}
150-
151-
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {
152-
return (wchar_t*)wcspbrk(__s1, __s2);
153-
}
154-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
155-
wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {
156-
return __libcpp_wcspbrk(__s1, __s2);
157-
}
158-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcspbrk(wchar_t* __s1, const wchar_t* __s2) {
159-
return __libcpp_wcspbrk(__s1, __s2);
160-
}
161-
162-
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcsrchr(const wchar_t* __s, wchar_t __c) {
163-
return (wchar_t*)wcsrchr(__s, __c);
164-
}
165-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t* wcsrchr(const wchar_t* __s, wchar_t __c) {
166-
return __libcpp_wcsrchr(__s, __c);
167-
}
168-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcsrchr(wchar_t* __s, wchar_t __c) {
169-
return __libcpp_wcsrchr(__s, __c);
170-
}
171-
172-
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wcsstr(const wchar_t* __s1, const wchar_t* __s2) {
173-
return (wchar_t*)wcsstr(__s1, __s2);
174-
}
175-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
176-
wcsstr(const wchar_t* __s1, const wchar_t* __s2) {
177-
return __libcpp_wcsstr(__s1, __s2);
178-
}
179-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wcsstr(wchar_t* __s1, const wchar_t* __s2) {
180-
return __libcpp_wcsstr(__s1, __s2);
181-
}
182-
183-
inline _LIBCPP_HIDE_FROM_ABI wchar_t* __libcpp_wmemchr(const wchar_t* __s, wchar_t __c, size_t __n) {
184-
return (wchar_t*)wmemchr(__s, __c, __n);
185-
}
186-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const wchar_t*
187-
wmemchr(const wchar_t* __s, wchar_t __c, size_t __n) {
188-
return __libcpp_wmemchr(__s, __c, __n);
189-
}
190-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wmemchr(wchar_t* __s, wchar_t __c, size_t __n) {
191-
return __libcpp_wmemchr(__s, __c, __n);
192-
}
193-
}
194-
# endif
195-
196-
# if defined(__cplusplus) && (defined(_LIBCPP_MSVCRT_LIKE) || defined(__MVS__))
197-
extern "C" {
198-
size_t mbsnrtowcs(
199-
wchar_t* __restrict __dst, const char** __restrict __src, size_t __nmc, size_t __len, mbstate_t* __restrict __ps);
200-
size_t wcsnrtombs(
201-
char* __restrict __dst, const wchar_t** __restrict __src, size_t __nwc, size_t __len, mbstate_t* __restrict __ps);
202-
} // extern "C"
203-
# endif // __cplusplus && (_LIBCPP_MSVCRT || __MVS__)
204-
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
205-
# endif // _LIBCPP_WCHAR_H
132+
// This section is not safe to include multiple times, so it goes in a seperate
133+
// file which is marked as non textual in the modulemap.
134+
# include <__wchar.h>
135+
# endif
206136

207137
#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

0 commit comments

Comments
 (0)