Skip to content

Commit

Permalink
[libc++] Various cleanups in the ranges tests
Browse files Browse the repository at this point in the history
- Rename test files to follow conventions better
- Split constructor tests that were in a single file
- Add missing tests for take_view and transform_view's default constructors
- Add missing tests for transform_view's view/function constructor
- Fix include guards
- Mark some tests as being specific to libc++

Differential Revision: https://reviews.llvm.org/D108829
  • Loading branch information
ldionne committed Aug 30, 2021
1 parent 9721197 commit 770602c
Show file tree
Hide file tree
Showing 26 changed files with 322 additions and 90 deletions.
Expand Up @@ -9,30 +9,28 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// unspecified begin;
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::begin on an array of incomplete type.

#include <ranges>

#include <type_traits>

using begin_t = decltype(std::ranges::begin);

template <class T>
requires(!std::invocable<begin_t&, T>)
void f() {}
template <class T> void f() requires std::invocable<begin_t&, T> { }
template <class T> void f() { }

void test() {
struct incomplete;
f<incomplete(&)[]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}
f<incomplete(&)[10]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}
f<incomplete(&)[2][2]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}

// This is okay because calling `std::ranges::begin` on any rvalue is ill-formed.
f<incomplete(&&)[10]>();
Expand Down
Expand Up @@ -9,24 +9,24 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// ranges::cbegin;
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::cbegin on an array of incomplete type.

#include <ranges>

#include <type_traits>

using cbegin_t = decltype(std::ranges::cbegin);

template <class T>
requires(!std::invocable<cbegin_t&, T>)
void f() {}
template <class T> void f() requires std::invocable<cbegin_t&, T> { }
template <class T> void f() { }

void test() {
struct incomplete;
f<incomplete(&)[10]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}

// This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
f<incomplete(&&)[10]>();
Expand Down
Expand Up @@ -9,18 +9,19 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// unspecified begin;
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::cend on an array of incomplete type.

#include <ranges>

#include <type_traits>

using cend_t = decltype(std::ranges::cend);

template <class T>
requires(!std::invocable<cend_t&, T>)
void f() {}
template <class T> void f() requires std::invocable<cend_t&, T> { }
template <class T> void f() { }

