[Mlir-commits] [mlir] [lld] [flang] [clang] [llvm] [openmp] [libcxx] [libc++][streams] P1759R6: Native handles and file streams (PR #76632)

Hristo Hristov llvmlistbot at llvm.org
Wed Jan 3 03:28:51 PST 2024


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/76632

>From 1165b11477ab59122a4db35221fcefe3c9505387 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 17:34:56 +0200
Subject: [PATCH 01/21] [libc++][streams] P1759R6: Native handles and file
 streams

Implements: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1759r6.html

- https://eel.is/c++draft/filebuf
- https://eel.is/c++draft/ifstream
- https://eel.is/c++draft/ofstream
- https://eel.is/c++draft/fstream
---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/ReleaseNotes/18.rst               |  1 +
 libcxx/docs/Status/Cxx2cPapers.csv            |  2 +-
 libcxx/include/fstream                        | 59 +++++++++++++++++++
 libcxx/include/version                        |  2 +-
 libcxx/src/CMakeLists.txt                     |  1 +
 libcxx/src/fstream.cpp                        | 33 +++++++++++
 .../fstream.version.compile.pass.cpp          | 16 ++---
 .../version.version.compile.pass.cpp          | 16 ++---
 .../generate_feature_test_macro_components.py |  1 -
 10 files changed, 107 insertions(+), 26 deletions(-)
 create mode 100644 libcxx/src/fstream.cpp

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index ad12b109023154..0427615a9636fd 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -418,7 +418,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_freestanding_variant``                  *unimplemented*
     --------------------------------------------------- -----------------
-    ``__cpp_lib_fstream_native_handle``                 *unimplemented*
+    ``__cpp_lib_fstream_native_handle``                 ``202306L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_function_ref``                          *unimplemented*
     --------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index fa60a581652d6a..e6f1adf4d5529b 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -58,6 +58,7 @@ Implemented Papers
 - P2870R3 - Remove basic_string::reserve()
 - P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?)
 - P0521R0 - Proposed Resolution for CA 14 (shared_ptr use_count/unique)
+- P1759R6 - Native handles and file streams
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index ff83648aa76830..1d7807a4291a99 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -19,7 +19,7 @@
 "`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
 "`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
 "`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
-"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","","",""
+"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","|Complete|","18.0",""
 "`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
 "`P1383R2 <https://wg21.link/P1383R2>`__","LWG","More ``constexpr`` for ``<cmath>`` and ``<complex>``","Varna June 2023","","",""
 "`P2734R0 <https://wg21.link/P2734R0>`__","LWG","Adding the new SI prefixes","Varna June 2023","|Complete|","17.0",""
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 7a4e15b55d56fe..9609ff420220fa 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -73,6 +73,7 @@ public:
     typedef typename traits_type::int_type int_type;
     typedef typename traits_type::pos_type pos_type;
     typedef typename traits_type::off_type off_type;
+    using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
 
     basic_ifstream();
     explicit basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in);
@@ -85,6 +86,7 @@ public:
     void swap(basic_ifstream& rhs);
 
     basic_filebuf<char_type, traits_type>* rdbuf() const;
+    native_handle_type native_handle() const noexcept; // Since C++26
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::in);
     void open(const string& s, ios_base::openmode mode = ios_base::in);
@@ -110,6 +112,7 @@ public:
     typedef typename traits_type::int_type int_type;
     typedef typename traits_type::pos_type pos_type;
     typedef typename traits_type::off_type off_type;
+    using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
 
     basic_ofstream();
     explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
@@ -122,6 +125,8 @@ public:
     void swap(basic_ofstream& rhs);
 
     basic_filebuf<char_type, traits_type>* rdbuf() const;
+    native_handle_type native_handle() const noexcept; // Since C++26
+
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::out);
     void open(const string& s, ios_base::openmode mode = ios_base::out);
@@ -148,6 +153,7 @@ public:
     typedef typename traits_type::int_type int_type;
     typedef typename traits_type::pos_type pos_type;
     typedef typename traits_type::off_type off_type;
+    using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
 
     basic_fstream();
     explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
@@ -160,6 +166,7 @@ public:
     void swap(basic_fstream& rhs);
 
     basic_filebuf<char_type, traits_type>* rdbuf() const;
+    native_handle_type native_handle() const noexcept; // Since C++26
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
     void open(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
@@ -219,6 +226,13 @@ public:
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
   typedef typename traits_type::state_type state_type;
+#  if _LIBCPP_STD_VER >= 26
+#    if defined(_LIBCPP_WIN32API)
+  using native_handle_type = void*; // HANDLE
+#    else
+  using native_handle_type = int; // POSIX file descriptor
+#    endif
+#  endif
 
   // 27.9.1.2 Constructors/destructor:
   basic_filebuf();
@@ -245,6 +259,9 @@ public:
 #  endif
   _LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode);
   basic_filebuf* close();
+#  if _LIBCPP_STD_VER >= 26
+  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle();
+#  endif
 
   _LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
 
@@ -1024,6 +1041,9 @@ public:
   typedef typename traits_type::int_type int_type;
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
+#  if _LIBCPP_STD_VER >= 26
+  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+#  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_ifstream();
   _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const char* __s, ios_base::openmode __mode = ios_base::in);
@@ -1041,6 +1061,9 @@ public:
   _LIBCPP_HIDE_FROM_ABI void swap(basic_ifstream& __rhs);
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+#  if _LIBCPP_STD_VER >= 26
+  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+#  endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::in);
 #  ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1116,6 +1139,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_ifstream<_CharT, _Traits>::rdbuf()
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
+// #  if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_ifstream<_CharT, _Traits>::native_handle() const noexcept {
+//   return rdbuf()->native_handle();
+// }
+// #  endif
+
 template <class _CharT, class _Traits>
 inline bool basic_ifstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
@@ -1171,6 +1202,9 @@ public:
   typedef typename traits_type::int_type int_type;
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
+#  if _LIBCPP_STD_VER >= 26
+  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+#  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_ofstream();
   _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const char* __s, ios_base::openmode __mode = ios_base::out);
@@ -1190,6 +1224,9 @@ public:
   _LIBCPP_HIDE_FROM_ABI void swap(basic_ofstream& __rhs);
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+#  if _LIBCPP_STD_VER >= 26
+  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+#  endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::out);
 #  ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1266,6 +1303,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_ofstream<_CharT, _Traits>::rdbuf()
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
+// #  if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_ofstream<_CharT, _Traits>::native_handle() const noexcept {
+//   return rdbuf()->native_handle();
+// }
+// #  endif
+
 template <class _CharT, class _Traits>
 inline bool basic_ofstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
@@ -1321,6 +1366,9 @@ public:
   typedef typename traits_type::int_type int_type;
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
+#  if _LIBCPP_STD_VER >= 26
+  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+#  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_fstream();
   _LIBCPP_HIDE_FROM_ABI explicit basic_fstream(const char* __s,
@@ -1345,6 +1393,9 @@ public:
   _LIBCPP_HIDE_FROM_ABI void swap(basic_fstream& __rhs);
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+#  if _LIBCPP_STD_VER >= 26
+  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+#  endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   _LIBCPP_HIDE_FROM_ABI void open(const char* __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
 #  ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1420,6 +1471,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_fstream<_CharT, _Traits>::rdbuf() c
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
+// #  if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_fstream<_CharT, _Traits>::native_handle() const noexcept {
+//   return rdbuf()->native_handle();
+// }
+// #  endif
+
 template <class _CharT, class _Traits>
 inline bool basic_fstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
diff --git a/libcxx/include/version b/libcxx/include/version
index 768710ef5c84aa..a2bb11b62a44d3 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -495,7 +495,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 // # define __cpp_lib_freestanding_optional                202311L
 // # define __cpp_lib_freestanding_string_view             202311L
 // # define __cpp_lib_freestanding_variant                 202311L
-// # define __cpp_lib_fstream_native_handle                202306L
+# define __cpp_lib_fstream_native_handle                202306L
 // # define __cpp_lib_function_ref                         202306L
 // # define __cpp_lib_hazard_pointer                       202306L
 // # define __cpp_lib_linalg                               202311L
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 329964a001363b..b931460ec76297 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -14,6 +14,7 @@ set(LIBCXX_SOURCES
   filesystem/filesystem_error.cpp
   filesystem/path_parser.h
   filesystem/path.cpp
+  fstream.cpp
   functional.cpp
   hash.cpp
   include/apple_availability.h
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
new file mode 100644
index 00000000000000..c680ff638fe7e5
--- /dev/null
+++ b/libcxx/src/fstream.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+#include <cassert>
+#include <cstdio>
+#include <fstream>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+template <class _CharT, class _Traits>
+basic_filebuf<_CharT, _Traits>::native_handle_type basic_filebuf<_CharT, _Traits>::native_handle() {
+  assert(is_open());
+  // __file_ is a FILE*
+#  if defined(_LIBCPP_WIN32API)
+  // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+  intptr_t __handle = _get_osfhandle(::fileno(__file_));
+  if (__handle == -1)
+    return nullptr;
+  return reinterpret_cast<void*>(__handle);
+#  else
+  return ::fileno(__file_);
+#  endif
+}
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
index 981f5420ff7e0f..eab0313b2c1ef7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
@@ -56,17 +56,11 @@
 
 #elif TEST_STD_VER > 23
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_fstream_native_handle
-#     error "__cpp_lib_fstream_native_handle should be defined in c++26"
-#   endif
-#   if __cpp_lib_fstream_native_handle != 202306L
-#     error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_fstream_native_handle
-#     error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_fstream_native_handle
+#   error "__cpp_lib_fstream_native_handle should be defined in c++26"
+# endif
+# if __cpp_lib_fstream_native_handle != 202306L
+#   error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
 # endif
 
 #endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 650a14b019ed87..af7037a1392fbf 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -6490,17 +6490,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_fstream_native_handle
-#     error "__cpp_lib_fstream_native_handle should be defined in c++26"
-#   endif
-#   if __cpp_lib_fstream_native_handle != 202306L
-#     error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_fstream_native_handle
-#     error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_fstream_native_handle
+#   error "__cpp_lib_fstream_native_handle should be defined in c++26"
+# endif
+# if __cpp_lib_fstream_native_handle != 202306L
+#   error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 2f506f32f565cb..cb7c532c05251f 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -570,7 +570,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_fstream_native_handle",
             "values": {"c++26": 202306},  # P1759R6 Native handles and file streams
             "headers": ["fstream"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_function_ref",

>From 9d4b10e4739c44e867ae40dc942fc6577212d94e Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 22:28:46 +0200
Subject: [PATCH 02/21] Added tests

---
 libcxx/include/fstream                        | 70 ++++++++++---------
 libcxx/src/fstream.cpp                        | 17 +++--
 .../filebuf.members/native_handle.pass.cpp    | 52 ++++++++++++++
 .../fstream.members/native_handle.pass.cpp    | 57 +++++++++++++++
 .../ifstream.members/native_handle.pass.cpp   | 57 +++++++++++++++
 .../ofstream.members/native_handle.pass.cpp   | 59 ++++++++++++++++
 .../file.streams/fstreams/test_helpers.h      | 33 +++++++++
 7 files changed, 305 insertions(+), 40 deletions(-)
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 9609ff420220fa..f0cb5bb50fc9b6 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -215,8 +215,37 @@ _LIBCPP_PUSH_MACROS
 
 #if !defined(_LIBCPP_HAS_NO_FILESYSTEM)
 
+#  if defined(_LIBCPP_WIN32API)
+#    define WIN32_LEAN_AND_MEAN
+#    define NOMINMAX
+#    include <io.h>
+#    include <windows.h>
+#  endif
+
+#include <fcntl.h>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#  if _LIBCPP_STD_VER >= 26
+#    if defined(_LIBCPP_WIN32API)
+using __filebuf_native_handle_type = void*; // HANDLE
+#    else
+using __filebuf_native_handle_type = int; // POSIX file descriptor
+#    endif
+_LIBCPP_HIDE_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept;
+__filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
+#    if defined(_LIBCPP_WIN32API)
+  // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+  intptr_t __handle = _get_osfhandle(::fileno(__file));
+  if (__handle == -1)
+    return nullptr;
+  return reinterpret_cast<void*>(__handle);
+#    else
+  return ::fileno(__file);
+#    endif
+}
+#  endif
+
 template <class _CharT, class _Traits>
 class _LIBCPP_TEMPLATE_VIS basic_filebuf : public basic_streambuf<_CharT, _Traits> {
 public:
@@ -227,11 +256,7 @@ public:
   typedef typename traits_type::off_type off_type;
   typedef typename traits_type::state_type state_type;
 #  if _LIBCPP_STD_VER >= 26
-#    if defined(_LIBCPP_WIN32API)
-  using native_handle_type = void*; // HANDLE
-#    else
-  using native_handle_type = int; // POSIX file descriptor
-#    endif
+  using native_handle_type = __filebuf_native_handle_type;
 #  endif
 
   // 27.9.1.2 Constructors/destructor:
@@ -260,7 +285,10 @@ public:
   _LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode);
   basic_filebuf* close();
 #  if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle();
+  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
+    assert(is_open());
+    return std::__filebuf_native_handle(__file_);
+  }
 #  endif
 
   _LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
@@ -1042,7 +1070,7 @@ public:
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
 #  if _LIBCPP_STD_VER >= 26
-  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+  using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
 #  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_ifstream();
@@ -1139,14 +1167,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_ifstream<_CharT, _Traits>::rdbuf()
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
-// #  if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_ifstream<_CharT, _Traits>::native_handle() const noexcept {
-//   return rdbuf()->native_handle();
-// }
-// #  endif
-
 template <class _CharT, class _Traits>
 inline bool basic_ifstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
@@ -1203,7 +1223,7 @@ public:
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
 #  if _LIBCPP_STD_VER >= 26
-  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+  using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
 #  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_ofstream();
@@ -1303,14 +1323,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_ofstream<_CharT, _Traits>::rdbuf()
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
-// #  if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_ofstream<_CharT, _Traits>::native_handle() const noexcept {
-//   return rdbuf()->native_handle();
-// }
-// #  endif
-
 template <class _CharT, class _Traits>
 inline bool basic_ofstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
@@ -1367,7 +1379,7 @@ public:
   typedef typename traits_type::pos_type pos_type;
   typedef typename traits_type::off_type off_type;
 #  if _LIBCPP_STD_VER >= 26
-  using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+  using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
 #  endif
 
   _LIBCPP_HIDE_FROM_ABI basic_fstream();
@@ -1471,14 +1483,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_fstream<_CharT, _Traits>::rdbuf() c
   return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
 }
 
-// #  if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_fstream<_CharT, _Traits>::native_handle() const noexcept {
-//   return rdbuf()->native_handle();
-// }
-// #  endif
-
 template <class _CharT, class _Traits>
 inline bool basic_fstream<_CharT, _Traits>::is_open() const {
   return __sb_.is_open();
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index c680ff638fe7e5..e5611e2d48b0a6 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -7,25 +7,28 @@
 //===----------------------------------------------------------------------===//
 
 #include <__config>
-#include <cassert>
 #include <cstdio>
 #include <fstream>
 
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 26
-template <class _CharT, class _Traits>
-basic_filebuf<_CharT, _Traits>::native_handle_type basic_filebuf<_CharT, _Traits>::native_handle() {
-  assert(is_open());
-  // __file_ is a FILE*
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
 #  if defined(_LIBCPP_WIN32API)
   // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
-  intptr_t __handle = _get_osfhandle(::fileno(__file_));
+  intptr_t __handle = _get_osfhandle(::fileno(__file));
   if (__handle == -1)
     return nullptr;
   return reinterpret_cast<void*>(__handle);
 #  else
-  return ::fileno(__file_);
+  return ::fileno(__file);
 #  endif
 }
 #endif
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..4104aa061e1546
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_filebuf;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+  std::basic_filebuf<CharT> f;
+  assert(!f.is_open());
+  std::filesystem::path p = get_temp_file_name();
+  f.open(p, std::ios_base::in);
+  assert(f.is_open());
+  assert(is_handle_valid(f.native_handle()));
+  assert(is_handle_valid(std::as_const(f).native_handle()));
+  static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..44da8bd3e18bad
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_fstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+                               typename std::basic_fstream<CharT>::native_handle_type>);
+
+  std::basic_fstream<CharT> f;
+  static_assert(noexcept(f.native_handle()));
+  assert(!f.is_open());
+  std::filesystem::path p = get_temp_file_name();
+  f.open(p);
+  assert(f.is_open());
+  assert(f.native_handle() == f.rdbuf()->native_handle());
+  assert(is_handle_valid(f.native_handle()));
+  assert(is_handle_valid(std::as_const(f).native_handle()));
+  static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..1345b72b158e28
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ifstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+                               typename std::basic_ifstream<CharT>::native_handle_type>);
+
+  std::basic_ifstream<CharT> f;
+  static_assert(noexcept(f.native_handle()));
+  assert(!f.is_open());
+  std::filesystem::path p = get_temp_file_name();
+  f.open(p);
+  assert(f.is_open());
+  assert(f.native_handle() == f.rdbuf()->native_handle());
+  assert(is_handle_valid(f.native_handle()));
+  assert(is_handle_valid(std::as_const(f).native_handle()));
+  static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..cd69c8087608df
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ofstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+                               typename std::basic_ofstream<CharT>::native_handle_type>);
+
+  std::basic_ofstream<CharT> f;
+  static_assert(noexcept(f.native_handle()));
+  assert(!f.is_open());
+  std::filesystem::path p = get_temp_file_name();
+  f.open(p);
+  assert(f.is_open());
+  assert(f.native_handle() == f.rdbuf()->native_handle());
+  assert(f.native_handle());
+  assert(std::as_const(f).native_handle());
+  assert(is_handle_valid(f.native_handle()));
+  assert(is_handle_valid(std::as_const(f).native_handle()));
+  static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
new file mode 100644
index 00000000000000..06ddbf8287f039
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
+#define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
+
+#include <cstdio>
+
+#if defined(_LIBCPP_WIN32API)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#else
+#  include <fcntl.h>
+#endif
+
+#if defined(_LIBCPP_WIN32API)
+auto is_handle_valid([[maybe_unused]] HANDLE handle) {
+  // TODO: GetFileInformationByHandle
+  return true;
+};
+#else
+// POSIX
+auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+#endif
+
+#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file

>From 37a871ace443c45dae2c048a91de712a1c369fe4 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 11:25:48 +0200
Subject: [PATCH 03/21] Added missing include

---
 libcxx/include/fstream | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index f0cb5bb50fc9b6..5598943268276d 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -195,6 +195,7 @@ typedef basic_fstream<wchar_t> wfstream;
 #include <__utility/move.h>
 #include <__utility/swap.h>
 #include <__utility/unreachable.h>
+#include <cassert>
 #include <cstdio>
 #include <filesystem>
 #include <istream>

