From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 20F023858407; Thu, 4 Aug 2022 18:38:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 20F023858407 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-1966] libstdc++: Add comparisons to std::default_sentinel_t (LWG 3719) X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 8e34d92ef29a175b84cc7f5185db43656ae762bb X-Git-Newrev: db33daa4677997399485176303406794dc900987 Message-Id: <20220804183822.20F023858407@sourceware.org> Date: Thu, 4 Aug 2022 18:38:22 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Aug 2022 18:38:22 -0000 https://gcc.gnu.org/g:db33daa4677997399485176303406794dc900987 commit r13-1966-gdb33daa4677997399485176303406794dc900987 Author: Jonathan Wakely Date: Thu Aug 4 12:48:22 2022 +0100 libstdc++: Add comparisons to std::default_sentinel_t (LWG 3719) This library defect was recently approved for C++23. libstdc++-v3/ChangeLog: * include/bits/fs_dir.h (directory_iterator): Add comparison with std::default_sentinel_t. Remove redundant operator!= for C++20. * (recursive_directory_iterator): Likewise. * include/bits/iterator_concepts.h [!__cpp_lib_concepts] (default_sentinel_t, default_sentinel): Define even if concepts are not supported. * include/bits/regex.h (regex_iterator): Add comparison with std::default_sentinel_t. Remove redundant operator!= for C++20. (regex_token_iterator): Likewise. (regex_token_iterator::_M_end_of_seq()): Add noexcept. * testsuite/27_io/filesystem/iterators/lwg3719.cc: New test. * testsuite/28_regex/iterators/regex_iterator/lwg3719.cc: New test. * testsuite/28_regex/iterators/regex_token_iterator/lwg3719.cc: New test. Diff: --- libstdc++-v3/include/bits/fs_dir.h | 33 ++++++++++++++---- libstdc++-v3/include/bits/iterator_concepts.h | 28 +++++++++++++--- libstdc++-v3/include/bits/regex.h | 24 ++++++++++++- .../27_io/filesystem/iterators/lwg3719.cc | 39 ++++++++++++++++++++++ .../28_regex/iterators/regex_iterator/lwg3719.cc | 29 ++++++++++++++++ .../iterators/regex_token_iterator/lwg3719.cc | 29 ++++++++++++++++ 6 files changed, 169 insertions(+), 13 deletions(-) diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h index ca37952ec17..bec2b7674ef 100644 --- a/libstdc++-v3/include/bits/fs_dir.h +++ b/libstdc++-v3/include/bits/fs_dir.h @@ -36,8 +36,9 @@ # include # include -#if __cplusplus > 201703L +#if __cplusplus >= 202002L # include // std::strong_ordering +# include // std::default_sentinel_t #endif namespace std _GLIBCXX_VISIBILITY(default) @@ -420,9 +421,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 return __pr; } - private: - directory_iterator(const path&, directory_options, error_code*); - friend bool operator==(const directory_iterator& __lhs, const directory_iterator& __rhs) noexcept @@ -431,10 +429,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 && !__lhs._M_dir.owner_before(__rhs._M_dir); } +#if __cplusplus >= 202002L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3719. Directory iterators should be usable with default sentinel + bool operator==(default_sentinel_t) const noexcept + { return !_M_dir; } +#endif + +#if __cpp_impl_three_way_comparison < 201907L friend bool operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs) noexcept { return !(__lhs == __rhs); } +#endif + + private: + directory_iterator(const path&, directory_options, error_code*); friend class recursive_directory_iterator; @@ -519,9 +529,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 void disable_recursion_pending() noexcept; - private: - recursive_directory_iterator(const path&, directory_options, error_code*); - friend bool operator==(const recursive_directory_iterator& __lhs, const recursive_directory_iterator& __rhs) noexcept @@ -530,10 +537,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 && !__lhs._M_dirs.owner_before(__rhs._M_dirs); } +#if __cplusplus >= 202002L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3719. Directory iterators should be usable with default sentinel + bool operator==(default_sentinel_t) const noexcept + { return !_M_dirs; } +#endif + +#if __cpp_impl_three_way_comparison < 201907L friend bool operator!=(const recursive_directory_iterator& __lhs, const recursive_directory_iterator& __rhs) noexcept { return !(__lhs == __rhs); } +#endif + + private: + recursive_directory_iterator(const path&, directory_options, error_code*); struct _Dir_stack; std::__shared_ptr<_Dir_stack> _M_dirs; diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index a04c970b03b..cf66c63f395 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -32,15 +32,35 @@ #pragma GCC system_header +#if __cplusplus >= 202002L #include #include // to_address #include // identity, ranges::less -#if __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION + /** A sentinel type that can be used to check for the end of a range. + * + * For some iterator types the past-the-end sentinel value is independent + * of the underlying sequence, and a default sentinel can be used with them. + * For example, a `std::counted_iterator` keeps a count of how many elements + * remain, and so checking for the past-the-end value only requires checking + * if that count has reached zero. A past-the-end `std::istream_iterator` is + * equal to the default-constructed value, which can be easily checked. + * + * Comparing iterators of these types to `std::default_sentinel` is a + * convenient way to check if the end has been reached. + * + * @since C++20 + */ + struct default_sentinel_t { }; + + /// A default sentinel value. + inline constexpr default_sentinel_t default_sentinel{}; + +#if __cpp_lib_concepts struct input_iterator_tag; struct output_iterator_tag; struct forward_iterator_tag; @@ -924,9 +944,6 @@ namespace ranges inline constexpr unreachable_sentinel_t unreachable_sentinel{}; - struct default_sentinel_t { }; - inline constexpr default_sentinel_t default_sentinel{}; - // This is the namespace for [range.access] CPOs. namespace ranges::__cust_access { @@ -983,7 +1000,8 @@ namespace ranges } // namespace __detail +#endif // C++20 library concepts _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 library concepts +#endif // C++20 #endif // _ITERATOR_CONCEPTS_H diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/bits/regex.h index 24298e35e2c..561c8fc564a 100644 --- a/libstdc++-v3/include/bits/regex.h +++ b/libstdc++-v3/include/bits/regex.h @@ -28,6 +28,10 @@ * Do not attempt to use it directly. @headername{regex} */ +#if __cplusplus >= 202002L +# include // std::default_sentinel_t +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -2760,12 +2764,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 bool operator==(const regex_iterator&) const noexcept; +#if __cplusplus >= 202002L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3719. Directory iterators should be usable with default sentinel + bool operator==(default_sentinel_t) const noexcept + { return _M_pregex == nullptr; } +#endif + +#if __cpp_impl_three_way_comparison < 201907L /** * @brief Tests the inequivalence of two regex iterators. */ bool operator!=(const regex_iterator& __rhs) const noexcept { return !(*this == __rhs); } +#endif /** * @brief Dereferences a %regex_iterator. @@ -2968,12 +2981,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 bool operator==(const regex_token_iterator& __rhs) const; +#if __cplusplus >= 202002L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3719. Directory iterators should be usable with default sentinel + bool operator==(default_sentinel_t) const noexcept + { return _M_end_of_seq(); } +#endif + +#if __cpp_impl_three_way_comparison < 201907L /** * @brief Compares a %regex_token_iterator to another for inequality. */ bool operator!=(const regex_token_iterator& __rhs) const { return !(*this == __rhs); } +#endif /** * @brief Dereferences a %regex_token_iterator. @@ -3022,7 +3044,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } constexpr bool - _M_end_of_seq() const + _M_end_of_seq() const noexcept { return _M_result == nullptr; } // [28.12.2.2.4] diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/lwg3719.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/lwg3719.cc new file mode 100644 index 00000000000..c19cddc74f9 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/lwg3719.cc @@ -0,0 +1,39 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +// LWG 3719. Directory iterators should be usable with default sentinel + +void +test_dir_iter() +{ + std::filesystem::directory_iterator d0; + VERIFY( d0 == std::default_sentinel ); + std::filesystem::directory_iterator d1("."); + VERIFY( d1 != std::default_sentinel ); + + static_assert( noexcept(d0 == std::default_sentinel) ); + static_assert( noexcept(d0 != std::default_sentinel) ); +} + +void +test_recursive_dir_iter() +{ + std::filesystem::recursive_directory_iterator d0; + VERIFY( d0 == std::default_sentinel ); + std::filesystem::recursive_directory_iterator d1("."); + VERIFY( d1 != std::default_sentinel ); + + static_assert( noexcept(d0 == std::default_sentinel) ); + static_assert( noexcept(d0 != std::default_sentinel) ); +} + +int main() +{ + test_dir_iter(); + test_recursive_dir_iter(); +} diff --git a/libstdc++-v3/testsuite/28_regex/iterators/regex_iterator/lwg3719.cc b/libstdc++-v3/testsuite/28_regex/iterators/regex_iterator/lwg3719.cc new file mode 100644 index 00000000000..e8c8f79364a --- /dev/null +++ b/libstdc++-v3/testsuite/28_regex/iterators/regex_iterator/lwg3719.cc @@ -0,0 +1,29 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include + +// LWG 3719. Directory iterators should be usable with default sentinel + +void +test_iter() +{ + std::sregex_token_iterator r0; + VERIFY( r0 == std::default_sentinel ); + std::string haystack = "a needle in a haystack"; + std::regex needle("needle"); + std::sregex_iterator r1(haystack.begin(), haystack.end(), needle); + VERIFY( r1 != std::default_sentinel ); + ++r1; + VERIFY( r1 == std::default_sentinel ); + + static_assert( noexcept(r0 == std::default_sentinel) ); // GCC extension + static_assert( noexcept(r0 != std::default_sentinel) ); // GCC extension +} + +int main() +{ + test_iter(); +} diff --git a/libstdc++-v3/testsuite/28_regex/iterators/regex_token_iterator/lwg3719.cc b/libstdc++-v3/testsuite/28_regex/iterators/regex_token_iterator/lwg3719.cc new file mode 100644 index 00000000000..5c36acead74 --- /dev/null +++ b/libstdc++-v3/testsuite/28_regex/iterators/regex_token_iterator/lwg3719.cc @@ -0,0 +1,29 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include + +// LWG 3719. Directory iterators should be usable with default sentinel + +void +test_iter() +{ + std::sregex_iterator r0; + VERIFY( r0 == std::default_sentinel ); + std::string haystack = "a needle in a haystack"; + std::regex needle("needle"); + std::sregex_iterator r1(haystack.begin(), haystack.end(), needle); + VERIFY( r1 != std::default_sentinel ); + ++r1; + VERIFY( r1 == std::default_sentinel ); + + static_assert( noexcept(r0 == std::default_sentinel) ); // GCC extension + static_assert( noexcept(r0 != std::default_sentinel) ); // GCC extension +} + +int main() +{ + test_iter(); +}