[libcxx-commits] [libcxx] [libc++] Make sure we implement and test LWG2280 properly (PR #67670)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 28 06:06:51 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/67670.diff
4 Files Affected:
- (modified) libcxx/include/__iterator/access.h (+9-18)
- (modified) libcxx/include/iterator (+4-4)
- (modified) libcxx/test/std/iterators/iterator.range/begin-end.array.pass.cpp (+15-2)
- (modified) libcxx/test/std/iterators/iterator.range/begin-end.container.pass.cpp (+27-2)
``````````diff
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;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/67670
More information about the libcxx-commits
mailing list