diff --git a/libcxx/include/istream b/libcxx/include/istream --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -1378,13 +1378,19 @@ #ifndef _LIBCPP_CXX03_LANG -template +template inline _LIBCPP_INLINE_VISIBILITY -basic_istream<_CharT, _Traits>& -operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp&& __x) +typename enable_if +< + (__has_in_stream_op<_Stream&, _Tp& >::value || + __has_in_stream_op<_Stream&, _Tp&&>::value) && + is_base_of::value, + _Stream&& +>::type +operator>>(_Stream&& __is, _Tp&& __x) { __is >> _VSTD::forward<_Tp>(__x); - return __is; + return _VSTD::move(__is); } #endif // _LIBCPP_CXX03_LANG diff --git a/libcxx/include/ostream b/libcxx/include/ostream --- a/libcxx/include/ostream +++ b/libcxx/include/ostream @@ -1032,7 +1032,8 @@ inline _LIBCPP_INLINE_VISIBILITY typename enable_if < - !is_lvalue_reference<_Stream>::value && + (__has_out_stream_op<_Stream&, _Tp&>::value || + __has_out_stream_op<_Stream&&, _Tp&>::value) && is_base_of::value, _Stream&& >::type diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -3974,6 +3974,35 @@ template using _IsCharLikeType = _And, is_trivial<_CharT> >; +#ifndef _LIBCPP_CXX03_LANG +// __has_stream_op + +template +struct __has_out_stream_op +{ + template + static auto test(int) -> decltype(declval<_T1>() << declval<_U1>()); + + template + static auto test(...) -> false_type; + + static constexpr bool value = !is_same(0))>::value; +}; + +template +struct __has_in_stream_op +{ + template + static auto test(int) -> decltype(declval<_T1>() >> declval<_U1>()); + + template + static auto test(...) -> false_type; + + static constexpr bool value = !is_same(0))>::value; +}; + +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_END_NAMESPACE_STD #if _LIBCPP_STD_VER > 14 diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/ios_base_operator_overload_resolution.fail.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/ios_base_operator_overload_resolution.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/ios_base_operator_overload_resolution.fail.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template > +// class basic_istream; + +// template +// basic_ostream& +// operator>>(basic_istream&& os, const T& x); + +// LWG: 2534 and 1203 + +#include + +#include "test_macros.h" + +struct A {}; + +int main(int, char**) +{ + std::istringstream() >> A{}; // expected-error-re {{invalid operands to binary expression {{.*}}}} + + return 0; +} diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/perfect_forwarding.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/perfect_forwarding.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/perfect_forwarding.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template +// basic_istream& +// operator>>(basic_istream&& is, T&& x); + +#include +#include +#include + +#include "test_macros.h" + +struct Foo{}; + +bool rval = false; +bool lval = false; + +void operator>>(std::istream&, Foo&&){ rval = true; } +void operator>>(std::istream&, Foo& ){ lval = true; } + +int main(int, char**) +{ + { + std::istringstream() >> Foo{}; + assert(rval); + } + { + Foo foo; + std::istringstream() >> foo; + assert(lval); + } + + return 0; +} diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -380,7 +380,7 @@ 2525[fund.ts.v2] get_memory_resource should be const and noexceptIssaquah 2527[fund.ts.v2] ALLOCATOR_OF for function::operator= has incorrect defaultIssaquah 2531future::get should explicitly state that the shared state is releasedIssaquah - 2534Constrain rvalue stream operatorsIssaquah + 2534Constrain rvalue stream operatorsIssaquahComplete 2536What should <complex.h> do?IssaquahComplete 2540unordered_multimap::insert hint iteratorIssaquahComplete 2543LWG 2148 (hash support for enum types) seems under-specifiedIssaquahComplete