Louis Dionne 427a5cf105
[libc++] Add support for bounded iterators in std::array (#110729)
This patch introduces a new kind of bounded iterator that knows the size
of its valid range at compile-time, as in std::array. This allows computing
the end of the range from the start of the range and the size, which requires
storing only the start of the range in the iterator instead of both the start
and the size (or start and end). The iterator wrapper is otherwise identical
in design to the existing __bounded_iter.

Since this requires changing the type of the iterators returned by
std::array, this new bounded iterator is controlled by an ABI flag.

As a drive-by, centralize the tests for std::array::operator[] and add
missing tests for OOB operator[] on non-empty arrays.

Fixes #70864
2024-11-07 09:23:21 -05:00

80 lines
2.9 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <array>
// Test that operator[] triggers an assertion when accessing the array out-of-bounds.
#include <array>
#include "check_assertion.h"
int main(int, char**) {
// Check with an empty array
{
{
using Array = std::array<int, 0>;
Array c = {};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[0], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(c[1], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(cc[0], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(cc[1], "cannot call array<T, 0>::operator[] on a zero-sized array");
}
{
using Array = std::array<const int, 0>;
Array c = {{}};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[0], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(c[1], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(cc[0], "cannot call array<T, 0>::operator[] on a zero-sized array");
TEST_LIBCPP_ASSERT_FAILURE(cc[1], "cannot call array<T, 0>::operator[] on a zero-sized array");
}
}
// Check with non-empty arrays
{
{
using Array = std::array<int, 1>;
Array c = {};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[2], "out-of-bounds access in std::array<T, N>");
TEST_LIBCPP_ASSERT_FAILURE(cc[2], "out-of-bounds access in std::array<T, N>");
}
{
using Array = std::array<const int, 1>;
Array c = {{}};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[2], "out-of-bounds access in std::array<T, N>");
TEST_LIBCPP_ASSERT_FAILURE(cc[2], "out-of-bounds access in std::array<T, N>");
}
{
using Array = std::array<int, 5>;
Array c = {};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[99], "out-of-bounds access in std::array<T, N>");
TEST_LIBCPP_ASSERT_FAILURE(cc[99], "out-of-bounds access in std::array<T, N>");
}
{
using Array = std::array<const int, 5>;
Array c = {{}};
Array const& cc = c;
TEST_LIBCPP_ASSERT_FAILURE(c[99], "out-of-bounds access in std::array<T, N>");
TEST_LIBCPP_ASSERT_FAILURE(cc[99], "out-of-bounds access in std::array<T, N>");
}
}
return 0;
}