Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include <__type_traits/is_trivially_relocatable.h>
#include <memory>
#include <string>

#include "constexpr_char_traits.h"
#include "test_allocator.h"

static_assert(std::__libcpp_is_trivially_relocatable<char>::value, "");
static_assert(std::__libcpp_is_trivially_relocatable<int>::value, "");
static_assert(std::__libcpp_is_trivially_relocatable<double>::value, "");

struct Empty {};
static_assert(std::__libcpp_is_trivially_relocatable<Empty>::value, "");

struct TriviallyCopyable {
char c;
int i;
Empty s;
};
static_assert(std::__libcpp_is_trivially_relocatable<TriviallyCopyable>::value, "");

struct NotTriviallyCopyable {
NotTriviallyCopyable(const NotTriviallyCopyable&);
~NotTriviallyCopyable();
};
static_assert(!std::__libcpp_is_trivially_relocatable<NotTriviallyCopyable>::value, "");

struct MoveOnlyTriviallyCopyable {
MoveOnlyTriviallyCopyable(const MoveOnlyTriviallyCopyable&) = delete;
MoveOnlyTriviallyCopyable& operator=(const MoveOnlyTriviallyCopyable&) = delete;
MoveOnlyTriviallyCopyable(MoveOnlyTriviallyCopyable&&) = default;
MoveOnlyTriviallyCopyable& operator=(MoveOnlyTriviallyCopyable&&) = default;
};
#ifndef _MSC_VER
static_assert(std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>::value, "");
#else
static_assert(!std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>::value, "");
#endif
// standard library types
// ----------------------

// basic_string
struct MyChar {
char c;
};
template <class T>
struct NotTriviallyRelocatableCharTraits : constexpr_char_traits<T> {
NotTriviallyRelocatableCharTraits(const NotTriviallyRelocatableCharTraits&);
NotTriviallyRelocatableCharTraits& operator=(const NotTriviallyRelocatableCharTraits&);
~NotTriviallyRelocatableCharTraits();
};

static_assert(std::__libcpp_is_trivially_relocatable<
std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value,
"");
static_assert(std::__libcpp_is_trivially_relocatable<
std::basic_string<char, NotTriviallyRelocatableCharTraits<char>, std::allocator<char> > >::value,
"");
static_assert(std::__libcpp_is_trivially_relocatable<
std::basic_string<MyChar, constexpr_char_traits<MyChar>, std::allocator<MyChar> > >::value,
"");
static_assert(
std::__libcpp_is_trivially_relocatable<
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, std::allocator<MyChar> > >::value,
"");
static_assert(!std::__libcpp_is_trivially_relocatable<
std::basic_string<char, std::char_traits<char>, test_allocator<char> > >::value,
"");
static_assert(
!std::__libcpp_is_trivially_relocatable<
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, test_allocator<MyChar> > >::value,
"");

// unique_ptr
struct NotTriviallyRelocatableDeleter {
NotTriviallyRelocatableDeleter(const NotTriviallyRelocatableDeleter&);
NotTriviallyRelocatableDeleter& operator=(const NotTriviallyRelocatableDeleter&);
~NotTriviallyRelocatableDeleter();

template <class T>
void operator()(T*);
};

struct NotTriviallyRelocatablePointer {
struct pointer {
pointer(const pointer&);
pointer& operator=(const pointer&);
~pointer();
};

template <class T>
void operator()(T*);
};

static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int> >::value, "");
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<NotTriviallyCopyable> >::value, "");
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[]> >::value, "");
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int, NotTriviallyRelocatableDeleter> >::value,
"");
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], NotTriviallyRelocatableDeleter> >::value,
"");
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int, NotTriviallyRelocatablePointer> >::value,
"");
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], NotTriviallyRelocatablePointer> >::value,
"");

// TODO: Mark all the trivially relocatable STL types as such
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Ensure that all the elements in the vector are destroyed, especially when reallocating the internal buffer

// UNSUPPORTED: c++03

#include <algorithm>
#include <array>
#include <cassert>
#include <vector>

#include "test_macros.h"

struct DestroyTracker {
TEST_CONSTEXPR_CXX20 DestroyTracker(std::vector<bool>& vec) : vec_(&vec), index_(vec.size()) { vec.push_back(false); }

TEST_CONSTEXPR_CXX20 DestroyTracker(const DestroyTracker& other) : vec_(other.vec_), index_(vec_->size()) {
vec_->push_back(false);
}

TEST_CONSTEXPR_CXX20 DestroyTracker& operator=(const DestroyTracker&) { return *this; }
TEST_CONSTEXPR_CXX20 ~DestroyTracker() { (*vec_)[index_] = true; }

std::vector<bool>* vec_;
size_t index_;
};

template <class Operation>
TEST_CONSTEXPR_CXX20 void test(Operation operation) {
std::vector<bool> all_destroyed;

{
std::vector<DestroyTracker> v;
for (size_t i = 0; i != 100; ++i)
operation(v, all_destroyed);
}

assert(std::all_of(all_destroyed.begin(), all_destroyed.end(), [](bool b) { return b; }));
}

TEST_CONSTEXPR_CXX20 bool test() {
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) { vec.emplace_back(tracker); });
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) { vec.push_back(tracker); });
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) { vec.emplace(vec.begin(), tracker); });
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) { vec.insert(vec.begin(), tracker); });
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) { vec.resize(vec.size() + 1, tracker); });
#if TEST_STD_VER >= 23
test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) {
vec.insert_range(vec.begin(), std::array<DestroyTracker, 2>{tracker, tracker});
});

test([](std::vector<DestroyTracker>& vec, std::vector<bool>& tracker) {
vec.append_range(std::array<DestroyTracker, 2>{tracker, tracker});
});
#endif

return true;
}

int main() {
test();
#if TEST_STD_VER >= 20
static_assert(test());
#endif
}
11 changes: 7 additions & 4 deletions libcxx/test/support/count_new.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,18 @@ class MemCounter

void deleteCalled(void * p)
{
assert(p);
if (p) {
--outstanding_new;
++delete_called;
}
}

void alignedDeleteCalled(void *p, std::size_t a) {
deleteCalled(p);
++aligned_delete_called;
last_delete_align = a;
if (p) {
deleteCalled(p);
++aligned_delete_called;
last_delete_align = a;
}
}

void newArrayCalled(std::size_t s)
Expand Down