>From 5aeb33918bd80840469cec803ba054f1f4aeec8e Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 14:38:06 +0200
Subject: [PATCH 04/21] WIP: Addressed some comments and simplified/generalized
 the tests

---
 libcxx/include/fstream                        | 22 +++-----
 libcxx/src/fstream.cpp                        |  9 +--
 .../fstream.members/native_handle.pass.cpp    | 34 +-----------
 .../ifstream.members/native_handle.pass.cpp   | 35 +-----------
 .../ofstream.members/native_handle.pass.cpp   | 36 +-----------
 .../file.streams/fstreams/test_helpers.h      | 55 ++++++++++++++-----
 6 files changed, 60 insertions(+), 131 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 5598943268276d..ab854cf534e7fb 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -195,7 +195,6 @@ typedef basic_fstream<wchar_t> wfstream;
 #include <__utility/move.h>
 #include <__utility/swap.h>
 #include <__utility/unreachable.h>
-#include <cassert>
 #include <cstdio>
 #include <filesystem>
 #include <istream>
@@ -223,24 +222,21 @@ _LIBCPP_PUSH_MACROS
 #    include <windows.h>
 #  endif
 
-#include <fcntl.h>
+// #  include <fcntl.h>
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #  if _LIBCPP_STD_VER >= 26
 #    if defined(_LIBCPP_WIN32API)
-using __filebuf_native_handle_type = void*; // HANDLE
-#    else
-using __filebuf_native_handle_type = int; // POSIX file descriptor
+using __filebuf_native_handle_type = HANDLE;
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file);
+#    else // POSIX
+using __filebuf_native_handle_type = int; // File descriptor
 #    endif
-_LIBCPP_HIDE_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept;
-__filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
+
+_LIBCPP_HIDE_FROM_ABI inline __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
 #    if defined(_LIBCPP_WIN32API)
-  // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
-  intptr_t __handle = _get_osfhandle(::fileno(__file));
-  if (__handle == -1)
-    return nullptr;
-  return reinterpret_cast<void*>(__handle);
+  return __filebuf_windows_native_handle(__file);
 #    else
   return ::fileno(__file);
 #    endif
@@ -287,7 +283,7 @@ public:
   basic_filebuf* close();
 #  if _LIBCPP_STD_VER >= 26
   _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
-    assert(is_open());
+    _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
     return std::__filebuf_native_handle(__file_);
   }
 #  endif
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index e5611e2d48b0a6..814d912e7d22b3 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -20,17 +20,14 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 26
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
 #  if defined(_LIBCPP_WIN32API)
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file) noexcept {
   // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
   intptr_t __handle = _get_osfhandle(::fileno(__file));
   if (__handle == -1)
     return nullptr;
-  return reinterpret_cast<void*>(__handle);
-#  else
-  return ::fileno(__file);
+  return reinterpret_cast<__filebuf_native_handle_type>(__handle);
 #  endif
-}
 #endif
 
-_LIBCPP_END_NAMESPACE_STD
+  _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
index 44da8bd3e18bad..900475069a1c9b 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -14,43 +14,13 @@
 
 // native_handle_type native_handle() const noexcept;
 
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-#  define WIN32_LEAN_AND_MEAN
-#  define NOMINMAX
-#  include <io.h>
-#  include <windows.h>
-#endif
-
-#include "platform_support.h"
 #include "test_macros.h"
 #include "../test_helpers.h"
 
-template <typename CharT>
-void test() {
-  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
-                               typename std::basic_fstream<CharT>::native_handle_type>);
-
-  std::basic_fstream<CharT> f;
-  static_assert(noexcept(f.native_handle()));
-  assert(!f.is_open());
-  std::filesystem::path p = get_temp_file_name();
-  f.open(p);
-  assert(f.is_open());
-  assert(f.native_handle() == f.rdbuf()->native_handle());
-  assert(is_handle_valid(f.native_handle()));
-  assert(is_handle_valid(std::as_const(f).native_handle()));
-  static_assert(noexcept(f.native_handle()));
-}
-
 int main(int, char**) {
-  test<char>();
+  test_native_handle<char, std::basic_fstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
+  test_native_handle<wchar_t, std::basic_fstream<wchar_t>>();
 #endif
 
   return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
index 1345b72b158e28..ffe5e922225da8 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -14,44 +14,15 @@
 
 // native_handle_type native_handle() const noexcept;
 
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-#  define WIN32_LEAN_AND_MEAN
-#  define NOMINMAX
-#  include <io.h>
-#  include <windows.h>
-#endif
-
-#include "platform_support.h"
 #include "test_macros.h"
 #include "../test_helpers.h"
 
-template <typename CharT>
-void test() {
-  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
-                               typename std::basic_ifstream<CharT>::native_handle_type>);
-
-  std::basic_ifstream<CharT> f;
-  static_assert(noexcept(f.native_handle()));
-  assert(!f.is_open());
-  std::filesystem::path p = get_temp_file_name();
-  f.open(p);
-  assert(f.is_open());
-  assert(f.native_handle() == f.rdbuf()->native_handle());
-  assert(is_handle_valid(f.native_handle()));
-  assert(is_handle_valid(std::as_const(f).native_handle()));
-  static_assert(noexcept(f.native_handle()));
-}
-
 int main(int, char**) {
-  test<char>();
+  test_native_handle<char, std::basic_ifstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
+  test_native_handle<wchar_t, std::basic_ifstream<wchar_t>>();
 #endif
 
   return 0;
 }
+
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
index cd69c8087608df..45f0841dad18cb 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -14,45 +14,13 @@
 
 // native_handle_type native_handle() const noexcept;
 
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-#  define WIN32_LEAN_AND_MEAN
-#  define NOMINMAX
-#  include <io.h>
-#  include <windows.h>
-#endif
-
-#include "platform_support.h"
 #include "test_macros.h"
 #include "../test_helpers.h"
 
-template <typename CharT>
-void test() {
-  static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
-                               typename std::basic_ofstream<CharT>::native_handle_type>);
-
-  std::basic_ofstream<CharT> f;
-  static_assert(noexcept(f.native_handle()));
-  assert(!f.is_open());
-  std::filesystem::path p = get_temp_file_name();
-  f.open(p);
-  assert(f.is_open());
-  assert(f.native_handle() == f.rdbuf()->native_handle());
-  assert(f.native_handle());
-  assert(std::as_const(f).native_handle());
-  assert(is_handle_valid(f.native_handle()));
-  assert(is_handle_valid(std::as_const(f).native_handle()));
-  static_assert(noexcept(f.native_handle()));
-}
-
 int main(int, char**) {
-  test<char>();
+  test_native_handle<char, std::basic_ofstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
+  test_native_handle<wchar_t, std::basic_ofstream<wchar_t>>();
 #endif
 
   return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 06ddbf8287f039..7691c04c750448 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -9,25 +9,52 @@
 #ifndef TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
 #define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
 
-#include <cstdio>
-
-#if defined(_LIBCPP_WIN32API)
-#  define WIN32_LEAN_AND_MEAN
-#  define NOMINMAX
-#  include <io.h>
-#  include <windows.h>
-#else
-#  include <fcntl.h>
-#endif
-
-#if defined(_LIBCPP_WIN32API)
+#if _LIBCPP_STD_VER >= 26
+
+#  include <cassert>
+#  include <cstdio>
+#  include <fstream>
+#  include <filesystem>
+#  include <utility>
+
+#  if defined(_LIBCPP_WIN32API)
+#    define WIN32_LEAN_AND_MEAN
+#    define NOMINMAX
+#    include <io.h>
+#    include <windows.h>
+#  else
+#    include <fcntl.h>
+#  endif
+
+#  include "platform_support.h"
+
+#  if defined(_LIBCPP_WIN32API)
 auto is_handle_valid([[maybe_unused]] HANDLE handle) {
   // TODO: GetFileInformationByHandle
   return true;
 };
-#else
+#  else
 // POSIX
 auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
-#endif
+#  endif
+
+template <typename CharT, typename StreamT>
+void test_native_handle() {
+  static_assert(
+      std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
+
+  StreamT f;
+  static_assert(noexcept(f.native_handle()));
+  assert(!f.is_open());
+  std::filesystem::path p = get_temp_file_name();
+  f.open(p);
+  assert(f.is_open());
+  assert(f.native_handle() == f.rdbuf()->native_handle());
+  assert(is_handle_valid(f.native_handle()));
+  assert(is_handle_valid(std::as_const(f).native_handle()));
+  static_assert(noexcept(f.native_handle()));
+}
+
+#endif // _LIBCPP_STD_VER >= 26
 
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file

>From 822633dd56bf65b25a265aafb3c16b7e1f071bb4 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 14:48:56 +0200
Subject: [PATCH 05/21] WIP: Fixed formatting error

---
 .../fstreams/filebuf.members/native_handle.pass.cpp        | 7 -------
 .../fstreams/ifstream.members/native_handle.pass.cpp       | 1 -
 .../std/input.output/file.streams/fstreams/test_helpers.h  | 4 ++--
 3 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 4104aa061e1546..790cc91effc822 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -19,13 +19,6 @@
 #include <filesystem>
 #include <utility>
 
-#if defined(_LIBCPP_WIN32API)
-#  define WIN32_LEAN_AND_MEAN
-#  define NOMINMAX
-#  include <io.h>
-#  include <windows.h>
-#endif
-
 #include "platform_support.h"
 #include "test_macros.h"
 #include "../test_helpers.h"
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
index ffe5e922225da8..95a95cb69560b7 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -25,4 +25,3 @@ int main(int, char**) {
 
   return 0;
 }
-
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 7691c04c750448..a3069549315611 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -30,7 +30,7 @@
 
 #  if defined(_LIBCPP_WIN32API)
 auto is_handle_valid([[maybe_unused]] HANDLE handle) {
-  // TODO: GetFileInformationByHandle
+  // TODO: Maybe test HANDLE with GetFileInformationByHandle??
   return true;
 };
 #  else
@@ -57,4 +57,4 @@ void test_native_handle() {
 
 #endif // _LIBCPP_STD_VER >= 26
 
-#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file
+#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H

>From ecaf77e4da4fa56db9a07b738bcc0b75fa2b7b5a Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 15:18:13 +0200
Subject: [PATCH 06/21] WIP: Refactored `fstream->native_handle()`
 implementation

---
 libcxx/include/fstream                        | 38 ++++++++-----------
 libcxx/src/fstream.cpp                        |  4 +-
 .../file.streams/fstreams/test_helpers.h      |  7 ++--
 3 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index ab854cf534e7fb..6f6e36f259f381 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -215,32 +215,12 @@ _LIBCPP_PUSH_MACROS
 
 #if !defined(_LIBCPP_HAS_NO_FILESYSTEM)
 
-#  if defined(_LIBCPP_WIN32API)
-#    define WIN32_LEAN_AND_MEAN
-#    define NOMINMAX
-#    include <io.h>
-#    include <windows.h>
-#  endif
-
-// #  include <fcntl.h>
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #  if _LIBCPP_STD_VER >= 26
 #    if defined(_LIBCPP_WIN32API)
-using __filebuf_native_handle_type = HANDLE;
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file);
-#    else // POSIX
-using __filebuf_native_handle_type = int; // File descriptor
-#    endif
-
-_LIBCPP_HIDE_FROM_ABI inline __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
-#    if defined(_LIBCPP_WIN32API)
-  return __filebuf_windows_native_handle(__file);
-#    else
-  return ::fileno(__file);
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file);
 #    endif
-}
 #  endif
 
 template <class _CharT, class _Traits>
