Rewrite and cleanup unique_ptr tests.

This patch almost entirely rewrites the unique_ptr tests. There are a couple
of reasons for this:

A) Most of the *.fail.cpp tests were either incorrect or could be better written
  as a *.pass.cpp test that uses <type_traits> to check if certain operations
  are valid (Ex. Using static_assert(!std::is_copy_constructible_v<T>) instead
  of writing a failure test).

B) [unique.ptr.runtime] has very poor test coverage. Many of the constructors
  and assignment operators have to tests at all. The special members that have
  tests have very few test cases and are typically way out of date.

C) The tests for [unique.ptr.single] and [unique.ptr.runtime] are largely
  duplicates of each other. This means common requirements have two different
  sets of tests in two different test files. This makes the tests harder to
  maintain than if there was a single copy.

To address (A) this patch changes almost all of the *.fail.cpp tests into
.pass.cpp tests using type traits; Allowing the *.fail.cpp tests to be removed.

The address (B) and (C) the tests for [unique.ptr.single] and [unique.ptr.runtime]
have been combined into a single directory, allowing both specializations to share
common tests. Tests specific to the single/runtime specializations are given the
suffix "*.single.pass.cpp" or "*.runtime.pass.cpp".

Finally the unique.ptr test have been moved into the correct directory according
to the standard. Specifically they have been removed from "utilities/memory" into
"utilities/smartptr".

PS. This patch also adds newly written tests for upcoming unique_ptr changes/fixes.
However since these tests don't currently pass they are guarded by the macro
TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES. This allows other STL's to validate
the tests before libc++ implements the changes. The relevant libc++ changes should
land in the next week.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@300388 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2017-04-15 05:28:06 +00:00
parent dfac40a8fc
commit 81f58e5052
173 changed files with 2380 additions and 6899 deletions

View File

@@ -0,0 +1,119 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <memory>
// unique_ptr
// Test unique_ptr move assignment
// test move assignment. Should only require a MoveConstructible deleter, or if
// deleter is a reference, not even that.
#include <memory>
#include <utility>
#include <cassert>
#include "deleter_types.h"
#include "unique_ptr_test_helper.h"
struct GenericDeleter {
void operator()(void*) const;
};
template <bool IsArray>
void test_basic() {
typedef typename std::conditional<IsArray, A[], A>::type VT;
const int expect_alive = IsArray ? 5 : 1;
{
std::unique_ptr<VT> s1(newValue<VT>(expect_alive));
A* p = s1.get();
std::unique_ptr<VT> s2(newValue<VT>(expect_alive));
assert(A::count == (expect_alive * 2));
s2 = std::move(s1);
assert(A::count == expect_alive);
assert(s2.get() == p);
assert(s1.get() == 0);
}
assert(A::count == 0);
{
std::unique_ptr<VT, Deleter<VT> > s1(newValue<VT>(expect_alive),
Deleter<VT>(5));
A* p = s1.get();
std::unique_ptr<VT, Deleter<VT> > s2(newValue<VT>(expect_alive));
assert(A::count == (expect_alive * 2));
s2 = std::move(s1);
assert(s2.get() == p);
assert(s1.get() == 0);
assert(A::count == expect_alive);
assert(s2.get_deleter().state() == 5);
assert(s1.get_deleter().state() == 0);
}
assert(A::count == 0);
{
CDeleter<VT> d1(5);
std::unique_ptr<VT, CDeleter<VT>&> s1(newValue<VT>(expect_alive), d1);
A* p = s1.get();
CDeleter<VT> d2(6);
std::unique_ptr<VT, CDeleter<VT>&> s2(newValue<VT>(expect_alive), d2);
s2 = std::move(s1);
assert(s2.get() == p);
assert(s1.get() == 0);
assert(A::count == expect_alive);
assert(d1.state() == 5);
assert(d2.state() == 5);
}
assert(A::count == 0);
}
template <bool IsArray>
void test_sfinae() {
typedef typename std::conditional<IsArray, int[], int>::type VT;
{
typedef std::unique_ptr<VT> U;
static_assert(!std::is_assignable<U, U&>::value, "");
static_assert(!std::is_assignable<U, const U&>::value, "");
static_assert(!std::is_assignable<U, const U&&>::value, "");
static_assert(std::is_assignable<U, U&&>::value, "");
}
{
typedef std::unique_ptr<VT, GenericDeleter> U;
static_assert(!std::is_assignable<U, U&>::value, "");
static_assert(!std::is_assignable<U, const U&>::value, "");
static_assert(!std::is_assignable<U, const U&&>::value, "");
static_assert(std::is_assignable<U, U&&>::value, "");
}
{
typedef std::unique_ptr<VT, NCDeleter<VT>&> U;
static_assert(!std::is_assignable<U, U&>::value, "");
static_assert(!std::is_assignable<U, const U&>::value, "");
static_assert(!std::is_assignable<U, const U&&>::value, "");
static_assert(std::is_assignable<U, U&&>::value, "");
}
{
typedef std::unique_ptr<VT, const NCDeleter<VT>&> U;
static_assert(!std::is_assignable<U, U&>::value, "");
static_assert(!std::is_assignable<U, const U&>::value, "");
static_assert(!std::is_assignable<U, const U&&>::value, "");
static_assert(std::is_assignable<U, U&&>::value, "");
}
}
int main() {
{
test_basic</*IsArray*/ false>();
test_sfinae<false>();
}
{
test_basic</*IsArray*/ true>();
test_sfinae<true>();
}
}

