From patchwork Fri Apr 30 13:48:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1472318 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=dkACcPYk; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWtyd3qFtz9sTD for ; Fri, 30 Apr 2021 23:49:28 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 32DEB384F02B; Fri, 30 Apr 2021 13:49:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 32DEB384F02B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1619790546; bh=iQHDO7AkPCWGYO32iV2j+q/PsROiYpxpj49ekinnNhs=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=dkACcPYki0UBlioBlxEuRf+ADKZEzgb9tKXmQ7tr6SWFxEbYRrKln3jnFfVbRy7hB 7Q2ISKp/3y7mT37CWcs12tWubh1m9i84RWQ/M/ctWKksp5zTS2/pLY013CrnTa8fAd 4LsiKM1Ke4eMf1ETwIiRdRP8C9PX2znAAozw7Fy0= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id BE069384F01B for ; Fri, 30 Apr 2021 13:49:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org BE069384F01B Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-434-Ctcc1_gIOgKQWwFPmR5dKQ-1; Fri, 30 Apr 2021 09:48:27 -0400 X-MC-Unique: Ctcc1_gIOgKQWwFPmR5dKQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EF7851006C81; Fri, 30 Apr 2021 13:48:26 +0000 (UTC) Received: from localhost (unknown [10.33.36.164]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4BE795D9E2; Fri, 30 Apr 2021 13:48:26 +0000 (UTC) Date: Fri, 30 Apr 2021 14:48:25 +0100 To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Implement LWG 1203 for rvalue iostreams Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-14.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" 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. Tested powerpc64le-linux. Committed to trunk. commit aa475c4ac80733f85ba47b109fc1900f05e810e2 Author: Jonathan Wakely Date: Fri Apr 30 14:07:28 2021 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. 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*>())); + 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 - 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 {}; - - 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(); }