Skip to content

Commit 6be11e3

Browse files
committed
[libcxx] Implement c++2a char8_t input/output of std::filesystem::path
This implements the std::filesystem parts of P0482 (which is already marked as in progress), and applies the actions that are suggested in P1423. Differential Revision: https://reviews.llvm.org/D90222
1 parent c17fdca commit 6be11e3

File tree

9 files changed

+100
-6
lines changed

9 files changed

+100
-6
lines changed

libcxx/docs/Cxx2aStatusPaperStatus.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
"`P1208 <https://wg21.link/P1208>`__","LWG","Adopt source_location for C++20","Cologne","",""
116116
"`P1355 <https://wg21.link/P1355>`__","LWG","Exposing a narrow contract for ceil2","Cologne","|Complete|","9.0"
117117
"`P1361 <https://wg21.link/P1361>`__","LWG","Integration of chrono with text formatting","Cologne","",""
118-
"`P1423 <https://wg21.link/P1423>`__","LWG","char8_t backward compatibility remediation","Cologne","",""
118+
"`P1423 <https://wg21.link/P1423>`__","LWG","char8_t backward compatibility remediation","Cologne","|In Progress|",""
119119
"`P1424 <https://wg21.link/P1424>`__","LWG","'constexpr' feature macro concerns","Cologne","Superseded by `P1902 <https://wg21.link/P1902>`__",""
120120
"`P1466 <https://wg21.link/P1466>`__","LWG","Miscellaneous minor fixes for chrono","Cologne","",""
121121
"`P1474 <https://wg21.link/P1474>`__","LWG","Helpful pointers for ContiguousIterator","Cologne","",""

libcxx/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,9 @@ API Changes
5656
- ``ceil2`` has been renamed to ``bit_ceil``
5757
- ``floor2`` has been renamed to ``bit_floor``
5858
- ``log2p1`` has been renamed to ``bit_width``
59+
60+
- In C++20 mode, ``std::filesystem::path::u8string()`` and
61+
``generic_u8string()`` now return ``std::u8string`` according to P0428,
62+
while they return ``std::string`` in C++17. This can cause source
63+
incompatibility, which is discussed and acknowledged in P1423, but that
64+
paper doesn't suggest any remediation for this incompatibility.

libcxx/include/__config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,12 @@ typedef unsigned int char32_t;
989989
# define _LIBCPP_DEPRECATED_IN_CXX20
990990
#endif
991991

992+
#if !defined(_LIBCPP_NO_HAS_CHAR8_T)
993+
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED
994+
#else
995+
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T
996+
#endif
997+
992998
// Macros to enter and leave a state where deprecation warnings are suppressed.
993999
#if !defined(_LIBCPP_SUPPRESS_DEPRECATED_PUSH) && \
9941000
(defined(_LIBCPP_COMPILER_CLANG) || defined(_LIBCPP_COMPILER_GCC))

libcxx/include/filesystem

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,13 @@ struct __can_convert_char<wchar_t> {
547547
static const bool value = true;
548548
using __char_type = wchar_t;
549549
};
550+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
551+
template <>
552+
struct __can_convert_char<char8_t> {
553+
static const bool value = true;
554+
using __char_type = char8_t;
555+
};
556+
#endif
550557
template <>
551558
struct __can_convert_char<char16_t> {
552559
static const bool value = true;
@@ -995,7 +1002,11 @@ public:
9951002
_LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; }
9961003

9971004
_LIBCPP_INLINE_VISIBILITY _VSTD::string string() const { return __pn_; }
1005+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1006+
_LIBCPP_INLINE_VISIBILITY _VSTD::u8string u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); }
1007+
#else
9981008
_LIBCPP_INLINE_VISIBILITY _VSTD::string u8string() const { return __pn_; }
1009+
#endif
9991010

10001011
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
10011012
template <class _ECharT, class _Traits = char_traits<_ECharT>,
@@ -1023,7 +1034,11 @@ public:
10231034

10241035
// generic format observers
10251036
_VSTD::string generic_string() const { return __pn_; }
1037+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1038+
_VSTD::u8string generic_u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); }
1039+
#else
10261040
_VSTD::string generic_u8string() const { return __pn_; }
1041+
#endif
10271042

10281043
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
10291044
template <class _ECharT, class _Traits = char_traits<_ECharT>,
@@ -1213,23 +1228,37 @@ _LIBCPP_FUNC_VIS
12131228
size_t hash_value(const path& __p) noexcept;
12141229

12151230
template <class _Source>
1216-
_LIBCPP_INLINE_VISIBILITY
1231+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T
12171232
typename enable_if<__is_pathable<_Source>::value, path>::type
12181233
u8path(const _Source& __s) {
12191234
static_assert(
1235+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1236+
is_same<typename __is_pathable<_Source>::__char_type, char8_t>::value ||
1237+
#endif
12201238
is_same<typename __is_pathable<_Source>::__char_type, char>::value,
12211239
"u8path(Source const&) requires Source have a character type of type "
1222-
"'char'");
1240+
"'char'"
1241+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1242+
" or 'char8_t'"
1243+
#endif
1244+
);
12231245
return path(__s);
12241246
}
12251247

