From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 22F13385E000 for ; Thu, 6 May 2021 17:28:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 22F13385E000 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-177-8I9uBwS5PPidoBTUylIpCQ-1; Thu, 06 May 2021 13:28:22 -0400 X-MC-Unique: 8I9uBwS5PPidoBTUylIpCQ-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 79640801817 for ; Thu, 6 May 2021 17:28:21 +0000 (UTC) Received: from localhost (unknown [10.33.36.164]) by smtp.corp.redhat.com (Postfix) with ESMTP id 16F165D9CA; Thu, 6 May 2021 17:28:20 +0000 (UTC) Date: Thu, 6 May 2021 18:28:20 +0100 From: Jonathan Wakely To: Stephan Bergmann Cc: libstdc++@gcc.gnu.org Subject: Re: [committed] libstdc++: Implement LWG 1203 for rvalue iostreams Message-ID: <20210506172820.GC3008@redhat.com> References: <6f91ec9a-888e-cfc4-8d93-9bf9d563266a@redhat.com> <20210506170956.GB3008@redhat.com> MIME-Version: 1.0 In-Reply-To: <20210506170956.GB3008@redhat.com> 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-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, 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: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 May 2021 17:28:26 -0000 On 06/05/21 18:09 +0100, Jonathan Wakely wrote: >On 06/05/21 17:55 +0200, Stephan Bergmann wrote: >>On 30/04/2021 15:48, Jonathan Wakely via Libstdc++ wrote: >>>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. >> >>FWIW, it looks like this is causing issues for Clang (at least Clang >>11 and recent Clang 13 trunk): >> >>>$ cat test.cc >>>#include >>>int i = 1 << std::ios::erase_event; >> >>(i.e., using and enum in namespace std), >> >>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -fsyntax-only test.cc >>>In file included from test.cc:1: >>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/ostream:727:33: error: cannot initialize a parameter of type 'std::ios_base *' with an rvalue of type 'int *' >>> __rval_streamable(ios_base* = (_Tp*)nullptr); >>> ^ ~~~~~~~~~~~~~ >>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/ostream:733:25: note: in instantiation of default function argument expression for '__rval_streamable' required here >>> typename = decltype(std::__rval_streamable<_Os>() >>> ^ >>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/ostream:748:12: note: in instantiation of default argument for '__rvalue_stream_insertion_t' required here >>> inline __rvalue_stream_insertion_t<_Ostream, _Tp> >>> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>>test.cc:2:11: note: while substituting deduced template arguments into function template 'operator<<' [with _Ostream = int, _Tp = std::ios_base::event] >>>int i = 1 << std::ios::erase_event; >>> ^ >>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/ostream:727:33: note: passing argument to parameter here >>> __rval_streamable(ios_base* = (_Tp*)nullptr); >>> ^ >>>1 error generated. > >It looks like the failed conversion with the default argument is not >in the immediate context, so is an error not a substitution failure. >Clang is probably right, so I'll change it. > >The reason I did it that way was to save instantiating >std::is_convertible but also because it seemed like an easy way to >avoid confusing diagnostics that say: > >error: forming pointer to reference type 'std::basic_ostream&' > >for overload resolution failures for operator<< (because those >diagnostics are already hundreds of lines long and confusing enough >already). > >This seems to work: > >--- a/libstdc++-v3/include/std/ostream >+++ b/libstdc++-v3/include/std/ostream >@@ -722,9 +722,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > __rval_streamable(); > #else > template- typename = _Require<__not_<__is_one_of<_Tp, _Tp&, ios_base>>>> >+ typename = _Require<__not_>, >+ is_convertible<_Tp*, ios_base*>>> > _Tp& >- __rval_streamable(ios_base* = (_Tp*)nullptr); >+ __rval_streamable(); > #endif > > // SFINAE helper to check constraints for operator<<(Ostream&&, const T&). > > >I'll finish testing that. Actually, if the function parameter can't be used for the convertible check then there's no benefit to that function at all. It's simpler to just put all the constraints directly on the alias template that also checks the operator<< expression: // SFINAE helper to check constraints for operator<<(Ostream&&, const T&). // If the constraints are satisfied, it is an alias for Ostream&&. #if __cpp_lib_concepts // Use concepts if possible because they're cheaper to evaluate. template requires (!is_same_v<_Os, ios_base>) && (!is_lvalue_reference_v<_Os>) && requires (_Os* __os, ios_base* __b, const _Tp& __t) { __b = __os; *__os << __t; } #else template>, is_convertible<_Os*, ios_base*>>, typename = decltype(std::declval<_Os&>() << std::declval())> #endif using __rvalue_stream_insertion_t = _Os&&;