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. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@324189 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -28,12 +28,13 @@
|
|||||||
|
|
||||||
path operator/ (const path& lhs, const path& rhs);
|
path operator/ (const path& lhs, const path& rhs);
|
||||||
|
|
||||||
|
// fs.path.io operators are friends of path.
|
||||||
template <class charT, class traits>
|
template <class charT, class traits>
|
||||||
basic_ostream<charT, traits>&
|
friend basic_ostream<charT, traits>&
|
||||||
operator<<(basic_ostream<charT, traits>& os, const path& p);
|
operator<<(basic_ostream<charT, traits>& os, const path& p);
|
||||||
|
|
||||||
template <class charT, class traits>
|
template <class charT, class traits>
|
||||||
basic_istream<charT, traits>&
|
friend basic_istream<charT, traits>&
|
||||||
operator>>(basic_istream<charT, traits>& is, path& p);
|
operator>>(basic_istream<charT, traits>& is, path& p);
|
||||||
|
|
||||||
template <class Source>
|
template <class Source>
|
||||||
@@ -994,6 +995,40 @@ public:
|
|||||||
iterator begin() const;
|
iterator begin() const;
|
||||||
iterator end() 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:
|
private:
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
path& __assign_view(__string_view const& __s) noexcept { __pn_ = string_type(__s); return *this; }
|
path& __assign_view(__string_view const& __s) noexcept { __pn_ = string_type(__s); return *this; }
|
||||||
@@ -1037,39 +1072,6 @@ path operator/(const path& __lhs, const path& __rhs) {
|
|||||||
return path(__lhs) /= __rhs;
|
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>
|
template <class _Source>
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
typename enable_if<__is_pathable<_Source>::value, path>::type
|
typename enable_if<__is_pathable<_Source>::value, path>::type
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
#include "test_iterators.h"
|
#include "test_iterators.h"
|
||||||
@@ -35,6 +36,8 @@
|
|||||||
MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
|
MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
|
||||||
MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
|
MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <class CharT>
|
template <class CharT>
|
||||||
void doIOTest() {
|
void doIOTest() {
|
||||||
using namespace fs;
|
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() {
|
int main() {
|
||||||
doIOTest<char>();
|
doIOTest<char>();
|
||||||
doIOTest<wchar_t>();
|
doIOTest<wchar_t>();
|
||||||
//doIOTest<char16_t>();
|
//doIOTest<char16_t>();
|
||||||
//doIOTest<char32_t>();
|
//doIOTest<char32_t>();
|
||||||
|
test_LWG2989();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/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/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/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/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/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>
|
<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> 2851 - Wording changes only</li>
|
||||||
<li> 2969 - We don't have PMRs yet</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> 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> 3000 - We don't have PMRs yet</li>
|
||||||
<li> 3002 - No networking TS implementation yet</li>
|
<li> 3002 - No networking TS implementation yet</li>
|
||||||
<li> 3004 - Wording changes only</li>
|
<li> 3004 - Wording changes only</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user