[libcxx-commits] [libcxx] fdc41e1 - [libc++] Implement LWG1203

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Sep 22 14:15:45 PDT 2020


Author: Louis Dionne
Date: 2020-09-22T17:15:31-04:00
New Revision: fdc41e11f9687a50c97e2a59663bf2d541ff5489

URL: https://github.com/llvm/llvm-project/commit/fdc41e11f9687a50c97e2a59663bf2d541ff5489
DIFF: https://github.com/llvm/llvm-project/commit/fdc41e11f9687a50c97e2a59663bf2d541ff5489.diff

LOG: [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

Added: 
    libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/not_istreamable.verify.cpp
    libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/not_ostreamable.verify.cpp
    libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/rvalue.pass.cpp

Modified: 
    libcxx/include/istream
    libcxx/include/ostream
    libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp
    libcxx/www/cxx2a_status.html

Removed: 
    libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/CharT_pointer.pass.cpp


################################################################################
diff  --git a/libcxx/include/istream b/libcxx/include/istream
index bfbe5f24728e..5145157aa42a 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -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

diff  --git a/libcxx/include/ostream b/libcxx/include/ostream
index 697732d54e6d..fc0bf69e9d92 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -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);

diff  --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/not_istreamable.verify.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/not_istreamable.verify.cpp
new file mode 100644
index 000000000000..1a03ed69b140
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/not_istreamable.verify.cpp
@@ -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}}

diff  --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp
index df65aed76dfd..70ada3a9239f 100644
--- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp
@@ -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 @@ struct testbuf
     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;
 }

diff  --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/not_ostreamable.verify.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/not_ostreamable.verify.cpp
new file mode 100644
index 000000000000..7ca36c562261
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/not_ostreamable.verify.cpp
@@ -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}}

diff  --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/CharT_pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/rvalue.pass.cpp
similarity index 71%
rename from libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/CharT_pointer.pass.cpp
rename to libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/rvalue.pass.cpp
index 87ab6bae3907..99e70c425169 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/CharT_pointer.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.rvalue/rvalue.pass.cpp
@@ -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 @@ class testbuf
         }
 };
 
+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;
 }

diff  --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html
index d1bf4744b495..25d9f24a001f 100644
--- a/libcxx/www/cxx2a_status.html
+++ b/libcxx/www/cxx2a_status.html
@@ -468,7 +468,7 @@ <h3>Library Working group Issues Status</h3>
 	<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>


        


More information about the libcxx-commits mailing list