From 2fc65041beabcb4c970deeb8ece010c10b0b40f9 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sun, 28 Aug 2016 21:26:01 +0000 Subject: [PATCH] Implement LWG 2711. Constrain path members. llvm-svn: 279945 --- libcxx/include/experimental/filesystem | 3 + .../path.member/path.append.pass.cpp | 55 ++++++++++++++++ .../path.member/path.assign/source.pass.cpp | 44 +++++++++++++ .../path.member/path.concat.pass.cpp | 63 +++++++++++++++++++ .../path.construct/source.pass.cpp | 32 ++++++++++ libcxx/test/support/test_iterators.h | 24 +++---- libcxx/www/cxx1z_status.html | 2 +- 7 files changed, 211 insertions(+), 12 deletions(-) diff --git a/libcxx/include/experimental/filesystem b/libcxx/include/experimental/filesystem index 7211c6b1efcc..fa2face130f4 100644 --- a/libcxx/include/experimental/filesystem +++ b/libcxx/include/experimental/filesystem @@ -453,6 +453,9 @@ class _LIBCPP_TYPE_VIS directory_entry; template struct __can_convert_char { static const bool value = false; }; +template struct __can_convert_char + : public __can_convert_char<_Tp> { +}; template <> struct __can_convert_char { static const bool value = true; using __char_type = char; diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp index 93892fbe10e4..f344e1153071 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp @@ -246,6 +246,60 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) } } + + +template ()))> +constexpr bool has_append(int) { return true; } +template +constexpr bool has_append(long) { return false; } + +template ()))> +constexpr bool has_append_op(int) { return true; } +template +constexpr bool has_append_op(long) { return false; } + +template +constexpr bool has_append() { + static_assert(has_append(0) == has_append_op(0), "must be same"); + return has_append(0) && has_append_op(0); +} + +void test_sfinae() +{ + using namespace fs; + { + using It = const char* const; + static_assert(has_append(), ""); + } + { + using It = input_iterator; + static_assert(has_append(), ""); + } + { + 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; + static_assert(has_append(), ""); + } + { + using It = output_iterator; + static_assert(!has_append(), ""); + + } + { + static_assert(!has_append(), ""); + } + { + static_assert(!has_append(), ""); + static_assert(!has_append(), ""); + } +} + int main() { using namespace fs; @@ -266,4 +320,5 @@ int main() doAppendSourceAllocTest(TC); doAppendSourceAllocTest(TC); } + test_sfinae(); } diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp index ae725a88590e..9e48cbf1e7f2 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp @@ -170,6 +170,49 @@ void RunTestCase(MultiStringType const& MS) { } } +template ()))> +constexpr bool has_assign(int) { return true; } +template +constexpr bool has_assign(long) { return false; } +template +constexpr bool has_assign() { return has_assign(0); } + +void test_sfinae() { + using namespace fs; + { + using It = const char* const; + static_assert(std::is_assignable::value, ""); + static_assert(has_assign(), ""); + } + { + using It = input_iterator; + static_assert(std::is_assignable::value, ""); + static_assert(has_assign(), ""); + } + { + 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; + static_assert(std::is_assignable::value, ""); + static_assert(has_assign(), ""); + } + { + using It = output_iterator; + static_assert(!std::is_assignable::value, ""); + static_assert(!has_assign(), ""); + + } + { + static_assert(!std::is_assignable::value, ""); + static_assert(!has_assign(), ""); + } +} + int main() { for (auto const& MS : PathList) { RunTestCase(MS); @@ -177,4 +220,5 @@ int main() { RunTestCase(MS); RunTestCase(MS); } + test_sfinae(); } diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp index cd627b8c842f..89269362d06f 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp @@ -265,6 +265,68 @@ void doConcatECharTest(ConcatOperatorTestcase const& TC) } } + +template ()))> +constexpr bool has_concat(int) { return true; } +template +constexpr bool has_concat(long) { return false; } + +template ()))> +constexpr bool has_concat_op(int) { return true; } +template +constexpr bool has_concat_op(long) { return false; } +template +constexpr bool has_concat_op() { return has_concat_op(0); } + +template +constexpr bool has_concat() { + static_assert(has_concat(0) == has_concat_op(0), "must be same"); + return has_concat(0) && has_concat_op(0); +} + +void test_sfinae() { + using namespace fs; + { + static_assert(has_concat_op(), ""); + static_assert(has_concat_op(), ""); + static_assert(has_concat_op(), ""); + static_assert(has_concat_op(), ""); + } + { + using It = const char* const; + static_assert(has_concat(), ""); + } + { + using It = input_iterator; + static_assert(has_concat(), ""); + } + { + 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; + static_assert(has_concat(), ""); + } + { + using It = output_iterator; + static_assert(!has_concat(), ""); + } + { + static_assert(!has_concat(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(), ""); + } + { + static_assert(!has_concat(), ""); + } +} + int main() { using namespace fs; @@ -323,4 +385,5 @@ int main() doConcatECharTest(TC); doConcatECharTest(TC); } + test_sfinae(); } diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp index 402225de11bc..a04f35af5780 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp @@ -80,6 +80,37 @@ void RunTestCase(MultiStringType const& MS) { } } +void test_sfinae() { + using namespace fs; + { + using It = const char* const; + static_assert(std::is_constructible::value, ""); + } + { + using It = input_iterator; + static_assert(std::is_constructible::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; + static_assert(std::is_constructible::value, ""); + } + { + using It = output_iterator; + static_assert(!std::is_constructible::value, ""); + + } + { + static_assert(!std::is_constructible::value, ""); + } +} + int main() { for (auto const& MS : PathList) { RunTestCase(MS); @@ -87,4 +118,5 @@ int main() { RunTestCase(MS); RunTestCase(MS); } + test_sfinae(); } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index d4a079971b15..fb5c06ad9431 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -53,25 +53,27 @@ public: void operator,(T const &) DELETE_FUNCTION; }; -template +template class input_iterator { + using Traits = std::iterator_traits; It it_; - template friend class input_iterator; + template friend class input_iterator; public: typedef std::input_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::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::reference reference; + typedef typename Traits::reference reference; It base() const {return it_;} input_iterator() : it_() {} explicit input_iterator(It it) : it_(it) {} - template - input_iterator(const input_iterator& u) :it_(u.it_) {} + template + input_iterator(const input_iterator& 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 +template inline bool -operator==(const input_iterator& x, const input_iterator& y) +operator==(const input_iterator& x, const input_iterator& y) { return x.base() == y.base(); } -template +template inline bool -operator!=(const input_iterator& x, const input_iterator& y) +operator!=(const input_iterator& x, const input_iterator& y) { return !(x == y); } diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html index 7c67de789a02..41af346cd5fd 100644 --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -298,7 +298,7 @@ 2707path construction and assignment should have "string_type&&" overloadsOuluComplete 2709offsetof is unnecessarily impreciseOulu 2710"Effects: Equivalent to ..." doesn't count "Synchronization:" as determined semanticsOuluComplete - 2711path is convertible from approximately everything under the sunOulu + 2711path is convertible from approximately everything under the sunOuluComplete 2716Specification of shuffle and sample disallows lvalue URNGsOulu 2718Parallelism bug in [algorithms.parallel.exec] p2Oulu 2719permissions function should not be noexcept due to narrow contractOuluComplete