[libcxx-commits] [libcxx] [libc++] Implement LWG3430 std::fstream & co. should be constructible from string_view (PR #85079)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 14 06:26:31 PDT 2024


https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/85079

>From 50656d0781b4e516c5475ee0c37d98e85209c54d Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 13 Mar 2024 21:51:17 +0800
Subject: [PATCH 1/3] [libc++] Implement LWG3430 std::fstream & co. should be
 constructible from string_view

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/docs/Status/Cxx23Issues.csv            |  2 +-
 libcxx/include/fstream                        | 19 ++++++++++---------
 .../fstreams/fstream.cons/path.pass.cpp       |  7 +++++++
 .../fstreams/ifstream.cons/path.pass.cpp      |  5 +++++
 .../fstreams/ofstream.cons/path.pass.cpp      |  5 +++++
 5 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index e00345533b865d..87f60fa5278e70 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -64,7 +64,7 @@
 `2818 <https://wg21.link/LWG2818>`__,"``::std::`` everywhere rule needs tweaking","June 2021","|Nothing To Do|",""
 `2997 <https://wg21.link/LWG2997>`__,"LWG 491 and the specification of ``{forward_,}list::unique``","June 2021","",""
 `3410 <https://wg21.link/LWG3410>`__,"``lexicographical_compare_three_way`` is overspecified","June 2021","|Complete|","17.0","|spaceship|"
-`3430 <https://wg21.link/LWG3430>`__,"``std::fstream`` & co. should be constructible from string_view","June 2021","",""
+`3430 <https://wg21.link/LWG3430>`__,"``std::fstream`` & co. should be constructible from string_view","June 2021","|Complete|","19.0",""
 `3462 <https://wg21.link/LWG3462>`__,"ยง[formatter.requirements]: Formatter requirements forbid use of ``fc.arg()``","June 2021","|Nothing To Do|","","|format|"
 `3481 <https://wg21.link/LWG3481>`__,"``viewable_range`` mishandles lvalue move-only views","June 2021","Superseded by `P2415R2 <https://wg21.link/P2415R2>`__","","|ranges|"
 `3506 <https://wg21.link/LWG3506>`__,"Missing allocator-extended constructors for ``priority_queue``","June 2021","|Complete|","14.0"
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 776641b347e6c1..5932a42e1b5392 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -78,8 +78,7 @@ public:
     basic_ifstream();
     explicit basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in);
     explicit basic_ifstream(const string& s, ios_base::openmode mode = ios_base::in);
-    explicit basic_ifstream(const filesystem::path& p,
-                            ios_base::openmode mode = ios_base::in); // C++17
+    template<class T> explicit basic_ifstream(const T& s, ios_base::openmode mode = ios_base::in); // Since C++17
     basic_ifstream(basic_ifstream&& rhs);
 
     basic_ifstream& operator=(basic_ifstream&& rhs);
@@ -117,8 +116,7 @@ public:
     basic_ofstream();
     explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
     explicit basic_ofstream(const string& s, ios_base::openmode mode = ios_base::out);
-    explicit basic_ofstream(const filesystem::path& p,
-                            ios_base::openmode mode = ios_base::out); // C++17
+    template<class T> explicit basic_ofstream(const T& s, ios_base::openmode mode = ios_base::out); // Since C++17
     basic_ofstream(basic_ofstream&& rhs);
 
     basic_ofstream& operator=(basic_ofstream&& rhs);
@@ -158,8 +156,8 @@ public:
     basic_fstream();
     explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
     explicit basic_fstream(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
-    explicit basic_fstream(const filesystem::path& p,
-                           ios_base::openmode mode = ios_base::in|ios_base::out); C++17
+    template<class T>
+    explicit basic_fstream(const T& s, ios_base::openmode mode = ios_base::in | ios_base::out); // Since C++17
     basic_fstream(basic_fstream&& rhs);
 
     basic_fstream& operator=(basic_fstream&& rhs);
@@ -1043,8 +1041,9 @@ public:
 #  endif
   _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const string& __s, ios_base::openmode __mode = ios_base::in);
 #  if _LIBCPP_STD_VER >= 17
+  template <class _Tp, std::enable_if_t<std::is_same_v<_Tp, std::filesystem::path>>* = nullptr>
   _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(
-      const filesystem::path& __p, ios_base::openmode __mode = ios_base::in)
+      const _Tp& __p, ios_base::openmode __mode = ios_base::in)
       : basic_ifstream(__p.c_str(), __mode) {}
 #  endif // _LIBCPP_STD_VER >= 17
   _LIBCPP_HIDE_FROM_ABI basic_ifstream(basic_ifstream&& __rhs);
@@ -1197,8 +1196,9 @@ public:
   _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const string& __s, ios_base::openmode __mode = ios_base::out);
 
 #  if _LIBCPP_STD_VER >= 17
+  template <class _Tp, std::enable_if_t<std::is_same_v<_Tp, std::filesystem::path>>* = nullptr>
   _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(
-      const filesystem::path& __p, ios_base::openmode __mode = ios_base::out)
+      const _Tp& __p, ios_base::openmode __mode = ios_base::out)
       : basic_ofstream(__p.c_str(), __mode) {}
 #  endif // _LIBCPP_STD_VER >= 17
 
@@ -1356,8 +1356,9 @@ public:
                                                ios_base::openmode __mode = ios_base::in | ios_base::out);
 
 #  if _LIBCPP_STD_VER >= 17
+  template <class _Tp, std::enable_if_t<std::is_same_v<_Tp, std::filesystem::path>>* = nullptr>
   _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_fstream(
-      const filesystem::path& __p, ios_base::openmode __mode = ios_base::in | ios_base::out)
+      const _Tp& __p, ios_base::openmode __mode = ios_base::in | ios_base::out)
       : basic_fstream(__p.c_str(), __mode) {}
 #  endif // _LIBCPP_STD_VER >= 17
 
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
index bc75d04740da02..e0e211b4478a7d 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
@@ -21,11 +21,18 @@
 #include <fstream>
 #include <filesystem>
 #include <cassert>
+#include <type_traits>
+
 #include "test_macros.h"
 #include "platform_support.h"
 
 namespace fs = std::filesystem;
 
