forked from OSchip/llvm-project
Implement LWG 2711. Constrain path members.
llvm-svn: 279945
This commit is contained in:
parent
24b481370a
commit
2fc65041be
|
@ -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;
|
||||
|
|
|
@ -246,6 +246,60 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -170,6 +170,49 @@ void RunTestCase(MultiStringType const& MS) {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -265,6 +265,68 @@ void doConcatECharTest(ConcatOperatorTestcase const& TC)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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<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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue