[llvm] [ADT] Simplify a constructor of iterator_range (NFC) (PR #158005)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 11 00:13:38 PDT 2025


https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/158005

Without this patch, we determine whether one iterator type can be
converted to another in a roundabout way.  Specifically,
explicitly_convertible uses std::void_t to determine whether the given
conversion expression is well formed, yielding
std::true_type/std::false_type.  Then the boolean value is passed to
std::enable_if_t to obtain void again.  That is, we are doing a
roundtrip from void to a boolean value and back.

This patch removes the roundtrip by directly using std::void_t inside
the constructor's template parameter list.

Now, explicitly_converted_t is very similar to std::is_constructible,
but there a couple of corner cases where they evaluate to different
values.  For now, this patch sticks to the same expression
decltype(static_cast<To>(...)) to be safe.


>From 8ba6acf92569b4147f7b0389d1a5b7e060920342 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Tue, 9 Sep 2025 22:19:20 -0700
Subject: [PATCH] [ADT] Simplify a constructor of iterator_range (NFC)

Without this patch, we determine whether one iterator type can be
converted to another in a roundabout way.  Specifically,
explicitly_convertible uses std::void_t to determine whether the given
conversion expression is well formed, yielding
std::true_type/std::false_type.  Then the boolean value is passed to
std::enable_if_t to obtain void again.  That is, we are doing a
roundtrip from void to a boolean value and back.

This patch removes the roundtrip by directly using std::void_t inside
the constructor's template parameter list.

Now, explicitly_converted_t is very similar to std::is_constructible,
but there a couple of corner cases where they evaluate to different
values.  For now, this patch sticks to the same expression
decltype(static_cast<To>(...)) to be safe.
---
 llvm/include/llvm/ADT/iterator_range.h | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/llvm/include/llvm/ADT/iterator_range.h b/llvm/include/llvm/ADT/iterator_range.h
index 8e9b22f2d4dfa..cc8070eb4d528 100644
--- a/llvm/include/llvm/ADT/iterator_range.h
+++ b/llvm/include/llvm/ADT/iterator_range.h
@@ -24,16 +24,6 @@
 
 namespace llvm {
 
-template <typename From, typename To, typename = void>
-struct explicitly_convertible : std::false_type {};
-
-template <typename From, typename To>
-struct explicitly_convertible<
-    From, To,
-    std::void_t<decltype(static_cast<To>(
-        std::declval<std::add_rvalue_reference_t<From>>()))>> : std::true_type {
-};
-
 /// A range adaptor for a pair of iterators.
 ///
 /// This just wraps two iterators into a range-compatible interface. Nothing
@@ -42,6 +32,10 @@ template <typename IteratorT>
 class iterator_range {
   IteratorT begin_iterator, end_iterator;
 
+  template <typename From, typename To>
+  using explicitly_converted_t = decltype(static_cast<To>(
+      std::declval<std::add_rvalue_reference_t<From>>()));
+
 public:
 #if defined(__GNUC__) &&                                                       \
     (__GNUC__ == 7 || (__GNUC__ == 8 && __GNUC_MINOR__ < 4))
@@ -49,10 +43,9 @@ class iterator_range {
   // See https://github.com/llvm/llvm-project/issues/63843
   template <typename Container>
 #else
-  template <
-      typename Container,
-      std::enable_if_t<explicitly_convertible<
-          llvm::detail::IterOfRange<Container>, IteratorT>::value> * = nullptr>
+  template <typename Container,
+            std::void_t<explicitly_converted_t<
+                llvm::detail::IterOfRange<Container>, IteratorT>> * = nullptr>
 #endif
   iterator_range(Container &&c)
       : begin_iterator(adl_begin(c)), end_iterator(adl_end(c)) {



More information about the llvm-commits mailing list