[libcxx-commits] [libcxx] [libc++][format] Disables narrow string to wide string formatters. (PR #128355)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sat Feb 22 05:40:39 PST 2025


https://github.com/mordante created https://github.com/llvm/llvm-project/pull/128355

Implements:
- 3944. Formatters converting sequences of char to sequences of wchar_t

Fixes: #105342

>From d098020de9628c66f7e10959c426a101ca9705c1 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sat, 22 Feb 2025 14:37:24 +0100
Subject: [PATCH] [libc++][format] Disable formatter<const char*, wchar_t>.

Implements:
- 3944. Formatters converting sequences of char to sequences of wchar_t

Fixes: #105342
---
 libcxx/docs/Status/Cxx2cIssues.csv               |  2 +-
 libcxx/include/__format/formatter.h              | 12 +++++++-----
 libcxx/include/__format/formatter_string.h       | 13 +++++++++++++
 .../concept.formattable.compile.pass.cpp         | 16 ++++++++++++++++
 4 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 1ec23dfabd5ea..8a521e7d6686e 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -62,7 +62,7 @@
 "`LWG4053 <https://wg21.link/LWG4053>`__","Unary call to ``std::views::repeat`` does not decay the argument","2024-03 (Tokyo)","|Complete|","19",""
 "`LWG4054 <https://wg21.link/LWG4054>`__","Repeating a ``repeat_view`` should repeat the view","2024-03 (Tokyo)","|Complete|","19",""
 "","","","","",""
-"`LWG3944 <https://wg21.link/LWG3944>`__","Formatters converting sequences of ``char`` to sequences of ``wchar_t``","2024-06 (St. Louis)","","",""
+"`LWG3944 <https://wg21.link/LWG3944>`__","Formatters converting sequences of ``char`` to sequences of ``wchar_t``","2024-06 (St. Louis)","|Complete|","21",""
 "`LWG4060 <https://wg21.link/LWG4060>`__","``submdspan`` preconditions do not forbid creating invalid pointer","2024-06 (St. Louis)","","",""
 "`LWG4061 <https://wg21.link/LWG4061>`__","Should ``std::basic_format_context`` be default-constructible/copyable/movable?","2024-06 (St. Louis)","|Complete|","19",""
 "`LWG4071 <https://wg21.link/LWG4071>`__","``reference_wrapper`` comparisons are not SFINAE-friendly","2024-06 (St. Louis)","|Complete|","19",""
diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h
index 10c244b6d1895..e8386f5ca9c79 100644
--- a/libcxx/include/__format/formatter.h
+++ b/libcxx/include/__format/formatter.h
@@ -21,6 +21,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 20
 
+struct __disabled_formatter {
+  __disabled_formatter()                                       = delete;
+  __disabled_formatter(const __disabled_formatter&)            = delete;
+  __disabled_formatter& operator=(const __disabled_formatter&) = delete;
+};
+
 /// The default formatter template.
 ///
 /// [format.formatter.spec]/5
@@ -31,11 +37,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 /// - is_copy_assignable_v<F>, and
 /// - is_move_assignable_v<F>.
 template <class _Tp, class _CharT>
-struct _LIBCPP_TEMPLATE_VIS formatter {
-  formatter()                            = delete;
-  formatter(const formatter&)            = delete;
-  formatter& operator=(const formatter&) = delete;
-};
+struct _LIBCPP_TEMPLATE_VIS formatter : __disabled_formatter {};
 
 #  if _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h
index 30084e582214d..112c731e67ed7 100644
--- a/libcxx/include/__format/formatter_string.h
+++ b/libcxx/include/__format/formatter_string.h
@@ -125,6 +125,19 @@ struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT
   }
 };
 
+#  if _LIBCPP_HAS_WIDE_CHARACTERS
+template <>
+struct formatter<char*, wchar_t> : __disabled_formatter {};
+template <>
+struct formatter<const char*, wchar_t> : __disabled_formatter {};
+template <size_t _Size>
+struct formatter<char[_Size], wchar_t> : __disabled_formatter {};
+template <class _Traits, class _Allocator>
+struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> : __disabled_formatter {};
+template <class _Traits>
+struct formatter<basic_string_view<char, _Traits>, wchar_t> : __disabled_formatter {};
+#  endif // _LIBCPP_HAS_WIDE_CHARACTERS
+
 #  if _LIBCPP_STD_VER >= 23
 template <>
 inline constexpr bool enable_nonlocking_formatter_optimization<char*> = true;
diff --git a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
index ec27acd75e110..ac60307766d24 100644
--- a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
@@ -292,6 +292,21 @@ void test_LWG3631() {
   assert_is_not_formattable<std::pair<volatile int, volatile int>, CharT>();
 }
 
+void test_LWG3944() {
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  assert_is_not_formattable<char*, wchar_t>();
+  assert_is_not_formattable<const char*, wchar_t>();
+  assert_is_not_formattable<char[42], wchar_t>();
+  assert_is_not_formattable<std::string, wchar_t>();
+  assert_is_not_formattable<std::string_view, wchar_t>();
+
+  assert_is_formattable<std::vector<char>, wchar_t>();
+  assert_is_formattable<std::set<char>, wchar_t>();
+  assert_is_formattable<std::map<char, char>, wchar_t>();
+  assert_is_formattable<std::tuple<char>, wchar_t>();
+#endif
+}
+
 class c {
   void f();
   void fc() const;
@@ -417,6 +432,7 @@ void test() {
   test_P1636<CharT>();
   test_P2286<CharT>();
   test_LWG3631<CharT>();
+  test_LWG3944();
   test_abstract_class<CharT>();
   test_disabled<CharT>();
 }



More information about the libcxx-commits mailing list