diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 86d80354c9978..cc437681ec62c 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -2271,17 +2271,15 @@ template class enumerator { explicit enumerator(R &&Range) : TheRange(std::forward(Range)) {} enumerator_iter begin() { - return enumerator_iter(0, std::begin(TheRange)); + return enumerator_iter(0, adl_begin(TheRange)); } enumerator_iter begin() const { - return enumerator_iter(0, std::begin(TheRange)); + return enumerator_iter(0, adl_begin(TheRange)); } - enumerator_iter end() { - return enumerator_iter(std::end(TheRange)); - } + enumerator_iter end() { return enumerator_iter(adl_end(TheRange)); } enumerator_iter end() const { - return enumerator_iter(std::end(TheRange)); + return enumerator_iter(adl_end(TheRange)); } private: diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index a1636237b4eeb..fda4577283d2e 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -260,6 +260,46 @@ TEST(STLExtrasTest, EnumerateLifetimeSemanticsLValue) { EXPECT_EQ(1, Destructors); } +namespace some_namespace { +struct some_struct { + std::vector data; + std::string swap_val; +}; + +std::vector::const_iterator begin(const some_struct &s) { + return s.data.begin(); +} + +std::vector::const_iterator end(const some_struct &s) { + return s.data.end(); +} + +void swap(some_struct &lhs, some_struct &rhs) { + // make swap visible as non-adl swap would even seem to + // work with std::swap which defaults to moving + lhs.swap_val = "lhs"; + rhs.swap_val = "rhs"; +} + +struct requires_move {}; +int *begin(requires_move &&) { return nullptr; } +int *end(requires_move &&) { return nullptr; } +} // namespace some_namespace + +TEST(STLExtrasTest, EnumerateCustomBeginEnd) { + // Check that `enumerate` uses ADL to find `begin`/`end` iterators + // of the enumerated type. + some_namespace::some_struct X{}; + X.data = {1, 2, 3}; + + unsigned Iters = 0; + for (auto [Idx, Val] : enumerate(X)) { + EXPECT_EQ(Val, X.data[Idx]); + ++Iters; + } + EXPECT_EQ(Iters, 3u); +} + TEST(STLExtrasTest, CountAdaptor) { std::vector v; @@ -375,32 +415,6 @@ TEST(STLExtrasTest, AppendRange) { EXPECT_THAT(Str, ElementsAre('a', 'b', 'c', '\0', 'd', 'e', 'f', '\0')); } -namespace some_namespace { -struct some_struct { - std::vector data; - std::string swap_val; -}; - -std::vector::const_iterator begin(const some_struct &s) { - return s.data.begin(); -} - -std::vector::const_iterator end(const some_struct &s) { - return s.data.end(); -} - -void swap(some_struct &lhs, some_struct &rhs) { - // make swap visible as non-adl swap would even seem to - // work with std::swap which defaults to moving - lhs.swap_val = "lhs"; - rhs.swap_val = "rhs"; -} - -struct requires_move {}; -int *begin(requires_move &&) { return nullptr; } -int *end(requires_move &&) { return nullptr; } -} // namespace some_namespace - TEST(STLExtrasTest, ADLTest) { some_namespace::some_struct s{{1, 2, 3, 4, 5}, ""}; some_namespace::some_struct s2{{2, 4, 6, 8, 10}, ""};