View File

@@ -0,0 +1,124 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <memory>
// unique_ptr
// Test unique_ptr converting move assignment
#include <memory>
#include <utility>
#include <cassert>
#include "unique_ptr_test_helper.h"
template <class APtr, class BPtr>
void testAssign(APtr& aptr, BPtr& bptr) {
A* p = bptr.get();
assert(A::count == 2);
aptr = std::move(bptr);
assert(aptr.get() == p);
assert(bptr.get() == 0);
assert(A::count == 1);
assert(B::count == 1);
}
template <class LHS, class RHS>
void checkDeleter(LHS& lhs, RHS& rhs, int LHSState, int RHSState) {
assert(lhs.get_deleter().state() == LHSState);
assert(rhs.get_deleter().state() == RHSState);
}
template <class T>
struct NCConvertingDeleter {
NCConvertingDeleter() = default;
NCConvertingDeleter(NCConvertingDeleter const&) = delete;
NCConvertingDeleter(NCConvertingDeleter&&) = default;
template <class U>
NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
void operator()(T*) const {}
};
template <class T>
struct NCConvertingDeleter<T[]> {
NCConvertingDeleter() = default;
NCConvertingDeleter(NCConvertingDeleter const&) = delete;
NCConvertingDeleter(NCConvertingDeleter&&) = default;
template <class U>
NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
void operator()(T*) const {}
};
struct GenericDeleter {
void operator()(void*) const;
};
struct NCGenericDeleter {
NCGenericDeleter() = default;
NCGenericDeleter(NCGenericDeleter const&) = delete;
NCGenericDeleter(NCGenericDeleter&&) = default;
void operator()(void*) const {}
};
void test_sfinae() {
using DA = NCConvertingDeleter<A[]>; // non-copyable deleters
using DAC = NCConvertingDeleter<const A[]>; // non-copyable deleters
using DB = NCConvertingDeleter<B[]>;
using UA = std::unique_ptr<A[]>;
using UAC = std::unique_ptr<const A[]>;
using UB = std::unique_ptr<B[]>;
using UAD = std::unique_ptr<A[], DA>;
using UACD = std::unique_ptr<const A[], DAC>;
using UBD = std::unique_ptr<B[], DB>;
{ // cannot move from an lvalue
static_assert(std::is_assignable<UAC, UA&&>::value, "");
static_assert(!std::is_assignable<UAC, UA&>::value, "");
static_assert(!std::is_assignable<UAC, const UA&>::value, "");
}
{ // cannot move if the deleter-types cannot convert
static_assert(std::is_assignable<UACD, UAD&&>::value, "");
static_assert(!std::is_assignable<UACD, UAC&&>::value, "");
static_assert(!std::is_assignable<UAC, UACD&&>::value, "");
}
{ // cannot move-convert with reference deleters of different types
using UA1 = std::unique_ptr<A[], DA&>;
using UA2 = std::unique_ptr<A[], DAC&>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
}
{ // cannot move-convert with reference deleters of different types
using UA1 = std::unique_ptr<A[], const DA&>;
using UA2 = std::unique_ptr<A[], const DAC&>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
}
{ // cannot move-convert from unique_ptr<Single>
using UA1 = std::unique_ptr<A[]>;
using UA2 = std::unique_ptr<A>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
}
{ // cannot move-convert from unique_ptr<Array[]>
using UA1 = std::unique_ptr<A[], NCGenericDeleter>;
using UA2 = std::unique_ptr<A, NCGenericDeleter>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
}
}
int main() {
test_sfinae();
// FIXME: add tests
}

View File

@@ -0,0 +1,145 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <memory>
// unique_ptr
// Test unique_ptr converting move assignment
#include <memory>
#include <utility>
#include <cassert>
#include "deleter_types.h"
#include "unique_ptr_test_helper.h"
template <class APtr, class BPtr>
void testAssign(APtr& aptr, BPtr& bptr) {
A* p = bptr.get();
assert(A::count == 2);
aptr = std::move(bptr);
assert(aptr.get() == p);
assert(bptr.get() == 0);
assert(A::count == 1);
assert(B::count == 1);
}
template <class LHS, class RHS>
void checkDeleter(LHS& lhs, RHS& rhs, int LHSState, int RHSState) {
assert(lhs.get_deleter().state() == LHSState);
assert(rhs.get_deleter().state() == RHSState);
}
template <class T>
struct NCConvertingDeleter {
NCConvertingDeleter() = default;
NCConvertingDeleter(NCConvertingDeleter const&) = delete;
NCConvertingDeleter(NCConvertingDeleter&&) = default;
template <class U>
NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
void operator()(T*) const {}
};
template <class T>
struct NCConvertingDeleter<T[]> {
NCConvertingDeleter() = default;
NCConvertingDeleter(NCConvertingDeleter const&) = delete;
NCConvertingDeleter(NCConvertingDeleter&&) = default;
template <class U>
NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
void operator()(T*) const {}
};
struct NCGenericDeleter {
NCGenericDeleter() = default;
NCGenericDeleter(NCGenericDeleter const&) = delete;
NCGenericDeleter(NCGenericDeleter&&) = default;
void operator()(void*) const {}
};
void test_sfinae() {
using DA = NCConvertingDeleter<A>; // non-copyable deleters
using DB = NCConvertingDeleter<B>;
using UA = std::unique_ptr<A>;
using UB = std::unique_ptr<B>;
using UAD = std::unique_ptr<A, DA>;
using UBD = std::unique_ptr<B, DB>;
{ // cannot move from an lvalue
static_assert(std::is_assignable<UA, UB&&>::value, "");
static_assert(!std::is_assignable<UA, UB&>::value, "");
static_assert(!std::is_assignable<UA, const UB&>::value, "");
}
{ // cannot move if the deleter-types cannot convert
static_assert(std::is_assignable<UAD, UBD&&>::value, "");
static_assert(!std::is_assignable<UAD, UB&&>::value, "");
static_assert(!std::is_assignable<UA, UBD&&>::value, "");
}
{ // cannot move-convert with reference deleters of different types
using UA1 = std::unique_ptr<A, DA&>;
using UB1 = std::unique_ptr<B, DB&>;
static_assert(!std::is_assignable<UA1, UB1&&>::value, "");
}
{ // cannot move-convert with reference deleters of different types
using UA1 = std::unique_ptr<A, const DA&>;
using UB1 = std::unique_ptr<B, const DB&>;
static_assert(!std::is_assignable<UA1, UB1&&>::value, "");
}
{ // cannot move-convert from unique_ptr<Array[]>
using UA1 = std::unique_ptr<A>;
using UA2 = std::unique_ptr<A[]>;
using UB1 = std::unique_ptr<B[]>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
static_assert(!std::is_assignable<UA1, UB1&&>::value, "");
}
{ // cannot move-convert from unique_ptr<Array[]>
using UA1 = std::unique_ptr<A, NCGenericDeleter>;
using UA2 = std::unique_ptr<A[], NCGenericDeleter>;
using UB1 = std::unique_ptr<B[], NCGenericDeleter>;
static_assert(!std::is_assignable<UA1, UA2&&>::value, "");
static_assert(!std::is_assignable<UA1, UB1&&>::value, "");
}
}
int main() {
test_sfinae();
{
std::unique_ptr<B> bptr(new B);
std::unique_ptr<A> aptr(new A);
testAssign(aptr, bptr);
}
assert(A::count == 0);
assert(B::count == 0);
{
Deleter<B> del(42);
std::unique_ptr<B, Deleter<B> > bptr(new B, std::move(del));
std::unique_ptr<A, Deleter<A> > aptr(new A);
testAssign(aptr, bptr);
checkDeleter(aptr, bptr, 42, 0);
}
assert(A::count == 0);
assert(B::count == 0);
{
CDeleter<A> adel(6);
CDeleter<B> bdel(42);
std::unique_ptr<B, CDeleter<B>&> bptr(new B, bdel);
std::unique_ptr<A, CDeleter<A>&> aptr(new A, adel);
testAssign(aptr, bptr);
checkDeleter(aptr, bptr, 42, 42);
}
assert(A::count == 0);
assert(B::count == 0);
}

View File

@@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <memory>
// unique_ptr
// Test unique_ptr move assignment
#include <memory>
#include <cassert>
#include "unique_ptr_test_helper.h"
// test assignment from null
template <bool IsArray>
void test_basic() {
typedef typename std::conditional<IsArray, A[], A>::type VT;
const int expect_alive = IsArray ? 5 : 1;
{
std::unique_ptr<VT> s2(newValue<VT>(expect_alive));
assert(A::count == expect_alive);
s2 = NULL;
assert(A::count == 0);
assert(s2.get() == 0);
}
assert(A::count == 0);
}
int main() {
test_basic</*IsArray*/ false>();
test_basic<true>();
}

View File

@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <memory>
// unique_ptr
// Test unique_ptr move assignment
#include <memory>
#include <cassert>
#include "unique_ptr_test_helper.h"
// test assignment from null
template <bool IsArray>
void test_basic() {
typedef typename std::conditional<IsArray, A[], A>::type VT;
const int expect_alive = IsArray ? 5 : 1;
{
std::unique_ptr<VT> s2(newValue<VT>(expect_alive));
assert(A::count == expect_alive);
s2 = nullptr;
assert(A::count == 0);
assert(s2.get() == 0);
}
assert(A::count == 0);
}
int main() {
test_basic</*IsArray*/ false>();
test_basic<true>();
}