aboutsummaryrefslogtreecommitdiff
path: root/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp')
-rw-r--r--test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp420
1 files changed, 420 insertions, 0 deletions
diff --git a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp
new file mode 100644
index 000000000000..8d83c3c8888a
--- /dev/null
+++ b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp
@@ -0,0 +1,420 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 ctor
+
+#include <memory>
+#include <cassert>
+
+#include "test_macros.h"
+#include "unique_ptr_test_helper.h"
+#include "type_id.h"
+
+template <int ID = 0>
+struct GenericDeleter {
+ void operator()(void*) const {}
+};
+
+template <int ID = 0>
+struct GenericConvertingDeleter {
+
+ template <int OID>
+ GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
+
+ template <int OID>
+ GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) {
+ return *this;
+ }
+
+ void operator()(void*) const {}
+};
+
+template <class T, class U>
+using EnableIfNotSame = typename std::enable_if<
+ !std::is_same<typename std::decay<T>::type, typename std::decay<U>::type>::value
+>::type;
+
+template <class Templ, class Other>
+struct is_specialization;
+
+template <template <int> class Templ, int ID1, class Other>
+struct is_specialization<Templ<ID1>, Other> : std::false_type {};
+
+template <template <int> class Templ, int ID1, int ID2>
+struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
+
+template <class Templ, class Other>
+using EnableIfSpecialization = typename std::enable_if<
+ is_specialization<Templ, typename std::decay<Other>::type >::value
+ >::type;
+
+template <int ID> struct TrackingDeleter;
+template <int ID> struct ConstTrackingDeleter;
+
+template <int ID>
+struct TrackingDeleter {
+ TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
+
+ TrackingDeleter(TrackingDeleter const&)
+ : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
+
+ TrackingDeleter(TrackingDeleter&&)
+ : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
+
+ template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
+ TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
+
+ TrackingDeleter& operator=(TrackingDeleter const&) {
+ arg_type = &makeArgumentID<TrackingDeleter const&>();
+ return *this;
+ }
+
+ TrackingDeleter& operator=(TrackingDeleter &&) {
+ arg_type = &makeArgumentID<TrackingDeleter &&>();
+ return *this;
+ }
+
+ template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
+ TrackingDeleter& operator=(T&&) {
+ arg_type = &makeArgumentID<T&&>();
+ return *this;
+ }
+
+ void operator()(void*) const {}
+
+public:
+ TypeID const* reset() const {
+ TypeID const* tmp = arg_type;
+ arg_type = nullptr;
+ return tmp;
+ }
+
+ mutable TypeID const* arg_type;
+};
+
+template <int ID>
+struct ConstTrackingDeleter {
+ ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {}
+
+ ConstTrackingDeleter(ConstTrackingDeleter const&)
+ : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {}
+
+ ConstTrackingDeleter(ConstTrackingDeleter&&)
+ : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {}
+
+ template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
+ ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
+
+ const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const {
+ arg_type = &makeArgumentID<ConstTrackingDeleter const&>();
+ return *this;
+ }
+
+ const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const {
+ arg_type = &makeArgumentID<ConstTrackingDeleter &&>();
+ return *this;
+ }
+
+ template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
+ const ConstTrackingDeleter& operator=(T&&) const {
+ arg_type = &makeArgumentID<T&&>();
+ return *this;
+ }
+
+ void operator()(void*) const {}
+
+public:
+ TypeID const* reset() const {
+ TypeID const* tmp = arg_type;
+ arg_type = nullptr;
+ return tmp;
+ }
+
+ mutable TypeID const* arg_type;
+};
+
+template <class ExpectT, int ID>
+bool checkArg(TrackingDeleter<ID> const& d) {
+ return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
+}
+
+template <class ExpectT, int ID>
+bool checkArg(ConstTrackingDeleter<ID> const& d) {
+ return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
+}
+
+template <class From, bool AssignIsConst = false>
+struct AssignDeleter {
+ AssignDeleter() = default;
+ AssignDeleter(AssignDeleter const&) = default;
+ AssignDeleter(AssignDeleter&&) = default;
+
+ AssignDeleter& operator=(AssignDeleter const&) = delete;
+ AssignDeleter& operator=(AssignDeleter &&) = delete;
+
+ template <class T> AssignDeleter& operator=(T&&) && = delete;
+ template <class T> AssignDeleter& operator=(T&&) const && = delete;
+
+ template <class T, class = typename std::enable_if<
+ std::is_same<T&&, From>::value && !AssignIsConst
+ >::type>
+ AssignDeleter& operator=(T&&) & { return *this; }
+
+ template <class T, class = typename std::enable_if<
+ std::is_same<T&&, From>::value && AssignIsConst
+ >::type>
+ const AssignDeleter& operator=(T&&) const & { return *this; }
+
+ template <class T>
+ void operator()(T) const {}
+};
+
+template <class VT, class DDest, class DSource>
+ void doDeleterTest() {
+ using U1 = std::unique_ptr<VT, DDest>;
+ using U2 = std::unique_ptr<VT, DSource>;
+ static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
+ typename std::decay<DDest>::type ddest;
+ typename std::decay<DSource>::type dsource;
+ U1 u1(nullptr, ddest);
+ U2 u2(nullptr, dsource);
+ u1 = std::move(u2);
+}
+
+template <bool IsArray>
+void test_sfinae() {
+ typedef typename std::conditional<IsArray, A[], A>::type VT;
+
+ { // Test that different non-reference deleter types are allowed so long
+ // as they convert to each other.
+ using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
+ using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
+ static_assert(std::is_assignable<U1, U2&&>::value, "");
+ }
+ { // Test that different non-reference deleter types are disallowed when
+ // they cannot convert.
+ using U1 = std::unique_ptr<VT, GenericDeleter<0> >;
+ using U2 = std::unique_ptr<VT, GenericDeleter<1> >;
+ static_assert(!std::is_assignable<U1, U2&&>::value, "");
+ }
+ { // Test that if the deleter assignment is not valid the assignment operator
+ // SFINAEs.
+ using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >;
+ using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
+ using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
+ using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
+ using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
+ static_assert(!std::is_assignable<U1, U2&&>::value, "");
+ static_assert(!std::is_assignable<U1, U3&&>::value, "");
+ static_assert(!std::is_assignable<U1, U4&&>::value, "");
+ static_assert(!std::is_assignable<U1, U5&&>::value, "");
+
+ using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
+ static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
+ }
+ { // Test that if the deleter assignment is not valid the assignment operator
+ // SFINAEs.
+ using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> & >;
+ using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
+ using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
+ using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
+ using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
+
+ static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
+ static_assert(std::is_nothrow_assignable<U1, U3&&>::value, "");
+ static_assert(std::is_nothrow_assignable<U1, U4&&>::value, "");
+ static_assert(std::is_nothrow_assignable<U1, U5&&>::value, "");
+
+ using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> &>;
+ static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
+ }
+ { // Test that non-reference destination deleters can be assigned
+ // from any source deleter type with a sutible conversion. Including
+ // reference types.
+ using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
+ using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
+ using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>;
+ using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
+ using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>;
+ using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
+ static_assert(std::is_assignable<U1, U2&&>::value, "");
+ static_assert(std::is_assignable<U1, U3&&>::value, "");
+ static_assert(std::is_assignable<U1, U4&&>::value, "");
+ static_assert(std::is_assignable<U1, U5&&>::value, "");
+ static_assert(std::is_assignable<U1, U6&&>::value, "");
+ }
+ /////////////////////////////////////////////////////////////////////////////
+ {
+ using Del = GenericDeleter<0>;
+ using AD = AssignDeleter<Del&&>;
+ using ADC = AssignDeleter<Del&&, /*AllowConstAssign*/true>;
+ doDeleterTest<VT, AD, Del>();
+ doDeleterTest<VT, AD&, Del>();
+ doDeleterTest<VT, ADC const&, Del>();
+ }
+ {
+ using Del = GenericDeleter<0>;
+ using AD = AssignDeleter<Del&>;
+ using ADC = AssignDeleter<Del&, /*AllowConstAssign*/true>;
+ doDeleterTest<VT, AD, Del&>();
+ doDeleterTest<VT, AD&, Del&>();
+ doDeleterTest<VT, ADC const&, Del&>();
+ }
+ {
+ using Del = GenericDeleter<0>;
+ using AD = AssignDeleter<Del const&>;
+ using ADC = AssignDeleter<Del const&, /*AllowConstAssign*/true>;
+ doDeleterTest<VT, AD, Del const&>();
+ doDeleterTest<VT, AD&, Del const&>();
+ doDeleterTest<VT, ADC const&, Del const&>();
+ }
+}
+
+
+template <bool IsArray>
+void test_noexcept() {
+ typedef typename std::conditional<IsArray, A[], A>::type VT;
+ {
+ typedef std::unique_ptr<const VT> APtr;
+ typedef std::unique_ptr<VT> BPtr;
+ static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
+ }
+ {
+ typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr;
+ typedef std::unique_ptr<VT, CDeleter<VT> > BPtr;
+ static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
+ }
+ {
+ typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr;
+ typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr;
+ static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
+ }
+ {
+ typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr;
+ typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
+ static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
+ }
+}
+
+template <bool IsArray>
+void test_deleter_value_category() {
+ typedef typename std::conditional<IsArray, A[], A>::type VT;
+ using TD1 = TrackingDeleter<1>;
+ using TD2 = TrackingDeleter<2>;
+ TD1 d1;
+ TD2 d2;
+ using CD1 = ConstTrackingDeleter<1>;
+ using CD2 = ConstTrackingDeleter<2>;
+ CD1 cd1;
+ CD2 cd2;
+
+ { // Test non-reference deleter conversions
+ using U1 = std::unique_ptr<VT, TD1 >;
+ using U2 = std::unique_ptr<VT, TD2 >;
+ U1 u1;
+ U2 u2;
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2&&>(u1.get_deleter()));
+ }
+ { // Test assignment to non-const ref
+ using U1 = std::unique_ptr<VT, TD1& >;
+ using U2 = std::unique_ptr<VT, TD2 >;
+ U1 u1(nullptr, d1);
+ U2 u2;
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2&&>(u1.get_deleter()));
+ }
+ { // Test assignment to const&.
+ using U1 = std::unique_ptr<VT, CD1 const& >;
+ using U2 = std::unique_ptr<VT, CD2 >;
+ U1 u1(nullptr, cd1);
+ U2 u2;
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<CD2&&>(u1.get_deleter()));
+ }
+
+ { // Test assignment from non-const ref
+ using U1 = std::unique_ptr<VT, TD1 >;
+ using U2 = std::unique_ptr<VT, TD2& >;
+ U1 u1;
+ U2 u2(nullptr, d2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2&>(u1.get_deleter()));
+ }
+ { // Test assignment from const ref
+ using U1 = std::unique_ptr<VT, TD1 >;
+ using U2 = std::unique_ptr<VT, TD2 const& >;
+ U1 u1;
+ U2 u2(nullptr, d2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2 const&>(u1.get_deleter()));
+ }
+
+ { // Test assignment from non-const ref
+ using U1 = std::unique_ptr<VT, TD1& >;
+ using U2 = std::unique_ptr<VT, TD2& >;
+ U1 u1(nullptr, d1);
+ U2 u2(nullptr, d2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2&>(u1.get_deleter()));
+ }
+ { // Test assignment from const ref
+ using U1 = std::unique_ptr<VT, TD1& >;
+ using U2 = std::unique_ptr<VT, TD2 const& >;
+ U1 u1(nullptr, d1);
+ U2 u2(nullptr, d2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<TD2 const&>(u1.get_deleter()));
+ }
+
+ { // Test assignment from non-const ref
+ using U1 = std::unique_ptr<VT, CD1 const& >;
+ using U2 = std::unique_ptr<VT, CD2 & >;
+ U1 u1(nullptr, cd1);
+ U2 u2(nullptr, cd2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<CD2 &>(u1.get_deleter()));
+ }
+ { // Test assignment from const ref
+ using U1 = std::unique_ptr<VT, CD1 const& >;
+ using U2 = std::unique_ptr<VT, CD2 const& >;
+ U1 u1(nullptr, cd1);
+ U2 u2(nullptr, cd2);
+ u1.get_deleter().reset();
+ u1 = std::move(u2);
+ assert(checkArg<CD2 const&>(u1.get_deleter()));
+ }
+}
+
+int main() {
+ {
+ test_sfinae</*IsArray*/false>();
+ test_noexcept<false>();
+ test_deleter_value_category<false>();
+ }
+ {
+ test_sfinae</*IsArray*/true>();
+ test_noexcept<true>();
+ test_deleter_value_category<true>();
+ }
+}