https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/67670
>From 72bda6810909f90f22dc77a04cabf0b4c19668cf Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Tue, 26 Sep 2023 19:02:00 -0400 Subject: [PATCH 1/2] [libc++] Make sure we implement and test LWG2280 properly We did not mark std::begin/std::end as noexcept for C-style arrays, we did not have conditional noexcept on cbegin/cend, and we did not mark array cbegin/cend as constexpr in all Standard modes. Since this is a LWG issue, we should implement it as a DR in all Standard modes as usual. This patch fixes these issues and adds test coverage. Fixes #67471. --- libcxx/include/__iterator/access.h | 27 ++++++----------- libcxx/include/iterator | 8 ++--- .../iterator.range/begin-end.array.pass.cpp | 17 +++++++++-- .../begin-end.container.pass.cpp | 29 +++++++++++++++++-- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/libcxx/include/__iterator/access.h b/libcxx/include/__iterator/access.h index d7bcb3378d56ca1..2782400ea771be6 100644 --- a/libcxx/include/__iterator/access.h +++ b/libcxx/include/__iterator/access.h @@ -20,19 +20,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp, size_t _Np> -_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 -_Tp* -begin(_Tp (&__array)[_Np]) -{ - return __array; +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* begin(_Tp (&__array)[_Np]) _NOEXCEPT { + return __array; } template <class _Tp, size_t _Np> -_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 -_Tp* -end(_Tp (&__array)[_Np]) -{ - return __array + _Np; +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* end(_Tp (&__array)[_Np]) _NOEXCEPT { + return __array + _Np; } #if !defined(_LIBCPP_CXX03_LANG) @@ -72,17 +66,14 @@ end(const _Cp& __c) -> decltype(__c.end()) #if _LIBCPP_STD_VER >= 14 template <class _Cp> -_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 -auto cbegin(const _Cp& __c) -> decltype(_VSTD::begin(__c)) -{ - return _VSTD::begin(__c); +_LIBCPP_HIDE_FROM_ABI constexpr auto cbegin(const _Cp& __c) noexcept(noexcept(std::begin(__c))) + -> decltype(std::begin(__c)) { + return std::begin(__c); } template <class _Cp> -_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 -auto cend(const _Cp& __c) -> decltype(_VSTD::end(__c)) -{ - return _VSTD::end(__c); +_LIBCPP_HIDE_FROM_ABI constexpr auto cend(const _Cp& __c) noexcept(noexcept(std::end(__c))) -> decltype(std::end(__c)) { + return std::end(__c); } #endif diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 36fca48a03bbb60..dcba1e1c4fba05b 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -638,11 +638,11 @@ template <class C> constexpr auto begin(C& c) -> decltype(c.begin()); template <class C> constexpr auto begin(const C& c) -> decltype(c.begin()); // constexpr since C++17 template <class C> constexpr auto end(C& c) -> decltype(c.end()); // constexpr since C++17 template <class C> constexpr auto end(const C& c) -> decltype(c.end()); // constexpr since C++17 -template <class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept; // constexpr since C++14 -template <class T, size_t N> constexpr T* end(T (&array)[N]) noexcept; // constexpr since C++14 +template <class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept; +template <class T, size_t N> constexpr T* end(T (&array)[N]) noexcept; -template <class C> constexpr auto cbegin(const C& c) -> decltype(std::begin(c)); // C++14 -template <class C> constexpr auto cend(const C& c) -> decltype(std::end(c)); // C++14 +template <class C> constexpr auto cbegin(const C& c) noexcept(see-below) -> decltype(std::begin(c)); // C++14 +template <class C> constexpr auto cend(const C& c) noexcept(see-below) -> decltype(std::end(c)); // C++14 template <class C> constexpr auto rbegin(C& c) -> decltype(c.rbegin()); // C++14, constexpr since C++17 template <class C> constexpr auto rbegin(const C& c) -> decltype(c.rbegin()); // C++14, constexpr since C++17 template <class C> constexpr auto rend(C& c) -> decltype(c.rend()); // C++14, constexpr since C++17 diff --git a/libcxx/test/std/iterators/iterator.range/begin-end.array.pass.cpp b/libcxx/test/std/iterators/iterator.range/begin-end.array.pass.cpp index 4b6a3bf11de2775..5161069ec866783 100644 --- a/libcxx/test/std/iterators/iterator.range/begin-end.array.pass.cpp +++ b/libcxx/test/std/iterators/iterator.range/begin-end.array.pass.cpp @@ -10,8 +10,8 @@ // <iterator> // -// template <class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept; // constexpr since C++14 -// template <class T, size_t N> constexpr T* end(T (&array)[N]) noexcept; // constexpr since C++14 +// template <class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept; +// template <class T, size_t N> constexpr T* end(T (&array)[N]) noexcept; // // template <class T, size_t N> constexpr reverse_iterator<T*> rbegin(T (&array)[N]); // C++14, constexpr since C++17 // template <class T, size_t N> constexpr reverse_iterator<T*> rend(T (&array)[N]); // C++14, constexpr since C++17 @@ -27,16 +27,20 @@ TEST_CONSTEXPR_CXX14 bool test() { // std::begin(T (&)[N]) / std::end(T (&)[N]) { + ASSERT_NOEXCEPT(std::begin(a)); ASSERT_SAME_TYPE(decltype(std::begin(a)), int*); assert(std::begin(a) == a); + ASSERT_NOEXCEPT(std::end(a)); ASSERT_SAME_TYPE(decltype(std::end(a)), int*); assert(std::end(a) == a + 3); // kind of overkill since it follows from the definition, but worth testing + ASSERT_NOEXCEPT(std::begin(ca)); ASSERT_SAME_TYPE(decltype(std::begin(ca)), const int*); assert(std::begin(ca) == ca); + ASSERT_NOEXCEPT(std::end(ca)); ASSERT_SAME_TYPE(decltype(std::end(ca)), const int*); assert(std::end(ca) == ca + 3); } @@ -79,5 +83,14 @@ int main(int, char**) { static_assert(test_r(), ""); #endif + // Make sure std::begin(T (&)[N]) and std::end(T (&)[N]) are constexpr in C++11 too (see LWG2280). + { + static constexpr int a[] = {1, 2, 3}; + constexpr auto b = std::begin(a); + assert(b == a); + constexpr auto e = std::end(a); + assert(e == a + 3); + } + return 0; } diff --git a/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp b/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp index 51e8e4994ebe15b..0c81dd62f24c410 100644 --- a/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp +++ b/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp @@ -15,8 +15,8 @@ // template <class C> constexpr auto end(C& c) -> decltype(c.end()); // constexpr since C++17 // template <class C> constexpr auto end(const C& c) -> decltype(c.end()); // constexpr since C++17 // -// template <class C> constexpr auto cbegin(const C& c) -> decltype(std::begin(c)); // C++14 -// template <class C> constexpr auto cend(const C& c) -> decltype(std::end(c)); // C++14 +// template <class C> constexpr auto cbegin(const C& c) noexcept(see-below) -> decltype(std::begin(c)); // C++14 +// template <class C> constexpr auto cend(const C& c) noexcept(see-below) -> decltype(std::end(c)); // C++14 // template <class C> constexpr auto rbegin(C& c) -> decltype(c.rbegin()); // C++14, constexpr since C++17 // template <class C> constexpr auto rbegin(const C& c) -> decltype(c.rbegin()); // C++14, constexpr since C++17 // template <class C> constexpr auto rend(C& c) -> decltype(c.rend()); // C++14, constexpr since C++17 @@ -127,5 +127,30 @@ int main(int, char**) { static_assert(test<std::array<int, 3>>()); #endif + // Note: Properly testing the conditional noexcept-ness propagation in std::cbegin and std::cend + // requires using C-style arrays, because those are the only ones with a noexcept std::begin + // and std::end inside namespace std + { + int a[] = {1, 2, 3}; + auto const& ca = a; + ASSERT_NOEXCEPT(std::cbegin(ca)); + ASSERT_NOEXCEPT(std::cend(ca)); + + // kind of overkill, but whatever + ASSERT_NOEXCEPT(std::cbegin(a)); + ASSERT_NOEXCEPT(std::cend(a)); + } + + // Make sure std::cbegin and std::cend are constexpr in C++14 too (see LWG2280). +#if TEST_STD_VER >= 14 + { + static constexpr int a[] = {1, 2, 3}; + constexpr auto b = std::cbegin(a); + assert(b == a); + constexpr auto e = std::cend(a); + assert(e == a + 3); + } +#endif + return 0; } >From fcef41798555bc72d1a7796d06fcc05e535c1fb2 Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Thu, 26 Oct 2023 09:33:56 -0400 Subject: [PATCH 2/2] Fix C++11 test --- .../std/iterators/iterator.range/begin-end.container.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp b/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp index 0c81dd62f24c410..b795140c2e66a21 100644 --- a/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp +++ b/libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp @@ -130,6 +130,7 @@ int main(int, char**) { // Note: Properly testing the conditional noexcept-ness propagation in std::cbegin and std::cend // requires using C-style arrays, because those are the only ones with a noexcept std::begin // and std::end inside namespace std +#if TEST_STD_VER >= 14 { int a[] = {1, 2, 3}; auto const& ca = a; @@ -142,7 +143,6 @@ int main(int, char**) { } // Make sure std::cbegin and std::cend are constexpr in C++14 too (see LWG2280). -#if TEST_STD_VER >= 14 { static constexpr int a[] = {1, 2, 3}; constexpr auto b = std::cbegin(a); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits