[libc++] Complete overhaul of constexpr support in std::array
This commit adds missing support for constexpr in std::array under all
standard modes up to and including C++20. It also transforms the <array>
tests to check for constexpr-friendliness under the right standard modes.
Fixes https://llvm.org/PR40124
Fixes rdar://57522096
Supersedes https://reviews.llvm.org/D60666
Differential Revision: https://reviews.llvm.org/D80452
diff --git a/libcxx/test/std/containers/sequences/array/at.pass.cpp b/libcxx/test/std/containers/sequences/array/at.pass.cpp
index 0454643..ed4ab80 100644
--- a/libcxx/test/std/containers/sequences/array/at.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/at.pass.cpp
@@ -8,10 +8,7 @@
// <array>
-// reference operator[] (size_type)
-// const_reference operator[] (size_type); // constexpr in C++14
-// reference at (size_type)
-// const_reference at (size_type); // constexpr in C++14
+// reference at (size_type); // constexpr in C++17
#include <array>
#include <cassert>
@@ -26,100 +23,91 @@
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"
-#if TEST_STD_VER > 14
-constexpr bool check_idx( size_t idx, double val )
-{
- std::array<double, 3> arr = {1, 2, 3.5};
- return arr.at(idx) == val;
-}
-#endif
-int main(int, char**)
+TEST_CONSTEXPR_CXX17 bool tests()
{
{
typedef double T;
typedef std::array<T, 3> C;
C c = {1, 2, 3.5};
- C::reference r1 = c.at(0);
+ typename C::reference r1 = c.at(0);
assert(r1 == 1);
r1 = 5.5;
- assert(c.front() == 5.5);
+ assert(c[0] == 5.5);
- C::reference r2 = c.at(2);
+ typename C::reference r2 = c.at(2);
assert(r2 == 3.5);
r2 = 7.5;
- assert(c.back() == 7.5);
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
- try
- {
- TEST_IGNORE_NODISCARD c.at(3);
- assert(false);
- }
- catch (const std::out_of_range &) {}
-#endif
+ assert(c[2] == 7.5);
}
+ return true;
+}
+
+void test_exceptions()
+{
#ifndef TEST_HAS_NO_EXCEPTIONS
{
- typedef double T;
- typedef std::array<T, 0> C;
- C c = {};
- C const& cc = c;
- try
- {
- TEST_IGNORE_NODISCARD c.at(0);
+ std::array<int, 4> array = {1, 2, 3, 4};
+
+ try {
+ TEST_IGNORE_NODISCARD array.at(4);
+ assert(false);
+ } catch (std::out_of_range const&) {
+ // pass
+ } catch (...) {
assert(false);
}
- catch (const std::out_of_range &) {}
- try
- {
- TEST_IGNORE_NODISCARD cc.at(0);
+
+ try {
+ TEST_IGNORE_NODISCARD array.at(5);
+ assert(false);
+ } catch (std::out_of_range const&) {
+ // pass
+ } catch (...) {
assert(false);
}
- catch (const std::out_of_range &) {}
- }
-#endif
- {
- typedef double T;
- typedef std::array<T, 3> C;
- const C c = {1, 2, 3.5};
- C::const_reference r1 = c.at(0);
- assert(r1 == 1);
- C::const_reference r2 = c.at(2);
- assert(r2 == 3.5);
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
- try
- {
- TEST_IGNORE_NODISCARD c.at(3);
+ try {
+ TEST_IGNORE_NODISCARD array.at(6);
+ assert(false);
+ } catch (std::out_of_range const&) {
+ // pass
+ } catch (...) {
assert(false);
}
- catch (const std::out_of_range &) {}
-#endif
+
+ try {
+ TEST_IGNORE_NODISCARD array.at(-1);
+ assert(false);
+ } catch (std::out_of_range const&) {
+ // pass
+ } catch (...) {
+ assert(false);
+ }
}
-#if TEST_STD_VER > 11
{
- typedef double T;
- typedef std::array<T, 3> C;
- constexpr C c = {1, 2, 3.5};
+ std::array<int, 0> array = {};
- constexpr T t1 = c.at(0);
- static_assert (t1 == 1, "");
-
- constexpr T t2 = c.at(2);
- static_assert (t2 == 3.5, "");
+ try {
+ TEST_IGNORE_NODISCARD array.at(0);
+ assert(false);
+ } catch (std::out_of_range const&) {
+ // pass
+ } catch (...) {
+ assert(false);
+ }
}
#endif
+}
-#if TEST_STD_VER > 14
- {
- static_assert (check_idx(0, 1), "");
- static_assert (check_idx(1, 2), "");
- static_assert (check_idx(2, 3.5), "");
- }
+int main(int, char**)
+{
+ tests();
+ test_exceptions();
+
+#if TEST_STD_VER >= 17
+ static_assert(tests(), "");
#endif
-
- return 0;
+ return 0;
}