blob: 53c81be7f029aa972c1f70f764755653590f44db [file] [log] [blame]
// Copyright (C) 2021-2025 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
// PR libstdc++/100577
#include <ranges>
#include <functional>
#if __STDC_HOSTED__
#include <string>
#endif
namespace ranges = std::ranges;
namespace views = std::ranges::views;
void
test01()
{
// Verify adaptors are deemed to have simple extra arguments when appropriate.
using views::__adaptor::__adaptor_has_simple_extra_args;
using std::identity;
static_assert(__adaptor_has_simple_extra_args<decltype(views::transform), identity>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::filter), identity>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::drop), int>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::take), int>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::take_while), identity>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::drop_while), identity>);
static_assert(__adaptor_has_simple_extra_args<decltype(views::lazy_split), char>);
#if __STDC_HOSTED__
static_assert(__adaptor_has_simple_extra_args<decltype(views::lazy_split), std::string_view>);
static_assert(!__adaptor_has_simple_extra_args<decltype(views::lazy_split), std::string>);
#endif
using views::__adaptor::__closure_has_simple_call_op;
__closure_has_simple_call_op auto a00 = views::all;
__closure_has_simple_call_op auto a01 = views::transform(std::identity{});
__closure_has_simple_call_op auto a02 = views::filter(std::identity{});
__closure_has_simple_call_op auto a03 = views::drop(42);
__closure_has_simple_call_op auto a04 = views::take(42);
__closure_has_simple_call_op auto a05 = views::take_while(std::identity{});
__closure_has_simple_call_op auto a06 = views::drop_while(std::identity{});
__closure_has_simple_call_op auto a07 = views::join;
__closure_has_simple_call_op auto a08 = views::common;
__closure_has_simple_call_op auto a09 = views::reverse;
__closure_has_simple_call_op auto a10 = views::keys;
__closure_has_simple_call_op auto a11 = views::lazy_split(' ');
__closure_has_simple_call_op auto a11a = views::split(' ');
// Verify composition of simple closures is simple.
__closure_has_simple_call_op auto b
= (a00 | a01) | (a02 | a03) | (a04 | a05 | a06) | (a07 | a08 | a09 | a10) | a11;
#if __STDC_HOSTED__
// Verify views::lazy_split(non_view_range) is an exception.
extern std::string s;
auto a12 = views::lazy_split(s);
static_assert(!__closure_has_simple_call_op<decltype(a12)>);
static_assert(!__closure_has_simple_call_op<decltype(a12 | a00)>);
static_assert(!__closure_has_simple_call_op<decltype(a00 | a12)>);
// Likewise views::split(non_view_range).
auto a12a = views::split(s);
static_assert(!__closure_has_simple_call_op<decltype(a12a)>);
static_assert(!__closure_has_simple_call_op<decltype(a12a | a00)>);
static_assert(!__closure_has_simple_call_op<decltype(a00 | a12a)>);
#endif
}
void
test02()
{
// Range adaptor closures with a simple operator() aren't implemented using a
// fallback deleted overload, so when a call is ill-formed overload resolution
// fails.
extern int x[10];
struct { } badarg;
views::transform(badarg)(x); // { dg-error "no match" }
views::filter(badarg)(x); // { dg-error "no match" }
views::take_while(badarg)(x); // { dg-error "no match" }
views::drop_while(badarg)(x); // { dg-error "no match" }
(views::transform(badarg) | views::all)(x); // { dg-error "no match" }
(views::filter(badarg) | views::all)(x); // { dg-error "no match" }
(views::take_while(badarg) | views::all)(x); // { dg-error "no match" }
(views::drop_while(badarg) | views::all)(x); // { dg-error "no match" }
// In C++20 mode, range adaptor closures with non-simple operator() are
// implemented using a fallback deleted overload, so when a call is
// ill-formed overload resolution succeeds but selects the deleted overload
// (but only when the closure is invoked as an rvalue).
views::lazy_split(badarg)(x); // { dg-error "deleted function|no match" }
(views::lazy_split(badarg) | views::all)(x); // { dg-error "deleted function|no match" }
auto a0 = views::lazy_split(badarg);
a0(x); // { dg-error "no match" };
auto a1 = a0 | views::all;
a1(x); // { dg-error "no match" }
views::split(badarg)(x); // { dg-error "deleted function|no match" }
(views::split(badarg) | views::all)(x); // { dg-error "deleted function|no match" }
auto a0a = views::split(badarg);
a0a(x); // { dg-error "no match" };
auto a1a = a0a | views::all;
a1a(x); // { dg-error "no match" }
views::take(badarg)(x); // { dg-error "deleted|no match" }
views::drop(badarg)(x); // { dg-error "deleted|no match" }
(views::take(badarg) | views::all)(x); // { dg-error "deleted|no match" }
(views::drop(badarg) | views::all)(x); // { dg-error "deleted|no match" }
}
void
test03()
{
// PR libstdc++/100940
extern int x[10];
struct S { operator int() && { return 5; }; };
x | std::views::take(S{});
x | std::views::drop(S{});
}
void
test04()
{
#if __STDC_HOSTED__
// Non-trivially-copyable extra arguments make a closure not simple.
using F = std::function<bool(bool)>;
static_assert(!std::is_trivially_copyable_v<F>);
using views::__adaptor::__closure_has_simple_call_op;
static_assert(!__closure_has_simple_call_op<decltype(views::take_while(std::declval<F>()))>);
static_assert(!__closure_has_simple_call_op<decltype(views::drop_while(std::declval<F>()))>);
static_assert(!__closure_has_simple_call_op<decltype(views::filter(std::declval<F>()))>);
static_assert(!__closure_has_simple_call_op<decltype(views::transform(std::declval<F>()))>);
#endif
}
// { dg-prune-output "in requirements" }