https://github.com/Zingam updated https://github.com/llvm/llvm-project/pull/77190
>From 1d2c365efe493b4d62cb84a517d00a7d9dbd58b7 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@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 <zin...@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>>(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits