Skip to content

Commit 03c2862

Browse files
[libc++][ranges] Reject non-class types in ranges::to (#135802)
This patch adds `static_assert` using `is_class_v` and `is_union_v` to reject no-class type template parameters. Fixes #132133 --------- Co-authored-by: A. Jiang <[email protected]>
1 parent a3d05e8 commit 03c2862

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

libcxx/include/__ranges/to.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
#include <__ranges/size.h>
2727
#include <__ranges/transform_view.h>
2828
#include <__type_traits/add_pointer.h>
29+
#include <__type_traits/is_class.h>
2930
#include <__type_traits/is_const.h>
31+
#include <__type_traits/is_union.h>
3032
#include <__type_traits/is_volatile.h>
3133
#include <__type_traits/type_identity.h>
3234
#include <__utility/declval.h>
@@ -81,7 +83,7 @@ template <class _Container, input_range _Range, class... _Args>
8183
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
8284
static_assert(
8385
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");
84-
86+
static_assert(is_class_v<_Container> || is_union_v<_Container>, "The target must be a class type or union type");
8587
// First see if the non-recursive case applies -- the conversion target is either:
8688
// - a range with a convertible value type;
8789
// - a non-range type which might support being created from the input argument(s) (e.g. an `optional`).
@@ -208,7 +210,7 @@ template <class _Container, class... _Args>
208210
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
209211
static_assert(
210212
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");
211-
213+
static_assert(is_class_v<_Container> || is_union_v<_Container>, "The target must be a class type or union type");
212214
auto __to_func = []<input_range _Range, class... _Tail>(_Range&& __range, _Tail&&... __tail) static
213215
requires requires { //
214216
/**/ ranges::to<_Container>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);

libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,79 @@
1414
#include <ranges>
1515
#include <vector>
1616

17-
void test() {
17+
void test_cv_qualifications() {
1818
using R = std::vector<int>;
19-
R in = {1, 2, 3};
19+
R in = {1, 2, 3};
2020

21-
(void)std::ranges::to<const R>(in); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
22-
(void)(in | std::ranges::to<const R>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
23-
(void)std::ranges::to<volatile R>(in); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
24-
(void)(in | std::ranges::to<volatile R>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
21+
//expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
22+
(void)std::ranges::to<const R>(in);
23+
//expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
24+
(void)(in | std::ranges::to<const R>());
25+
26+
//expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
27+
(void)std::ranges::to<volatile R>(in);
28+
29+
//expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
30+
(void)(in | std::ranges::to<volatile R>());
31+
}
32+
//unexpected_types
33+
void ff();
34+
void test_unexpected_types() {
35+
struct C {
36+
int member;
37+
int f();
38+
};
39+
40+
enum color { red, green, blue };
41+
using member_func_ptr = decltype(&C::f);
42+
using member_ptr = decltype(&C::member);
43+
using func_ptr = decltype(&ff);
44+
using func_t = decltype(ff);
45+
46+
struct R {
47+
int* begin() const { return nullptr; };
48+
int* end() const { return nullptr; };
49+
50+
operator int() const;
51+
operator int*() const;
52+
operator func_ptr() const;
53+
operator member_func_ptr() const;
54+
operator member_ptr() const;
55+
operator color() const;
56+
};
57+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
58+
(void)std::ranges::to<int>(R{});
59+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
60+
(void)(R{} | std::ranges::to<int>());
61+
62+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
63+
(void)std::ranges::to<int*>(R{});
64+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
65+
(void)(R{} | std::ranges::to<int*>());
66+
67+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
68+
(void)std::ranges::to<func_ptr>(R{});
69+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
70+
(void)(R{} | std::ranges::to<func_ptr>());
71+
72+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
73+
(void)std::ranges::to<member_ptr>(R{});
74+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
75+
(void)(R{} | std::ranges::to<member_ptr>());
76+
77+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
78+
(void)std::ranges::to<func_t>(R{});
79+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
80+
(void)(R{} | std::ranges::to<func_t>());
81+
82+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
83+
(void)std::ranges::to<void>(R{});
84+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
85+
//expected-error-re@*:* {{static assertion failed{{.*}}ranges::to: unable to convert to the given container type.}}
86+
(void)(R{} | std::ranges::to<void>());
87+
88+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
89+
(void)std::ranges::to<color>(R{});
90+
//expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class type}}
91+
(void)(R{} | std::ranges::to<color>());
2592
}

0 commit comments

Comments
 (0)