[libcxx-commits] [libcxx] 03c2862 - [libc++][ranges] Reject non-class types in ranges::to (#135802)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 24 01:30:02 PDT 2025


Author: Yuzhiy
Date: 2025-04-24T10:29:59+02:00
New Revision: 03c2862404a9ab19940f87f8fb2dbe01818ab439

URL: https://github.com/llvm/llvm-project/commit/03c2862404a9ab19940f87f8fb2dbe01818ab439
DIFF: https://github.com/llvm/llvm-project/commit/03c2862404a9ab19940f87f8fb2dbe01818ab439.diff

LOG: [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 <de34 at live.cn>

Added: 
    

Modified: 
    libcxx/include/__ranges/to.h
    libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__ranges/to.h b/libcxx/include/__ranges/to.h
index c937b0656de87..3a2bc42969f7b 100644
--- a/libcxx/include/__ranges/to.h
+++ b/libcxx/include/__ranges/to.h
@@ -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>
@@ -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`).
@@ -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)...);

diff  --git a/libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp b/libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp
index c3ab002558a03..0800ee8cf7bae 100644
--- a/libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.utility/range.utility.conv/to.static_assert.verify.cpp
@@ -14,12 +14,79 @@
 #include <ranges>
 #include <vector>
 
-void test() {
+void test_cv_qualifications() {
   using R = std::vector<int>;
-  R in = {1, 2, 3};
+  R in    = {1, 2, 3};
 
-  (void)std::ranges::to<const R>(in); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
-  (void)(in | std::ranges::to<const R>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
-  (void)std::ranges::to<volatile R>(in); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
-  (void)(in | std::ranges::to<volatile R>()); //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
+  //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
+  (void)std::ranges::to<const R>(in);
+  //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be const-qualified, please remove the const}}
+  (void)(in | std::ranges::to<const R>());
+
+  //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
+  (void)std::ranges::to<volatile R>(in);
+
+  //expected-error-re@*:* {{static assertion failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
+  (void)(in | std::ranges::to<volatile R>());
+}
+//unexpected_types
+void ff();
+void test_unexpected_types() {
+  struct C {
+    int member;
+    int f();
+  };
+
+  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;
+    operator int*() const;
+    operator func_ptr() const;
+    operator member_func_ptr() const;
+    operator member_ptr() const;
+    operator color() const;
+  };
+  //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<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}}
+  //expected-error-re@*:* {{static assertion failed{{.*}}ranges::to: unable to convert to the given container type.}}
+  (void)(R{} | std::ranges::to<void>());
+
+  //expected-error-re@*:* {{static assertion failed{{.*}}The target must be a class 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>());
 }


        


More information about the libcxx-commits mailing list