Adds negative tests for preconditions on inserting into a full inplace_vector and erasing non-existent elementsi at compile-time. This ensures coverage for the inplace_vector<T, 0> specialization.
Also extends element access tests to cover front() and back() methods, and const and mutable overloads for all accesses. PR libstdc++/119137 libstdc++-v3/ChangeLog: * testsuite/23_containers/inplace_vector/access/elem.cc: Cover front and back methods and const calls. * testsuite/23_containers/inplace_vector/access/elem_neg.cc: Likewise. * testsuite/23_containers/inplace_vector/access/single_insert.cc: New test. * testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc: New test. * testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc: New test. --- Test for existing functionality. OK for trunk? .../inplace_vector/access/elem.cc | 35 +-- .../inplace_vector/access/elem_neg.cc | 44 ++-- .../inplace_vector/access/single_insert.cc | 215 ++++++++++++++++++ .../inplace_vector/modifiers/erase_neg.cc | 43 ++++ .../modifiers/single_insert_neg.cc | 42 ++++ 5 files changed, 347 insertions(+), 32 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/access/single_insert.cc create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc index 8b1f492dd51..bc06aa09425 100644 --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc @@ -41,11 +41,17 @@ test_out_of_capacity() #endif } -template<typename T> + +template<bool Const, typename T, size_t N> +using InplaceVector = std::conditional_t<Const, + const std::inplace_vector<T, N>, + std::inplace_vector<T, N>>; + +template<bool Const, typename T> constexpr void test_access() { - std::inplace_vector<T, 10> v{1, 2, 3, 4, 5}; + InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5}; auto& e0a = v[0]; auto& e0b = v.at(0); @@ -53,23 +59,26 @@ test_access() VERIFY( &e0a == &e0b ); VERIFY( &e0a == &e0c ); VERIFY( &e0a == &v.begin()[0] ); + VERIFY( &e0a == &v.cbegin()[0] ); VERIFY( &e0a == v.data() ); VERIFY( e0a == T(1) ); auto& e3a = v[2]; - auto& e3b = std::as_const(v).at(2); + auto& e3b = v.at(2); VERIFY( &e3a == &e3b ); VERIFY( &e3a == &v.begin()[2] ); - VERIFY( &e3a == std::as_const(v).data() + 2 ); + VERIFY( &e3a == &v.cbegin()[2] ); + VERIFY( &e3a == v.data() + 2 ); VERIFY( e3a == T(3) ); - auto& e4a = as_const(v)[4]; + auto& e4a = v[4]; auto& e4b = v.at(4); - auto& e4c = as_const(v).back(); + auto& e4c = v.back(); VERIFY( &e4a == &e4b ); VERIFY( &e4a == &e4c ); + VERIFY( &e4a == &v.begin()[4] ); VERIFY( &e4a == &v.cbegin()[4] ); - VERIFY( &e4a == as_const(v).data() + 4 ); + VERIFY( &e4a == v.data() + 4 ); VERIFY( e4a == T(5) ); #ifdef __cpp_exceptions @@ -88,15 +97,6 @@ test_access() catch (std::out_of_range const&) { } - - try - { - (void)as_const(v).at(7); - VERIFY(false); - } - catch (std::out_of_range const&) - { - } #endif } @@ -105,7 +105,8 @@ int main() auto test_all = [] { test_out_of_capacity<0, int>(); test_out_of_capacity<4, int>(); - test_access<int>(); + test_access<true, int>(); + test_access<false, int>(); return true; }; diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc index 7e6780163ab..b2bff0d6387 100644 --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc @@ -2,49 +2,63 @@ #include <inplace_vector> -template<size_t N, typename T> +template<bool Const, typename T, size_t N> +using InplaceVector + = std::conditional_t<Const, + const std::inplace_vector<T, N>, + std::inplace_vector<T, N>>; + +template<bool Const, size_t N, typename T> constexpr bool test_front_on_empty() { - std::inplace_vector<T, N> v; + InplaceVector<Const, T, N> v; (void)v.front(); // { dg-error "in 'constexpr' expansion of" } return true; } -template<size_t N, typename T> +template<bool Const, size_t N, typename T> constexpr bool test_back_on_empty() { - std::inplace_vector<T, N> v; + InplaceVector<Const, T, N> v; (void)v.back(); // { dg-error "in 'constexpr' expansion of" } return true; } -template<size_t N, typename T> +template<bool Const, size_t N, typename T> constexpr bool test_out_of_capacity() { - std::inplace_vector<T, N> v; + InplaceVector<Const, T, N> v; (void)v[N+2]; // { dg-error "in 'constexpr' expansion of" } return true; } -template<typename T> +template<bool Const, typename T> constexpr bool test_out_of_size() { - std::inplace_vector<T, 10> v{1, 2, 3, 4, 5}; + InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5}; (void)v[7]; // { dg-error "in 'constexpr' expansion of" } return true; } -static_assert(test_front_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_front_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_back_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_back_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_out_of_capacity<0, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_out_of_capacity<4, int>()); // { dg-error "in 'constexpr' expansion of" } -static_assert(test_out_of_size<int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_front_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_front_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_back_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_back_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_capacity<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_capacity<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_size<false, int>()); // { dg-error "in 'constexpr' expansion of" } + +static_assert(test_front_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_front_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_back_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_back_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_capacity<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_capacity<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_out_of_size<true, int>()); // { dg-error "in 'constexpr' expansion of" } // { dg-prune-output "non-constant condition for static assertion" } // { dg-prune-output "is not a constant expression" } diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/single_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/single_insert.cc new file mode 100644 index 00000000000..d5e893cc7f3 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/single_insert.cc @@ -0,0 +1,215 @@ +// { dg-do run { target c++26 } } + +#include <inplace_vector> + +#include <span> +#include <testsuite_hooks.h> + +struct X +{ + X() = default; + constexpr X(int p) : v(p) {} + constexpr X(const X& o) : v(o.v) { } // not trivial + constexpr X& operator=(const X& o) // not trivial + { v = o.v; return *this; } + + int v; + + friend auto operator<=>(const X&, const X&) = default; +}; + +template<typename T, typename V, size_t N> +constexpr bool +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; +}; + +template<size_t N, typename T> +constexpr void +test_add_to_full() +{ + using namespace __gnu_test; + + T a[]{1,2,3,4,5,6,7,8,9}; + const T c(10); + + std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N)); + + VERIFY( v.try_emplace_back(1) == nullptr ); + VERIFY( eq<T>(v, {a, N}) ); + VERIFY( v.try_push_back(T(1)) == nullptr ); + VERIFY( eq<T>(v, {a, N}) ); + VERIFY( v.try_push_back(c) == nullptr ); + VERIFY( eq<T>(v, {a, N}) ); + +#ifdef __cpp_exceptions +#ifdef __cpp_lib_constexpr_exceptions +#error remove the consteval check +#endif + if consteval { + return; + } + + try + { + v.emplace_back(1); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.push_back(T(1)); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.push_back(c); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.insert(v.end(), T(1)); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.insert(v.begin(), c); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.emplace(v.end(), c); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); + + try + { + v.emplace(v.begin(), T(2)); + VERIFY(false); + } + catch (std::bad_alloc const&) + { + } + VERIFY( eq<T>(v, {a, N}) ); +#endif +} + +template<typename T> +constexpr void +test_inserts() +{ + T a[]{3,14,13,1,2,3,4,5,3,7,8,3,10,11,3}; + const T c(3); + + std::inplace_vector<T, 20> v; + + v.emplace_back(1); + VERIFY( eq<T>(v, {a+3, 1}) ); + v.push_back(T(2)); + VERIFY( eq<T>(v, {a+3, 2}) ); + v.push_back(c); + VERIFY( eq<T>(v, {a+3, 3}) ); + + v.unchecked_emplace_back(4); + VERIFY( eq<T>(v, {a+3, 4}) ); + v.unchecked_push_back(T(5)); + VERIFY( eq<T>(v, {a+3, 5}) ); + v.unchecked_push_back(c); + VERIFY( eq<T>(v, {a+3, 6}) ); + + T* ptr = v.try_emplace_back(7); + VERIFY( eq<T>(v, {a+3, 7}) ); + VERIFY( ptr = &v.back() ); + ptr = v.try_push_back(T(8)); + VERIFY( eq<T>(v, {a+3, 8}) ); + VERIFY( ptr = &v.back() ); + ptr = v.try_push_back(c); + VERIFY( eq<T>(v, {a+3, 9}) ); + VERIFY( ptr = &v.back() ); + + auto it = v.emplace(v.end(), 10); + VERIFY( eq<T>(v, {a+3, 10}) ); + VERIFY( it == v.end()-1 ); + it = v.insert(v.end(), T(11)); + VERIFY( eq<T>(v, {a+3, 11}) ); + VERIFY( it == v.end()-1 ); + it = v.insert(v.end(), c); + VERIFY( eq<T>(v, {a+3, 12}) ); + VERIFY( it == v.end()-1 ); + + it = v.emplace(v.begin(), 13); + VERIFY( eq<T>(v, {a+2, 13}) ); + VERIFY( it == v.begin() ); + it = v.insert(v.begin(), T(14)); + VERIFY( eq<T>(v, {a+1, 14}) ); + VERIFY( it == v.begin() ); + it = v.insert(v.begin(), c); + VERIFY( eq<T>(v, {a+0, 15}) ); + VERIFY( it == v.begin() ); + + it = v.emplace(v.begin()+2, 22); + VERIFY( *it == 22 ); + VERIFY( it == v.begin()+2 ); + it = v.insert(v.begin()+6, T(24)); + VERIFY( *it == 24 ); + VERIFY( it == v.begin()+6 ); + it = v.insert(v.begin()+13, c); + VERIFY( *it == 3 ); + VERIFY( it == v.begin()+13 ); +} + +int main() +{ + auto test_all = [] { + test_add_to_full<0, int>(); + test_add_to_full<0, X>(); + + test_add_to_full<4, int>(); + + test_inserts<int>(); +#ifdef __cpp_lib_constexpr_inplace_vector +#error uncomemnt test_inserts<X>() +#endif + if ! consteval { + test_add_to_full<4, X>(); + test_inserts<X>(); + } + return true; + }; + + test_all(); + static_assert(test_all());; +} diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc new file mode 100644 index 00000000000..a1f43b3b53b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc @@ -0,0 +1,43 @@ +// { dg-do compile { target c++26 } } + +#include <inplace_vector> + +template<size_t N, typename T> +constexpr bool +test_pop_back_on_empty() +{ + std::inplace_vector<T, N> v; + v.pop_back(); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +template<size_t N, typename T> +constexpr bool +test_erase_begin_on_empty() +{ + std::inplace_vector<T, N> v; + v.erase(v.begin()); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +template<size_t N, typename T> +constexpr bool +test_erase_end(size_t size = 0) +{ + std::inplace_vector<T, N> v(size, T()); + v.erase(v.end()); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +static_assert(test_pop_back_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_pop_back_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_begin_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_begin_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_end<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_end<4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_end<4, int>(2)); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_erase_end<4, int>(4)); // { dg-error "in 'constexpr' expansion of" } + +// { dg-prune-output "non-constant condition for static assertion" } +// { dg-prune-output "is not a constant expression" } +// { dg-prune-output "call to non-'constexpr' function" } diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc new file mode 100644 index 00000000000..0552b8c2b7d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc @@ -0,0 +1,42 @@ +// { dg-do compile { target c++26 } } + +#include <inplace_vector> + +template<size_t N, typename T> +constexpr bool +test_unchecked_emplace_back() +{ + std::inplace_vector<T, N> v(N, T(1)); + v.unchecked_emplace_back(); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +template<size_t N, typename T> +constexpr bool +test_push_back_lvalue() +{ + auto val = T();; + std::inplace_vector<T, N> v(N, T(1)); + v.unchecked_push_back(val); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +template<size_t N, typename T> +constexpr bool +test_push_back_rvalue() +{ + std::inplace_vector<T, N> v(N, T(1)); + v.unchecked_push_back(T()); // { dg-error "in 'constexpr' expansion of" } + return true; +} + +static_assert(test_unchecked_emplace_back<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_unchecked_emplace_back<4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_push_back_lvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_push_back_lvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_push_back_rvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" } +static_assert(test_push_back_rvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" } + +// { dg-prune-output "non-constant condition for static assertion" } +// { dg-prune-output "is not a constant expression" } +// { dg-prune-output "call to non-'constexpr' function" } -- 2.49.0