[libcxx-commits] [libcxx] a3f17ba - [libc++] Implement P2467R1: Support exclusive mode for fstreams

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 17 14:27:38 PST 2023


Author: PragmaTwice
Date: 2023-11-17T17:27:30-05:00
New Revision: a3f17ba3febbd546f2342ffc780ac93b694fdc8d

URL: https://github.com/llvm/llvm-project/commit/a3f17ba3febbd546f2342ffc780ac93b694fdc8d
DIFF: https://github.com/llvm/llvm-project/commit/a3f17ba3febbd546f2342ffc780ac93b694fdc8d.diff

LOG: [libc++] Implement P2467R1: Support exclusive mode for fstreams

This patch brings std::ios_base::noreplace from P2467R1 to libc++.
This requires compiling the shared library in C++23 mode since otherwise
fstream::open(...) doesn't know about the new flag.

Differential Revision: https://reviews.llvm.org/D137640
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    libcxx/test/std/language.support/support.limits/support.limits.general/ios.version.compile.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/18.rst
    libcxx/docs/Status/Cxx23Papers.csv
    libcxx/include/fstream
    libcxx/include/ios
    libcxx/include/version
    libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/open_pointer.pass.cpp
    libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/pointer.pass.cpp
    libcxx/test/std/input.output/file.streams/fstreams/fstream.members/open_pointer.pass.cpp
    libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/pointer.pass.cpp
    libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/open_pointer.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 9b4e46404d658ea..3b2dff3108b0f60 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -332,6 +332,8 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_invoke_r``                              ``202106L``
     --------------------------------------------------- -----------------
+    ``__cpp_lib_ios_noreplace``                         ``202207L``
+    --------------------------------------------------- -----------------
     ``__cpp_lib_is_scoped_enum``                        ``202011L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_mdspan``                                ``202207L``

diff  --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index d5df7fde5be91af..5f5ff83ca551240 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -48,6 +48,7 @@ Implemented Papers
 - P2538R1 - ADL-proof ``std::projected``
 - P2614R2 - Deprecate ``numeric_limits::has_denorm``
 - P0053R7 - C++ Synchronized Buffered Ostream (in the experimental library)
+- P2467R1 - Support exclusive mode for fstreams
 
 
 Improvements and New Features

diff  --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 19b1dd8eb5a446f..a7a34f474ff575d 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -76,7 +76,7 @@
 "`P2446R2 <https://wg21.link/P2446R2>`__","LWG","``views::as_rvalue``","July 2022","|Complete|","16.0","|ranges|"
 "`P2460R2 <https://wg21.link/P2460R2>`__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","",""
 "`P2465R3 <https://wg21.link/P2465R3>`__","LWG","Standard Library Modules ``std`` and ``std.compat``","July 2022","",""
-"`P2467R1 <https://wg21.link/P2467R1>`__","LWG","Support exclusive mode for ``fstreams``","July 2022","",""
+"`P2467R1 <https://wg21.link/P2467R1>`__","LWG","Support exclusive mode for ``fstreams``","July 2022","|Complete|","18.0",""
 "`P2474R2 <https://wg21.link/P2474R2>`__","LWG","``views::repeat``","July 2022","|Complete|","17.0","|ranges|"
 "`P2494R2 <https://wg21.link/P2494R2>`__","LWG","Relaxing range adaptors to allow for move only types","July 2022","|Complete|","17.0","|ranges|"
 "`P2499R0 <https://wg21.link/P2499R0>`__","LWG","``string_view`` range constructor should be ``explicit``","July 2022","|Complete|","16.0","|ranges|"

