From 519cf0128796091eea589e8b8d925cd33ae503f1 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 4 Jul 2025 07:57:26 +0300 Subject: [PATCH 1/6] [libc++][istream] P3223R2 Making `std::istream::ignore` less surprising Implements [P3223R2](https://wg21.link/P3223R2) # References - https://github.com/cplusplus/draft/pull/7996 --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/include/istream | 8 ++++ .../ignore.char_type.pass.cpp | 41 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 08b32bb508dc1..34735ca515d53 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -51,6 +51,7 @@ Implemented Papers - P2441R2: ``views::join_with`` (`Github `__) - P2711R1: Making multi-param constructors of ``views`` ``explicit`` (`Github `__) - P2770R0: Stashing stashing ``iterators`` for proper flattening (`Github `__) +- P3223R2: Making ``std::istream::ignore`` less surprising Improvements and New Features ----------------------------- diff --git a/libcxx/include/istream b/libcxx/include/istream index 02546902494e3..1343d2d81ac38 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -70,6 +70,7 @@ public: basic_istream& getline(char_type* s, streamsize n, char_type delim); basic_istream& ignore(streamsize n = 1, int_type delim = traits_type::eof()); + basic_istream& ignore(streamsize n, char_type delim); // Since C++26 int_type peek(); basic_istream& read (char_type* s, streamsize n); streamsize readsome(char_type* s, streamsize n); @@ -291,6 +292,13 @@ public: basic_istream& getline(char_type* __s, streamsize __n, char_type __dlm); basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); +# if __LIBCPP_STD_VER >= 26 + basic_istream& ignore(streamsize __n, char_type __delim) + requires is_same_v + { + return ignore(__n, traits::to_int_type(__delim)); + } +# endif int_type peek(); basic_istream& read(char_type* __s, streamsize __n); streamsize readsome(char_type* __s, streamsize __n); diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp new file mode 100644 index 0000000000000..2074ecef0bd33 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// Requires 396145d in the built library. +// XFAIL: using-built-library-before-llvm-9 + +// + +// basic_istream& ignore(streamsize n, char_type delim); + +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + std::istringstream in("\xF0\x9F\xA4\xA1 Clown Face"); + in.ignore(100, '\xA1'); // ignore up to '\xA1' delimiter, + // previously might have ignored to EOF + + assert(in.gcount() == 4); // 4 bytes were ignored + assert(in.peek() == ' '); // next character is a space + + std::string s1; // read the next word + in >> s1; + assert(s1 == "Clown"); + + in.ignore(100, -1L); // ambiguous overload, + // previously equivalent to (int)-1L + + return 0; +} From 40652b391f1d8ac11fb2f1599d8d36a00ed9b426 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 4 Jul 2025 09:56:25 +0300 Subject: [PATCH 2/6] Some fixes --- libcxx/include/istream | 17 +++++++++--- .../ignore.char_type.pass.cpp | 15 +++++------ .../istream.unformatted/ignore.verify.cpp | 27 +++++++++++++++++++ 3 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.verify.cpp diff --git a/libcxx/include/istream b/libcxx/include/istream index 1343d2d81ac38..001fb91ec1b67 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -172,6 +172,7 @@ template # include <__type_traits/conjunction.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_base_of.h> +# include <__type_traits/is_same.h> # include <__type_traits/make_unsigned.h> # include <__utility/declval.h> # include <__utility/forward.h> @@ -292,11 +293,13 @@ public: basic_istream& getline(char_type* __s, streamsize __n, char_type __dlm); basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); -# if __LIBCPP_STD_VER >= 26 - basic_istream& ignore(streamsize __n, char_type __delim) +# if _LIBCPP_STD_VER >= 26 + // _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) + // requires is_same_v; + _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) requires is_same_v { - return ignore(__n, traits::to_int_type(__delim)); + return this->ignore(__n, _Traits::to_int_type(__delim)); } # endif int_type peek(); @@ -873,6 +876,14 @@ basic_istream<_CharT, _Traits>& basic_istream<_CharT, _Traits>::ignore(streamsiz return *this; } +// # if _LIBCPP_STD_VER >= 26 +// template +// basic_istream& basic_istream<_CharT, _Traits>& +// basic_istream<_CharT, _Traits>::ignore(streamsize __n, char_type __delim) { +// return this->ignore(__n, _Traits::to_int_type(__delim)); +// } +// # endif + template typename basic_istream<_CharT, _Traits>::int_type basic_istream<_CharT, _Traits>::peek() { ios_base::iostate __state = ios_base::goodbit; diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp index 2074ecef0bd33..6f3fe59c0cbc5 100644 --- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp @@ -25,17 +25,14 @@ int main(int, char**) { std::istringstream in("\xF0\x9F\xA4\xA1 Clown Face"); in.ignore(100, '\xA1'); // ignore up to '\xA1' delimiter, - // previously might have ignored to EOF + // previously might have ignored to EOF - assert(in.gcount() == 4); // 4 bytes were ignored - assert(in.peek() == ' '); // next character is a space + assert(in.gcount() == 4); // 4 bytes were ignored + assert(in.peek() == ' '); // next character is a space - std::string s1; // read the next word - in >> s1; - assert(s1 == "Clown"); - - in.ignore(100, -1L); // ambiguous overload, - // previously equivalent to (int)-1L + std::string str; // read the next word + in >> str; + assert(str == "Clown"); return 0; } diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.verify.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.verify.cpp new file mode 100644 index 0000000000000..54d13cac69b94 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.verify.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// Requires 396145d in the built library. +// XFAIL: using-built-library-before-llvm-9 + +// + +// basic_istream& ignore(streamsize n, char_type delim); + +#include +#include +#include + +#include "test_macros.h" + +void test() { + std::istringstream in("\xF0\x9F\xA4\xA1 Clown Face"); + in.ignore(100, -1L); // expected-error {{call to member function 'ignore' is ambiguous}} +} From b43663105bf89d8b2ca3235d0336d3ae9ac7b5ac Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 4 Jul 2025 09:57:14 +0300 Subject: [PATCH 3/6] Cleanup --- libcxx/include/istream | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libcxx/include/istream b/libcxx/include/istream index 001fb91ec1b67..83ba1799cae91 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -294,8 +294,6 @@ public: basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); # if _LIBCPP_STD_VER >= 26 - // _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) - // requires is_same_v; _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) requires is_same_v { @@ -876,14 +874,6 @@ basic_istream<_CharT, _Traits>& basic_istream<_CharT, _Traits>::ignore(streamsiz return *this; } -// # if _LIBCPP_STD_VER >= 26 -// template -// basic_istream& basic_istream<_CharT, _Traits>& -// basic_istream<_CharT, _Traits>::ignore(streamsize __n, char_type __delim) { -// return this->ignore(__n, _Traits::to_int_type(__delim)); -// } -// # endif - template typename basic_istream<_CharT, _Traits>::int_type basic_istream<_CharT, _Traits>::peek() { ios_base::iostate __state = ios_base::goodbit; From bbaadc186854454e7da30c7b2d25c4a4d4e03ff0 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 4 Jul 2025 10:04:24 +0300 Subject: [PATCH 4/6] Cleanup --- .../input.streams/istream.unformatted/ignore.char_type.pass.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp index 6f3fe59c0cbc5..9d83a7ea15027 100644 --- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/ignore.char_type.pass.cpp @@ -16,7 +16,6 @@ // basic_istream& ignore(streamsize n, char_type delim); #include -#include #include #include From 341fe8552378a0e6a601b1dd35400d726703571c Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Sat, 5 Jul 2025 08:05:53 +0300 Subject: [PATCH 5/6] Update libcxx/include/istream --- libcxx/include/istream | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/istream b/libcxx/include/istream index 83ba1799cae91..7f15c32f67b9c 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -294,7 +294,7 @@ public: basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) + basic_istream& ignore(streamsize __n, char_type __delim) requires is_same_v { return this->ignore(__n, _Traits::to_int_type(__delim)); From 4cb58c00e1bd6fd967f94279ca03384675acc9ba Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Sat, 5 Jul 2025 17:01:18 +0300 Subject: [PATCH 6/6] Update libcxx/include/istream --- libcxx/include/istream | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/istream b/libcxx/include/istream index 7f15c32f67b9c..7a3aa3d31a019 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -294,7 +294,7 @@ public: basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); # if _LIBCPP_STD_VER >= 26 - basic_istream& ignore(streamsize __n, char_type __delim) + inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& ignore(streamsize __n, char_type __delim) requires is_same_v { return this->ignore(__n, _Traits::to_int_type(__delim));