Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[libc++] Improve the test coverage for std::vector::emplace #132440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 6, 2025

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Mar 21, 2025

This patch refactors the test for std::vector::emplace back to cover new corner cases, and increase coverage for normal cases as well.

This is building towards #129328.

@ldionne ldionne requested a review from a team as a code owner March 21, 2025 18:11
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2025

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

This patch refactors the test for std::vector::emplace back to cover new corner cases, and increase coverage for normal cases as well. This is in preparation for reworking the implementation of emplace.


Full diff: https://github.com/llvm/llvm-project/pull/132440.diff

3 Files Affected:

  • (modified) libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h (+29-1)
  • (modified) libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp (+306-117)
  • (removed) libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp (-101)
diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h b/libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h
index 72cd47a50b2c0..92bea5997337a 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h
+++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h
@@ -38,7 +38,35 @@ struct Throws {
 };
 
 bool Throws::sThrows = false;
-#endif
+
+struct ThrowingMove {
+  TEST_CONSTEXPR ThrowingMove() : value(0), do_throw(false) {}
+  TEST_CONSTEXPR explicit ThrowingMove(int v) : value(v), do_throw(false) {}
+  TEST_CONSTEXPR explicit ThrowingMove(int v, bool do_throw) : value(v), do_throw(do_throw) {}
+
+  ThrowingMove(const ThrowingMove& rhs)        = default;
+  ThrowingMove& operator=(const ThrowingMove&) = default;
+
+  TEST_CONSTEXPR_CXX14 ThrowingMove(ThrowingMove&& rhs) : value(rhs.value), do_throw(rhs.do_throw) {
+    if (do_throw)
+      throw 1;
+  }
+  TEST_CONSTEXPR_CXX14 ThrowingMove& operator=(ThrowingMove&& rhs) {
+    value    = rhs.value;
+    do_throw = rhs.do_throw;
+    if (do_throw)
+      throw 1;
+    return *this;
+  }
+
+  TEST_CONSTEXPR_CXX14 friend bool operator==(ThrowingMove const& lhs, ThrowingMove const& rhs) {
+    return lhs.value == rhs.value;
+  }
+
+  int value;
+  bool do_throw;
+};
+#endif // TEST_HAS_NO_EXCEPTIONS
 
 struct Tracker {
   int copy_assignments = 0;
diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp
index 667ce483806e7..3431f4336d1e2 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp
@@ -7,150 +7,339 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03 && !stdlib=libc++
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=9000000
 
 // <vector>
 
 // template <class... Args> iterator emplace(const_iterator pos, Args&&... args);
 
-#include <vector>
 #include <cassert>
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+#include <vector>
 
-#include "test_macros.h"
-#include "test_allocator.h"
-#include "min_allocator.h"
 #include "asan_testing.h"
+#include "common.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
 
-class A {
-  int i_;
-  double d_;
+struct NonCopyable {
+  int i;
 
-  A(const A&);
-  A& operator=(const A&);
+  TEST_CONSTEXPR_CXX14 explicit NonCopyable(int i) : i(i) {}
 
-public:
-  TEST_CONSTEXPR_CXX14 A(int i, double d) : i_(i), d_(d) {}
+  NonCopyable(NonCopyable const&)            = delete;
+  NonCopyable& operator=(NonCopyable const&) = delete;
 
-  TEST_CONSTEXPR_CXX14 A(A&& a) : i_(a.i_), d_(a.d_) {
-    a.i_ = 0;
-    a.d_ = 0;
-  }
+  TEST_CONSTEXPR_CXX14 NonCopyable(NonCopyable&& other) : i(other.i) { other.i = -1; }
 
-  TEST_CONSTEXPR_CXX14 A& operator=(A&& a) {
-    i_   = a.i_;
-    d_   = a.d_;
-    a.i_ = 0;
-    a.d_ = 0;
+  TEST_CONSTEXPR_CXX14 NonCopyable& operator=(NonCopyable&& other) {
+    i       = other.i;
+    other.i = -1;
     return *this;
   }
 
-  TEST_CONSTEXPR_CXX14 int geti() const { return i_; }
-  TEST_CONSTEXPR_CXX14 double getd() const { return d_; }
+  TEST_CONSTEXPR_CXX14 friend bool operator==(NonCopyable const& lhs, NonCopyable const& rhs) { return lhs.i == rhs.i; }
 };
 
-TEST_CONSTEXPR_CXX20 bool tests() {
+template <class T>
+struct has_moved_from_sentinel : std::false_type {};
+
+template <>
+struct has_moved_from_sentinel<NonCopyable> : std::true_type {};
+
+template <template <class...> class Allocator, class T>
+TEST_CONSTEXPR_CXX20 void test() {
+  using Vector   = std::vector<T, Allocator<T> >;
+  using Iterator = typename Vector::iterator;
+
+  // Check the return type
+  {
+    Vector v;
+    ASSERT_SAME_TYPE(decltype(v.emplace(v.cbegin(), 1)), Iterator);
+  }
+
+  // Emplace at the end of a vector with increasing size
+  {
+    Vector v;
+
+    // starts with size 0
+    {
+      Iterator it = v.emplace(v.cend(), 0);
+      assert(it == v.end() - 1);
+      assert(v.size() == 1);
+      assert(v[0] == T(0));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size 1
+    {
+      Iterator it = v.emplace(v.cend(), 1);
+      assert(it == v.end() - 1);
+      assert(v.size() == 2);
+      assert(v[0] == T(0));
+      assert(v[1] == T(1));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size 2
+    {
+      Iterator it = v.emplace(v.cend(), 2);
+      assert(it == v.end() - 1);
+      assert(v.size() == 3);
+      assert(v[0] == T(0));
+      assert(v[1] == T(1));
+      assert(v[2] == T(2));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size n...
+    for (std::size_t n = 3; n != 100; ++n) {
+      Iterator it = v.emplace(v.cend(), n);
+      assert(it == v.end() - 1);
+      assert(v.size() == n + 1);
+      for (std::size_t i = 0; i != n + 1; ++i)
+        assert(v[i] == T(i));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+  }
+
+  // Emplace at the start of a vector with increasing size
+  {
+    Vector v;
+
+    // starts with size 0
+    {
+      Iterator it = v.emplace(v.cbegin(), 0);
+      assert(it == v.begin());
+      assert(v.size() == 1);
+      assert(v[0] == T(0));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size 1
+    {
+      Iterator it = v.emplace(v.cbegin(), 1);
+      assert(it == v.begin());
+      assert(v.size() == 2);
+      assert(v[0] == T(1));
+      assert(v[1] == T(0));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size 2
+    {
+      Iterator it = v.emplace(v.cbegin(), 2);
+      assert(it == v.begin());
+      assert(v.size() == 3);
+      assert(v[0] == T(2));
+      assert(v[1] == T(1));
+      assert(v[2] == T(0));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // starts with size n...
+    for (std::size_t n = 3; n != 100; ++n) {
+      Iterator it = v.emplace(v.cbegin(), n);
+      assert(it == v.begin());
+      assert(v.size() == n + 1);
+      for (std::size_t i = 0; i != n + 1; ++i)
+        assert(v[i] == T(n - i));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+  }
+
+  // Emplace somewhere inside the vector
   {
-    std::vector<A> c;
-    std::vector<A>::iterator i = c.emplace(c.cbegin(), 2, 3.5);
-    assert(i == c.begin());
-    assert(c.size() == 1);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(is_contiguous_container_asan_correct(c));
-    i = c.emplace(c.cend(), 3, 4.5);
-    assert(i == c.end() - 1);
-    assert(c.size() == 2);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    assert(is_contiguous_container_asan_correct(c));
-    i = c.emplace(c.cbegin() + 1, 4, 6.5);
-    assert(i == c.begin() + 1);
-    assert(c.size() == 3);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c[1].geti() == 4);
-    assert(c[1].getd() == 6.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    assert(is_contiguous_container_asan_correct(c));
+    Vector v;
+    v.emplace_back(0);
+    v.emplace_back(1);
+    v.emplace_back(2);
+    // vector is {0, 1, 2}
+
+    {
+      Iterator it = v.emplace(v.cbegin() + 1, 3);
+      // vector is {0, 3, 1, 2}
+      assert(it == v.begin() + 1);
+      assert(v.size() == 4);
+      assert(v[0] == T(0));
+      assert(v[1] == T(3));
+      assert(v[2] == T(1));
+      assert(v[3] == T(2));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    {
+      Iterator it = v.emplace(v.cbegin() + 2, 4);
+      // vector is {0, 3, 4, 1, 2}
+      assert(it == v.begin() + 2);
+      assert(v.size() == 5);
+      assert(v[0] == T(0));
+      assert(v[1] == T(3));
+      assert(v[2] == T(4));
+      assert(v[3] == T(1));
+      assert(v[4] == T(2));
+      assert(is_contiguous_container_asan_correct(v));
+    }
   }
+
+  // Emplace after reserving
   {
-    std::vector<A, limited_allocator<A, 7> > c;
-    std::vector<A, limited_allocator<A, 7> >::iterator i = c.emplace(c.cbegin(), 2, 3.5);
-    assert(i == c.begin());
-    assert(c.size() == 1);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(is_contiguous_container_asan_correct(c));
-    i = c.emplace(c.cend(), 3, 4.5);
-    assert(i == c.end() - 1);
-    assert(c.size() == 2);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    assert(is_contiguous_container_asan_correct(c));
-    i = c.emplace(c.cbegin() + 1, 4, 6.5);
-    assert(i == c.begin() + 1);
-    assert(c.size() == 3);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c[1].geti() == 4);
-    assert(c[1].getd() == 6.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    assert(is_contiguous_container_asan_correct(c));
+    Vector v;
+    v.emplace_back(0);
+    v.emplace_back(1);
+    v.emplace_back(2);
+    // vector is {0, 1, 2}
+
+    v.reserve(1000);
+    Iterator it = v.emplace(v.cbegin() + 1, 3);
+    assert(it == v.begin() + 1);
+    assert(v.size() == 4);
+    assert(v[0] == T(0));
+    assert(v[1] == T(3));
+    assert(v[2] == T(1));
+    assert(v[3] == T(2));
+    assert(is_contiguous_container_asan_correct(v));
   }
+
+  // Emplace with the same type that's stored in the vector (as opposed to just constructor arguments)
   {
-    std::vector<A, min_allocator<A> > c;
-    std::vector<A, min_allocator<A> >::iterator i = c.emplace(c.cbegin(), 2, 3.5);
-    assert(i == c.begin());
-    assert(c.size() == 1);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    i = c.emplace(c.cend(), 3, 4.5);
-    assert(i == c.end() - 1);
-    assert(c.size() == 2);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    i = c.emplace(c.cbegin() + 1, 4, 6.5);
-    assert(i == c.begin() + 1);
-    assert(c.size() == 3);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c[1].geti() == 4);
-    assert(c[1].getd() == 6.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
+    Vector v;
+    Iterator it = v.emplace(v.cbegin(), T(1));
+    assert(it == v.begin());
+    assert(v.size() == 1);
+    assert(v[0] == T(1));
+    assert(is_contiguous_container_asan_correct(v));
   }
+
+  // Emplace from an element inside the vector itself. This is interesting for two reasons. First, if the
+  // vector must increase capacity, the implementation needs to make sure that it doesn't end up inserting
+  // from a dangling reference.
+  //
+  // Second, if the vector doesn't need to grow but its elements get shifted internally, the implementation
+  // must make sure that it doesn't end up inserting from an element whose position has changed.
   {
-    std::vector<A, safe_allocator<A> > c;
-    std::vector<A, safe_allocator<A> >::iterator i = c.emplace(c.cbegin(), 2, 3.5);
-    assert(i == c.begin());
-    assert(c.size() == 1);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    i = c.emplace(c.cend(), 3, 4.5);
-    assert(i == c.end() - 1);
-    assert(c.size() == 2);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
-    i = c.emplace(c.cbegin() + 1, 4, 6.5);
-    assert(i == c.begin() + 1);
-    assert(c.size() == 3);
-    assert(c.front().geti() == 2);
-    assert(c.front().getd() == 3.5);
-    assert(c[1].geti() == 4);
-    assert(c[1].getd() == 6.5);
-    assert(c.back().geti() == 3);
-    assert(c.back().getd() == 4.5);
+    // When capacity must increase
+    {
+      Vector v;
+      v.emplace_back(0);
+      v.emplace_back(1);
+
+      while (v.size() < v.capacity()) {
+        v.emplace_back(2);
+      }
+      assert(v.size() == v.capacity());
+      // vector is {0, 1, 2...}
+
+      std::size_t old_cap = v.capacity();
+      v.emplace(v.cbegin(), std::move(v[1]));
+      assert(v.capacity() > old_cap); // test the test
+
+      // vector is {1, 0, -1, 2...}
+      // Note that old v[1] has been set to -1 when it was moved-from
+      assert(v.size() >= 3);
+      assert(v[0] == T(1));
+      assert(v[1] == T(0));
+      if (has_moved_from_sentinel<T>::value)
+        assert(v[2] == T(-1));
+      assert(is_contiguous_container_asan_correct(v));
+    }
+
+    // When elements shift around
+    {
+      Vector v;
+      v.emplace_back(0);
+      v.emplace_back(1);
+      // vector is {0, 1}
+
+      v.reserve(3);
+      std::size_t old_cap = v.capacity();
+      v.emplace(v.cbegin(), std::move(v[1]));
+      assert(v.capacity() == old_cap); // test the test
+
+      // vector is {1, 0, -1}
+      // Note that old v[1] has been set to -1 when it was moved-from
+      assert(v.size() == 3);
+      assert(v[0] == T(1));
+      assert(v[1] == T(0));
+      if (has_moved_from_sentinel<T>::value)
+        assert(v[2] == T(-1));
+      assert(is_contiguous_container_asan_correct(v));
+    }
   }
 
+  // Make sure that we don't reallocate when we have sufficient capacity
+  {
+    Vector v;
+    v.reserve(8);
+    assert(v.capacity() >= 8);
+
+    std::size_t old_capacity = v.capacity();
+    v.emplace_back(0);
+    v.emplace_back(1);
+    v.emplace_back(2);
+    v.emplace_back(3);
+    assert(v.capacity() == old_capacity);
+
+    v.emplace(v.cend(), 4);
+    assert(v.size() == 5);
+    assert(v.capacity() == old_capacity);
+    assert(v[0] == T(0));
+    assert(v[1] == T(1));
+    assert(v[2] == T(2));
+    assert(v[3] == T(3));
+    assert(v[4] == T(4));
+    assert(is_contiguous_container_asan_correct(v));
+  }
+
+  // Make sure that we correctly handle the case where an exception would be thrown if moving the element into place.
+  // This is a very specific test that aims to validate that the implementation doesn't create a temporary object e.g.
+  // on the stack and then moves it into its final location inside the newly allocated vector storage.
+  //
+  // If that were the case, and if the element happened to throw upon move construction or move assignment into its
+  // final location, we would have invalidated iterators despite the overall emplace being required to have the
+  // strong exception safety guarantee.
+  //
+  // Instead, a conforming implementation needs to emplace the new element into its final location immediately, and
+  // only after this has been done, then start making non-reversible changes to the vector's underlying storage.
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  {
+    std::vector<ThrowingMove, Allocator<ThrowingMove> > v;
+    v.emplace_back(0, /* do throw */ false);
+    v.emplace_back(1, /* do throw */ false);
+
+    while (v.size() < v.capacity()) {
+      v.emplace_back(2, /* do throw */ false);
+    }
+    assert(v.size() == v.capacity()); // the next emplace will be forced to invalidate iterators
+
+    v.emplace(v.cend(), 3, /* do throw */ true); // this shouldn't throw since we shouldn't move
+
+    assert(v.size() >= 3);
+    assert(v[0] == ThrowingMove(0));
+    assert(v[1] == ThrowingMove(1));
+    assert(v.back() == ThrowingMove(3));
+    assert(is_contiguous_container_asan_correct(v));
+  }
+#endif // TEST_HAS_NO_EXCEPTIONS
+}
+
+TEST_CONSTEXPR_CXX20 bool tests() {
+  test<std::allocator, int>();
+  test<min_allocator, int>();
+  test<safe_allocator, int>();
+
+  test<std::allocator, NonCopyable>();
+  test<min_allocator, NonCopyable>();
+  test<safe_allocator, NonCopyable>();
+
+  test<std::allocator, NonTriviallyRelocatable>();
+  test<min_allocator, NonTriviallyRelocatable>();
+  test<safe_allocator, NonTriviallyRelocatable>();
+
+  // test<limited_allocator<int, 7> >();
   return true;
 }
 
diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
deleted file mode 100644
index 43990b148cad6..0000000000000
--- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-// <vector>
-
-// template <class... Args> iterator emplace(const_iterator pos, Args&&... args);
-
-#include <vector>
-#include <cassert>
-
-#include "test_macros.h"
-#include "min_allocator.h"
-#include "asan_testing.h"
-
-TEST_CONSTEXPR_CXX20 bool tests() {
-  {
-    std::vector<int> v;
-    v.reserve(3);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int> v;
-    v.reserve(4);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int, min_allocator<int>> v;
-    v.reserve(3);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int, min_allocator<int>> v;
-    v.reserve(4);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int, safe_allocator<int>> v;
-    v.reserve(3);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int, safe_allocator<int>> v;
-    v.reserve(4);
-    assert(is_contiguous_container_asan_correct(v));
-    v = {1, 2, 3};
-    v.emplace(v.begin(), v.back());
-    assert(v[0] == 3);
-    assert(is_contiguous_container_asan_correct(v));
-  }
-  {
-    std::vector<int> v;
-    v.reserve(8);
-    std::size_t old_capacity = v.capacity();
-    assert(old_capacity >= 8);
-
-    v.resize(4); // keep the existing capacity
-    assert(v.capacity() == old_capacity);
-
-    v.emplace(v.cend(), 42);
-    assert(v.size() == 5);
-    assert(v.capacity() == old_capacity);
-    assert(v[4] == 42);
-  }
-
-  return true;
-}
-
-int main(int, char**) {
-  tests();
-#if TEST_STD_VER > 17
-  static_assert(tests());
-#endif
-  return 0;
-}

@ldionne ldionne force-pushed the review/tr-2-improve-tests-for-emplace branch from 00fb86b to 7524b2d Compare March 24, 2025 19:07
Copy link
Contributor

@winner245 winner245 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mostly LGTM, with some nitpicks.

ldionne added 6 commits April 3, 2025 19:00
This patch refactors the test for std::vector::emplace back to cover
new corner cases, and increase coverage for normal cases as well.
This is in preparation for reworking the implementation of emplace.
@ldionne ldionne force-pushed the review/tr-2-improve-tests-for-emplace branch from ab85261 to 71eb8d1 Compare April 3, 2025 23:38
@ldionne ldionne merged commit 60b43ef into llvm:main May 6, 2025
82 checks passed
@ldionne ldionne deleted the review/tr-2-improve-tests-for-emplace branch May 6, 2025 19:29
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 6, 2025

LLVM Buildbot has detected a new failure on builder fuchsia-x86_64-linux running on fuchsia-debian-64-us-central1-b-1 while building libcxx at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/11/builds/14528

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/fuchsia-linux.py ...' (failure)
...
[243/2503] Generating header stdbit.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/stdbit.yaml
[244/2503] Generating header setjmp.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/setjmp.yaml
[245/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.common_constants.dir/common_constants.cpp.obj
[246/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingl.dir/issignalingl.cpp.obj
[247/2503] Generating header ctype.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/ctype.yaml
[248/2503] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.bcopy.dir/bcopy.cpp.obj
[249/2503] Generating header string.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/string.yaml
[250/2503] Generating header time.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/time.yaml
[251/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonical.dir/iscanonical.cpp.obj
[252/2503] Building CXX object libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj
FAILED: libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/./bin/clang++ --target=armv7m-none-eabi -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/include/armv7m-unknown-none-eabi --target=armv7m-none-eabi -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" -D_LIBCPP_PRINT=1 -mthumb -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/runtimes/runtimes-armv7m-none-eabi-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=armv7m-none-eabi -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_TYPES_TIME_T_IS_32_BIT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -MF libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj.d -o libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp:13:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/libc_assert.h:25:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/integer_to_string.h:70:
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:31: error: use of undeclared identifier 'uint16_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:62: error: use of undeclared identifier 'uint8_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                                                              ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:31: error: use of undeclared identifier 'uint32_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:62: error: use of undeclared identifier 'uint16_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                                                              ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:81:38: error: use of undeclared identifier 'uint8_t'
   81 |   if constexpr (cpp::is_same_v<word, uint8_t>) {
      |                                      ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:82:18: error: use of undeclared identifier 'uint16_t'
   82 |     return split<uint16_t>(uint16_t(a) * uint16_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:83:45: error: use of undeclared identifier 'uint16_t'
   83 |   } else if constexpr (cpp::is_same_v<word, uint16_t>) {
      |                                             ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:84:18: error: use of undeclared identifier 'uint32_t'
   84 |     return split<uint32_t>(uint32_t(a) * uint32_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:332:57: error: unknown type name 'uint64_t'
  332 | template <size_t Bits, bool Signed, typename WordType = uint64_t>
      |                                                         ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:643:36: error: unknown type name 'uint64_t'
  643 |   LIBC_INLINE constexpr void pow_n(uint64_t power) {
      |                                    ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1066:31: error: use of undeclared identifier 'uint32_t'
 1066 |                               uint32_t
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1071:62: error: use of undeclared identifier 'uint16_t'
Step 6 (build) failure: build (failure)
...
[243/2503] Generating header stdbit.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/stdbit.yaml
[244/2503] Generating header setjmp.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/setjmp.yaml
[245/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.common_constants.dir/common_constants.cpp.obj
[246/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingl.dir/issignalingl.cpp.obj
[247/2503] Generating header ctype.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/ctype.yaml
[248/2503] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.bcopy.dir/bcopy.cpp.obj
[249/2503] Generating header string.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/string.yaml
[250/2503] Generating header time.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/time.yaml
[251/2503] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonical.dir/iscanonical.cpp.obj
[252/2503] Building CXX object libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj
FAILED: libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/./bin/clang++ --target=armv7m-none-eabi -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/include/armv7m-unknown-none-eabi --target=armv7m-none-eabi -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" -D_LIBCPP_PRINT=1 -mthumb -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-ubecu2oe/runtimes/runtimes-armv7m-none-eabi-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=armv7m-none-eabi -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_TYPES_TIME_T_IS_32_BIT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -MF libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj.d -o libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp:13:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/libc_assert.h:25:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/integer_to_string.h:70:
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:31: error: use of undeclared identifier 'uint16_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:62: error: use of undeclared identifier 'uint8_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                                                              ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:31: error: use of undeclared identifier 'uint32_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:62: error: use of undeclared identifier 'uint16_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                                                              ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:81:38: error: use of undeclared identifier 'uint8_t'
   81 |   if constexpr (cpp::is_same_v<word, uint8_t>) {
      |                                      ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:82:18: error: use of undeclared identifier 'uint16_t'
   82 |     return split<uint16_t>(uint16_t(a) * uint16_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:83:45: error: use of undeclared identifier 'uint16_t'
   83 |   } else if constexpr (cpp::is_same_v<word, uint16_t>) {
      |                                             ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:84:18: error: use of undeclared identifier 'uint32_t'
   84 |     return split<uint32_t>(uint32_t(a) * uint32_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:332:57: error: unknown type name 'uint64_t'
  332 | template <size_t Bits, bool Signed, typename WordType = uint64_t>
      |                                                         ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:643:36: error: unknown type name 'uint64_t'
  643 |   LIBC_INLINE constexpr void pow_n(uint64_t power) {
      |                                    ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1066:31: error: use of undeclared identifier 'uint32_t'
 1066 |                               uint32_t
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1071:62: error: use of undeclared identifier 'uint16_t'

GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
)

This patch refactors the test for std::vector::emplace back to cover new
corner cases, and increase coverage for normal cases as well.

This is building towards llvm#129328.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants