Author: ericwf Date: Sun Aug 28 16:26:01 2016 New Revision: 279945 URL: http://llvm.org/viewvc/llvm-project?rev=279945&view=rev Log: Implement LWG 2711. Constrain path members.
Modified: libcxx/trunk/include/experimental/filesystem libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp libcxx/trunk/test/support/test_iterators.h libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/experimental/filesystem URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/filesystem?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/include/experimental/filesystem (original) +++ libcxx/trunk/include/experimental/filesystem Sun Aug 28 16:26:01 2016 @@ -453,6 +453,9 @@ class _LIBCPP_TYPE_VIS directory_entry; template <class _Tp> struct __can_convert_char { static const bool value = false; }; +template <class _Tp> struct __can_convert_char<const _Tp> + : public __can_convert_char<_Tp> { +}; template <> struct __can_convert_char<char> { static const bool value = true; using __char_type = char; Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp (original) +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp Sun Aug 28 16:26:01 2016 @@ -246,6 +246,60 @@ void doAppendSourceTest(AppendOperatorTe } } + + +template <class It, class = decltype(fs::path{}.append(std::declval<It>()))> +constexpr bool has_append(int) { return true; } +template <class It> +constexpr bool has_append(long) { return false; } + +template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))> +constexpr bool has_append_op(int) { return true; } +template <class It> +constexpr bool has_append_op(long) { return false; } + +template <class It> +constexpr bool has_append() { + static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same"); + return has_append<It>(0) && has_append_op<It>(0); +} + +void test_sfinae() +{ + using namespace fs; + { + using It = const char* const; + static_assert(has_append<It>(), ""); + } + { + using It = input_iterator<const char*>; + static_assert(has_append<It>(), ""); + } + { + struct Traits { + using iterator_category = std::input_iterator_tag; + using value_type = const char; + using pointer = const char*; + using reference = const char&; + using difference_type = std::ptrdiff_t; + }; + using It = input_iterator<const char*, Traits>; + static_assert(has_append<It>(), ""); + } + { + using It = output_iterator<const char*>; + static_assert(!has_append<It>(), ""); + + } + { + static_assert(!has_append<int*>(), ""); + } + { + static_assert(!has_append<char>(), ""); + static_assert(!has_append<const char>(), ""); + } +} + int main() { using namespace fs; @@ -266,4 +320,5 @@ int main() doAppendSourceAllocTest<char>(TC); doAppendSourceAllocTest<wchar_t>(TC); } + test_sfinae(); } Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp (original) +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp Sun Aug 28 16:26:01 2016 @@ -170,6 +170,49 @@ void RunTestCase(MultiStringType const& } } +template <class It, class = decltype(fs::path{}.assign(std::declval<It>()))> +constexpr bool has_assign(int) { return true; } +template <class It> +constexpr bool has_assign(long) { return false; } +template <class It> +constexpr bool has_assign() { return has_assign<It>(0); } + +void test_sfinae() { + using namespace fs; + { + using It = const char* const; + static_assert(std::is_assignable<path, It>::value, ""); + static_assert(has_assign<It>(), ""); + } + { + using It = input_iterator<const char*>; + static_assert(std::is_assignable<path, It>::value, ""); + static_assert(has_assign<It>(), ""); + } + { + struct Traits { + using iterator_category = std::input_iterator_tag; + using value_type = const char; + using pointer = const char*; + using reference = const char&; + using difference_type = std::ptrdiff_t; + }; + using It = input_iterator<const char*, Traits>; + static_assert(std::is_assignable<path, It>::value, ""); + static_assert(has_assign<It>(), ""); + } + { + using It = output_iterator<const char*>; + static_assert(!std::is_assignable<path, It>::value, ""); + static_assert(!has_assign<It>(), ""); + + } + { + static_assert(!std::is_assignable<path, int*>::value, ""); + static_assert(!has_assign<int*>(), ""); + } +} + int main() { for (auto const& MS : PathList) { RunTestCase<char>(MS); @@ -177,4 +220,5 @@ int main() { RunTestCase<char16_t>(MS); RunTestCase<char32_t>(MS); } + test_sfinae(); } Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp (original) +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp Sun Aug 28 16:26:01 2016 @@ -265,6 +265,68 @@ void doConcatECharTest(ConcatOperatorTes } } + +template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))> +constexpr bool has_concat(int) { return true; } +template <class It> +constexpr bool has_concat(long) { return false; } + +template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))> +constexpr bool has_concat_op(int) { return true; } +template <class It> +constexpr bool has_concat_op(long) { return false; } +template <class It> +constexpr bool has_concat_op() { return has_concat_op<It>(0); } + +template <class It> +constexpr bool has_concat() { + static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same"); + return has_concat<It>(0) && has_concat_op<It>(0); +} + +void test_sfinae() { + using namespace fs; + { + static_assert(has_concat_op<char>(), ""); + static_assert(has_concat_op<const char>(), ""); + static_assert(has_concat_op<char16_t>(), ""); + static_assert(has_concat_op<const char16_t>(), ""); + } + { + using It = const char* const; + static_assert(has_concat<It>(), ""); + } + { + using It = input_iterator<const char*>; + static_assert(has_concat<It>(), ""); + } + { + struct Traits { + using iterator_category = std::input_iterator_tag; + using value_type = const char; + using pointer = const char*; + using reference = const char&; + using difference_type = std::ptrdiff_t; + }; + using It = input_iterator<const char*, Traits>; + static_assert(has_concat<It>(), ""); + } + { + using It = output_iterator<const char*>; + static_assert(!has_concat<It>(), ""); + } + { + static_assert(!has_concat<int>(0), ""); + // operator+=(int) is well formed since it converts to operator+=(value_type) + // but concat(int) isn't valid because there is no concat(value_type). + // This should probably be addressed by a LWG issue. + static_assert(has_concat_op<int>(), ""); + } + { + static_assert(!has_concat<int*>(), ""); + } +} + int main() { using namespace fs; @@ -323,4 +385,5 @@ int main() doConcatECharTest<char16_t>(TC); doConcatECharTest<char32_t>(TC); } + test_sfinae(); } Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp (original) +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp Sun Aug 28 16:26:01 2016 @@ -80,6 +80,37 @@ void RunTestCase(MultiStringType const& } } +void test_sfinae() { + using namespace fs; + { + using It = const char* const; + static_assert(std::is_constructible<path, It>::value, ""); + } + { + using It = input_iterator<const char*>; + static_assert(std::is_constructible<path, It>::value, ""); + } + { + struct Traits { + using iterator_category = std::input_iterator_tag; + using value_type = const char; + using pointer = const char*; + using reference = const char&; + using difference_type = std::ptrdiff_t; + }; + using It = input_iterator<const char*, Traits>; + static_assert(std::is_constructible<path, It>::value, ""); + } + { + using It = output_iterator<const char*>; + static_assert(!std::is_constructible<path, It>::value, ""); + + } + { + static_assert(!std::is_constructible<path, int*>::value, ""); + } +} + int main() { for (auto const& MS : PathList) { RunTestCase<char>(MS); @@ -87,4 +118,5 @@ int main() { RunTestCase<char16_t>(MS); RunTestCase<char32_t>(MS); } + test_sfinae(); } Modified: libcxx/trunk/test/support/test_iterators.h URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_iterators.h?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/test/support/test_iterators.h (original) +++ libcxx/trunk/test/support/test_iterators.h Sun Aug 28 16:26:01 2016 @@ -53,25 +53,27 @@ public: void operator,(T const &) DELETE_FUNCTION; }; -template <class It> +template <class It, + class ItTraits = It> class input_iterator { + using Traits = std::iterator_traits<ItTraits>; It it_; - template <class U> friend class input_iterator; + template <class U, class T> friend class input_iterator; public: typedef std::input_iterator_tag iterator_category; - typedef typename std::iterator_traits<It>::value_type value_type; - typedef typename std::iterator_traits<It>::difference_type difference_type; + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; typedef It pointer; - typedef typename std::iterator_traits<It>::reference reference; + typedef typename Traits::reference reference; It base() const {return it_;} input_iterator() : it_() {} explicit input_iterator(It it) : it_(it) {} - template <class U> - input_iterator(const input_iterator<U>& u) :it_(u.it_) {} + template <class U, class T> + input_iterator(const input_iterator<U, T>& u) :it_(u.it_) {} reference operator*() const {return *it_;} pointer operator->() const {return it_;} @@ -89,18 +91,18 @@ public: void operator,(T const &) DELETE_FUNCTION; }; -template <class T, class U> +template <class T, class TV, class U, class UV> inline bool -operator==(const input_iterator<T>& x, const input_iterator<U>& y) +operator==(const input_iterator<T, TV>& x, const input_iterator<U, UV>& y) { return x.base() == y.base(); } -template <class T, class U> +template <class T, class TV, class U, class UV> inline bool -operator!=(const input_iterator<T>& x, const input_iterator<U>& y) +operator!=(const input_iterator<T, TV>& x, const input_iterator<U, UV>& y) { return !(x == y); } Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=279945&r1=279944&r2=279945&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Sun Aug 28 16:26:01 2016 @@ -298,7 +298,7 @@ <tr><td><a href="http://wg21.link/LWG2707">2707</a></td><td>path construction and assignment should have "string_type&&" overloads</td><td>Oulu</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2709">2709</a></td><td>offsetof is unnecessarily imprecise</td><td>Oulu</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2710">2710</a></td><td>"Effects: Equivalent to ..." doesn't count "Synchronization:" as determined semantics</td><td>Oulu</td><td>Complete</td></tr> - <tr><td><a href="http://wg21.link/LWG2711">2711</a></td><td>path is convertible from approximately everything under the sun</td><td>Oulu</td><td></td></tr> + <tr><td><a href="http://wg21.link/LWG2711">2711</a></td><td>path is convertible from approximately everything under the sun</td><td>Oulu</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2716">2716</a></td><td>Specification of shuffle and sample disallows lvalue URNGs</td><td>Oulu</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2718">2718</a></td><td>Parallelism bug in [algorithms.parallel.exec] p2</td><td>Oulu</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2719">2719</a></td><td>permissions function should not be noexcept due to narrow contract</td><td>Oulu</td><td>Complete</td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits