From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 328563AA8026; Thu, 6 May 2021 13:06:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 328563AA8026 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 r11-8369] libstdc++: Implement LWG 1203 for rvalue iostreams X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-11 X-Git-Oldrev: 4f354e7447c27f2a9dfa7fee392355a1c9ef046c X-Git-Newrev: ca7d2f2ec9142995179a5d832a946b50de05e659 Message-Id: <20210506130641.328563AA8026@sourceware.org> Date: Thu, 6 May 2021 13:06:41 +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, 06 May 2021 13:06:41 -0000 https://gcc.gnu.org/g:ca7d2f2ec9142995179a5d832a946b50de05e659 commit r11-8369-gca7d2f2ec9142995179a5d832a946b50de05e659 Author: Jonathan Wakely Date: Fri Apr 30 14:07:28 2021 +0100 libstdc++: Implement LWG 1203 for rvalue iostreams This implements the resolution of LWG 1203 so that the constraints for rvalue stream insertion/extraction are simpler, and the return type is the original rvalue stream type not its base class. Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: * include/std/istream (operator>>(Istream&&, x&)): Simplify, as per LWG 1203. * include/std/ostream (operator<<(Ostream&&, const x&)): Likewise. * testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc: Adjust dg-error pattern. * testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc: Likewise. * testsuite/27_io/basic_istream/extractors_other/char/4.cc: Define is_extractable trait to replace std::__is_extractable. Make it work with rvalue streams as well as lvalues, to replace f() and g() helper functions. * testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc: Likewise. * testsuite/27_io/basic_ostream/inserters_other/char/6.cc: Define is_insertable trait to replace std::__is_insertable. Make it work with rvalue streams as well as lvalues, to replace f() and g() helper functions. * testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc: Likewise. * testsuite/27_io/filesystem/path/io/dr2989.cc: Prune additional errors from new constraints. * testsuite/27_io/rvalue_streams-2.cc: Remove PR 80675 checks, which are no longer expected to compile. * testsuite/27_io/rvalue_streams.cc: Adjust existing test. Verify LWG 1203 changes. (cherry picked from commit aa475c4ac80733f85ba47b109fc1900f05e810e2) Diff: --- libstdc++-v3/include/std/istream | 74 ++++-------------- libstdc++-v3/include/std/ostream | 87 ++++++++-------------- .../extractors_character/char/lwg2499_neg.cc | 12 +-- .../extractors_character/wchar_t/lwg2499_neg.cc | 4 +- .../27_io/basic_istream/extractors_other/char/4.cc | 77 +++++++------------ .../basic_istream/extractors_other/wchar_t/4.cc | 77 +++++++------------ .../27_io/basic_ostream/inserters_other/char/6.cc | 78 +++++++------------ .../basic_ostream/inserters_other/wchar_t/6.cc | 78 +++++++------------ .../testsuite/27_io/filesystem/path/io/dr2989.cc | 1 + libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc | 11 --- libstdc++-v3/testsuite/27_io/rvalue_streams.cc | 74 ++++++++++++++++-- 11 files changed, 233 insertions(+), 340 deletions(-) diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream index 1e5ebe4e88c..ea34cce6298 100644 --- a/libstdc++-v3/include/std/istream +++ b/libstdc++-v3/include/std/istream @@ -953,80 +953,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ws(basic_istream<_CharT, _Traits>& __is); #if __cplusplus >= 201103L - template - basic_istream<_Ch, _Up>& - __is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*); - - template - struct __is_convertible_to_basic_istream_impl - { - using __istream_type = void; - }; - - template - using __do_is_convertible_to_basic_istream_impl = - decltype(__is_convertible_to_basic_istream_test - (declval::type*>())); - - template - struct __is_convertible_to_basic_istream_impl - <_Tp, - __void_t<__do_is_convertible_to_basic_istream_impl<_Tp>>> - { - using __istream_type = - __do_is_convertible_to_basic_istream_impl<_Tp>; - }; - - template - struct __is_convertible_to_basic_istream - : __is_convertible_to_basic_istream_impl<_Tp> - { - public: - using type = __not_::__istream_type>>; - constexpr static bool value = type::value; - }; - - template - struct __is_extractable : false_type {}; - - template - struct __is_extractable<_Istream, _Tp, - __void_t() - >> declval<_Tp>())>> - : true_type {}; - - template - using __rvalue_istream_type = - typename __is_convertible_to_basic_istream< - _Istream>::__istream_type; - - // [27.7.1.6] Rvalue stream extraction + // C++11 27.7.2.6 Rvalue stream extraction [istream.rvalue] // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2328. Rvalue stream extraction should use perfect forwarding + // 1203. More useful rvalue stream insertion + + // SFINAE helper to check constraints for operator>>(Istream&&, T&&). + // If the constraints are satisfied, it is an alias for Istream&&. + template() + >> std::declval<_Tp>())> + using __rvalue_stream_extraction_t = _Is&&; + /** * @brief Generic extractor for rvalue stream * @param __is An input stream. * @param __x A reference to the extraction target. - * @return is + * @return __is * * This is just a forwarding function to allow extraction from * rvalue streams since they won't bind to the extractor functions * that take an lvalue reference. */ template - inline - typename enable_if<__and_<__not_>, - __is_convertible_to_basic_istream<_Istream>, - __is_extractable< - __rvalue_istream_type<_Istream>, - _Tp&&>>::value, - __rvalue_istream_type<_Istream>>::type + inline __rvalue_stream_extraction_t<_Istream, _Tp> operator>>(_Istream&& __is, _Tp&& __x) { - __rvalue_istream_type<_Istream> __ret_is = __is; - __ret_is >> std::forward<_Tp>(__x); - return __ret_is; + __is >> std::forward<_Tp>(__x); + return std::move(__is); } #endif // C++11 diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index a70221f2513..fdd2a87665c 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -704,77 +704,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __os.flush(); } #if __cplusplus >= 201103L - template - basic_ostream<_Ch, _Up>& - __is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*); - - template - struct __is_convertible_to_basic_ostream_impl - { - using __ostream_type = void; - }; - + // C++11 27.7.3.9 Rvalue stream insertion [ostream.rvalue] + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 1203. More useful rvalue stream insertion + + // SFINAE helper to check constraints for operator<<(Ostream&&, const T&). + // If Ostream is publicly and unambiguously derived from ios_base, then + // __rval_streamable() is equivalent to declval(). + // Otherwise, it results in a substitution failure. Specifically, it will + // fail if Ostream is an lvalue reference or the same type as ios_base. + // Use concepts if possible because they're cheaper to evaluate. +#if __cpp_lib_concepts template - using __do_is_convertible_to_basic_ostream_impl = - decltype(__is_convertible_to_basic_ostream_test - (declval::type*>())); - - template - struct __is_convertible_to_basic_ostream_impl - <_Tp, - __void_t<__do_is_convertible_to_basic_ostream_impl<_Tp>>> - { - using __ostream_type = - __do_is_convertible_to_basic_ostream_impl<_Tp>; - }; - - template - struct __is_convertible_to_basic_ostream - : __is_convertible_to_basic_ostream_impl<_Tp> - { - public: - using type = __not_::__ostream_type>>; - constexpr static bool value = type::value; - }; - - template - struct __is_insertable : false_type {}; - - template - struct __is_insertable<_Ostream, _Tp, - __void_t() - << declval())>> - : true_type {}; + requires (!is_same_v<_Tp, ios_base>) + && requires (_Tp* __t, ios_base* __b) { __b = __t; } + _Tp& + __rval_streamable(); +#else + template>>> + _Tp& + __rval_streamable(ios_base* = (_Tp*)nullptr); +#endif - template - using __rvalue_ostream_type = - typename __is_convertible_to_basic_ostream< - _Ostream>::__ostream_type; + // SFINAE helper to check constraints for operator<<(Ostream&&, const T&). + // If the constraints are satisfied, it is an alias for Ostream&&. + template() + << std::declval())> + using __rvalue_stream_insertion_t = _Os&&; /** * @brief Generic inserter for rvalue stream * @param __os An input stream. * @param __x A reference to the object being inserted. - * @return os + * @return __os * * This is just a forwarding function to allow insertion to * rvalue streams since they won't bind to the inserter functions * that take an lvalue reference. */ template - inline - typename enable_if<__and_<__not_>, - __is_convertible_to_basic_ostream<_Ostream>, - __is_insertable< - __rvalue_ostream_type<_Ostream>, - const _Tp&>>::value, - __rvalue_ostream_type<_Ostream>>::type + inline __rvalue_stream_insertion_t<_Ostream, _Tp> operator<<(_Ostream&& __os, const _Tp& __x) { - __rvalue_ostream_type<_Ostream> __ret_os = __os; - __ret_os << __x; - return __ret_os; + __os << __x; + return std::move(__os); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc index 7a39e7c1a3c..abd68af8a9a 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc @@ -26,9 +26,9 @@ void test01(std::istream& in, char* pc, signed char* sc, unsigned char* uc) { - in >> pc; // { dg-error "here" } - in >> sc; // { dg-error "here" } - in >> uc; // { dg-error "here" } + in >> pc; // { dg-error "no match" } + in >> sc; // { dg-error "no match" } + in >> uc; // { dg-error "no match" } } struct CT : std::char_traits { }; @@ -37,9 +37,9 @@ void test02(std::basic_istream& in, char* pc, signed char* sc, unsigned char* uc) { - in >> pc; // { dg-error "here" } - in >> sc; // { dg-error "here" } - in >> uc; // { dg-error "here" } + in >> pc; // { dg-error "no match" } + in >> sc; // { dg-error "no match" } + in >> uc; // { dg-error "no match" } } // { dg-excess-errors "" } diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc index bc8dfacf5f5..214f8d6a931 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc @@ -26,7 +26,7 @@ void test01(std::wistream& in, wchar_t* wc) { - in >> wc; // { dg-error "here" } + in >> wc; // { dg-error "no match" } } struct WT : std::char_traits { }; @@ -34,7 +34,7 @@ struct WT : std::char_traits { }; void test02(std::basic_istream& in, wchar_t* wc) { - in >> wc; // { dg-error "here" } + in >> wc; // { dg-error "no match" } } // { dg-excess-errors "" } diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/4.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/4.cc index 5ad1c1b4e47..9f1e293474f 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/4.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/4.cc @@ -21,6 +21,21 @@ #include +template + struct is_extractable : std::false_type + { }; + +template using void_t = void; + +template + using extract_result + = decltype(std::declval() >> std::declval()); + +template + struct is_extractable>> + : std::true_type + { }; + struct X {}; std::istream& operator>>(std::istream&, X&) = delete; @@ -30,20 +45,6 @@ std::istream& operator>>(std::istream& is, Y&&) {return is;} struct Z{}; -template -auto f(T&&) -> decltype(void(std::declval() - >> std::declval()), - std::true_type()); - -std::false_type f(...); - -template -auto g(T&&) -> decltype(void(std::declval() - >> std::declval()), - std::true_type()); - -std::false_type g(...); - void test01() { Y y; @@ -52,42 +53,18 @@ void test01() is >> Y(); std::istringstream() >> y; std::istringstream() >> Y(); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); } int main() diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc index 94f2d9da09d..fc7f5505bf4 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc @@ -21,6 +21,21 @@ #include +template + struct is_extractable : std::false_type + { }; + +template using void_t = void; + +template + using extract_result + = decltype(std::declval() >> std::declval()); + +template + struct is_extractable>> + : std::true_type + { }; + struct X {}; std::wistream& operator>>(std::wistream&, X&) = delete; @@ -30,20 +45,6 @@ std::wistream& operator>>(std::wistream& is, Y&&) {return is;} struct Z{}; -template -auto f(T&&) -> decltype(void(std::declval() - >> std::declval()), - std::true_type()); - -std::false_type f(...); - -template -auto g(T&&) -> decltype(void(std::declval() - >> std::declval()), - std::true_type()); - -std::false_type g(...); - void test01() { Y y; @@ -52,42 +53,18 @@ void test01() is >> Y(); std::wistringstream() >> y; std::wistringstream() >> Y(); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(!std::__is_extractable::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); + static_assert(!is_extractable::value, ""); } int main() diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/6.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/6.cc index b86763c60fd..4801afcba6c 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/6.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/6.cc @@ -21,6 +21,22 @@ #include +template + struct is_insertable + : std::false_type + { }; + +template using void_t = void; + +template + using insert_result + = decltype(std::declval() << std::declval()); + +template + struct is_insertable>> + : std::true_type + { }; + struct X {}; std::ostream& operator<<(std::ostream&, const X&) = delete; @@ -30,20 +46,6 @@ std::ostream& operator<<(std::ostream&& os, const Y&) {return os;} struct Z{}; -template -auto f(T&&) -> decltype(void(std::declval() - << std::declval()), - std::true_type()); - -std::false_type f(...); - -template -auto g(T&&) -> decltype(void(std::declval() - << std::declval()), - std::true_type()); - -std::false_type g(...); - void test01() { Y y; @@ -52,42 +54,18 @@ void test01() os << Y(); std::ostringstream() << y; std::ostringstream() << Y(); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); } int main() diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc index 0994a949652..3efeb804b00 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc @@ -21,6 +21,22 @@ #include +template + struct is_insertable + : std::false_type + { }; + +template using void_t = void; + +template + using insert_result + = decltype(std::declval() << std::declval()); + +template + struct is_insertable>> + : std::true_type + { }; + struct X {}; std::wostream& operator<<(std::wostream&, const X&) = delete; @@ -30,20 +46,6 @@ std::wostream& operator<<(std::wostream&& os, const Y&) {return os;} struct Z{}; -template -auto f(T&&) -> decltype(void(std::declval() - << std::declval()), - std::true_type()); - -std::false_type f(...); - -template -auto g(T&&) -> decltype(void(std::declval() - << std::declval()), - std::true_type()); - -std::false_type g(...); - void test01() { Y y; @@ -52,42 +54,18 @@ void test01() os << Y(); std::wostringstream() << y; std::wostringstream() << Y(); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(!std::__is_insertable::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::true_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); - static_assert(std::is_same())), - std::false_type>::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); + static_assert(!is_insertable::value, ""); } int main() diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/io/dr2989.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/io/dr2989.cc index c5cda776477..609f1c32a0e 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/io/dr2989.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/io/dr2989.cc @@ -33,3 +33,4 @@ void foo(std::iostream& s) { s >> p; // { dg-error "no match" } } // { dg-prune-output "no type .*enable_if" } +// { dg-prune-output "no matching function for call to '__rval_streamable" } diff --git a/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc b/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc index 7aa09aef471..d2b6997e4b9 100644 --- a/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc +++ b/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc @@ -58,16 +58,7 @@ struct X { }; std::ostream& operator<<(std::ostream& os, const X&) { return os; } std::istream& operator>>(std::istream& is, X&&) { return is; } -struct O : std::ostream { }; - -void operator<<(O&, X) = delete; - -struct I : std::istream { }; - -void operator>>(I&, X) = delete; - // PR libstdc++/65543 -// PR libstdc++/80675 // PR libstdc++/80940 int main() { @@ -82,6 +73,4 @@ int main() MyStream2 stream2{}; stream2 << "aaa"; stream2 >> msi; - O{} << X{}; - I{} >> X{}; } diff --git a/libstdc++-v3/testsuite/27_io/rvalue_streams.cc b/libstdc++-v3/testsuite/27_io/rvalue_streams.cc index def706999a3..3d359091b76 100644 --- a/libstdc++-v3/testsuite/27_io/rvalue_streams.cc +++ b/libstdc++-v3/testsuite/27_io/rvalue_streams.cc @@ -25,8 +25,6 @@ void test01() { int i = 1742; - // This usage isn't supported by the current draft. - // std::string result = (std::ostringstream() << i).str(); std::ostringstream() << i; std::string result ("1742"); int i2; @@ -45,10 +43,10 @@ test02() { X x; std::istringstream is; - auto& ref1 = (std::move(is) >> x); + auto&& ref1 = (std::move(is) >> x); VERIFY( &ref1 == &is ); VERIFY( x.as_rvalue == false ); - auto& ref2 = (std::move(is) >> std::move(x)); + auto&& ref2 = (std::move(is) >> std::move(x)); VERIFY( &ref2 == &is ); VERIFY( x.as_rvalue == true ); @@ -57,6 +55,71 @@ test02() std::istringstream("x") >> &arr[0]; #endif std::istringstream("x") >> arr; + VERIFY( std::string(arr) == "x" ); +} + +// LWG 1203 More useful rvalue stream insertion +void +test03() +{ + int i = 1203; + std::string result = (std::ostringstream() << "i = " << i).str(); + VERIFY( result == "i = 1203" ); + + std::ostringstream os; + std::ostringstream&& ros = std::move(os) << result; + VERIFY( &ros == &os ); + VERIFY( ros.str() == result ); + + std::stringstream ss; + std::stringstream&& rss = std::move(ss) << result; + VERIFY( &rss == &ss ); + VERIFY( rss.str() == result ); + + std::istringstream is("first second third"); + std::istringstream&& ris = std::move(is) >> result; + VERIFY( &ris == &is ); + VERIFY( result == "first" ); + + std::stringstream ss2("fourth fifth sixth"); + std::stringstream&& rss2 = std::move(ss2) >> result; + VERIFY( &rss2 == &ss2 ); + VERIFY( result == "fourth" ); +} + +struct A { friend void operator<<(std::ios_base&, A) { } }; + +struct O : private std::ios_base { friend void operator<<(O&, int) { } }; + +template + struct is_insertable + : std::false_type + { }; + +template using void_t = void; + +template + using insert_result + = decltype(std::declval() << std::declval()); + +template + struct is_insertable>> + : std::true_type + { }; + +// LWG 1203 negative tests +void +test04() +{ + static_assert( is_insertable::value, + "valid using the friend operator<<" ); + static_assert( !is_insertable::value, + "ill-formed because ios_base is not derived from ios_base" ); + + static_assert( is_insertable::value, + "valid using the friend operator<<" ); + static_assert( !is_insertable::value, + "ill-formed because O is not publicly derived from ios_base" ); } int @@ -64,5 +127,6 @@ main() { test01(); test02(); - return 0; + test03(); + test04(); }