[llvm] [ArrayRef] Provide constructors from any type with a data() member (PR #145735)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 25 09:19:51 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-adt
Author: Benjamin Kramer (d0k)
<details>
<summary>Changes</summary>
The assumption here is that if data() returns a pointer and size()
exists it's something representing contiguous storage.
Modeled after the behavior of C++20 std::span and enables two-way
conversion between std::span (or really any span-like type) and
ArrayRef. Add a unit test that verifies this if std::span is around.
This also means we can get rid of specific conversions for std::vector
and SmallVector.
---
Full diff: https://github.com/llvm/llvm-project/pull/145735.diff
2 Files Affected:
- (modified) llvm/include/llvm/ADT/ArrayRef.h (+13-38)
- (modified) llvm/unittests/ADT/ArrayRefTest.cpp (+18-1)
``````````diff
diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h
index 4819c88471345..ddd2c7ce68c83 100644
--- a/llvm/include/llvm/ADT/ArrayRef.h
+++ b/llvm/include/llvm/ADT/ArrayRef.h
@@ -84,18 +84,19 @@ namespace llvm {
assert(begin <= end);
}
- /// Construct an ArrayRef from a SmallVector. This is templated in order to
- /// avoid instantiating SmallVectorTemplateCommon<T> whenever we
- /// copy-construct an ArrayRef.
- template<typename U>
- /*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
- : Data(Vec.data()), Length(Vec.size()) {
- }
-
- /// Construct an ArrayRef from a std::vector.
- template<typename A>
- /*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
- : Data(Vec.data()), Length(Vec.size()) {}
+ /// Construct an ArrayRef from a type that has a data() method that returns
+ /// a pointer convertible to const T *.
+ template <
+ typename C,
+ typename = std::enable_if_t<
+ std::conjunction_v<
+ std::is_convertible<
+ decltype(std::declval<const C &>().data()) *,
+ const T *const *>,
+ std::is_integral<decltype(std::declval<const C &>().size())>>,
+ void>>
+ /*implicit*/ constexpr ArrayRef(const C &V)
+ : Data(V.data()), Length(V.size()) {}
/// Construct an ArrayRef from a std::array
template <size_t N>
@@ -123,32 +124,6 @@ namespace llvm {
#pragma GCC diagnostic pop
#endif
- /// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
- /// ensure that only ArrayRefs of pointers can be converted.
- template <typename U>
- ArrayRef(const ArrayRef<U *> &A,
- std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
- * = nullptr)
- : Data(A.data()), Length(A.size()) {}
-
- /// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
- /// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
- /// whenever we copy-construct an ArrayRef.
- template <typename U, typename DummyT>
- /*implicit*/ ArrayRef(
- const SmallVectorTemplateCommon<U *, DummyT> &Vec,
- std::enable_if_t<std::is_convertible<U *const *, T const *>::value> * =
- nullptr)
- : Data(Vec.data()), Length(Vec.size()) {}
-
- /// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
- /// to ensure that only vectors of pointers can be converted.
- template <typename U, typename A>
- ArrayRef(const std::vector<U *, A> &Vec,
- std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
- * = nullptr)
- : Data(Vec.data()), Length(Vec.size()) {}
-
/// Construct an ArrayRef<T> from iterator_range<U*>. This uses SFINAE
/// to ensure that this is only used for iterator ranges over plain pointer
/// iterators.
diff --git a/llvm/unittests/ADT/ArrayRefTest.cpp b/llvm/unittests/ADT/ArrayRefTest.cpp
index 39a4a9b6a178c..3858d9064f9ca 100644
--- a/llvm/unittests/ADT/ArrayRefTest.cpp
+++ b/llvm/unittests/ADT/ArrayRefTest.cpp
@@ -8,10 +8,16 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <limits>
#include <vector>
+#if __has_include(<version>)
+#include <version>
+#endif
+#ifdef __cpp_lib_span
+#include <span>
+#endif
+
using namespace llvm;
// Check that the ArrayRef-of-pointer converting constructor only allows adding
@@ -406,4 +412,15 @@ TEST(ArrayRefTest, MutableArrayRefDeductionGuides) {
}
}
+#ifdef __cpp_lib_span
+static_assert(std::is_constructible_v<ArrayRef<int>, std::span<const int>>,
+ "should be able to construct ArrayRef from const std::span");
+static_assert(std::is_constructible_v<std::span<const int>, ArrayRef<int>>,
+ "should be able to construct const std::span from ArrayRef");
+static_assert(std::is_constructible_v<ArrayRef<int>, std::span<int>>,
+ "should be able to construct ArrayRef from mutable std::span");
+static_assert(!std::is_constructible_v<std::span<int>, ArrayRef<int>>,
+ "cannot construct mutable std::span from ArrayRef");
+#endif
+
} // end anonymous namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/145735
More information about the llvm-commits
mailing list