On Tue, 22 Jul 2025, Tomasz Kamiński wrote: > 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/modifiers/erase_neg.cc: > New test. > * testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc: > New test. > --- > v2 removes accidentally added access/single_insert.cc file with copy of > content > of modifiers/single_insert.cc.
LGTM > > .../inplace_vector/access/elem.cc | 35 ++++++++------- > .../inplace_vector/access/elem_neg.cc | 44 ++++++++++++------- > .../inplace_vector/modifiers/erase_neg.cc | 43 ++++++++++++++++++ > .../modifiers/single_insert_neg.cc | 42 ++++++++++++++++++ > 4 files changed, 132 insertions(+), 32 deletions(-) > 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/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 > >