PR libstdc++/80675, PR libstdc++/80940
authorVille Voutilainen <ville.voutilainen@gmail.com>
Wed, 21 Jun 2017 19:53:26 +0000 (22:53 +0300)
committerVille Voutilainen <ville@gcc.gnu.org>
Wed, 21 Jun 2017 19:53:26 +0000 (22:53 +0300)
* 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.

From-SVN: r249468

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/istream
libstdc++-v3/include/std/ostream
libstdc++-v3/testsuite/27_io/rvalue_streams-2.cc

index 676eaf8ae55819409d1994072899ba8d1f2f55eb..f2076a479f514683a42360f360e00504a09b5fac 100644 (file)
@@ -1,3 +1,27 @@
+2017-06-21  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.
+
 2017-06-21  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
 
        * config/abi/post/aarch64-linux-gnu/baseline_symbols.txt: Update.
index 85c0a5a2f4214231cf592415e767428d651ffeec..1fa25555771a46e41aa1937cee3c179dace50e17 100644 (file)
@@ -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_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
 
index 50b70a5080cb244e940b795ab0303857ff4c16e1..f7cab03c84125056a48e28882f9d1b1793ec202c 100644 (file)
@@ -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_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
 
index 2b46aa1cc69e807df6ebf237333460bd038adde8..9c20274d5415e610bc0c73009ab25b7bef9f5b4e 100644 (file)
@@ -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{};
 }