@@ -253,7 +233,13 @@ public:
   typedef typename traits_type::off_type off_type;
   typedef typename traits_type::state_type state_type;
 #  if _LIBCPP_STD_VER >= 26
-  using native_handle_type = __filebuf_native_handle_type;
+#    if defined(_LIBCPP_WIN32API)
+  using native_handle_type = void*; // HANDLE
+#    elif __has_include(<unistd.h>)
+  using native_handle_type = int; // POSIX file descriptor
+#    else
+#      error "Provide a file native handle!"
+#    endif
 #  endif
 
   // 27.9.1.2 Constructors/destructor:
@@ -284,7 +270,13 @@ public:
 #  if _LIBCPP_STD_VER >= 26
   _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
     _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
-    return std::__filebuf_native_handle(__file_);
+#    if defined(_LIBCPP_WIN32API)
+    return __filebuf_windows_native_handle(__file_);
+#    elif __has_include(<unistd.h>)
+    return ::fileno(__file_);
+#    else
+#      error "Provide a way to determine the file native handle!
+#    endif
   }
 #  endif
 
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index 814d912e7d22b3..27150389627594 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -21,12 +21,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 26
 #  if defined(_LIBCPP_WIN32API)
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file) noexcept {
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {
   // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
   intptr_t __handle = _get_osfhandle(::fileno(__file));
   if (__handle == -1)
     return nullptr;
-  return reinterpret_cast<__filebuf_native_handle_type>(__handle);
+  return reinterpret_cast<void*>(__handle);
 #  endif
 #endif
 
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index a3069549315611..fd6d732638ad32 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -29,13 +29,12 @@
 #  include "platform_support.h"
 
 #  if defined(_LIBCPP_WIN32API)
-auto is_handle_valid([[maybe_unused]] HANDLE handle) {
+bool is_handle_valid([[maybe_unused]] HANDLE handle) {
   // TODO: Maybe test HANDLE with GetFileInformationByHandle??
   return true;
 };
-#  else
-// POSIX
-auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+#  else // POSIX
+bool is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
 #  endif
 
 template <typename CharT, typename StreamT>

>From a066b7957ee85e6c208e531c12b6adf96a8ef3f8 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 09:17:09 +0200
Subject: [PATCH 07/21] Addressed comments

---
 libcxx/include/fstream                        |  2 +-
 libcxx/src/fstream.cpp                        |  9 ++++---
 .../filebuf.members/native_handle.pass.cpp    | 14 ++++++++--
 .../file.streams/fstreams/test_helpers.h      | 27 ++++++++++++++-----
 4 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 6f6e36f259f381..287c4280f18e99 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -238,7 +238,7 @@ public:
 #    elif __has_include(<unistd.h>)
   using native_handle_type = int; // POSIX file descriptor
 #    else
-#      error "Provide a file native handle!"
+#      error "Provide a native file handle!"
 #    endif
 #  endif
 
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index 27150389627594..f063b7020cb373 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -19,15 +19,18 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 26
-#  if defined(_LIBCPP_WIN32API)
+#if defined(_LIBCPP_WIN32API)
+
+// Confirm that `HANDLE` is `void*`
+static_assert(std::same_as<HANDLE, void*>);
+
 _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {
   // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
   intptr_t __handle = _get_osfhandle(::fileno(__file));
   if (__handle == -1)
     return nullptr;
   return reinterpret_cast<void*>(__handle);
-#  endif
+
 #endif
 
   _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 790cc91effc822..c87bda5382c85e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -30,9 +30,19 @@ void test() {
   std::filesystem::path p = get_temp_file_name();
   f.open(p, std::ios_base::in);
   assert(f.is_open());
-  assert(is_handle_valid(f.native_handle()));
-  assert(is_handle_valid(std::as_const(f).native_handle()));
+#if defined(_LIBCPP_WIN32API)
+  using HandleT = void*;
+#elif __has_include(<unistd.h>) // POSIX
+  using HandleT = int;
+#else
+#  error "Provide a native file handle!"
+#endif
+  std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+  assert(is_handle_valid(handle));
+  std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+  assert(is_handle_valid(const_handle));
   static_assert(noexcept(f.native_handle()));
+  static_assert(noexcept(std::as_const(f).native_handle()));
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index fd6d732638ad32..e32c8fb5fc9de3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -12,9 +12,11 @@
 #if _LIBCPP_STD_VER >= 26
 
 #  include <cassert>
+#  include <concepts>
 #  include <cstdio>
 #  include <fstream>
 #  include <filesystem>
+#  include <type_traits>
 #  include <utility>
 
 #  if defined(_LIBCPP_WIN32API)
@@ -29,12 +31,15 @@
 #  include "platform_support.h"
 
 #  if defined(_LIBCPP_WIN32API)
-bool is_handle_valid([[maybe_unused]] HANDLE handle) {
-  // TODO: Maybe test HANDLE with GetFileInformationByHandle??
+bool is_handle_valid([[void* handle) {
+  if (LPBY_HANDLE_FILE_INFORMATION & pFileInformation; !GetFileInformationByHandle(handle, &lpFileInformation))
+    return false;
   return true;
 };
-#  else // POSIX
+#  elif __has_include(<unistd.h>) // POSIX
 bool is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+#  else
+#    error "Provide a native file handle!"
 #  endif
 
 template <typename CharT, typename StreamT>
@@ -43,15 +48,25 @@ void test_native_handle() {
       std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
 
   StreamT f;
-  static_assert(noexcept(f.native_handle()));
+
   assert(!f.is_open());
   std::filesystem::path p = get_temp_file_name();
   f.open(p);
   assert(f.is_open());
   assert(f.native_handle() == f.rdbuf()->native_handle());
-  assert(is_handle_valid(f.native_handle()));
-  assert(is_handle_valid(std::as_const(f).native_handle()));
+#  if defined(_LIBCPP_WIN32API)
+  using HandleT = void*;
+#  elif __has_include(<unistd.h>) // POSIX
+  using HandleT = int;
+#  else
+#    error "Provide a native file handle!"
+#  endif
+  std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+  assert(is_handle_valid(handle));
+  std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+  assert(is_handle_valid(const_handle));
   static_assert(noexcept(f.native_handle()));
+  static_assert(noexcept(std::as_const(f).native_handle()));
 }
 
 #endif // _LIBCPP_STD_VER >= 26

>From f730cf84c1faa9ab05848776351813a3f4000d85 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 09:56:05 +0200
Subject: [PATCH 08/21] Minor tweak

---
 .../filebuf.members/native_handle.pass.cpp        |  7 -------
 .../file.streams/fstreams/test_helpers.h          | 15 ++++++---------
 2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index c87bda5382c85e..abcaf489e68019 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -30,13 +30,6 @@ void test() {
   std::filesystem::path p = get_temp_file_name();
   f.open(p, std::ios_base::in);
   assert(f.is_open());
-#if defined(_LIBCPP_WIN32API)
-  using HandleT = void*;
-#elif __has_include(<unistd.h>) // POSIX
-  using HandleT = int;
-#else
-#  error "Provide a native file handle!"
-#endif
   std::same_as<HandleT> decltype(auto) handle = f.native_handle();
   assert(is_handle_valid(handle));
   std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index e32c8fb5fc9de3..65ec8bded2d7e5 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -31,13 +31,17 @@
 #  include "platform_support.h"
 
 #  if defined(_LIBCPP_WIN32API)
-bool is_handle_valid([[void* handle) {
+using HandleT = void*;
+
+bool is_handle_valid([[HandleT handle) {
   if (LPBY_HANDLE_FILE_INFORMATION & pFileInformation; !GetFileInformationByHandle(handle, &lpFileInformation))
     return false;
   return true;
 };
 #  elif __has_include(<unistd.h>) // POSIX
-bool is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+using HandleT = int;
+
+bool is_handle_valid(HandleT fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
 #  else
 #    error "Provide a native file handle!"
 #  endif
@@ -54,13 +58,6 @@ void test_native_handle() {
   f.open(p);
   assert(f.is_open());
   assert(f.native_handle() == f.rdbuf()->native_handle());
-#  if defined(_LIBCPP_WIN32API)
-  using HandleT = void*;
-#  elif __has_include(<unistd.h>) // POSIX
-  using HandleT = int;
-#  else
-#    error "Provide a native file handle!"
-#  endif
   std::same_as<HandleT> decltype(auto) handle = f.native_handle();
   assert(is_handle_valid(handle));
   std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();

>From 1c253ed45af9112a21efa57395d88be3e5548a66 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 10:13:41 +0200
Subject: [PATCH 09/21] Try to fix CI

---
 libcxx/include/fstream | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 287c4280f18e99..09da5869c0d897 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -275,7 +275,7 @@ public:
 #    elif __has_include(<unistd.h>)
     return ::fileno(__file_);
 #    else
-#      error "Provide a way to determine the file native handle!
+#      error "Provide a way to determine the file native handle!"
 #    endif
   }
 #  endif

>From ebbf0a163adfdb27998997c858f57fc27c94d77b Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 10:15:18 +0200
Subject: [PATCH 10/21] Minor tweak

---
 .../std/input.output/file.streams/fstreams/test_helpers.h     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 65ec8bded2d7e5..90a597a11be6e2 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -31,7 +31,7 @@
 #  include "platform_support.h"
 
 #  if defined(_LIBCPP_WIN32API)
-using HandleT = void*;
+using HandleT = void*; // HANDLE
 
 bool is_handle_valid([[HandleT handle) {
   if (LPBY_HANDLE_FILE_INFORMATION & pFileInformation; !GetFileInformationByHandle(handle, &lpFileInformation))
@@ -39,7 +39,7 @@ bool is_handle_valid([[HandleT handle) {
   return true;
 };
 #  elif __has_include(<unistd.h>) // POSIX
-using HandleT = int;
+using HandleT = int; // POSIX file descriptor
 
 bool is_handle_valid(HandleT fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
 #  else

>From 206871cd51bcda2d057450c6516ff560a977b892 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Mon, 1 Jan 2024 10:42:27 +0200
Subject: [PATCH 11/21] Update
 libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h

---
 .../std/input.output/file.streams/fstreams/test_helpers.h     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 90a597a11be6e2..bd5109cae5c11a 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -33,8 +33,8 @@
 #  if defined(_LIBCPP_WIN32API)
 using HandleT = void*; // HANDLE
 
-bool is_handle_valid([[HandleT handle) {
-  if (LPBY_HANDLE_FILE_INFORMATION & pFileInformation; !GetFileInformationByHandle(handle, &lpFileInformation))
+bool is_handle_valid(void* handle) {
+  if (BY_HANDLE_FILE_INFORMATION fileInformation; !GetFileInformationByHandle(handle, &fileInformation))
     return false;
   return true;
 };

>From 888317870f2c98f0d333697d17a145dfccba945a Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 11:07:35 +0200
Subject: [PATCH 12/21] Updated tests

---
 .../filebuf.members/native_handle.pass.cpp    | 32 +++++++++++------
 .../file.streams/fstreams/test_helpers.h      | 34 ++++++++++++-------
 2 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index abcaf489e68019..17fe6ffde37a7f 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -25,17 +25,27 @@
 
 template <typename CharT>
 void test() {
-  std::basic_filebuf<CharT> f;
-  assert(!f.is_open());
-  std::filesystem::path p = get_temp_file_name();
-  f.open(p, std::ios_base::in);
-  assert(f.is_open());
-  std::same_as<HandleT> decltype(auto) handle = f.native_handle();
-  assert(is_handle_valid(handle));
-  std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
-  assert(is_handle_valid(const_handle));
-  static_assert(noexcept(f.native_handle()));
-  static_assert(noexcept(std::as_const(f).native_handle()));
+  HandleT native_handle{};
+  HandleT const_native_handle{};
+
+  {
+    std::basic_filebuf<CharT> f;
+    assert(!f.is_open());
+    std::filesystem::path p = get_temp_file_name();
+    f.open(p, std::ios_base::in);
+    assert(f.is_open());
+    std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+    native_handle                               = handle;
+    assert(is_handle_valid(native_handle));
+    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+    const_native_handle                               = const_handle;
+    assert(is_handle_valid(const_native_handle));
+    static_assert(noexcept(f.native_handle()));
+    static_assert(noexcept(std::as_const(f).native_handle()));
+  }
+
+  assert(!is_handle_valid(native_handle));
+  assert(!is_handle_valid(const_native_handle));
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index bd5109cae5c11a..395e58804f8e11 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -51,19 +51,29 @@ void test_native_handle() {
   static_assert(
       std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
 
-  StreamT f;
+  HandleT native_handle{};
+  HandleT const_native_handle{};
 
-  assert(!f.is_open());
-  std::filesystem::path p = get_temp_file_name();
-  f.open(p);
-  assert(f.is_open());
-  assert(f.native_handle() == f.rdbuf()->native_handle());
-  std::same_as<HandleT> decltype(auto) handle = f.native_handle();
-  assert(is_handle_valid(handle));
-  std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
-  assert(is_handle_valid(const_handle));
-  static_assert(noexcept(f.native_handle()));
-  static_assert(noexcept(std::as_const(f).native_handle()));
+  {
+    StreamT f;
+
+    assert(!f.is_open());
+    std::filesystem::path p = get_temp_file_name();
+    f.open(p);
+    assert(f.is_open());
+    assert(f.native_handle() == f.rdbuf()->native_handle());
+    std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+    native_handle                               = handle;
+    assert(is_handle_valid(native_handle));
+    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+    const_native_handle                               = const_handle;
+    assert(is_handle_valid(const_native_handle));
+    static_assert(noexcept(f.native_handle()));
+    static_assert(noexcept(std::as_const(f).native_handle()));
+  }
+
+  assert(!is_handle_valid(native_handle));
+  assert(!is_handle_valid(const_native_handle));
 }
 
 #endif // _LIBCPP_STD_VER >= 26

>From 7e342e4d118a468c8d7977b0b1a4bcfb40f4cf8a Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 12:50:23 +0200
Subject: [PATCH 13/21] Fixed Windows build

---
 libcxx/src/fstream.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index f063b7020cb373..a72f2de6dd6d56 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -30,7 +30,8 @@ _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) no
   if (__handle == -1)
     return nullptr;
   return reinterpret_cast<void*>(__handle);
+}
 
 #endif
 
-  _LIBCPP_END_NAMESPACE_STD
+_LIBCPP_END_NAMESPACE_STD

>From 344903cef9abccedd1d51c8aebc72a2035a505bb Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 12:57:19 +0200
Subject: [PATCH 14/21] Minor tweak

---
 libcxx/src/fstream.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index a72f2de6dd6d56..257ab4a2be531f 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if defined(_LIBCPP_WIN32API)
 
-// Confirm that `HANDLE` is `void*`
+// Confirm that `HANDLE` is `void*` as implemented in `basic_filebuf`
 static_assert(std::same_as<HANDLE, void*>);
 
 _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {

>From 6a422c94bd27666768290fad184f2d13f2bcf3db Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 14:02:59 +0200
Subject: [PATCH 15/21] Fix AIX CI

---
 libcxx/include/fstream | 2 +-
 libcxx/src/fstream.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 09da5869c0d897..e9d028c17a19d7 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -273,7 +273,7 @@ public:
 #    if defined(_LIBCPP_WIN32API)
     return __filebuf_windows_native_handle(__file_);
 #    elif __has_include(<unistd.h>)
-    return ::fileno(__file_);
+    return fileno(__file_);
 #    else
 #      error "Provide a way to determine the file native handle!"
 #    endif
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index 257ab4a2be531f..55a4442b9c7822 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -26,7 +26,7 @@ static_assert(std::same_as<HANDLE, void*>);
 
 _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {
   // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
-  intptr_t __handle = _get_osfhandle(::fileno(__file));
+  intptr_t __handle = _get_osfhandle(fileno(__file));
   if (__handle == -1)
     return nullptr;
   return reinterpret_cast<void*>(__handle);

>From 1eed2d6c9d6d0935f50a496a1dace3b0895d254f Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 18:02:09 +0200
Subject: [PATCH 16/21] Try to fix CI: `stage3 (generic-no-localization,
 libcxx-runners-8-set, OFF)` test

---
 libcxx/src/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index b931460ec76297..df13e8d1e1ff6d 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -14,7 +14,6 @@ set(LIBCXX_SOURCES
   filesystem/filesystem_error.cpp
   filesystem/path_parser.h
   filesystem/path.cpp
-  fstream.cpp
   functional.cpp
   hash.cpp
   include/apple_availability.h
@@ -86,6 +85,7 @@ endif()
 if (LIBCXX_ENABLE_LOCALIZATION)
   list(APPEND LIBCXX_SOURCES
     include/sso_allocator.h
+    fstream.cpp
     ios.cpp
     ios.instantiations.cpp
     iostream.cpp

>From 6f988092dbb22193a98149253973b293a5a0a937 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Wed, 3 Jan 2024 11:25:41 +0200
Subject: [PATCH 17/21] Addressed comments

---
 libcxx/include/fstream                        |   8 +-
 libcxx/src/CMakeLists.txt                     |   2 +-
 .../native_handle.assert.pass.cpp             |  26 +++++
 .../filebuf.members/native_handle.pass.cpp    |  28 +++--
 .../fstreams/filebuf/types.pass.cpp           |   4 +
 .../native_handle.assert.pass.cpp             |  26 +++++
 .../fstreams/fstream/types.pass.cpp           |   4 +
 .../native_handle.assert.pass.cpp             |  26 +++++
 .../fstreams/ifstream/types.pass.cpp          |   4 +
 .../native_handle.assert.pass.cpp             |  26 +++++
 .../fstreams/ofstream/types.pass.cpp          |   4 +
 .../file.streams/fstreams/test_helpers.h      | 110 ++++++++++--------
 .../file.streams/fstreams/types.h             |   8 ++
 13 files changed, 206 insertions(+), 70 deletions(-)
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index e9d028c17a19d7..cd22b53efaad4e 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -217,10 +217,8 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#  if _LIBCPP_STD_VER >= 26
-#    if defined(_LIBCPP_WIN32API)
+#  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_WIN32API)
 _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file);
-#    endif
 #  endif
 
 template <class _CharT, class _Traits>
@@ -271,14 +269,14 @@ public:
   _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
     _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
 #    if defined(_LIBCPP_WIN32API)
-    return __filebuf_windows_native_handle(__file_);
+    return std::__filebuf_windows_native_handle(__file_);
 #    elif __has_include(<unistd.h>)
     return fileno(__file_);
 #    else
 #      error "Provide a way to determine the file native handle!"
 #    endif
   }
-#  endif
+#  endif //  _LIBCPP_STD_VER >= 26
 
   _LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
 
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index df13e8d1e1ff6d..96e7c6362d8c31 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -84,8 +84,8 @@ endif()
 
 if (LIBCXX_ENABLE_LOCALIZATION)
   list(APPEND LIBCXX_SOURCES
-    include/sso_allocator.h
     fstream.cpp
+    include/sso_allocator.h
     ios.cpp
     ios.instantiations.cpp
     iostream.cpp
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
new file mode 100644
index 00000000000000..766ba40122a904
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_filebuf;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../test_helpers.h"
+
+int main(int, char**) {
+  test_assertion<std::basic_filebuf<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_assertion<std::basic_filebuf<wchar_t>>();
+#endif
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 17fe6ffde37a7f..e0691fe143ac83 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -25,27 +25,25 @@
 
 template <typename CharT>
 void test() {
-  HandleT native_handle{};
-  HandleT const_native_handle{};
+  std::basic_filebuf<CharT> f;
+  std::filesystem::path p = get_temp_file_name();
 
   {
-    std::basic_filebuf<CharT> f;
-    assert(!f.is_open());
-    std::filesystem::path p = get_temp_file_name();
-    f.open(p, std::ios_base::in);
-    assert(f.is_open());
+    assert(f.open(p, std::ios_base::in) != nullptr);
     std::same_as<HandleT> decltype(auto) handle = f.native_handle();
-    native_handle                               = handle;
-    assert(is_handle_valid(native_handle));
-    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
-    const_native_handle                               = const_handle;
-    assert(is_handle_valid(const_native_handle));
+    assert(is_handle_valid(handle));
+    f.close();
+    assert(!is_handle_valid(handle));
     static_assert(noexcept(f.native_handle()));
+  }
+  {
+    assert(f.open(p, std::ios_base::in) != nullptr);
+    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+    assert(is_handle_valid(const_handle));
+    f.close();
+    assert(!is_handle_valid(const_handle));
     static_assert(noexcept(std::as_const(f).native_handle()));
   }
-
-  assert(!is_handle_valid(native_handle));
-  assert(!is_handle_valid(const_native_handle));
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
index ad4249f4d80900..9e2a78d47acf07 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../types.h"
 
 int main(int, char**)
 {
@@ -32,6 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_filebuf<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_filebuf<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_filebuf<char>::off_type, std::char_traits<char>::off_type>::value), "");
+#  if _LIBCPP_STD_VER >= 26
+    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#endif
 
   return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
new file mode 100644
index 00000000000000..f4cefd6a4cbe65
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_fstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../test_helpers.h"
+
+int main(int, char**) {
+  test_assertion<std::basic_fstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_assertion<std::basic_fstream<wchar_t>>();
+#endif
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
index 9274b1854bf85b..2481d64dc1049e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../types.h"
 
 int main(int, char**)
 {
@@ -32,6 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_fstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
+#  if _LIBCPP_STD_VER >= 26
+    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#endif
 
   return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
new file mode 100644
index 00000000000000..f4476a66fdfce6
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ifstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../test_helpers.h"
+
+int main(int, char**) {
+  test_assertion<std::basic_ifstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_assertion<std::basic_ifstream<wchar_t>>();
+#endif
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
index 15a044021f6403..632f29410fbe8f 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../types.h"
 
 int main(int, char**)
 {
@@ -32,6 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ifstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
+#  if _LIBCPP_STD_VER >= 26
+    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#endif
 
   return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
new file mode 100644
index 00000000000000..f013a4772c4efb
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ofstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../test_helpers.h"
+
+int main(int, char**) {
+  test_assertion<std::basic_ofstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_assertion<std::basic_ofstream<wchar_t>>();
+#endif
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
index 0986d5907bac5f..4b2f860382b100 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../types.h"
 
 int main(int, char**)
 {
@@ -32,6 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ofstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
+#  if _LIBCPP_STD_VER >= 26
+    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#endif
 
   return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 395e58804f8e11..86cb562178eb22 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -9,73 +9,85 @@
 #ifndef TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
 #define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
 
-#if _LIBCPP_STD_VER >= 26
+#include <cassert>
+#include <concepts>
+#include <cstdio>
+#include <fstream>
+#include <filesystem>
+#include <type_traits>
 
-#  include <cassert>
-#  include <concepts>
-#  include <cstdio>
-#  include <fstream>
-#  include <filesystem>
-#  include <type_traits>
-#  include <utility>
+#if defined(_WIN32)
+#  define WIN32_LEAN_AND_MEAN
+#  define NOMINMAX
+#  include <io.h>
+#  include <windows.h>
+#else
+#  include <fcntl.h>
+#endif
 
-#  if defined(_LIBCPP_WIN32API)
-#    define WIN32_LEAN_AND_MEAN
-#    define NOMINMAX
-#    include <io.h>
-#    include <windows.h>
-#  else
-#    include <fcntl.h>
-#  endif
+#include "check_assertion.h"
+#include "platform_support.h"
+#include "types.h"
 
-#  include "platform_support.h"
-
-#  if defined(_LIBCPP_WIN32API)
-using HandleT = void*; // HANDLE
-
-bool is_handle_valid(void* handle) {
-  if (BY_HANDLE_FILE_INFORMATION fileInformation; !GetFileInformationByHandle(handle, &fileInformation))
-    return false;
-  return true;
-};
-#  elif __has_include(<unistd.h>) // POSIX
-using HandleT = int; // POSIX file descriptor
-
-bool is_handle_valid(HandleT fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
-#  else
-#    error "Provide a native file handle!"
-#  endif
+inline bool is_handle_valid(NativeHandleT handle) {
+#if defined(_WIN32)
+  BY_HANDLE_FILE_INFORMATION fileInformation;
+  return GetFileInformationByHandle(handle, &fileInformation));
+#elif __has_include(<unistd.h>) // POSIX
+  return fcntl(handle, F_GETFL) != -1 || errno != EBADF;
+#else
+#  error "Provide a native file handle!"
+#endif
+}
 
 template <typename CharT, typename StreamT>
 void test_native_handle() {
   static_assert(
       std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
 
-  HandleT native_handle{};
-  HandleT const_native_handle{};
+  std::filesystem::path p = get_temp_file_name();
 
+  // non-const
   {
     StreamT f;
 
-    assert(!f.is_open());
-    std::filesystem::path p = get_temp_file_name();
-    f.open(p);
-    assert(f.is_open());
+    assert(f.open(p) != nullptr);
     assert(f.native_handle() == f.rdbuf()->native_handle());
-    std::same_as<HandleT> decltype(auto) handle = f.native_handle();
-    native_handle                               = handle;
-    assert(is_handle_valid(native_handle));
-    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
-    const_native_handle                               = const_handle;
-    assert(is_handle_valid(const_native_handle));
+    std::same_as<NativeHandleT> decltype(auto) handle = f.native_handle();
+    assert(is_handle_valid(handle));
+    f.close();
+    assert(is_handle_valid(handle));
     static_assert(noexcept(f.native_handle()));
-    static_assert(noexcept(std::as_const(f).native_handle()));
   }
+  // const
+  {
+    StreamT cf;
 
-  assert(!is_handle_valid(native_handle));
-  assert(!is_handle_valid(const_native_handle));
+    assert(cf.open(p) != nullptr);
+    std::same_as<NativeHandleT> decltype(auto) const_handle = cf.native_handle();
+    assert(is_handle_valid(const_handle));
+    cf.close();
+    assert(!is_handle_valid(const_handle));
+    static_assert(noexcept(cf.native_handle()));
+  }
 }
 
-#endif // _LIBCPP_STD_VER >= 26
+template <typename StreamT>
+void test_native_handle_assertion() {
+  std::filesystem::path p = get_temp_file_name();
+
+  // non-const
+  {
+    StreamT f;
+
+    TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened");
+  }
+  // const
+  {
+    StreamT cf;
+
+    TEST_LIBCPP_ASSERT_FAILURE(cf.native_handle(), "File must be opened");
+  }
+}
 
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/types.h b/libcxx/test/std/input.output/file.streams/fstreams/types.h
index b919ba20185373..e905e2529c7809 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/types.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/types.h
@@ -80,4 +80,12 @@ struct LibraryDefaultBuffer {
   void operator()(std::basic_ifstream<CharT>&) const {}
 };
 
+#if defined(_WIN32)
+using NativeHandleT = void*; // HANDLE
+#elif __has_include(<unistd.h>)
+using NativeHandleT = int; // POSIX file descriptor
+#else
+#  error "Provide a native file handle!"
+#endif
+
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TYPES_H

>From 73cdf122ec883a64bc7981e515684212e408f96f Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 3 Jan 2024 12:17:27 +0200
Subject: [PATCH 18/21] Refactor tests and fix issues

---
 .../native_handle.assert.pass.cpp             |  4 +-
 .../filebuf.members/native_handle.pass.cpp    |  8 +++-
 .../fstreams/filebuf/types.pass.cpp           |  6 +--
 .../native_handle.assert.pass.cpp             |  4 +-
 .../fstreams/fstream/types.pass.cpp           |  6 +--
 .../native_handle.assert.pass.cpp             |  4 +-
 .../fstreams/ifstream/types.pass.cpp          |  6 +--
 .../native_handle.assert.pass.cpp             |  4 +-
 .../fstreams/ofstream/types.pass.cpp          |  6 +--
 .../file.streams/fstreams/test_helpers.h      | 37 ++++++++-----------
 10 files changed, 42 insertions(+), 43 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
index 766ba40122a904..24f20c306628d5 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
@@ -19,8 +19,8 @@
 #include "../test_helpers.h"
 
 int main(int, char**) {
-  test_assertion<std::basic_filebuf<char>>();
+  test_native_handle_assertion<std::basic_filebuf<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test_assertion<std::basic_filebuf<wchar_t>>();
+  test_native_handle_assertion<std::basic_filebuf<wchar_t>>();
 #endif
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index e0691fe143ac83..3562e15cf8b889 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -28,17 +28,21 @@ void test() {
   std::basic_filebuf<CharT> f;
   std::filesystem::path p = get_temp_file_name();
 
+  // non-const
   {
     assert(f.open(p, std::ios_base::in) != nullptr);
-    std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+    std::same_as<NativeHandleT> decltype(auto) handle = f.native_handle();
     assert(is_handle_valid(handle));
     f.close();
     assert(!is_handle_valid(handle));
     static_assert(noexcept(f.native_handle()));
   }
+  // const
   {
+    const std::basic_filebuf<CharT> cf;
+
     assert(f.open(p, std::ios_base::in) != nullptr);
-    std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+    std::same_as<NativeHandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
     assert(is_handle_valid(const_handle));
     f.close();
     assert(!is_handle_valid(const_handle));
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
index 9e2a78d47acf07..17c26df68e149a 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
@@ -33,9 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_filebuf<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_filebuf<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_filebuf<char>::off_type, std::char_traits<char>::off_type>::value), "");
-#  if _LIBCPP_STD_VER >= 26
-    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#if _LIBCPP_STD_VER >= 26
+    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
 #endif
 
-  return 0;
+    return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
index f4cefd6a4cbe65..53220c0f552605 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
@@ -19,8 +19,8 @@
 #include "../test_helpers.h"
 
 int main(int, char**) {
-  test_assertion<std::basic_fstream<char>>();
+  test_native_handle_assertion<std::basic_fstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test_assertion<std::basic_fstream<wchar_t>>();
+  test_native_handle_assertion<std::basic_fstream<wchar_t>>();
 #endif
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
index 2481d64dc1049e..6583f43ed2ecd1 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
@@ -33,9 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_fstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
-#  if _LIBCPP_STD_VER >= 26
-    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#if _LIBCPP_STD_VER >= 26
+    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
 #endif
 
-  return 0;
+    return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
index f4476a66fdfce6..38206df45af516 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
@@ -19,8 +19,8 @@
 #include "../test_helpers.h"
 
 int main(int, char**) {
-  test_assertion<std::basic_ifstream<char>>();
+  test_native_handle_assertion<std::basic_ifstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test_assertion<std::basic_ifstream<wchar_t>>();
+  test_native_handle_assertion<std::basic_ifstream<wchar_t>>();
 #endif
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
index 632f29410fbe8f..9b4a169ff95150 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
@@ -33,9 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ifstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
-#  if _LIBCPP_STD_VER >= 26
-    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#if _LIBCPP_STD_VER >= 26
+    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
 #endif
 
-  return 0;
+    return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
index f013a4772c4efb..85e9f4956de677 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
@@ -19,8 +19,8 @@
 #include "../test_helpers.h"
 
 int main(int, char**) {
-  test_assertion<std::basic_ofstream<char>>();
+  test_native_handle_assertion<std::basic_ofstream<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test_assertion<std::basic_ofstream<wchar_t>>();
+  test_native_handle_assertion<std::basic_ofstream<wchar_t>>();
 #endif
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
index 4b2f860382b100..9f362754360874 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
@@ -33,9 +33,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ofstream<char>::int_type, std::char_traits<char>::int_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
-#  if _LIBCPP_STD_VER >= 26
-    static_assert((std::is_same<std::basic_fstream<char>::native_handle_type, NativeHandleT);
+#if _LIBCPP_STD_VER >= 26
+    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
 #endif
 
-  return 0;
+    return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 86cb562178eb22..54d4047a8651b4 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -15,6 +15,7 @@
 #include <fstream>
 #include <filesystem>
 #include <type_traits>
+#include <utility>
 
 #if defined(_WIN32)
 #  define WIN32_LEAN_AND_MEAN
@@ -45,30 +46,30 @@ void test_native_handle() {
   static_assert(
       std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
 
+  StreamT f;
   std::filesystem::path p = get_temp_file_name();
 
   // non-const
   {
-    StreamT f;
-
-    assert(f.open(p) != nullptr);
-    assert(f.native_handle() == f.rdbuf()->native_handle());
+    f.open(p);
     std::same_as<NativeHandleT> decltype(auto) handle = f.native_handle();
     assert(is_handle_valid(handle));
+    assert(f.rdbuf()->native_handle() == handle);
+    assert(std::as_const(f).rdbuf()->native_handle() == handle);
     f.close();
-    assert(is_handle_valid(handle));
+    assert(!is_handle_valid(handle));
     static_assert(noexcept(f.native_handle()));
   }
   // const
   {
-    StreamT cf;
-
-    assert(cf.open(p) != nullptr);
-    std::same_as<NativeHandleT> decltype(auto) const_handle = cf.native_handle();
+    f.open(p);
+    std::same_as<NativeHandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
     assert(is_handle_valid(const_handle));
-    cf.close();
+    assert(f.rdbuf()->native_handle() == const_handle);
+    assert(std::as_const(f).rdbuf()->native_handle() == const_handle);
+    f.close();
     assert(!is_handle_valid(const_handle));
-    static_assert(noexcept(cf.native_handle()));
+    static_assert(noexcept(std::as_const(f).native_handle()));
   }
 }
 
@@ -76,18 +77,12 @@ template <typename StreamT>
 void test_native_handle_assertion() {
   std::filesystem::path p = get_temp_file_name();
 
-  // non-const
-  {
-    StreamT f;
+  StreamT f;
 
-    TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened");
-  }
+  // non-const
+  { TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened"); }
   // const
-  {
-    StreamT cf;
-
-    TEST_LIBCPP_ASSERT_FAILURE(cf.native_handle(), "File must be opened");
-  }
+  { TEST_LIBCPP_ASSERT_FAILURE(std::as_const(f).native_handle(), "File must be opened"); }
 }
 
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H

>From 00807fbb19bc422a1a6d36674f21f3e25b4abca5 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 3 Jan 2024 12:56:31 +0200
Subject: [PATCH 19/21] Refactored native handle type tests

---
 .../filebuf.members/native_handle.assert.pass.cpp     |  2 +-
 .../fstreams/filebuf.members/native_handle.pass.cpp   |  2 +-
 .../file.streams/fstreams/filebuf/types.pass.cpp      |  6 +++++-
 .../fstream.members/native_handle.assert.pass.cpp     |  2 +-
 .../fstreams/fstream.members/native_handle.pass.cpp   |  2 +-
 .../file.streams/fstreams/fstream/types.pass.cpp      |  6 +++++-
 .../ifstream.members/native_handle.assert.pass.cpp    |  2 +-
 .../fstreams/ifstream.members/native_handle.pass.cpp  |  2 +-
 .../file.streams/fstreams/ifstream/types.pass.cpp     |  6 +++++-
 .../{test_helpers.h => native_handle_test_helpers.h}  | 11 +++++++++--
 .../ofstream.members/native_handle.assert.pass.cpp    |  2 +-
 .../fstreams/ofstream.members/native_handle.pass.cpp  |  2 +-
 .../file.streams/fstreams/ofstream/types.pass.cpp     |  6 +++++-
 13 files changed, 37 insertions(+), 14 deletions(-)
 rename libcxx/test/std/input.output/file.streams/fstreams/{test_helpers.h => native_handle_test_helpers.h} (86%)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
index 24f20c306628d5..69e68e639e17eb 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
@@ -16,7 +16,7 @@
 
 #include <fstream>
 
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle_assertion<std::basic_filebuf<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 3562e15cf8b889..d2e42bb1eb536e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -21,7 +21,7 @@
 
 #include "platform_support.h"
 #include "test_macros.h"
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 template <typename CharT>
 void test() {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
index 17c26df68e149a..ac5f2b59c10eb3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../native_handle_test_helpers.h"
 #include "../types.h"
 
 int main(int, char**)
@@ -34,7 +35,10 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_filebuf<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_filebuf<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
+    test_native_handle_type< std::basic_filebuf<char>>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test_native_handle_type< std::basic_filebuf<wchar_t>>();
+#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
index 53220c0f552605..b137ba1997d7c7 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
@@ -16,7 +16,7 @@
 
 #include <fstream>
 
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle_assertion<std::basic_fstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
index 900475069a1c9b..a7229512385ab3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -15,7 +15,7 @@
 // native_handle_type native_handle() const noexcept;
 
 #include "test_macros.h"
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle<char, std::basic_fstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
index 6583f43ed2ecd1..2964b9c7289439 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../native_handle_test_helpers.h"
 #include "../types.h"
 
 int main(int, char**)
@@ -34,7 +35,10 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_fstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
+    test_native_handle_type < std::basic_fstream<char>>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test_native_handle_type < std::basic_fstream<wchar_t>>();
+#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
index 38206df45af516..b460b60f531a6f 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
@@ -16,7 +16,7 @@
 
 #include <fstream>
 
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle_assertion<std::basic_ifstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
index 95a95cb69560b7..c2aff949c8fa7b 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -15,7 +15,7 @@
 // native_handle_type native_handle() const noexcept;
 
 #include "test_macros.h"
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle<char, std::basic_ifstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
index 9b4a169ff95150..7f63b3ceddc3c2 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../native_handle_test_helpers.h"
 #include "../types.h"
 
 int main(int, char**)
@@ -34,7 +35,10 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ifstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
+    test_native_handle_type < std::basic_ifstream<char>>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test_native_handle_type < std::basic_ifstream<wchar_t>>();
+#  endif
 #endif
 
     return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
similarity index 86%
rename from libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
rename to libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
index 54d4047a8651b4..4698f9aee94ff9 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
@@ -42,7 +42,7 @@ inline bool is_handle_valid(NativeHandleT handle) {
 }
 
 template <typename CharT, typename StreamT>
-void test_native_handle() {
+inline void test_native_handle() {
   static_assert(
       std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
 
@@ -74,7 +74,7 @@ void test_native_handle() {
 }
 
 template <typename StreamT>
-void test_native_handle_assertion() {
+inline void test_native_handle_assertion() {
   std::filesystem::path p = get_temp_file_name();
 
   StreamT f;
@@ -85,4 +85,11 @@ void test_native_handle_assertion() {
   { TEST_LIBCPP_ASSERT_FAILURE(std::as_const(f).native_handle(), "File must be opened"); }
 }
 
+template <typename StreamT>
+inline void test_native_handle_type() {
+  static_assert(std::is_trivially_copyable_v<typename StreamT::native_handle_type>);
+  static_assert(std::semiregular<typename StreamT::native_handle_type>);
+  static_assert(std::is_same_v<typename StreamT::native_handle_type, NativeHandleT>);
+}
+
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
index 85e9f4956de677..4aee707f909a95 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
@@ -16,7 +16,7 @@
 
 #include <fstream>
 
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle_assertion<std::basic_ofstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
index 45f0841dad18cb..88b3a00934cc42 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -15,7 +15,7 @@
 // native_handle_type native_handle() const noexcept;
 
 #include "test_macros.h"
-#include "../test_helpers.h"
+#include "../native_handle_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle<char, std::basic_ofstream<char>>();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
index 9f362754360874..7f9746949e2377 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
@@ -23,6 +23,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "../native_handle_test_helpers.h"
 #include "../types.h"
 
 int main(int, char**)
@@ -34,7 +35,10 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ofstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    static_assert(std::is_same_v<std::basic_fstream<char>::native_handle_type, NativeHandleT>);
+    test_native_handle_type < std::basic_ofstream<char>>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test_native_handle_type < std::basic_ofstream<wchar_t>>();
+#  endif
 #endif
 
     return 0;

>From aa89d7ed9833307c59f979b90636f68076bfe9f0 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 3 Jan 2024 13:02:29 +0200
Subject: [PATCH 20/21] Try to fix CI

---
 .../input.output/file.streams/fstreams/fstream/types.pass.cpp | 4 ++--
 .../file.streams/fstreams/ifstream/types.pass.cpp             | 4 ++--
 .../file.streams/fstreams/ofstream/types.pass.cpp             | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
index 2964b9c7289439..fd06839d878dff 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
@@ -35,9 +35,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_fstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_fstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    test_native_handle_type < std::basic_fstream<char>>();
+    test_native_handle_type< std::basic_fstream<char>>();
 #  ifndef TEST_HAS_NO_WIDE_CHARACTERS
-    test_native_handle_type < std::basic_fstream<wchar_t>>();
+    test_native_handle_type< std::basic_fstream<wchar_t>>();
 #  endif
 #endif
 
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
index 7f63b3ceddc3c2..6c74f76499ac12 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
@@ -35,9 +35,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ifstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ifstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    test_native_handle_type < std::basic_ifstream<char>>();
+    test_native_handle_type< std::basic_ifstream<char>>();
 #  ifndef TEST_HAS_NO_WIDE_CHARACTERS
-    test_native_handle_type < std::basic_ifstream<wchar_t>>();
+    test_native_handle_type< std::basic_ifstream<wchar_t>>();
 #  endif
 #endif
 
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
index 7f9746949e2377..3163fc4f8e6fc3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
@@ -35,9 +35,9 @@ int main(int, char**)
     static_assert((std::is_same<std::basic_ofstream<char>::pos_type, std::char_traits<char>::pos_type>::value), "");
     static_assert((std::is_same<std::basic_ofstream<char>::off_type, std::char_traits<char>::off_type>::value), "");
 #if _LIBCPP_STD_VER >= 26
-    test_native_handle_type < std::basic_ofstream<char>>();
+    test_native_handle_type< std::basic_ofstream<char>>();
 #  ifndef TEST_HAS_NO_WIDE_CHARACTERS
-    test_native_handle_type < std::basic_ofstream<wchar_t>>();
+    test_native_handle_type< std::basic_ofstream<wchar_t>>();
 #  endif
 #endif
 

>From e481a7e83dabb9b09decbdf9a7a9d2448b58dd56 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 3 Jan 2024 13:28:24 +0200
Subject: [PATCH 21/21] Try to fix CI

---
 .../file.streams/fstreams/filebuf/types.pass.cpp       |  6 ++++--
 .../file.streams/fstreams/fstream/types.pass.cpp       |  6 ++++--
 .../file.streams/fstreams/ifstream/types.pass.cpp      |  6 ++++--
 .../file.streams/fstreams/ofstream/types.pass.cpp      |  6 ++++--
 .../std/input.output/file.streams/fstreams/types.h     | 10 ++++++----
 5 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
index ac5f2b59c10eb3..38a25e35996f93 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
@@ -23,8 +23,10 @@
 #include <type_traits>
 
 #include "test_macros.h"
-#include "../native_handle_test_helpers.h"
-#include "../types.h"
+
+#if _LIBCPP_STD_VER >= 26
+#  include "../native_handle_test_helpers.h"
+#endif
 
 int main(int, char**)
 {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
index fd06839d878dff..65beed717c49c6 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream/types.pass.cpp
@@ -23,8 +23,10 @@
 #include <type_traits>
 
 #include "test_macros.h"
-#include "../native_handle_test_helpers.h"
-#include "../types.h"
+
+#if _LIBCPP_STD_VER >= 26
+#  include "../native_handle_test_helpers.h"
+#endif
 
 int main(int, char**)
 {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
index 6c74f76499ac12..fc4948b734dda3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream/types.pass.cpp
@@ -23,8 +23,10 @@
 #include <type_traits>
 
 #include "test_macros.h"
-#include "../native_handle_test_helpers.h"
-#include "../types.h"
+
+#if _LIBCPP_STD_VER >= 26
+#  include "../native_handle_test_helpers.h"
+#endif
 
 int main(int, char**)
 {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
index 3163fc4f8e6fc3..bcec00b1f8c27d 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream/types.pass.cpp
@@ -23,8 +23,10 @@
 #include <type_traits>
 
 #include "test_macros.h"
-#include "../native_handle_test_helpers.h"
-#include "../types.h"
+
+#if _LIBCPP_STD_VER >= 26
+#  include "../native_handle_test_helpers.h"
+#endif
 
 int main(int, char**)
 {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/types.h b/libcxx/test/std/input.output/file.streams/fstreams/types.h
index e905e2529c7809..66f311725034bb 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/types.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/types.h
@@ -80,12 +80,14 @@ struct LibraryDefaultBuffer {
   void operator()(std::basic_ifstream<CharT>&) const {}
 };
 
-#if defined(_WIN32)
+#if _LIBCPP_STD_VER >= 26
+#  if defined(_WIN32)
 using NativeHandleT = void*; // HANDLE
-#elif __has_include(<unistd.h>)
+#  elif __has_include(<unistd.h>)
 using NativeHandleT = int; // POSIX file descriptor
-#else
-#  error "Provide a native file handle!"
+#  else
+#    error "Provide a native file handle!"
+#  endif
 #endif
 
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TYPES_H



More information about the Mlir-commits mailing list