void test() {
struct incomplete;
Expand All @@ -30,10 +31,8 @@ void test() {
f<incomplete(&)[10]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-3 {{no matching function for call to 'f'}}
f<incomplete(&)[2][2]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}

// This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
f<incomplete(&&)[10]>();
Expand Down
Expand Up @@ -9,18 +9,19 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// unspecified begin;
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::end on an array of incomplete type.

#include <ranges>

#include <type_traits>

using end_t = decltype(std::ranges::end);

template <class T>
requires(!std::invocable<end_t&, T>)
void f() {}
template <class T> void f() requires std::invocable<end_t&, T> { }
template <class T> void f() { }

void test() {
struct incomplete;
Expand All @@ -30,10 +31,8 @@ void test() {
f<incomplete(&)[10]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-3 {{no matching function for call to 'f'}}
f<incomplete(&)[2][2]>();
// expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
// expected-error@-2 {{no matching function for call to 'f'}}

// This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
f<incomplete(&&)[10]>();
Expand Down
Expand Up @@ -9,8 +9,10 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// std::ranges::data
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::data on an array of incomplete type.

#include <ranges>

Expand Down
Expand Up @@ -9,8 +9,10 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// REQUIRES: libc++

// std::ranges::empty
// Test the libc++ specific behavior that we provide a better diagnostic when calling
// std::ranges::empty on an array of incomplete type.

#include <ranges>

Expand Down
Expand Up @@ -32,7 +32,7 @@ struct ZeroOnDestroy : std::ranges::view_base {
constexpr ForwardIter end() const { return ForwardIter(); }

~ZeroOnDestroy() {
memset(buff, 0, sizeof(buff));
std::memset(buff, 0, sizeof(buff));
}

static auto dropFirstFour() {
Expand Down
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// take_view() requires default_initializable<V> = default;

#include <ranges>
#include <cassert>

int buff[8] = {1, 2, 3, 4, 5, 6, 7, 8};

struct DefaultConstructible : std::ranges::view_base {
constexpr DefaultConstructible() : begin_(buff), end_(buff + 8) { }
constexpr int const* begin() const { return begin_; }
constexpr int const* end() const { return end_; }
private:
int const* begin_;
int const* end_;
};

struct NonDefaultConstructible : std::ranges::view_base {
NonDefaultConstructible() = delete;
int* begin() const;
int* end() const;
};

constexpr bool test() {
{
std::ranges::take_view<DefaultConstructible> tv;
assert(tv.begin() == buff);
assert(tv.size() == 0);
}

// Test SFINAE-friendliness
{
static_assert( std::is_default_constructible_v<std::ranges::take_view<DefaultConstructible>>);
static_assert(!std::is_default_constructible_v<std::ranges::take_view<NonDefaultConstructible>>);
}

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Expand Up @@ -10,7 +10,6 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// take_view() requires default_initializable<V> = default;
// constexpr take_view(V base, range_difference_t<V> count);

#include <ranges>
Expand All @@ -21,27 +20,6 @@
#include "test_range.h"
#include "types.h"

int globalBuffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};

template<bool IsDefaultCtorable>
struct DefaultConstructible : std::ranges::view_base {
DefaultConstructible() requires IsDefaultCtorable = default;
DefaultConstructible(int*);
int* begin();
sentinel_wrapper<int*> end();
};

struct SizedRandomAccessViewToGlobal : std::ranges::view_base {
RandomAccessIter begin() { return RandomAccessIter(globalBuffer); }
RandomAccessIter begin() const { return RandomAccessIter(globalBuffer); }
sentinel_wrapper<RandomAccessIter> end() {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(globalBuffer + 8)};
}
sentinel_wrapper<RandomAccessIter> end() const {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(globalBuffer + 8)};
}
};

constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};

Expand Down Expand Up @@ -70,13 +48,5 @@ int main(int, char**) {
test();
static_assert(test());

// Tests for the default ctor.
static_assert( std::default_initializable<DefaultConstructible<true>>);
static_assert(!std::default_initializable<DefaultConstructible<false>>);

std::ranges::take_view<SizedRandomAccessViewToGlobal> tv;
assert(*tv.base().begin() == 1);
assert(tv.size() == 0);

return 0;
}
@@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// transform_view() requires std::default_initializable<V> &&
// std::default_initializable<F> = default;

#include <ranges>

#include <cassert>
#include <type_traits>

constexpr int buff[] = {1, 2, 3};

struct DefaultConstructibleView : std::ranges::view_base {
constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 3) { }
constexpr int const* begin() const { return begin_; }
constexpr int const* end() const { return end_; }
private:
int const* begin_;
int const* end_;
};

struct DefaultConstructibleFunction {
int state_;
constexpr DefaultConstructibleFunction() : state_(100) { }
constexpr int operator()(int i) const { return i + state_; }
};

struct NoDefaultView : std::ranges::view_base {
NoDefaultView() = delete;
int* begin() const;
int* end() const;
};

struct NoDefaultFunction {
NoDefaultFunction() = delete;
constexpr int operator()(int i) const;
};

constexpr bool test() {
{
std::ranges::transform_view<DefaultConstructibleView, DefaultConstructibleFunction> view;
assert(view.size() == 3);
assert(view[0] == 101);
assert(view[1] == 102);
assert(view[2] == 103);
}

{
std::ranges::transform_view<DefaultConstructibleView, DefaultConstructibleFunction> view = {};
assert(view.size() == 3);
assert(view[0] == 101);
assert(view[1] == 102);
assert(view[2] == 103);
}

static_assert(!std::is_default_constructible_v<std::ranges::transform_view<NoDefaultView, DefaultConstructibleFunction>>);
static_assert(!std::is_default_constructible_v<std::ranges::transform_view<DefaultConstructibleView, NoDefaultFunction>>);
static_assert(!std::is_default_constructible_v<std::ranges::transform_view<NoDefaultView, NoDefaultFunction>>);

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}

0 comments on commit 770602c

Please sign in to comment.