diff  --git a/libcxx/include/fstream b/libcxx/include/fstream
index 4b777f82efb6cbe..cfe1ff82ba24468 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -552,6 +552,18 @@ const char* basic_filebuf<_CharT, _Traits>::__make_mdstring(
   case ios_base::in | ios_base::out | ios_base::app | ios_base::binary:
   case ios_base::in | ios_base::app | ios_base::binary:
     return "a+b" _LIBCPP_FOPEN_CLOEXEC_MODE;
+#if _LIBCPP_STD_VER >= 23
+  case ios_base::out | ios_base::noreplace:
+  case ios_base::out | ios_base::trunc | ios_base::noreplace:
+    return "wx" _LIBCPP_FOPEN_CLOEXEC_MODE;
+  case ios_base::in | ios_base::out | ios_base::trunc | ios_base::noreplace:
+    return "w+x" _LIBCPP_FOPEN_CLOEXEC_MODE;
+  case ios_base::out | ios_base::binary | ios_base::noreplace:
+  case ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
+    return "wbx" _LIBCPP_FOPEN_CLOEXEC_MODE;
+  case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
+    return "w+bx" _LIBCPP_FOPEN_CLOEXEC_MODE;
+#endif // _LIBCPP_STD_VER >= 23
   default:
     return nullptr;
   }
@@ -665,6 +677,22 @@ basic_filebuf<_CharT, _Traits>::open(const wchar_t* __s, ios_base::openmode __mo
         case ios_base::in | ios_base::app | ios_base::binary:
             __mdstr = L"a+b";
             break;
+#  if _LIBCPP_STD_VER >= 23
+        case ios_base::out | ios_base::noreplace:
+        case ios_base::out | ios_base::trunc | ios_base::noreplace:
+          __mdstr = L"wx";
+          break;
+        case ios_base::in | ios_base::out | ios_base::trunc | ios_base::noreplace:
+          __mdstr = L"w+x";
+          break;
+        case ios_base::out | ios_base::binary | ios_base::noreplace:
+        case ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
+          __mdstr = L"wbx";
+          break;
+        case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
+          __mdstr = L"w+bx";
+          break;
+#  endif // _LIBCPP_STD_VER >= 23
         default:
             __rt = nullptr;
             break;

diff  --git a/libcxx/include/ios b/libcxx/include/ios
index a31a558d5103f44..14e6c7f92f1e5f6 100644
--- a/libcxx/include/ios
+++ b/libcxx/include/ios
@@ -58,6 +58,7 @@ public:
     static constexpr openmode ate;
     static constexpr openmode binary;
     static constexpr openmode in;
+    static constexpr openmode noreplace; // since C++23
     static constexpr openmode out;
     static constexpr openmode trunc;
 
@@ -277,12 +278,15 @@ public:
     static const iostate goodbit = 0x0;
 
     typedef unsigned int openmode;
-    static const openmode app    = 0x01;
-    static const openmode ate    = 0x02;
-    static const openmode binary = 0x04;
-    static const openmode in     = 0x08;
-    static const openmode out    = 0x10;
-    static const openmode trunc  = 0x20;
+    static const openmode app       = 0x01;
+    static const openmode ate       = 0x02;
+    static const openmode binary    = 0x04;
+    static const openmode in        = 0x08;
+    static const openmode out       = 0x10;
+    static const openmode trunc     = 0x20;
+#if _LIBCPP_STD_VER >= 23
+    static const openmode noreplace = 0x40;
+#endif
 
     enum seekdir {beg, cur, end};
 

diff  --git a/libcxx/include/version b/libcxx/include/version
index 0db366af9e42e63..80f2920128da9d1 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -121,6 +121,7 @@ __cpp_lib_integral_constant_callable                    201304L <type_traits>
 __cpp_lib_interpolate                                   201902L <cmath> <numeric>
 __cpp_lib_invoke                                        201411L <functional>
 __cpp_lib_invoke_r                                      202106L <functional>
+__cpp_lib_ios_noreplace                                 202207L <ios>
 __cpp_lib_is_aggregate                                  201703L <type_traits>
 __cpp_lib_is_constant_evaluated                         201811L <type_traits>
 __cpp_lib_is_final                                      201402L <type_traits>
@@ -447,6 +448,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 // # define __cpp_lib_formatters                           202302L
 # define __cpp_lib_forward_like                         202207L
 # define __cpp_lib_invoke_r                             202106L
+# define __cpp_lib_ios_noreplace                        202207L
 # define __cpp_lib_is_scoped_enum                       202011L
 # define __cpp_lib_mdspan                               202207L
 // # define __cpp_lib_move_only_function                   202110L

diff  --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/open_pointer.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/open_pointer.pass.cpp
index 388d452a7da8a28..f070762b3b94d5e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/open_pointer.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/open_pointer.pass.cpp
@@ -10,6 +10,8 @@
 
 // basic_filebuf<charT,traits>* open(const char* s, ios_base::openmode mode);
 
+// XFAIL: LIBCXX-AIX-FIXME
+
 #include <fstream>
 #include <cassert>
 #include "test_macros.h"
@@ -52,5 +54,57 @@ int main(int, char**)
     std::remove(temp.c_str());
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 23
+    // Test all the noreplace flag combinations
+    {
+        std::ios_base::openmode modes[] = {
+            std::ios_base::out | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace |
+                std::ios_base::binary,
+        };
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::filebuf f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::filebuf f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::wfilebuf f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::wfilebuf f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+#  endif
+    }
+#endif // TEST_STD_VER >= 23
+
+    return 0;
 }

