diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h index a1317423cdd1a..1f2433b9a7667 100644 --- a/llvm/include/llvm/ADT/ArrayRef.h +++ b/llvm/include/llvm/ADT/ArrayRef.h @@ -149,6 +149,14 @@ namespace llvm { * = nullptr) : Data(Vec.data()), Length(Vec.size()) {} + /// Construct an ArrayRef from iterator_range. This uses SFINAE + /// to ensure that this is only used for iterator ranges over plain pointer + /// iterators. + template >> + ArrayRef(const iterator_range &Range) + : Data(Range.begin()), Length(llvm::size(Range)) {} + /// @} /// @name Simple Operations /// @{ diff --git a/llvm/unittests/ADT/ArrayRefTest.cpp b/llvm/unittests/ADT/ArrayRefTest.cpp index fb25ee19c0b20..a9d682c57f7a0 100644 --- a/llvm/unittests/ADT/ArrayRefTest.cpp +++ b/llvm/unittests/ADT/ArrayRefTest.cpp @@ -255,6 +255,64 @@ TEST(ArrayRefTest, ArrayRefFromStdArray) { } } +struct TestRandomAccessIterator { + using iterator_category = std::random_access_iterator_tag; +}; + +static_assert(!std::is_constructible_v< + ArrayRef, iterator_range>, + "cannot construct from iterator range with non-pointer iterator"); +static_assert(!std::is_constructible_v, iterator_range>, + "cannot construct from iterator range with non-pointer iterator"); + +class TestBase {}; + +class TestDerived : public TestBase {}; + +static_assert( + !std::is_constructible_v, iterator_range>, + "cannot construct ArrayRef with derived type"); +static_assert( + !std::is_constructible_v, iterator_range>, + "cannot construct ArrayRef base type"); +static_assert(!std::is_constructible_v, + iterator_range>, + "cannot construct ArrayRef pointer of base type"); + +static_assert( + !std::is_constructible_v, iterator_range>, + "cannot construct ArrayRef with non-const elements from const iterator " + "range"); +static_assert( + std::is_constructible_v, iterator_range>, + "should be able to construct ArrayRef from iterator_range over pointers"); +static_assert( + !std::is_constructible_v, iterator_range>, + "should be able to construct ArrayRef from iterator_range over pointers"); + +TEST(ArrayRefTest, ArrayRefFromIteratorRange) { + std::array A1{{42, -5, 0, 1000000, -1000000}}; + ArrayRef A2 = make_range(A1.begin(), A1.end()); + + EXPECT_EQ(A1.size(), A2.size()); + for (std::size_t i = 0; i < A1.size(); ++i) + EXPECT_EQ(A1[i], A2[i]); + + ArrayRef A3 = make_range(A1.begin(), A1.end()); + EXPECT_EQ(A1.size(), A3.size()); + for (std::size_t i = 0; i < A1.size(); ++i) + EXPECT_EQ(A1[i], A3[i]); +} + +TEST(ArrayRefTest, ArrayRefFromIteratorConstRange) { + std::array A1{{42, -5, 0, 1000000, -1000000}}; + ArrayRef A2 = make_range(A1.begin(), A1.end()); + + EXPECT_EQ(A1.size(), A2.size()); + for (std::size_t i = 0; i < A1.size(); ++i) + EXPECT_EQ(A1[i], A2[i]); +} + static_assert(std::is_trivially_copyable_v>, "trivially copyable");