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.
This commit is contained in:
Jonathan Wakely 2021-12-08 20:58:11 +00:00
parent 9e18a25331
commit a219139e98
5 changed files with 94 additions and 20 deletions

View File

@ -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 ): 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 |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 |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
}

View File

@ -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.

View File

@ -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

View File

@ -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() );
}

View File

@ -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() );
}