diff  --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/pointer.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/pointer.pass.cpp
index 63f8b049e69f2cf..18b22d6b214d92b 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/pointer.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.cons/pointer.pass.cpp
@@ -13,6 +13,8 @@
 
 // explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in | ios_base::out);
 
+// XFAIL: LIBCXX-AIX-FIXME
+
 #include <fstream>
 #include <cassert>
 #include "test_macros.h"
@@ -45,5 +47,53 @@ int main(int, char**)
     std::remove(temp.c_str());
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 23
+    // Test all the noreplace flag combinations
+    {
+        std::ios_base::openmode modes[] = {
+            std::ios_base::out | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace |
+                std::ios_base::binary,
+        };
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::fstream f(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::fstream f(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::wfstream f(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::wfstream f(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+#  endif
+    }
+#endif // TEST_STD_VER >= 23
+
+    return 0;
 }

diff  --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/open_pointer.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/open_pointer.pass.cpp
index acfc282d33ef5e2..790b9ef02f90259 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/open_pointer.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/open_pointer.pass.cpp
@@ -13,6 +13,8 @@
 
 // void open(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
 
+// XFAIL: LIBCXX-AIX-FIXME
+
 #include <fstream>
 #include <cassert>
 #include "test_macros.h"
@@ -51,5 +53,57 @@ int main(int, char**)
     std::remove(temp.c_str());
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 23
+    // Test all the noreplace flag combinations
+    {
+        std::ios_base::openmode modes[] = {
+            std::ios_base::out | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace |
+                std::ios_base::binary,
+        };
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::fstream f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::fstream f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::wfstream f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::wfstream f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+#  endif
+    }
+#endif // TEST_STD_VER >= 23
+
+    return 0;
 }

diff  --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/pointer.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/pointer.pass.cpp
index b43f0ff8ebd9f7b..23bd07a6560e803 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/pointer.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.cons/pointer.pass.cpp
@@ -13,6 +13,8 @@
 
 // explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
 
+// XFAIL: LIBCXX-AIX-FIXME
+
 #include <fstream>
 #include <cassert>
 #include "test_macros.h"
@@ -59,5 +61,53 @@ int main(int, char**)
     std::remove(temp.c_str());
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 23
+    // Test all the noreplace flag combinations
+    {
+        std::ios_base::openmode modes[] = {
+            std::ios_base::out | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace |
+                std::ios_base::binary,
+        };
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::ofstream f(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::ofstream f(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::wofstream f(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::wofstream f(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+#  endif
+    }
+#endif // TEST_STD_VER >= 23
+
+    return 0;
 }

diff  --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/open_pointer.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/open_pointer.pass.cpp
index 6b9d157ef4308b4..b0a68fd4340b759 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/open_pointer.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/open_pointer.pass.cpp
@@ -13,6 +13,8 @@
 
 // void open(const char* s, ios_base::openmode mode = ios_base::out);
 
+// XFAIL: LIBCXX-AIX-FIXME
+
 #include <fstream>
 #include <cassert>
 #include "test_macros.h"
@@ -59,5 +61,56 @@ int main(int, char**)
     std::remove(temp.c_str());
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 23
+    // Test all the noreplace flag combinations
+    {
+        std::ios_base::openmode modes[] = {
+            std::ios_base::out | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace,
+            std::ios_base::out | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace | std::ios_base::binary,
+            std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::noreplace |
+                std::ios_base::binary,
+        };
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::ofstream f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+
+          {
+            std::remove(tmp.c_str());
+
+            std::ofstream f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+        for (auto mode : modes) {
+          std::string tmp = get_temp_file_name(); // also creates the file
+
+          {
+            std::wofstream f;
+            f.open(tmp.c_str(), mode);
+            assert(!f.is_open()); // since it already exists
+          }
+          {
+            std::remove(tmp.c_str());
+
+            std::wofstream f;
+            f.open(tmp.c_str(), mode);
+            assert(f.is_open()); // since it doesn't exist
+          }
+        }
+#  endif
+    }
+#endif // TEST_STD_VER >= 23
+
+    return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ios.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ios.version.compile.pass.cpp
new file mode 100644
index 000000000000000..f245815eaa40d1b
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ios.version.compile.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+//
+// clang-format off
+
+// UNSUPPORTED: no-localization
+
+// <ios>
+
+// Test the feature test macros defined by <ios>
+
+/*  Constant                   Value
+    __cpp_lib_ios_noreplace    202207L [C++23]
+*/
+
+#include <ios>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 20
+
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 23
+
+# ifndef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should be defined in c++23"
+# endif
+# if __cpp_lib_ios_noreplace != 202207L
+#   error "__cpp_lib_ios_noreplace should have the value 202207L in c++23"
+# endif
+
+#elif TEST_STD_VER > 23
+
+# ifndef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should be defined in c++26"
+# endif
+# if __cpp_lib_ios_noreplace != 202207L
+#   error "__cpp_lib_ios_noreplace should have the value 202207L 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 1e4ff3b7f864a3f..783f5f6b0058e17 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
@@ -114,6 +114,7 @@
     __cpp_lib_interpolate                            201902L [C++20]
     __cpp_lib_invoke                                 201411L [C++17]
     __cpp_lib_invoke_r                               202106L [C++23]
+    __cpp_lib_ios_noreplace                          202207L [C++23]
     __cpp_lib_is_aggregate                           201703L [C++17]
     __cpp_lib_is_constant_evaluated                  201811L [C++20]
     __cpp_lib_is_final                               201402L [C++14]
@@ -602,6 +603,10 @@
 #   error "__cpp_lib_invoke_r should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should not be defined before c++17"
 # endif
@@ -1402,6 +1407,10 @@
 #   error "__cpp_lib_invoke_r should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should not be defined before c++17"
 # endif
@@ -2331,6 +2340,10 @@
 #   error "__cpp_lib_invoke_r should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should be defined in c++17"
 # endif
@@ -3536,6 +3549,10 @@
 #   error "__cpp_lib_invoke_r should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should be defined in c++20"
 # endif
@@ -4942,6 +4959,13 @@
 #   error "__cpp_lib_invoke_r should have the value 202106L in c++23"
 # endif
 
+# ifndef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should be defined in c++23"
+# endif
+# if __cpp_lib_ios_noreplace != 202207L
+#   error "__cpp_lib_ios_noreplace should have the value 202207L in c++23"
+# endif
+
 # ifndef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should be defined in c++23"
 # endif
@@ -6645,6 +6669,13 @@
 #   error "__cpp_lib_invoke_r should have the value 202106L in c++26"
 # endif
 
+# ifndef __cpp_lib_ios_noreplace
+#   error "__cpp_lib_ios_noreplace should be defined in c++26"
+# endif
+# if __cpp_lib_ios_noreplace != 202207L
+#   error "__cpp_lib_ios_noreplace should have the value 202207L in c++26"
+# endif
+
 # ifndef __cpp_lib_is_aggregate
 #   error "__cpp_lib_is_aggregate should be defined in c++26"
 # endif

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 0c07ac432d7c7e4..589845a3c13d781 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -659,6 +659,11 @@ def add_version_header(tc):
             "values": {"c++23": 202106},
             "headers": ["functional"],
         },
+        {
+            "name": "__cpp_lib_ios_noreplace",
+            "values": { "c++23": 202207 },
+            "headers": ["ios"],
+        },
         {
             "name": "__cpp_lib_is_aggregate",
             "values": {"c++17": 201703},


        


More information about the libcxx-commits mailing list