12261248
template <class _InputIt>
1227-
_LIBCPP_INLINE_VISIBILITY
1249+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T
12281250
typename enable_if<__is_pathable<_InputIt>::value, path>::type
12291251
u8path(_InputIt __f, _InputIt __l) {
12301252
static_assert(
1253+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1254+
is_same<typename __is_pathable<_InputIt>::__char_type, char8_t>::value ||
1255+
#endif
12311256
is_same<typename __is_pathable<_InputIt>::__char_type, char>::value,
1232-
"u8path(Iter, Iter) requires Iter have a value_type of type 'char'");
1257+
"u8path(Iter, Iter) requires Iter have a value_type of type 'char'"
1258+
#ifndef _LIBCPP_NO_HAS_CHAR8_T
1259+
" or 'char8_t'"
1260+
#endif
1261+
);
12331262
return path(__f, __l);
12341263
}
12351264

libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ void test_sfinae() {
123123
int main(int, char**) {
124124
for (auto const& MS : PathList) {
125125
RunTestCase<char>(MS);
126+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
127+
RunTestCase<char8_t>(MS);
128+
#endif
126129
RunTestCase<wchar_t>(MS);
127130
RunTestCase<char16_t>(MS);
128131
RunTestCase<char32_t>(MS);

libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,15 @@ int main(int, char**)
4545
assert(s == value);
4646
}
4747
{
48+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
49+
ASSERT_SAME_TYPE(decltype(p.generic_u8string()), std::u8string);
50+
std::u8string s = p.generic_u8string();
51+
assert(s == (const char8_t*)MS);
52+
#else
53+
ASSERT_SAME_TYPE(decltype(p.generic_u8string()), std::string);
4854
std::string s = p.generic_u8string();
4955
assert(s == (const char*)MS);
56+
#endif
5057
}
5158
{
5259
std::wstring s = p.generic_wstring();

libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,15 @@ int main(int, char**)
4646
assert(s == value);
4747
}
4848
{
49+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
50+
ASSERT_SAME_TYPE(decltype(p.u8string()), std::u8string);
51+
std::u8string s = p.u8string();
52+
assert(s == (const char8_t*)MS);
53+
#else
54+
ASSERT_SAME_TYPE(decltype(p.u8string()), std::string);
4955
std::string s = p.u8string();
5056
assert(s == (const char*)MS);
57+
#endif
5158
}
5259
{
5360
std::wstring s = p.wstring();

libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
// UNSUPPORTED: c++03
10+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
1011

1112
// <filesystem>
1213

@@ -48,6 +49,29 @@ int main(int, char**)
4849
path p = fs::u8path(In3, In3End);
4950
assert(p == In1);
5051
}
52+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t) && defined(_LIBCPP_VERSION)
53+
const char8_t* u8In1 = u8"abcd/efg";
54+
const std::u8string u8In2(u8In1);
55+
const auto u8In3 = u8In2.begin();
56+
const auto u8In3End = u8In2.end();
57+
// Proposed in P1423, marked tested only for libc++
58+
{
59+
path p = fs::u8path(u8In1);
60+
assert(p == In1);
61+
}
62+
{
63+
path p = fs::u8path(u8In2);
64+
assert(p == In1);
65+
}
66+
{
67+
path p = fs::u8path(u8In3);
68+
assert(p == In1);
69+
}
70+
{
71+
path p = fs::u8path(u8In3, u8In3End);
72+
assert(p == In1);
73+
}
74+
#endif
5175

5276
return 0;
5377
}

libcxx/test/support/filesystem_test_helper.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,16 +430,28 @@ struct CWDGuard {
430430

431431
// Misc test types
432432

433-
#define MKSTR(Str) {Str, TEST_CONCAT(L, Str), TEST_CONCAT(u, Str), TEST_CONCAT(U, Str)}
433+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
434+
#define CHAR8_ONLY(x) x,
435+
#else
436+
#define CHAR8_ONLY(x)
437+
#endif
438+
439+
#define MKSTR(Str) {Str, TEST_CONCAT(L, Str), CHAR8_ONLY(TEST_CONCAT(u8, Str)) TEST_CONCAT(u, Str), TEST_CONCAT(U, Str)}
434440

435441
struct MultiStringType {
436442
const char* s;
437443
const wchar_t* w;
444+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
445+
const char8_t* u8;
446+
#endif
438447
const char16_t* u16;
439448
const char32_t* u32;
440449

441450
operator const char* () const { return s; }
442451
operator const wchar_t* () const { return w; }
452+
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
453+
operator const char8_t* () const { return u8; }
454+
#endif
443455
operator const char16_t* () const { return u16; }
444456
operator const char32_t* () const { return u32; }
445457
};

0 commit comments

Comments
 (0)