+struct fake_path {};
+
+static_assert(std::is_constructible_v<std::fstream, fs::path>);
+static_assert(!std::is_constructible_v<std::fstream, fake_path>);
+
 int main(int, char**) {
   fs::path p = get_temp_file_name();
   {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
index cfbb8419fe1c5b..72030c2983e4b3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
@@ -29,6 +29,11 @@
 
 namespace fs = std::filesystem;
 
+struct fake_path {};
+
+static_assert(std::is_constructible_v<std::ifstream, fs::path>);
+static_assert(!std::is_constructible_v<std::ifstream, fake_path>);
+
 int main(int, char**) {
   {
     fs::path p;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
index 316ed776a48b54..01c90f326a130b 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
@@ -27,6 +27,11 @@
 
 namespace fs = std::filesystem;
 
+struct fake_path {};
+
+static_assert(std::is_constructible_v<std::ofstream, fs::path>);
+static_assert(!std::is_constructible_v<std::ofstream, fake_path>);
+
 int main(int, char**) {
   fs::path p = get_temp_file_name();
   {

>From 5e995e9bd13a9cace6df3c519c0041c584763af4 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 14 Mar 2024 21:18:58 +0800
Subject: [PATCH 2/3] [libc++] Refine test cases

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../fstreams/fstream.cons/path.pass.cpp       | 32 ++++++++++++++++--
 .../fstreams/ifstream.cons/path.pass.cpp      | 33 +++++++++++++++++--
 .../fstreams/ofstream.cons/path.pass.cpp      | 32 ++++++++++++++++--
 3 files changed, 88 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
index e0e211b4478a7d..bc2d85ec1b0bfd 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
@@ -24,14 +24,40 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "test_iterators.h"
 #include "platform_support.h"
 
 namespace fs = std::filesystem;
 
-struct fake_path {};
+template <class CharT>
+constexpr bool test_non_convert_to_path() {
 
-static_assert(std::is_constructible_v<std::fstream, fs::path>);
-static_assert(!std::is_constructible_v<std::fstream, fake_path>);
+  // String types
+  static_assert(!std::is_constructible_v<std::fstream, std::basic_string_view<CharT>>);
+  static_assert(!std::is_constructible_v<std::fstream, const std::basic_string_view<CharT>>);
+
+  // Char* pointers
+  if constexpr (!std::is_same_v<CharT, char>)
+    static_assert(!std::is_constructible_v<std::fstream, const CharT *>);
+
+  // Iterators
+  static_assert(!std::is_convertible_v<std::fstream, cpp17_input_iterator<const CharT *>>);
+
+  return true;
+}
+
+static_assert(test_non_convert_to_path<char>());
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(test_non_convert_to_path<wchar_t>());
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
+
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+static_assert(test_non_convert_to_path<char8_t>());
+#endif //  TEST_STD_VER > 17 && defined(__cpp_char8_t)
+
+static_assert(test_non_convert_to_path<char16_t>());
+static_assert(test_non_convert_to_path<char32_t>());
 
 int main(int, char**) {
   fs::path p = get_temp_file_name();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
index 72030c2983e4b3..41a0e4a1ada9fc 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
@@ -26,13 +26,40 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "test_iterators.h"
 
 namespace fs = std::filesystem;
 
-struct fake_path {};
+template <class CharT>
+constexpr bool test_non_convert_to_path() {
+
+  // String types
+  static_assert(!std::is_constructible_v<std::ifstream, std::basic_string_view<CharT>>);
+  static_assert(!std::is_constructible_v<std::ifstream, const std::basic_string_view<CharT>>);
+
+  // Char* pointers
+  if constexpr (!std::is_same_v<CharT, char>)
+    static_assert(!std::is_constructible_v<std::ifstream, const CharT *>);
+
+  // Iterators
+  static_assert(!std::is_convertible_v<std::ifstream, cpp17_input_iterator<const CharT *>>);
+
+  return true;
+}
+
+static_assert(test_non_convert_to_path<char>());
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(test_non_convert_to_path<wchar_t>());
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
+
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+static_assert(test_non_convert_to_path<char8_t>());
+#endif //  TEST_STD_VER > 17 && defined(__cpp_char8_t)
+
+static_assert(test_non_convert_to_path<char16_t>());
+static_assert(test_non_convert_to_path<char32_t>());
 
-static_assert(std::is_constructible_v<std::ifstream, fs::path>);
-static_assert(!std::is_constructible_v<std::ifstream, fake_path>);
 
 int main(int, char**) {
   {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
index 01c90f326a130b..a07e10721be8f4 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
@@ -24,13 +24,39 @@
 
 #include "platform_support.h"
 #include "test_macros.h"
+#include "test_iterators.h"
 
 namespace fs = std::filesystem;
 
-struct fake_path {};
+template <class CharT>
+constexpr bool test_non_convert_to_path() {
 
-static_assert(std::is_constructible_v<std::ofstream, fs::path>);
-static_assert(!std::is_constructible_v<std::ofstream, fake_path>);
+  // String types
+  static_assert(!std::is_constructible_v<std::ofstream, std::basic_string_view<CharT>>);
+  static_assert(!std::is_constructible_v<std::ofstream, const std::basic_string_view<CharT>>);
+
+  // Char* pointers
+  if constexpr (!std::is_same_v<CharT, char>)
+    static_assert(!std::is_constructible_v<std::ofstream, const CharT *>);
+
+  // Iterators
+  static_assert(!std::is_convertible_v<std::ofstream, cpp17_input_iterator<const CharT *>>);
+
+  return true;
+}
+
+static_assert(test_non_convert_to_path<char>());
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(test_non_convert_to_path<wchar_t>());
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
+
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+static_assert(test_non_convert_to_path<char8_t>());
+#endif //  TEST_STD_VER > 17 && defined(__cpp_char8_t)
+
+static_assert(test_non_convert_to_path<char16_t>());
+static_assert(test_non_convert_to_path<char32_t>());
 
 int main(int, char**) {
   fs::path p = get_temp_file_name();

>From 3090674b463dcc5e3ae31e9fcccdb5ac361781c2 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 14 Mar 2024 21:26:16 +0800
Subject: [PATCH 3/3] format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../file.streams/fstreams/fstream.cons/path.pass.cpp        | 5 ++---
 .../file.streams/fstreams/ifstream.cons/path.pass.cpp       | 6 ++----
 .../file.streams/fstreams/ofstream.cons/path.pass.cpp       | 5 ++---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
index bc2d85ec1b0bfd..a787b921a4bf4e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/path.pass.cpp
@@ -31,17 +31,16 @@ namespace fs = std::filesystem;
 
 template <class CharT>
 constexpr bool test_non_convert_to_path() {
-
   // String types
   static_assert(!std::is_constructible_v<std::fstream, std::basic_string_view<CharT>>);
   static_assert(!std::is_constructible_v<std::fstream, const std::basic_string_view<CharT>>);
 
   // Char* pointers
   if constexpr (!std::is_same_v<CharT, char>)
-    static_assert(!std::is_constructible_v<std::fstream, const CharT *>);
+    static_assert(!std::is_constructible_v<std::fstream, const CharT*>);
 
   // Iterators
-  static_assert(!std::is_convertible_v<std::fstream, cpp17_input_iterator<const CharT *>>);
+  static_assert(!std::is_convertible_v<std::fstream, cpp17_input_iterator<const CharT*>>);
 
   return true;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
index 41a0e4a1ada9fc..8d81ec3191dd64 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.cons/path.pass.cpp
@@ -32,17 +32,16 @@ namespace fs = std::filesystem;
 
 template <class CharT>
 constexpr bool test_non_convert_to_path() {
-
   // String types
   static_assert(!std::is_constructible_v<std::ifstream, std::basic_string_view<CharT>>);
   static_assert(!std::is_constructible_v<std::ifstream, const std::basic_string_view<CharT>>);
 
   // Char* pointers
   if constexpr (!std::is_same_v<CharT, char>)
-    static_assert(!std::is_constructible_v<std::ifstream, const CharT *>);
+    static_assert(!std::is_constructible_v<std::ifstream, const CharT*>);
 
   // Iterators
-  static_assert(!std::is_convertible_v<std::ifstream, cpp17_input_iterator<const CharT *>>);
+  static_assert(!std::is_convertible_v<std::ifstream, cpp17_input_iterator<const CharT*>>);
 
   return true;
 }
@@ -60,7 +59,6 @@ static_assert(test_non_convert_to_path<char8_t>());
 static_assert(test_non_convert_to_path<char16_t>());
 static_assert(test_non_convert_to_path<char32_t>());
 
-
 int main(int, char**) {
   {
     fs::path p;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
index a07e10721be8f4..d7da92f9a41d57 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/path.pass.cpp
@@ -30,17 +30,16 @@ namespace fs = std::filesystem;
 
 template <class CharT>
 constexpr bool test_non_convert_to_path() {
-
   // String types
   static_assert(!std::is_constructible_v<std::ofstream, std::basic_string_view<CharT>>);
   static_assert(!std::is_constructible_v<std::ofstream, const std::basic_string_view<CharT>>);
 
   // Char* pointers
   if constexpr (!std::is_same_v<CharT, char>)
-    static_assert(!std::is_constructible_v<std::ofstream, const CharT *>);
+    static_assert(!std::is_constructible_v<std::ofstream, const CharT*>);
 
   // Iterators
-  static_assert(!std::is_convertible_v<std::ofstream, cpp17_input_iterator<const CharT *>>);
+  static_assert(!std::is_convertible_v<std::ofstream, cpp17_input_iterator<const CharT*>>);
 
   return true;
 }



More information about the libcxx-commits mailing list