[libcxx] r324189 - Implement LWG2989: path's streaming operators allow everything under the sun.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 3 19:10:53 PST 2018


Author: ericwf
Date: Sat Feb  3 19:10:53 2018
New Revision: 324189

URL: http://llvm.org/viewvc/llvm-project?rev=324189&view=rev
Log:
Implement LWG2989: path's streaming operators allow everything under the sun.

Because path can be constructed from a ton of different types, including string
and wide strings, this caused it's streaming operators to suck up all sorts
of silly types via silly conversions. For example:

using namespace std::experimental::filesystem::v1;
std::wstring w(L"wide");
std::cout << w; // converts to path.

This patch tentatively adopts the resolution to LWG2989 and fixes the issue
by making the streaming operators friends of path.

Modified:
    libcxx/trunk/include/experimental/filesystem
    libcxx/trunk/test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp
    libcxx/trunk/www/upcoming_meeting.html

Modified: libcxx/trunk/include/experimental/filesystem
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/filesystem?rev=324189&r1=324188&r2=324189&view=diff
==============================================================================
--- libcxx/trunk/include/experimental/filesystem (original)
+++ libcxx/trunk/include/experimental/filesystem Sat Feb  3 19:10:53 2018
@@ -28,12 +28,13 @@
 
     path operator/ (const path& lhs, const path& rhs);
 
+    // fs.path.io operators are friends of path.
     template <class charT, class traits>
-    basic_ostream<charT, traits>&
+    friend basic_ostream<charT, traits>&
     operator<<(basic_ostream<charT, traits>& os, const path& p);
 
     template <class charT, class traits>
-    basic_istream<charT, traits>&
+    friend basic_istream<charT, traits>&
     operator>>(basic_istream<charT, traits>& is, path& p);
 
     template <class Source>
@@ -994,6 +995,40 @@ public:
     iterator begin() const;
     iterator end() const;
 
+
+    template <class _CharT, class _Traits>
+    _LIBCPP_INLINE_VISIBILITY
+    friend typename enable_if<is_same<_CharT, char>::value &&
+                       is_same<_Traits, char_traits<char>>::value,
+                       basic_ostream<_CharT, _Traits>&
+    >::type
+    operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+        __os << std::__quoted(__p.native());
+        return __os;
+    }
+
+    template <class _CharT, class _Traits>
+    _LIBCPP_INLINE_VISIBILITY
+    friend typename enable_if<!is_same<_CharT, char>::value ||
+                       !is_same<_Traits, char_traits<char>>::value,
+                       basic_ostream<_CharT, _Traits>&
+    >::type
+    operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+        __os << std::__quoted(__p.string<_CharT, _Traits>());
+        return __os;
+    }
+
+    template <class _CharT, class _Traits>
+    _LIBCPP_INLINE_VISIBILITY
+    friend basic_istream<_CharT, _Traits>&
+    operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
+    {
+        basic_string<_CharT, _Traits> __tmp;
+        __is >> __quoted(__tmp);
+        __p = __tmp;
+        return __is;
+    }
+
 private:
     inline _LIBCPP_INLINE_VISIBILITY
     path& __assign_view(__string_view const& __s) noexcept { __pn_ = string_type(__s); return *this; }
@@ -1037,39 +1072,6 @@ path operator/(const path& __lhs, const
     return path(__lhs) /= __rhs;
 }
 
-template <class _CharT, class _Traits>
-_LIBCPP_INLINE_VISIBILITY
-typename enable_if<is_same<_CharT, char>::value &&
-                   is_same<_Traits, char_traits<char>>::value,
-                   basic_ostream<_CharT, _Traits>&
->::type
-operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
-    __os << std::__quoted(__p.native());
-    return __os;
-}
-
-template <class _CharT, class _Traits>
-_LIBCPP_INLINE_VISIBILITY
-typename enable_if<!is_same<_CharT, char>::value ||
-                   !is_same<_Traits, char_traits<char>>::value,
-                   basic_ostream<_CharT, _Traits>&
->::type
-operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
-    __os << std::__quoted(__p.string<_CharT, _Traits>());
-    return __os;
-}
-
-template <class _CharT, class _Traits>
-_LIBCPP_INLINE_VISIBILITY
-basic_istream<_CharT, _Traits>&
-operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
-{
-    basic_string<_CharT, _Traits> __tmp;
-    __is >> __quoted(__tmp);
-    __p = __tmp;
-    return __is;
-}
-
 template <class _Source>
 _LIBCPP_INLINE_VISIBILITY
 typename enable_if<__is_pathable<_Source>::value, path>::type

Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp?rev=324189&r1=324188&r2=324189&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp Sat Feb  3 19:10:53 2018
@@ -26,6 +26,7 @@
 #include <type_traits>
 #include <sstream>
 #include <cassert>
