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

Reply via email to