Skip to content

[libc++][ranges] Reject non-class types in ranges::to #135802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 24, 2025
6 changes: 4 additions & 2 deletions libcxx/include/__ranges/to.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#include <__ranges/size.h>
#include <__ranges/transform_view.h>
#include <__type_traits/add_pointer.h>
#include <__type_traits/is_class.h>
#include <__type_traits/is_const.h>
#include <__type_traits/is_union.h>
#include <__type_traits/is_volatile.h>
#include <__type_traits/type_identity.h>
#include <__utility/declval.h>
Expand Down Expand Up @@ -81,7 +83,7 @@ template <class _Container, input_range _Range, class... _Args>
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
static_assert(
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");

static_assert(is_class_v<_Container> || is_union_v<_Container>, "The target must be a class type or union type");
// First see if the non-recursive case applies -- the conversion target is either:
// - a range with a convertible value type;
// - a non-range type which might support being created from the input argument(s) (e.g. an `optional`).
Expand Down Expand Up @@ -208,7 +210,7 @@ template <class _Container, class... _Args>
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
static_assert(
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");

static_assert(is_class_v<_Container> || is_union_v<_Container>, "The target must be a class type or union type");
auto __to_func = []<input_range _Range, class... _Tail>(_Range&& __range, _Tail&&... __tail) static
requires requires { //
/**/ ranges::to<_Container>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// 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, c++20

// Test that the "mandates" requirements on the given class are checked using `static_assert`.
#include <ranges>
void ff() {}
void test() {
struct C {
int member;
int f() { return 0; }
};

enum color { red, green, blue };
using member_func_ptr = decltype(&C::f);
using member_ptr = decltype(&C::member);
using func_ptr = decltype(&ff);
using func_t = decltype(ff);

struct R {
int* begin() const { return nullptr; };
int* end() const { return nullptr; };

operator int() const { return 0; }
operator int*() const { return nullptr; }
operator func_ptr() const { return nullptr; }
operator member_func_ptr() const { return nullptr; }
operator member_ptr() const { return nullptr; }
operator color() const { return color::red; }
};
(void)std::ranges::to<int>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} | std::ranges::to<
int>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)std::ranges::to<int*>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} | std::ranges::to<
int*>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)std::ranges::to<func_ptr>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} |
std::ranges::to<
func_ptr>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}

(void)std::ranges::to<member_ptr>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} |
std::ranges::to<
member_ptr>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}

(void)std::ranges::to<func_t>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} | std::ranges::to<
func_t>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}

(void)std::ranges::to<void>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} | std::ranges::to<
void>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
//expected-error-re@*:* {{static assertion failed{{.*}}ranges::to: unable to convert to the given container type.}}

(void)std::ranges::to<color>(
R{}); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
(void)(R{} | std::ranges::to<
color>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
}
Loading