+#include <iostream>
 
 #include "test_macros.h"
 #include "test_iterators.h"
@@ -35,6 +36,8 @@
 MultiStringType InStr =  MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
 MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
 
+
+
 template <class CharT>
 void doIOTest() {
   using namespace fs;
@@ -56,10 +59,40 @@ void doIOTest() {
   }
 }
 
+namespace impl {
+using namespace fs;
+
+template <class Stream, class Tp, class = decltype(std::declval<Stream&>() << std::declval<Tp&>())>
+std::true_type is_ostreamable_imp(int);
+
+template <class Stream, class Tp>
+std::false_type is_ostreamable_imp(long);
+
+template <class Stream, class Tp, class = decltype(std::declval<Stream&>() >> std::declval<Tp&>())>
+std::true_type is_istreamable_imp(int);
+
+template <class Stream, class Tp>
+std::false_type is_istreamable_imp(long);
+
+
+} // namespace impl
+
+template <class Stream, class Tp>
+struct is_ostreamable : decltype(impl::is_ostreamable_imp<Stream, Tp>(0)) {};
+template <class Stream, class Tp>
+struct is_istreamable : decltype(impl::is_istreamable_imp<Stream, Tp>(0)) {};
+
+void test_LWG2989() {
+  static_assert(!is_ostreamable<decltype(std::cout), std::wstring>::value, "");
+  static_assert(!is_ostreamable<decltype(std::wcout), std::string>::value, "");
+  static_assert(!is_istreamable<decltype(std::cin), std::wstring>::value, "");
+  static_assert(!is_istreamable<decltype(std::wcin), std::string>::value, "");
+}
 
 int main() {
   doIOTest<char>();
   doIOTest<wchar_t>();
   //doIOTest<char16_t>();
   //doIOTest<char32_t>();
+  test_LWG2989();
 }

Modified: libcxx/trunk/www/upcoming_meeting.html
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/upcoming_meeting.html?rev=324189&r1=324188&r2=324189&view=diff
==============================================================================
--- libcxx/trunk/www/upcoming_meeting.html (original)
+++ libcxx/trunk/www/upcoming_meeting.html Sat Feb  3 19:10:53 2018
@@ -67,7 +67,7 @@
 <tr><td><a href="https://wg21.link/LWG2851">2851</a></td><td><tt>std::filesystem</tt> enum classes are now underspecified</td><td>Jacksonville</td><td>Nothing to do</td></tr>
 <tr><td><a href="https://wg21.link/LWG2969">2969</a></td><td><tt>polymorphic_allocator::construct()</tt> shouldn't pass <tt>resource()</tt></td><td>Jacksonville</td><td></td></tr>
 <tr><td><a href="https://wg21.link/LWG2975">2975</a></td><td>Missing case for <tt>pair</tt> construction in scoped and polymorphic allocators</td><td>Jacksonville</td><td></td></tr>
-<tr><td><a href="https://wg21.link/LWG2989">2989</a></td><td><tt>path</tt>'s stream insertion operator lets you insert everything under the sun</td><td>Jacksonville</td><td></td></tr>
+<tr><td><a href="https://wg21.link/LWG2989">2989</a></td><td><tt>path</tt>'s stream insertion operator lets you insert everything under the sun</td><td>Jacksonville</td><td>Completed</td></tr>
 <tr><td><a href="https://wg21.link/LWG3000">3000</a></td><td><tt>monotonic_memory_resource::do_is_equal</tt> uses <tt>dynamic_cast</tt> unnecessarily</td><td>Jacksonville</td><td></td></tr>
 <tr><td><a href="https://wg21.link/LWG3002">3002</a></td><td>[networking.ts] <tt>basic_socket_acceptor::is_open()</tt> isn't <tt>noexcept</tt></td><td>Jacksonville</td><td></td></tr>
 <tr><td><a href="https://wg21.link/LWG3004">3004</a></td><td>§[string.capacity] and §[vector.capacity] should specify time complexity for <tt>capacity()</tt></td><td>Jacksonville</td><td><i>Nothing to do</i></td></tr>
@@ -104,7 +104,7 @@
 <li> 2851 - Wording changes only</li>
 <li> 2969 - We don't have PMRs yet</li>
 <li> 2975 - We can do the scoped_ bit, but the PMR stuff will have to wait.</li>
-<li> 2989 - Eric? </li>
+<li> 2989 - Proposed changes LGTM </li>
 <li> 3000 - We don't have PMRs yet</li>
 <li> 3002 - No networking TS implementation yet</li>
 <li> 3004 - Wording changes only</li>




More information about the cfe-commits mailing list