Skip to content

Commit 26be07b

Browse files
authored
[libc++][format] Disables narrow string to wide string formatters. (#128355)
Implements LWG3944: Formatters converting sequences of char to sequences of wchar_t Fixes: #105342
1 parent a841cf9 commit 26be07b

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

libcxx/docs/Status/Cxx2cIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"`LWG4053 <https://wg21.link/LWG4053>`__","Unary call to ``std::views::repeat`` does not decay the argument","2024-03 (Tokyo)","|Complete|","19",""
6363
"`LWG4054 <https://wg21.link/LWG4054>`__","Repeating a ``repeat_view`` should repeat the view","2024-03 (Tokyo)","|Complete|","19",""
6464
"","","","","",""
65-
"`LWG3944 <https://wg21.link/LWG3944>`__","Formatters converting sequences of ``char`` to sequences of ``wchar_t``","2024-06 (St. Louis)","","",""
65+
"`LWG3944 <https://wg21.link/LWG3944>`__","Formatters converting sequences of ``char`` to sequences of ``wchar_t``","2024-06 (St. Louis)","|Complete|","21",""
6666
"`LWG4060 <https://wg21.link/LWG4060>`__","``submdspan`` preconditions do not forbid creating invalid pointer","2024-06 (St. Louis)","","",""
6767
"`LWG4061 <https://wg21.link/LWG4061>`__","Should ``std::basic_format_context`` be default-constructible/copyable/movable?","2024-06 (St. Louis)","|Complete|","19",""
6868
"`LWG4071 <https://wg21.link/LWG4071>`__","``reference_wrapper`` comparisons are not SFINAE-friendly","2024-06 (St. Louis)","|Complete|","19",""

libcxx/include/__format/formatter.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2121

2222
#if _LIBCPP_STD_VER >= 20
2323

24+
struct __disabled_formatter {
25+
__disabled_formatter() = delete;
26+
__disabled_formatter(const __disabled_formatter&) = delete;
27+
__disabled_formatter& operator=(const __disabled_formatter&) = delete;
28+
};
29+
2430
/// The default formatter template.
2531
///
2632
/// [format.formatter.spec]/5
@@ -31,11 +37,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3137
/// - is_copy_assignable_v<F>, and
3238
/// - is_move_assignable_v<F>.
3339
template <class _Tp, class _CharT>
34-
struct _LIBCPP_TEMPLATE_VIS formatter {
35-
formatter() = delete;
36-
formatter(const formatter&) = delete;
37-
formatter& operator=(const formatter&) = delete;
38-
};
40+
struct _LIBCPP_TEMPLATE_VIS formatter : __disabled_formatter {};
3941

4042
# if _LIBCPP_STD_VER >= 23
4143

libcxx/include/__format/formatter_string.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@ struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT
125125
}
126126
};
127127

128+
# if _LIBCPP_HAS_WIDE_CHARACTERS
129+
template <>
130+
struct formatter<char*, wchar_t> : __disabled_formatter {};
131+
template <>
132+
struct formatter<const char*, wchar_t> : __disabled_formatter {};
133+
template <size_t _Size>
134+
struct formatter<char[_Size], wchar_t> : __disabled_formatter {};
135+
template <class _Traits, class _Allocator>
136+
struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> : __disabled_formatter {};
137+
template <class _Traits>
138+
struct formatter<basic_string_view<char, _Traits>, wchar_t> : __disabled_formatter {};
139+
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
140+
128141
# if _LIBCPP_STD_VER >= 23
129142
template <>
130143
inline constexpr bool enable_nonlocking_formatter_optimization<char*> = true;

libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,21 @@ void test_LWG3631() {
292292
assert_is_not_formattable<std::pair<volatile int, volatile int>, CharT>();
293293
}
294294

295+
void test_LWG3944() {
296+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
297+
assert_is_not_formattable<char*, wchar_t>();
298+
assert_is_not_formattable<const char*, wchar_t>();
299+
assert_is_not_formattable<char[42], wchar_t>();
300+
assert_is_not_formattable<std::string, wchar_t>();
301+
assert_is_not_formattable<std::string_view, wchar_t>();
302+
303+
assert_is_formattable<std::vector<char>, wchar_t>();
304+
assert_is_formattable<std::set<char>, wchar_t>();
305+
assert_is_formattable<std::map<char, char>, wchar_t>();
306+
assert_is_formattable<std::tuple<char>, wchar_t>();
307+
#endif
308+
}
309+
295310
class c {
296311
void f();
297312
void fc() const;
@@ -417,6 +432,7 @@ void test() {
417432
test_P1636<CharT>();
418433
test_P2286<CharT>();
419434
test_LWG3631<CharT>();
435+
test_LWG3944();
420436
test_abstract_class<CharT>();
421437
test_disabled<CharT>();
422438
}

0 commit comments

Comments
 (0)