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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits