[libc++] Implement LWG1203
Libc++ had an issue where nonsensical code like
decltype(std::stringstream{} << std::vector<int>{});
would compile, as long as you kept the expression inside decltype in
an unevaluated operand. This turned out to be that we didn't implement
LWG1203, which clarifies what we should do in that case.
rdar://58769296
This commit is contained in:
@@ -150,9 +150,9 @@ template <class charT, class traits>
|
||||
basic_istream<charT,traits>&
|
||||
ws(basic_istream<charT,traits>& is);
|
||||
|
||||
template <class charT, class traits, class T>
|
||||
basic_istream<charT, traits>&
|
||||
operator>>(basic_istream<charT, traits>&& is, T& x);
|
||||
// rvalue stream extraction
|
||||
template <class Stream, class T>
|
||||
Stream&& operator>>(Stream&& is, T&& x);
|
||||
|
||||
} // std
|
||||
|
||||
@@ -1378,13 +1378,23 @@ ws(basic_istream<_CharT, _Traits>& __is)
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _CharT, class _Traits, class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
basic_istream<_CharT, _Traits>&
|
||||
operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp&& __x)
|
||||
template <class _Stream, class _Tp, class = void>
|
||||
struct __is_istreamable : false_type { };
|
||||
|
||||
template <class _Stream, class _Tp>
|
||||
struct __is_istreamable<_Stream, _Tp, decltype(
|
||||
_VSTD::declval<_Stream>() >> _VSTD::declval<_Tp>(), void()
|
||||
)> : true_type { };
|
||||
|
||||
template <class _Stream, class _Tp, class = enable_if_t<
|
||||
_And<is_base_of<ios_base, _Stream>,
|
||||
__is_istreamable<_Stream&, _Tp&&>>::value
|
||||
>>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_Stream&& operator>>(_Stream&& __is, _Tp&& __x)
|
||||
{
|
||||
__is >> _VSTD::forward<_Tp>(__x);
|
||||
return __is;
|
||||
return _VSTD::move(__is);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
@@ -126,9 +126,8 @@ template <class charT, class traits>
|
||||
basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os);
|
||||
|
||||
// rvalue stream insertion
|
||||
template <class charT, class traits, class T>
|
||||
basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>&& os, const T& x);
|
||||
template <class Stream, class T>
|
||||
Stream&& operator<<(Stream&& os, const T& x);
|
||||
|
||||
} // std
|
||||
|
||||
@@ -1028,15 +1027,20 @@ flush(basic_ostream<_CharT, _Traits>& __os)
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _Stream, class _Tp, class = void>
|
||||
struct __is_ostreamable : false_type { };
|
||||
|
||||
template <class _Stream, class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
typename enable_if
|
||||
<
|
||||
!is_lvalue_reference<_Stream>::value &&
|
||||
is_base_of<ios_base, _Stream>::value,
|
||||
_Stream&&
|
||||
>::type
|
||||
operator<<(_Stream&& __os, const _Tp& __x)
|
||||
struct __is_ostreamable<_Stream, _Tp, decltype(
|
||||
_VSTD::declval<_Stream>() << _VSTD::declval<_Tp>(), void()
|
||||
)> : true_type { };
|
||||
|
||||
template <class _Stream, class _Tp, class = enable_if_t<
|
||||
_And<is_base_of<ios_base, _Stream>,
|
||||
__is_ostreamable<_Stream&, const _Tp&>>::value
|
||||
>>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_Stream&& operator<<(_Stream&& __os, const _Tp& __x)
|
||||
{
|
||||
__os << __x;
|
||||
return _VSTD::move(__os);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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++03
|
||||
|
||||
// Make sure the rvalue overload of operator>> isn't part of the overload set
|
||||
// when the type is not input streamable from a lvalue stream.
|
||||
|
||||
#include <istream>
|
||||
#include <utility>
|
||||
|
||||
struct Foo { };
|
||||
|
||||
using X = decltype(std::declval<std::istream>() >> std::declval<Foo&>()); // expected-error {{invalid operands to binary expression}}
|
||||
using Y = decltype(std::declval<std::istream>() >> std::declval<Foo>()); // expected-error {{invalid operands to binary expression}}
|
||||
@@ -10,9 +10,8 @@
|
||||
|
||||
// <istream>
|
||||
|
||||
// template <class charT, class traits, class T>
|
||||
// basic_istream<charT, traits>&
|
||||
// operator>>(basic_istream<charT, traits>&& is, T&& x);
|
||||
// template <class Stream, class T>
|
||||
// Stream&& operator>>(Stream&& is, T&& x);
|
||||
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
@@ -44,32 +43,44 @@ public:
|
||||
CharT* egptr() const {return base::egptr();}
|
||||
};
|
||||
|
||||
struct Int {
|
||||
int value;
|
||||
template <class CharT>
|
||||
friend void operator>>(std::basic_istream<CharT>& is, Int& self) {
|
||||
is >> self.value;
|
||||
}
|
||||
};
|
||||
|
||||
struct A{};
|
||||
struct A { };
|
||||
bool called = false;
|
||||
void operator>>(std::istream&, A&&){ called = true; }
|
||||
void operator>>(std::istream&, A&&) { called = true; }
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
testbuf<char> sb(" 123");
|
||||
int i = 0;
|
||||
std::istream(&sb) >> i;
|
||||
assert(i == 123);
|
||||
Int i = {0};
|
||||
std::istream is(&sb);
|
||||
std::istream&& result = (std::move(is) >> i);
|
||||
assert(&result == &is);
|
||||
assert(i.value == 123);
|
||||
}
|
||||
{
|
||||
testbuf<wchar_t> sb(L" 123");
|
||||
int i = 0;
|
||||
std::wistream(&sb) >> i;
|
||||
assert(i == 123);
|
||||
Int i = {0};
|
||||
std::wistream is(&sb);
|
||||
std::wistream&& result = (std::move(is) >> i);
|
||||
assert(&result == &is);
|
||||
assert(i.value == 123);
|
||||
}
|
||||
{ // test perfect forwarding
|
||||
{
|
||||
// test perfect forwarding
|
||||
assert(called == false);
|
||||
std::istringstream ss;
|
||||
auto&& out = (std::move(ss) >> A{});
|
||||
assert(&out == &ss);
|
||||
std::istringstream&& result = (std::move(ss) >> A{});
|
||||
assert(&result == &ss);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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++03
|
||||
|
||||
// Make sure the rvalue overload of operator<< isn't part of the overload set
|
||||
// when the type is not output streamable into a lvalue stream.
|
||||
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
|
||||
struct Foo { };
|
||||
|
||||
using X = decltype(std::declval<std::ostream>() << std::declval<Foo const&>()); // expected-error {{invalid operands to binary expression}}
|
||||
@@ -10,12 +10,8 @@
|
||||
|
||||
// <ostream>
|
||||
|
||||
// template <class charT, class traits = char_traits<charT> >
|
||||
// class basic_ostream;
|
||||
|
||||
// template <class charT, class traits, class T>
|
||||
// basic_ostream<charT, traits>&
|
||||
// operator<<(basic_ostream<charT, traits>&& os, const T& x);
|
||||
// template <class Stream, class T>
|
||||
// Stream&& operator<<(Stream&& os, const T& x);
|
||||
|
||||
#include <ostream>
|
||||
#include <cassert>
|
||||
@@ -55,19 +51,32 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
struct Int {
|
||||
int value;
|
||||
template <class CharT>
|
||||
friend void operator<<(std::basic_ostream<CharT>& os, Int const& self) {
|
||||
os << self.value;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
testbuf<char> sb;
|
||||
std::ostream(&sb) << "testing...";
|
||||
assert(sb.str() == "testing...");
|
||||
std::ostream os(&sb);
|
||||
Int const i = {123};
|
||||
std::ostream&& result = (std::move(os) << i);
|
||||
assert(&result == &os);
|
||||
assert(sb.str() == "123");
|
||||
}
|
||||
{
|
||||
testbuf<wchar_t> sb;
|
||||
std::wostream(&sb) << L"123";
|
||||
std::wostream os(&sb);
|
||||
Int const i = {123};
|
||||
std::wostream&& result = (std::move(os) << i);
|
||||
assert(&result == &os);
|
||||
assert(sb.str() == L"123");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -468,7 +468,7 @@
|
||||
<tr><td><a href="https://wg21.link/LWG3149">3149</a></td><td><tt>DefaultConstructible</tt> should require default initialization</td><td>Belfast</td><td></td></tr>
|
||||
|
||||
<tr><td></td><td></td><td></td><td></td></tr> -->
|
||||
<tr><td><a href="https://wg21.link/LWG1203">1203</a></td><td>More useful rvalue stream insertion</td><td>Prague</td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG1203">1203</a></td><td>More useful rvalue stream insertion</td><td>Prague</td><td>12.0</td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2859">2859</a></td><td>Definition of <em>reachable</em> in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object</td><td>Prague</td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG3018">3018</a></td><td><tt>shared_ptr</tt> of function type</td><td>Prague</td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG3050">3050</a></td><td>Conversion specification problem in <tt>chrono::duration</tt> constructor</td><td>Prague</td><td></td></tr>
|
||||
|
||||
Reference in New Issue
Block a user