[gcc r12-5878] libstdc++: Implement std::ios_base::noreplace for C++23 [PR59769]

Jonathan Wakely redi@gcc.gnu.org
Thu Dec 9 23:29:29 GMT 2021


https://gcc.gnu.org/g:a219139e986a4200a9105d7c1fa63735d2945994

commit r12-5878-ga219139e986a4200a9105d7c1fa63735d2945994
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Dec 8 20:58:11 2021 +0000

    libstdc++: Implement std::ios_base::noreplace for C++23 [PR59769]
    
    This implements my P2467R0 proposal to support opening an fstream in
    exclusive mode. The new constant is also supported pre-C++23 as
    std::ios_base::__noreplace.
    
    This proposal hasn't been approved for C++23 yet, but I am confident it
    will be, as this is restoring a feture found in pre-ISO C++ iostreams
    implementations (and still present in the MSVC library as _Noreplace).
    If the proposal fails for C++23 we can remove the ios::noreplace
    name and just keep ios::__noreplace as an extension.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/59769
            * config/io/basic_file_stdio.cc (fopen_mode): Add support for
            exclusive mode.
            * include/bits/ios_base.h (_S_noreplace): Define new enumerator.
            (ios_base::__noreplace): Define.
            (ios_base::noreplace): Define for C++23.
            * include/std/version (__cpp_lib_ios_noreplace): Define.
            * testsuite/27_io/basic_ofstream/open/char/noreplace.cc: New test.
            * testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc: New test.

Diff:
---
 libstdc++-v3/config/io/basic_file_stdio.cc         | 48 ++++++++++++----------
 libstdc++-v3/include/bits/ios_base.h               |  9 ++++
 libstdc++-v3/include/std/version                   |  1 +
 .../27_io/basic_ofstream/open/char/noreplace.cc    | 29 +++++++++++++
 .../27_io/basic_ofstream/open/wchar_t/noreplace.cc | 29 +++++++++++++
 5 files changed, 95 insertions(+), 21 deletions(-)

diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc
index ce4a6380ebb..06ee016d016 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.cc
+++ b/libstdc++-v3/config/io/basic_file_stdio.cc
@@ -78,32 +78,38 @@ namespace
 	out    = std::ios_base::out,
 	trunc  = std::ios_base::trunc,
 	app    = std::ios_base::app,
-	binary = std::ios_base::binary
+	binary = std::ios_base::binary,
+	noreplace = std::_S_noreplace
       };
 
     // _GLIBCXX_RESOLVE_LIB_DEFECTS
     // 596. 27.8.1.3 Table 112 omits "a+" and "a+b" modes.
-    switch (mode & (in|out|trunc|app|binary))
+    switch (mode & (in|out|trunc|app|binary|noreplace))
       {
-      case (   out                 ): return "w";
-      case (   out      |app       ): return "a";
-      case (             app       ): return "a";
-      case (   out|trunc           ): return "w";
-      case (in                     ): return "r";
-      case (in|out                 ): return "r+";
-      case (in|out|trunc           ): return "w+";
-      case (in|out      |app       ): return "a+";
-      case (in          |app       ): return "a+";
-
-      case (   out          |binary): return "wb";
-      case (   out      |app|binary): return "ab";
-      case (             app|binary): return "ab";
-      case (   out|trunc    |binary): return "wb";
-      case (in              |binary): return "rb";
-      case (in|out          |binary): return "r+b";
-      case (in|out|trunc    |binary): return "w+b";
-      case (in|out      |app|binary): return "a+b";
-      case (in          |app|binary): return "a+b";
+      case (   out                           ): return "w";
+      case (   out                 |noreplace): return "wx";
+      case (   out|trunc                     ): return "w";
+      case (   out|trunc           |noreplace): return "wx";
+      case (   out      |app                 ): return "a";
+      case (             app                 ): return "a";
+      case (in                               ): return "r";
+      case (in|out                           ): return "r+";
+      case (in|out|trunc                     ): return "w+";
+      case (in|out|trunc           |noreplace): return "w+x";
+      case (in|out      |app                 ): return "a+";
+      case (in          |app                 ): return "a+";
+
+      case (   out          |binary          ): return "wb";
+      case (   out          |binary|noreplace): return "wbx";
+      case (   out      |app|binary          ): return "ab";
+      case (             app|binary          ): return "ab";
+      case (   out|trunc    |binary          ): return "wb";
+      case (in              |binary          ): return "rb";
+      case (in|out          |binary          ): return "r+b";
+      case (in|out|trunc    |binary          ): return "w+b";
+      case (in|out|trunc    |binary|noreplace): return "w+bx";
+      case (in|out      |app|binary          ): return "a+b";
+      case (in          |app|binary          ): return "a+b";
 
       default: return 0; // invalid
       }
diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-v3/include/bits/ios_base.h
index d6626d4d26b..5db05524e1c 100644
--- a/libstdc++-v3/include/bits/ios_base.h
+++ b/libstdc++-v3/include/bits/ios_base.h
@@ -116,6 +116,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _S_in 		= 1L << 3,
       _S_out 		= 1L << 4,
       _S_trunc 		= 1L << 5,
+      _S_noreplace 	= 1L << 6,
       _S_ios_openmode_end = 1L << 16,
       _S_ios_openmode_max = __INT_MAX__,
       _S_ios_openmode_min = ~__INT_MAX__
@@ -466,6 +467,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     /// Truncate an existing stream when opening.  Default for @c ofstream.
     static const openmode trunc =	_S_trunc;
 
+    static const openmode __noreplace =	_S_noreplace;
+
+#if __cplusplus >= 202100L
+#define __cpp_lib_ios_noreplace 202200L
+    /// Open a file in exclusive mode.
+    static const openmode noreplace =	_S_noreplace;
+#endif
+
     // 27.4.2.1.5  Type ios_base::seekdir
     /**
      *  @brief This is an enumerated type.
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index eb612f57c73..23890037b6b 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -296,6 +296,7 @@
 #define __cpp_lib_adaptor_iterator_pair_constructor 202106L
 #define __cpp_lib_byteswap 202110L
 #define __cpp_lib_invoke_r 202106L
+#define __cpp_lib_ios_noreplace 202200L
 #define __cpp_lib_is_scoped_enum 202011L
 #if __cpp_lib_concepts
 # define __cpp_lib_monadic_optional 202110L
diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc
new file mode 100644
index 00000000000..e39f5928a1f
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc
@@ -0,0 +1,29 @@
+// { dg-do run }
+
+#include <ios>
+
+#if __cplusplus >= 202200L
+#ifndef __cpp_lib_ios_noreplace
+# error "Feature-test macro for ios::noreplace missing in <ios>"
+#elif __cpp_lib_ios_noreplace < 202200L
+# error "Feature-test macro for ios::noreplace has wrong value in <ios>"
+#endif
+#endif
+
+#include <fstream>
+#include <testsuite_hooks.h>
+
+int main()
+{
+#if __cpp_lib_ios_noreplace
+  std::ios::openmode noreplace = std::ios::noreplace;
+#else
+  std::ios::openmode noreplace = std::ios::__noreplace;
+#endif
+
+  std::ofstream of("noreplace");
+  VERIFY( of.is_open() );
+  of.close();
+  of.open("noreplace", noreplace);
+  VERIFY( ! of.is_open() );
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc
new file mode 100644
index 00000000000..77f11865ac4
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc
@@ -0,0 +1,29 @@
+// { dg-do run }
+
+#include <version>
+
+#if __cplusplus >= 202200L
+#ifndef __cpp_lib_ios_noreplace
+# error "Feature-test macro for ios::noreplace missing in <version>"
+#elif __cpp_lib_ios_noreplace < 202200L
+# error "Feature-test macro for ios::noreplace has wrong value in <version>"
+#endif
+#endif
+
+#include <fstream>
+#include <testsuite_hooks.h>
+
+int main()
+{
+#if __cpp_lib_ios_noreplace
+  std::wios::openmode noreplace = std::wios::noreplace;
+#else
+  std::wios::openmode noreplace = std::wios::__noreplace;
+#endif
+
+  std::wofstream of("noreplace");
+  VERIFY( of.is_open() );
+  of.close();
+  of.open("noreplace", noreplace);
+  VERIFY( ! of.is_open() );
+}


More information about the Libstdc++-cvs mailing list