diff mbox

[v3] PR libstdc++/80675, PR libstdc++/80940

Message ID CAFk2RUbEL6_Tvq59baTCSJpqdoiJ3SU3+pWw3pCSzPpa=mTuJA@mail.gmail.com
State New
Headers show

Commit Message

Ville Voutilainen June 10, 2017, 1:38 a.m. UTC
Tested on Linux-x64.

2017-06-10  Ville Voutilainen  <ville.voutilainen@gmail.com>

    PR libstdc++/80675
    PR libstdc++/80940
    * include/std/istream:
    (__is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*)): New.
    (__do_is_convertible_to_basic_istream_impl): Likewise.
    (__is_convertible_to_basic_istream_impl): Likewise.
    (__is_convertible_to_basic_istream): Use the new base.
    (__rvalue_istream_type): New.
    (operator>>(_Istream&&, _Tp&&)): Use the new helper alias
    for the SFINAE check, convert to the helper alias type before
    doing the actual extraction.
    * include/std/ostream:
    (__is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*)): New.
    (__do_is_convertible_to_basic_ostream_impl): Likewise.
    (__is_convertible_to_basic_ostream_impl): Likewise.
    (__is_convertible_to_basic_ostream): Use the new base.
    (__rvalue_ostream_type): New.
    (operator<<(_Ostream&&, const _Tp&)): Use the new helper alias
    for the SFINAE check, convert to the helper alias type before
    doing the actual insertion.
    * testsuite/27_io/rvalue_streams-2.cc: Add new tests.

Comments

Jonathan Wakely June 15, 2017, 11:01 a.m. UTC | #1
On 10/06/17 04:38 +0300, Ville Voutilainen wrote:
>-      static void __check(...);
>+  template<typename _Tp>
>+    struct __is_convertible_to_basic_istream
>+    : __is_convertible_to_basic_istream_impl<_Tp>
>+    {
>     public:
>-      using istream_type =
>-	decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
>-      using type = __not_<is_same<istream_type, void>>;
>+      using type = __not_<is_same<void,
>+        typename __is_convertible_to_basic_istream_impl<_Tp>::__istream_type>>;

This could use is_void<...> instead of is_same<void, ...>, same below.

Otherwise OK for trunk, thanks for dealing with this.

80940 is a regression, so we need this on gcc-7-branch too, assuming
it passes testing there.
diff mbox

Patch

diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream
index 85c0a5a..86a5d03 100644
--- a/libstdc++-v3/include/std/istream
+++ b/libstdc++-v3/include/std/istream
@@ -908,20 +908,39 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     ws(basic_istream<_CharT, _Traits>& __is);
 
 #if __cplusplus >= 201103L
+  template<typename _Ch, typename _Up>
+    basic_istream<_Ch, _Up>&
+    __is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*);
+
+  template<typename _Tp, typename = void>
+    struct __is_convertible_to_basic_istream_impl
+    {
+      using __istream_type = void;
+    };
 
   template<typename _Tp>
-    struct __is_convertible_to_basic_istream
+    using __do_is_convertible_to_basic_istream_impl =
+    decltype(__is_convertible_to_basic_istream_test
+	     (declval<typename remove_reference<_Tp>::type*>()));
+
+  template<typename _Tp>
+    struct __is_convertible_to_basic_istream_impl
+    <_Tp,
+     __void_t<__do_is_convertible_to_basic_istream_impl<_Tp>>>
     {
-      template<typename _Ch, typename _Up>
-      static basic_istream<_Ch, _Up>& __check(basic_istream<_Ch, _Up>*);
+      using __istream_type =
+	__do_is_convertible_to_basic_istream_impl<_Tp>;
+    };
 
-      static void __check(...);
+  template<typename _Tp>
+    struct __is_convertible_to_basic_istream
+    : __is_convertible_to_basic_istream_impl<_Tp>
+    {
     public:
-      using istream_type =
-	decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
-      using type = __not_<is_same<istream_type, void>>;
+      using type = __not_<is_same<void,
+        typename __is_convertible_to_basic_istream_impl<_Tp>::__istream_type>>;
       constexpr static bool value = type::value;
-  };
+    };
 
   template<typename _Istream, typename _Tp, typename = void>
     struct __is_extractable : false_type {};
@@ -932,6 +951,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					      >> declval<_Tp>())>>
     : true_type {};
 
+  template<typename _Istream>
+    using __rvalue_istream_type =
+      typename __is_convertible_to_basic_istream<
+	_Istream>::__istream_type;
+
   // [27.7.1.6] Rvalue stream extraction
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 2328. Rvalue stream extraction should use perfect forwarding
@@ -949,13 +973,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline
     typename enable_if<__and_<__not_<is_lvalue_reference<_Istream>>,
 			      __is_convertible_to_basic_istream<_Istream>,
-			      __is_extractable<_Istream&, _Tp&&>>::value,
-		       typename __is_convertible_to_basic_istream<
-			 _Istream>::istream_type>::type
+			      __is_extractable<
+				__rvalue_istream_type<_Istream>,
+				_Tp&&>>::value,
+		       __rvalue_istream_type<_Istream>>::type
     operator>>(_Istream&& __is, _Tp&& __x)
     {
-      __is >> std::forward<_Tp>(__x);
-      return __is;
+      __rvalue_istream_type<_Istream> __ret_is = __is;
+      __ret_is >> std::forward<_Tp>(__x);
+      return __ret_is;
     }
 #endif // C++11
 
diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream
index 50b70a5..cffcd06 100644
--- a/libstdc++-v3/include/std/ostream
+++ b/libstdc++-v3/include/std/ostream
@@ -613,19 +613,39 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __os.flush(); }
 
 #if __cplusplus >= 201103L
+  template<typename _Ch, typename _Up>
+    basic_ostream<_Ch, _Up>&
+    __is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*);
+
+  template<typename _Tp, typename = void>
+    struct __is_convertible_to_basic_ostream_impl
+    {
+      using __ostream_type = void;
+    };
+
+  template<typename _Tp>
+    using __do_is_convertible_to_basic_ostream_impl =
+    decltype(__is_convertible_to_basic_ostream_test
+	     (declval<typename remove_reference<_Tp>::type*>()));
+
+  template<typename _Tp>
+    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<typename _Tp>
     struct __is_convertible_to_basic_ostream
-  {
-    template<typename _Ch, typename _Up>
-    static basic_ostream<_Ch, _Up>& __check(basic_ostream<_Ch, _Up>*);
-
-    static void __check(...);
-  public:
-    using ostream_type =
-      decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
-    using type = __not_<is_same<ostream_type, void>>;
-    constexpr static bool value = type::value;
-  };
+    : __is_convertible_to_basic_ostream_impl<_Tp>
+    {
+    public:
+      using type = __not_<is_same<void,
+        typename __is_convertible_to_basic_ostream_impl<_Tp>::__ostream_type>>;
+      constexpr static bool value = type::value;
+    };
 
   template<typename _Ostream, typename _Tp, typename = void>
     struct __is_insertable : false_type {};
@@ -636,6 +656,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					     << declval<const _Tp&>())>>
 				    : true_type {};
 
+  template<typename _Ostream>
+    using __rvalue_ostream_type =
+      typename __is_convertible_to_basic_ostream<
+	_Ostream>::__ostream_type;
+
   /**
    *  @brief  Generic inserter for rvalue stream
    *  @param  __os  An input stream.
@@ -650,13 +675,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline
     typename enable_if<__and_<__not_<is_lvalue_reference<_Ostream>>,
 			      __is_convertible_to_basic_ostream<_Ostream>,
-			      __is_insertable<_Ostream&, const _Tp&>>::value,
-		       typename __is_convertible_to_basic_ostream<
-			 _Ostream>::ostream_type>::type
+			      __is_insertable<
+				__rvalue_ostream_type<_Ostream>,
+				const _Tp&>>::value,
+		       __rvalue_ostream_type<_Ostream>>::type
     operator<<(_Ostream&& __os, const _Tp& __x)
     {
-      __os << __x;
-      return __os;
+      __rvalue_ostream_type<_Ostream> __ret_os = __os;
+      __ret_os << __x;
+      return __ret_os;
     }
 #endif // C++11
 
diff --git a/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc b/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc
index 2b46aa1..9c20274 100644
--- a/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc
+++ b/libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc
@@ -24,11 +24,64 @@  struct A {};
 void operator<<(std::ostream&, const A&) { }
 void operator>>(std::istream&, A&) { }
 
+class MyStream : private std::ostream, private std::istream
+{
+public:
+  MyStream& operator <<(const char*)
+  {
+    return *this;
+  }
+  MyStream& operator >>(int&)
+  {
+    return *this;
+  }
+};
+
+class MyStream2
+{
+public:
+  MyStream2& operator <<(const char*)
+  {
+    return *this;
+  }
+  MyStream2& operator >>(int&)
+  {
+    return *this;
+  }
+private:
+  operator std::ostream&();
+  operator std::istream&();
+};
+
+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()
 {
   A a;
 
   std::ostringstream() << a;
   std::istringstream() >> a;
+  MyStream stream{};
+  stream << "aaa";
+  int msi;
+  stream >> msi;
+  MyStream2 stream2{};
+  stream2 << "aaa";
+  stream2 >> msi;
+  O{} << X{};
+  I{} >> X{};
 }