[libcxx-commits] [libcxx] Reapply "[libc++][streams] P1759R6: Native handles and file streams" (PR #77190)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jan 6 05:52:41 PST 2024


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

>From 1d2c365efe493b4d62cb84a517d00a7d9dbd58b7 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 6 Jan 2024 12:47:23 +0200
Subject: [PATCH 1/2] Revert "Revert "[libc++][streams] P1759R6: Native handles
 and file streams (#76632)""

This reverts commit 40c07b559aa6ab4bac074c943967d3207bc07ae0.
---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/ReleaseNotes/18.rst               |  1 +
 libcxx/docs/Status/Cxx2cPapers.csv            |  2 +-
 libcxx/include/fstream                        | 50 ++++++++++
 libcxx/include/version                        |  2 +-
 libcxx/src/CMakeLists.txt                     |  1 +
 libcxx/src/fstream.cpp                        | 37 +++++++
 .../native_handle.assert.pass.cpp             | 32 ++++++
 .../filebuf.members/native_handle.pass.cpp    | 58 +++++++++++
 .../fstreams/filebuf/types.pass.cpp           |  9 +-
 .../native_handle.assert.pass.cpp             | 32 ++++++
 .../fstream.members/native_handle.pass.cpp    | 27 ++++++
 .../fstreams/fstream/types.pass.cpp           |  9 +-
 .../native_handle.assert.pass.cpp             | 32 ++++++
 .../ifstream.members/native_handle.pass.cpp   | 27 ++++++
 .../fstreams/ifstream/types.pass.cpp          |  9 +-
 .../fstreams/native_handle_test_helpers.h     | 97 +++++++++++++++++++
 .../native_handle.assert.pass.cpp             | 32 ++++++
 .../ofstream.members/native_handle.pass.cpp   | 27 ++++++
 .../fstreams/ofstream/types.pass.cpp          |  9 +-
 .../file.streams/fstreams/types.h             | 10 ++
 .../fstream.version.compile.pass.cpp          | 16 +--
 .../version.version.compile.pass.cpp          | 16 +--
 .../generate_feature_test_macro_components.py |  1 -
 24 files changed, 508 insertions(+), 30 deletions(-)
 create mode 100644 libcxx/src/fstream.cpp
 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/filebuf.members/native_handle.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/fstream.members/native_handle.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/ifstream.members/native_handle.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 8ce5ec9f64ef9a..893a3b13ca06e0 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 cae2347be5fd61..882f53b8d9f83f 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -59,6 +59,7 @@ Implemented Papers
 - P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?)
 - P2821R5 - span.at()
 - 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 fa4a112d143673..5701717f39766c 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..cd22b53efaad4e 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);
@@ -210,6 +217,10 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_WIN32API)
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file);
+#  endif
+
 template <class _CharT, class _Traits>
 class _LIBCPP_TEMPLATE_VIS basic_filebuf : public basic_streambuf<_CharT, _Traits> {
 public:
@@ -219,6 +230,15 @@ 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
+#    elif __has_include(<unistd.h>)
+  using native_handle_type = int; // POSIX file descriptor
+#    else
+#      error "Provide a native file handle!"
+#    endif
+#  endif
 
   // 27.9.1.2 Constructors/destructor:
   basic_filebuf();
@@ -245,6 +265,18 @@ 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() const noexcept {
+    _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
+#    if defined(_LIBCPP_WIN32API)
+    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 //  _LIBCPP_STD_VER >= 26
 
   _LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
 
@@ -1024,6 +1056,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 +1076,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
@@ -1171,6 +1209,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 +1231,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
@@ -1321,6 +1365,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 +1392,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
diff --git a/libcxx/include/version b/libcxx/include/version
index d3c2791a7d0b2c..c96647894dce63 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -496,7 +496,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..96e7c6362d8c31 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -84,6 +84,7 @@ endif()
 
 if (LIBCXX_ENABLE_LOCALIZATION)
   list(APPEND LIBCXX_SOURCES
+    fstream.cpp
     include/sso_allocator.h
     ios.cpp
     ios.instantiations.cpp
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
new file mode 100644
index 00000000000000..55a4442b9c7822
--- /dev/null
+++ b/libcxx/src/fstream.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <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 defined(_LIBCPP_WIN32API)
+
+// 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 {
+  // 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
+
+_LIBCPP_END_NAMESPACE_STD
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..858f32e721658d
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.assert.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: availability-verbose_abort-missing
+
+// <fstream>
+
+// class basic_filebuf;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle_assertion<std::basic_filebuf<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle_assertion<std::basic_filebuf<wchar_t>>();
+#endif
+
+  return 0;
+}
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..22cc63e909c5aa
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../native_handle_test_helpers.h"
+
+template <typename CharT>
+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<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
+  {
+    assert(f.open(p, std::ios_base::in) != nullptr);
+    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));
+    static_assert(noexcept(std::as_const(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/filebuf/types.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf/types.pass.cpp
index ad4249f4d80900..53a5f78d5effb8 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"
 
 int main(int, char**)
 {
@@ -32,6 +33,12 @@ 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 TEST_STD_VER >= 26
+    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;
+    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..2e6cadbc64e3b5
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: availability-verbose_abort-missing
+
+// <fstream>
+
+// class basic_fstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle_assertion<std::basic_fstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle_assertion<std::basic_fstream<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..a7229512385ab3
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "test_macros.h"
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle<char, std::basic_fstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle<wchar_t, std::basic_fstream<wchar_t>>();
+#endif
+
+  return 0;
+}
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..0e275c53ed1891 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"
 
 int main(int, char**)
 {
@@ -32,6 +33,12 @@ 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 TEST_STD_VER >= 26
+    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;
+    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..5e55b730340917
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: availability-verbose_abort-missing
+
+// <fstream>
+
+// class basic_ifstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle_assertion<std::basic_ifstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle_assertion<std::basic_ifstream<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..c2aff949c8fa7b
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "test_macros.h"
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle<char, std::basic_ifstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle<wchar_t, std::basic_ifstream<wchar_t>>();
+#endif
+
+  return 0;
+}
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..580e1ed22cbae8 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"
 
 int main(int, char**)
 {
@@ -32,6 +33,12 @@ 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 TEST_STD_VER >= 26
+    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;
+    return 0;
 }
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
new file mode 100644
index 00000000000000..40bb2fe1948751
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <cassert>
+#include <concepts>
+#include <cstdio>
+#include <fstream>
+#include <filesystem>
+#include <type_traits>
+#include <utility>
+
+#if defined(_WIN32)
+#  include <io.h>
+#  include <windows.h>
+#else
+#  include <fcntl.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "types.h"
+
+#if TEST_STD_VER >= 26
+
+#  include "check_assertion.h"
+
+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>
+inline 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
+  {
+    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));
+    static_assert(noexcept(f.native_handle()));
+  }
+  // const
+  {
+    f.open(p);
+    std::same_as<NativeHandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+    assert(is_handle_valid(const_handle));
+    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(std::as_const(f).native_handle()));
+  }
+}
+
+template <typename StreamT>
+inline void test_native_handle_assertion() {
+  StreamT f;
+
+  // non-const
+  TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened");
+  // const
+  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 // #if TEST_STD_VER >= 26
+
+#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
new file mode 100644
index 00000000000000..d42aec1e99b9fb
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.assert.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: availability-verbose_abort-missing
+
+// <fstream>
+
+// class basic_ofstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <fstream>
+
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle_assertion<std::basic_ofstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle_assertion<std::basic_ofstream<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..88b3a00934cc42
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "test_macros.h"
+#include "../native_handle_test_helpers.h"
+
+int main(int, char**) {
+  test_native_handle<char, std::basic_ofstream<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_native_handle<wchar_t, std::basic_ofstream<wchar_t>>();
+#endif
+
+  return 0;
+}
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..242b4610af4a79 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"
 
 int main(int, char**)
 {
@@ -32,6 +33,12 @@ 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 TEST_STD_VER >= 26
+    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;
+    return 0;
 }
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..29c8ad2d06c407 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,14 @@ struct LibraryDefaultBuffer {
   void operator()(std::basic_ifstream<CharT>&) const {}
 };
 
+#if TEST_STD_VER >= 26
+#  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
+
 #endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TYPES_H
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 3b7f2d26feebd0..d5a0839b30f824 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
@@ -6511,17 +6511,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 3ad5170d73ffec..8ee92909dfa53c 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 132fd342ef3c84eed7c20560e19eee561fc8504d Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 6 Jan 2024 13:06:02 +0200
Subject: [PATCH 2/2] Fix build on Windows in C++26 mode

---
 libcxx/include/fstream                        |  2 +-
 .../native_handle.assert.pass.cpp             |  2 +-
 .../native_handle.assert.pass.cpp             |  2 +-
 .../native_handle.assert.pass.cpp             |  2 +-
 .../native_handle_assert_test_helpers.h       | 28 +++++++++++++++++++
 .../fstreams/native_handle_test_helpers.h     | 15 +---------
 .../native_handle.assert.pass.cpp             |  2 +-
 7 files changed, 34 insertions(+), 19 deletions(-)
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/native_handle_assert_test_helpers.h

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index cd22b53efaad4e..203cc6dfb4b134 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -218,7 +218,7 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_WIN32API)
-_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file);
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept;
 #  endif
 
 template <class _CharT, class _Traits>
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 858f32e721658d..9e4d88642d49e6 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
@@ -20,7 +20,7 @@
 
 #include <fstream>
 
-#include "../native_handle_test_helpers.h"
+#include "../native_handle_assert_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/fstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.assert.pass.cpp
index 2e6cadbc64e3b5..8fd37f68fc97a6 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
@@ -20,7 +20,7 @@
 
 #include <fstream>
 
-#include "../native_handle_test_helpers.h"
+#include "../native_handle_assert_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/ifstream.members/native_handle.assert.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.assert.pass.cpp
index 5e55b730340917..c17b778c4afad2 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
@@ -20,7 +20,7 @@
 
 #include <fstream>
 
-#include "../native_handle_test_helpers.h"
+#include "../native_handle_assert_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/native_handle_assert_test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_assert_test_helpers.h
new file mode 100644
index 00000000000000..b46228ac7fbae0
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_assert_test_helpers.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_ASSERT_TEST_HELPERS_H
+#define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_ASSERT_TEST_HELPERS_H
+
+#if !__has_include(<unistd.h>) || !__has_include(<sys/wait.h>)
+#  error "Requires UNIX headers"
+#endif
+
+#include "check_assertion.h"
+
+template <typename StreamT>
+inline void test_native_handle_assertion() {
+  StreamT f;
+
+  // non-const
+  TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened");
+  // const
+  TEST_LIBCPP_ASSERT_FAILURE(std::as_const(f).native_handle(), "File must be opened");
+}
+
+#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_ASSERT_TEST_HELPERS_H
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
index 40bb2fe1948751..4bc862d789848c 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/native_handle_test_helpers.h
@@ -25,17 +25,14 @@
 #endif
 
 #include "platform_support.h"
-#include "test_macros.h"
 #include "types.h"
 
 #if TEST_STD_VER >= 26
 
-#  include "check_assertion.h"
-
 inline bool is_handle_valid(NativeHandleT handle) {
 #  if defined(_WIN32)
   BY_HANDLE_FILE_INFORMATION fileInformation;
-  return GetFileInformationByHandle(handle, &fileInformation));
+  return GetFileInformationByHandle(handle, &fileInformation);
 #  elif __has_include(<unistd.h>) // POSIX
   return fcntl(handle, F_GETFL) != -1 || errno != EBADF;
 #  else
@@ -75,16 +72,6 @@ inline void test_native_handle() {
   }
 }
 
-template <typename StreamT>
-inline void test_native_handle_assertion() {
-  StreamT f;
-
-  // non-const
-  TEST_LIBCPP_ASSERT_FAILURE(f.native_handle(), "File must be opened");
-  // const
-  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>);
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 d42aec1e99b9fb..243be70ec94527 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
@@ -20,7 +20,7 @@
 
 #include <fstream>
 
-#include "../native_handle_test_helpers.h"
+#include "../native_handle_assert_test_helpers.h"
 
 int main(int, char**) {
   test_native_handle_assertion<std::basic_ofstream<char>>();



More information about the libcxx-commits mailing list