diff options
Diffstat (limited to 'libcxx/test')
41 files changed, 3178 insertions, 43 deletions
diff --git a/libcxx/test/libcxx/experimental/any/small_type.pass.cpp b/libcxx/test/libcxx/experimental/any/small_type.pass.cpp index e6595d4a4ab..96754126c99 100644 --- a/libcxx/test/libcxx/experimental/any/small_type.pass.cpp +++ b/libcxx/test/libcxx/experimental/any/small_type.pass.cpp @@ -14,7 +14,7 @@  // Check that the size and alignment of any are what we expect.  #include <experimental/any> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  constexpr std::size_t BufferSize = (sizeof(void*) * 3);  constexpr std::size_t BufferAlignment = alignof(void*); diff --git a/libcxx/test/libcxx/utilities/any/size_and_alignment.pass.cpp b/libcxx/test/libcxx/utilities/any/size_and_alignment.pass.cpp new file mode 100644 index 00000000000..55b6b38d0f0 --- /dev/null +++ b/libcxx/test/libcxx/utilities/any/size_and_alignment.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11 + +// <any> + +// Check that the size and alignment of any are what we expect. + +#include <any> + +int main() +{ +    using std::any; +    static_assert(sizeof(any) == sizeof(void*)*4, ""); +    static_assert(alignof(any) == alignof(void*), ""); +} diff --git a/libcxx/test/libcxx/utilities/any/small_type.pass.cpp b/libcxx/test/libcxx/utilities/any/small_type.pass.cpp new file mode 100644 index 00000000000..34d57c70573 --- /dev/null +++ b/libcxx/test/libcxx/utilities/any/small_type.pass.cpp @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11 + +// <any> + +// Check that the size and alignment of any are what we expect. + +#include <any> +#include "any_helpers.h" + +constexpr std::size_t BufferSize = (sizeof(void*) * 3); +constexpr std::size_t BufferAlignment = alignof(void*); +// Clang doesn't like "alignof(BufferAlignment * 2)" due to PR13986. +// So we create "DoubleBufferAlignment" instead. +constexpr std::size_t DoubleBufferAlignment = BufferAlignment * 2; + +class SmallThrowsDtor +{ +public: +    SmallThrowsDtor() {} +    SmallThrowsDtor(SmallThrowsDtor const &) noexcept {} +    SmallThrowsDtor(SmallThrowsDtor &&) noexcept {} +    ~SmallThrowsDtor() noexcept(false) {} +}; + + +struct alignas(1) MaxSizeType { +    char buff[BufferSize]; +}; + +struct alignas(BufferAlignment) MaxAlignType { +}; + +struct alignas(BufferAlignment) MaxSizeAndAlignType { +    char buff[BufferSize]; +}; + + +struct alignas(1) OverSizeType { +    char buff[BufferSize + 1]; +}; + +struct alignas(DoubleBufferAlignment) OverAlignedType { +}; + +struct alignas(DoubleBufferAlignment) OverSizeAndAlignedType { +    char buff[BufferSize + 1]; +}; + +int main() +{ +    using std::any; +    using std::__any_imp::_IsSmallObject; +    static_assert(_IsSmallObject<small>::value, ""); +    static_assert(_IsSmallObject<void*>::value, ""); +    static_assert(!_IsSmallObject<SmallThrowsDtor>::value, ""); +    static_assert(!_IsSmallObject<large>::value, ""); +    { +        // Check a type that meets the size requirement *exactly* and has +        // a lesser alignment requirement is considered small. +        typedef MaxSizeType T; +        static_assert(sizeof(T) == BufferSize, ""); +        static_assert(alignof(T) < BufferAlignment,   ""); +        static_assert(_IsSmallObject<T>::value, ""); +    } +    { +        // Check a type that meets the alignment requirement *exactly* and has +        // a lesser size is considered small. +        typedef MaxAlignType T; +        static_assert(sizeof(T) < BufferSize, ""); +        static_assert(alignof(T) == BufferAlignment,   ""); +        static_assert(_IsSmallObject<T>::value, ""); +    } +    { +        // Check a type that meets the size and alignment requirements *exactly* +        // is considered small. +        typedef MaxSizeAndAlignType T; +        static_assert(sizeof(T) == BufferSize, ""); +        static_assert(alignof(T) == BufferAlignment,   ""); +        static_assert(_IsSmallObject<T>::value, ""); +    } +    { +        // Check a type that meets the alignment requirements but is over-sized +        // is not considered small. +        typedef OverSizeType T; +        static_assert(sizeof(T) > BufferSize, ""); +        static_assert(alignof(T) < BufferAlignment, ""); +        static_assert(!_IsSmallObject<T>::value, ""); +    } +    { +        // Check a type that meets the size requirements but is over-aligned +        // is not considered small. +        typedef OverAlignedType T; +        static_assert(sizeof(T) < BufferSize, ""); +        static_assert(alignof(T) > BufferAlignment, ""); +        static_assert(!_IsSmallObject<T>::value, ""); +    } +    { +        // Check a type that exceeds both the size an alignment requirements +        // is not considered small. +        typedef OverSizeAndAlignedType T; +        static_assert(sizeof(T) > BufferSize, ""); +        static_assert(alignof(T) > BufferAlignment, ""); +        static_assert(!_IsSmallObject<T>::value, ""); +    } +} diff --git a/libcxx/test/libcxx/utilities/any/version.pass.cpp b/libcxx/test/libcxx/utilities/any/version.pass.cpp new file mode 100644 index 00000000000..5edee710d58 --- /dev/null +++ b/libcxx/test/libcxx/utilities/any/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +//                     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. +// +//===----------------------------------------------------------------------===// + +// <any> + +#include <any> + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp index 8ee575c408f..17b01fe630b 100644 --- a/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp @@ -18,7 +18,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp index 0a2d71967cd..49508febd94 100644 --- a/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp @@ -18,7 +18,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "test_macros.h"  using std::experimental::any; diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp index 8262990523c..b42a4ba2b05 100644 --- a/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp @@ -18,7 +18,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp index 3d0b34b2740..69341ca6b80 100644 --- a/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp @@ -16,7 +16,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp index b52c83fc388..3839e3afc81 100644 --- a/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp @@ -17,7 +17,7 @@  #include <type_traits>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp" diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp index 40534cb5506..2a050946afa 100644 --- a/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp @@ -18,7 +18,7 @@  #include <type_traits>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp index 7bb134efd28..a3ab0edc8b6 100644 --- a/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp @@ -23,7 +23,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp index 603490cef43..781ed73f2b3 100644 --- a/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp @@ -16,7 +16,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  int main()  { diff --git a/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp index 064935167eb..b1d31546896 100644 --- a/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp @@ -18,7 +18,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  using std::experimental::any;  using std::experimental::any_cast; diff --git a/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp index 8c681f37017..bdf0d511b81 100644 --- a/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp @@ -16,7 +16,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  int main()  { diff --git a/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp index 682b73bc98c..6d004840367 100644 --- a/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp +++ b/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp @@ -17,7 +17,7 @@  #include <experimental/any>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  int main()  { diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp index 9d9a5cdb472..46ddbe5b05a 100644 --- a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp @@ -21,7 +21,7 @@  #include <type_traits>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  using std::experimental::any;  using std::experimental::any_cast; diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp index e97560937fb..7efbafff83c 100644 --- a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -24,7 +24,7 @@  #include <type_traits>  #include <cassert> -#include "any_helpers.h" +#include "experimental_any_helpers.h"  #include "count_new.hpp"  #include "test_macros.h" diff --git a/libcxx/test/std/utilities/any/any.class/any.assign/copy.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.assign/copy.pass.cpp new file mode 100644 index 00000000000..fc76a2d8b95 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.assign/copy.pass.cpp @@ -0,0 +1,197 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any& operator=(any const &); + +// Test copy assignment + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template <class LHS, class RHS> +void test_copy_assign() { +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    LHS::reset(); +    RHS::reset(); +    { +        any lhs(LHS(1)); +        any const rhs(RHS(2)); + +        assert(LHS::count == 1); +        assert(RHS::count == 1); +        assert(RHS::copied == 0); + +        lhs = rhs; + +        assert(RHS::copied == 1); +        assert(LHS::count == 0); +        assert(RHS::count == 2); + +        assertContains<RHS>(lhs, 2); +        assertContains<RHS>(rhs, 2); +    } +    assert(LHS::count == 0); +    assert(RHS::count == 0); +} + +template <class LHS> +void test_copy_assign_empty() { +    assert(LHS::count == 0); +    LHS::reset(); +    { +        any lhs; +        any const rhs(LHS(42)); + +        assert(LHS::count == 1); +        assert(LHS::copied == 0); + +        lhs = rhs; + +        assert(LHS::copied == 1); +        assert(LHS::count == 2); + +        assertContains<LHS>(lhs, 42); +        assertContains<LHS>(rhs, 42); +    } +    assert(LHS::count == 0); +    LHS::reset(); +    { +        any lhs(LHS(1)); +        any const rhs; + +        assert(LHS::count == 1); +        assert(LHS::copied == 0); + +        lhs = rhs; + +        assert(LHS::copied == 0); +        assert(LHS::count == 0); + +        assertEmpty<LHS>(lhs); +        assertEmpty(rhs); +    } +    assert(LHS::count == 0); +} + +void test_copy_assign_self() { +    // empty +    { +        any a; +        a = a; +        assertEmpty(a); +        assert(globalMemCounter.checkOutstandingNewEq(0)); +    } +    assert(globalMemCounter.checkOutstandingNewEq(0)); +    // small +    { +        any a((small(1))); +        assert(small::count == 1); + +        a = a; + +        assert(small::count == 1); +        assertContains<small>(a, 1); +        assert(globalMemCounter.checkOutstandingNewEq(0)); +    } +    assert(small::count == 0); +    assert(globalMemCounter.checkOutstandingNewEq(0)); +    // large +    { +        any a(large(1)); +        assert(large::count == 1); + +        a = a; + +        assert(large::count == 1); +        assertContains<large>(a, 1); +        assert(globalMemCounter.checkOutstandingNewEq(1)); +    } +    assert(large::count == 0); +    assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +template <class Tp> +void test_copy_assign_throws() +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    auto try_throw = +    [](any& lhs, any const& rhs) { +        try { +            lhs = rhs; +            assert(false); +        } catch (my_any_exception const &) { +            // do nothing +        } catch (...) { +            assert(false); +        } +    }; +    // const lvalue to empty +    { +        any lhs; +        any const rhs((Tp(1))); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(Tp::count == 1); +        assertEmpty<Tp>(lhs); +        assertContains<Tp>(rhs); +    } +    { +        any lhs((small(2))); +        any const rhs((Tp(1))); +        assert(small::count == 1); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(small::count == 1); +        assert(Tp::count == 1); +        assertContains<small>(lhs, 2); +        assertContains<Tp>(rhs); +    } +    { +        any lhs((large(2))); +        any const rhs((Tp(1))); +        assert(large::count == 1); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(large::count == 1); +        assert(Tp::count == 1); +        assertContains<large>(lhs, 2); +        assertContains<Tp>(rhs); +    } +#endif +} + +int main() { +    test_copy_assign<small1, small2>(); +    test_copy_assign<large1, large2>(); +    test_copy_assign<small, large>(); +    test_copy_assign<large, small>(); +    test_copy_assign_empty<small>(); +    test_copy_assign_empty<large>(); +    test_copy_assign_self(); +    test_copy_assign_throws<small_throws_on_copy>(); +    test_copy_assign_throws<large_throws_on_copy>(); +} diff --git a/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp new file mode 100644 index 00000000000..bac3edb7cdb --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any& operator=(any &&); + +// Test move assignment. + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template <class LHS, class RHS> +void test_move_assign() { +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    { +        LHS const s1(1); +        any a(s1); +        RHS const s2(2); +        any a2(s2); + +        assert(LHS::count == 2); +        assert(RHS::count == 2); + +        a = std::move(a2); + +        assert(LHS::count == 1); +        assert(RHS::count == 2); + +        assertContains<RHS>(a, 2); +        assertEmpty<RHS>(a2); +    } +    assert(LHS::count == 0); +    assert(RHS::count == 0); +} + +template <class LHS> +void test_move_assign_empty() { +    assert(LHS::count == 0); +    { +        any a; +        any  a2((LHS(1))); + +        assert(LHS::count == 1); + +        a = std::move(a2); + +        assert(LHS::count == 1); + +        assertContains<LHS>(a, 1); +        assertEmpty<LHS>(a2); +    } +    assert(LHS::count == 0); +    { +        any a((LHS(1))); +        any a2; + +        assert(LHS::count == 1); + +        a = std::move(a2); + +        assert(LHS::count == 0); + +        assertEmpty<LHS>(a); +        assertEmpty(a2); +    } +    assert(LHS::count == 0); +} + +void test_move_assign_noexcept() { +    any a1; +    any a2; +    static_assert( +        noexcept(a1 = std::move(a2)) +      , "any & operator=(any &&) must be noexcept" +      ); +} + +int main() { +    test_move_assign_noexcept(); +    test_move_assign<small1, small2>(); +    test_move_assign<large1, large2>(); +    test_move_assign<small, large>(); +    test_move_assign<large, small>(); +    test_move_assign_empty<small>(); +    test_move_assign_empty<large>(); +} diff --git a/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp new file mode 100644 index 00000000000..d844fcfaa7c --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp @@ -0,0 +1,205 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any& operator=(any const &); + +// Test value copy and move assignment. + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template <class LHS, class RHS> +void test_assign_value() { +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    LHS::reset(); +    RHS::reset(); +    { +        any lhs(LHS(1)); +        any const rhs(RHS(2)); + +        assert(LHS::count == 1); +        assert(RHS::count == 1); +        assert(RHS::copied == 0); + +        lhs = rhs; + +        assert(RHS::copied == 1); +        assert(LHS::count == 0); +        assert(RHS::count == 2); + +        assertContains<RHS>(lhs, 2); +        assertContains<RHS>(rhs, 2); +    } +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    LHS::reset(); +    RHS::reset(); +    { +        any lhs(LHS(1)); +        any rhs(RHS(2)); + +        assert(LHS::count == 1); +        assert(RHS::count == 1); +        assert(RHS::moved == 1); + +        lhs = std::move(rhs); + +        assert(RHS::moved >= 1); +        assert(RHS::copied == 0); +        assert(LHS::count == 0); +        assert(RHS::count == 1); + +        assertContains<RHS>(lhs, 2); +        assertEmpty<RHS>(rhs); +    } +    assert(LHS::count == 0); +    assert(RHS::count == 0); +} + +template <class RHS> +void test_assign_value_empty() { +    assert(RHS::count == 0); +    RHS::reset(); +    { +        any lhs; +        RHS rhs(42); +        assert(RHS::count == 1); +        assert(RHS::copied == 0); + +        lhs = rhs; + +        assert(RHS::count == 2); +        assert(RHS::copied == 1); +        assert(RHS::moved >= 0); +        assertContains<RHS>(lhs, 42); +    } +    assert(RHS::count == 0); +    RHS::reset(); +    { +        any lhs; +        RHS rhs(42); +        assert(RHS::count == 1); +        assert(RHS::moved == 0); + +        lhs = std::move(rhs); + +        assert(RHS::count == 2); +        assert(RHS::copied == 0); +        assert(RHS::moved >= 1); +        assertContains<RHS>(lhs, 42); +    } +    assert(RHS::count == 0); +    RHS::reset(); +} + + +template <class Tp, bool Move = false> +void test_assign_throws() { +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    auto try_throw= +    [](any& lhs, auto&& rhs) { +        try { +            Move ? lhs = std::move(rhs) +                 : lhs = rhs; +            assert(false); +        } catch (my_any_exception const &) { +            // do nothing +        } catch (...) { +            assert(false); +        } +    }; +    // const lvalue to empty +    { +        any lhs; +        Tp rhs(1); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(Tp::count == 1); +        assertEmpty<Tp>(lhs); +    } +    { +        any lhs((small(2))); +        Tp  rhs(1); +        assert(small::count == 1); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(small::count == 1); +        assert(Tp::count == 1); +        assertContains<small>(lhs, 2); +    } +    { +        any lhs((large(2))); +        Tp rhs(1); +        assert(large::count == 1); +        assert(Tp::count == 1); + +        try_throw(lhs, rhs); + +        assert(large::count == 1); +        assert(Tp::count == 1); +        assertContains<large>(lhs, 2); +    } +#endif +} + + +// Test that any& operator=(ValueType&&) is *never* selected for: +// * std::in_place type. +// * Non-copyable types +void test_sfinae_constraints() { +    { +        using Tag = std::in_place_type_t<int>; +        using RawTag = std::remove_reference_t<Tag>; +        static_assert(!std::is_assignable<std::any, RawTag&&>::value, ""); +    } +    { +        struct Dummy { Dummy() = delete; }; +        using T = std::in_place_type_t<Dummy>; +        static_assert(!std::is_assignable<std::any, T>::value, ""); +    } +    { +        // Test that the ValueType&& constructor SFINAE's away when the +        // argument is non-copyable +        struct NoCopy { +          NoCopy() = default; +          NoCopy(NoCopy const&) = delete; +          NoCopy(NoCopy&&) = default; +        }; +        static_assert(!std::is_assignable<std::any, NoCopy>::value, ""); +    } +} + +int main() { +    test_assign_value<small1, small2>(); +    test_assign_value<large1, large2>(); +    test_assign_value<small, large>(); +    test_assign_value<large, small>(); +    test_assign_value_empty<small>(); +    test_assign_value_empty<large>(); +    test_assign_throws<small_throws_on_copy>(); +    test_assign_throws<large_throws_on_copy>(); +    test_assign_throws<throws_on_move, /* Move = */ true>(); +    test_sfinae_constraints(); +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp new file mode 100644 index 00000000000..03870caa531 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any(any const &); + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template <class Type> +void test_copy_throws() { +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    assert(Type::count == 0); +    { +        any const a((Type(42))); +        assert(Type::count == 1); +        try { +            any const a2(a); +            assert(false); +        } catch (my_any_exception const &) { +            // do nothing +        } catch (...) { +            assert(false); +        } +        assert(Type::count == 1); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +#endif +} + +void test_copy_empty() { +    DisableAllocationGuard g; ((void)g); // No allocations should occur. +    any a1; +    any a2(a1); + +    assertEmpty(a1); +    assertEmpty(a2); +} + +template <class Type> +void test_copy() +{ +    // Copying small types should not perform any allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    assert(Type::count == 0); +    Type::reset(); +    { +        any a((Type(42))); +        assert(Type::count == 1); +        assert(Type::copied == 0); + +        any a2(a); + +        assert(Type::copied == 1); +        assert(Type::count == 2); +        assertContains<Type>(a, 42); +        assertContains<Type>(a, 42); + +        // Modify a and check that a2 is unchanged +        modifyValue<Type>(a, -1); +        assertContains<Type>(a, -1); +        assertContains<Type>(a2, 42); + +        // modify a2 and check that a is unchanged +        modifyValue<Type>(a2, 999); +        assertContains<Type>(a, -1); +        assertContains<Type>(a2, 999); + +        // clear a and check that a2 is unchanged +        a.reset(); +        assertEmpty(a); +        assertContains<Type>(a2, 999); +    } +    assert(Type::count == 0); +} + +int main() { +    test_copy<small>(); +    test_copy<large>(); +    test_copy_empty(); +    test_copy_throws<small_throws_on_copy>(); +    test_copy_throws<large_throws_on_copy>(); +} diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/default.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/default.pass.cpp new file mode 100644 index 00000000000..9f9b826b612 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.cons/default.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any() noexcept; + +#include <any> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "any_helpers.h" +#include "count_new.hpp" + +#if TEST_HAS_BUILTIN_IDENTIFIER(__has_constant_initializer) +// std::any must have a constexpr default constructor, but it's a non-literal +// type so we can't create a constexpr variable. This tests that we actually +// get 'constant initialization'. +std::any a; +static_assert(__has_constant_initializer(a), +              "any must be constant initializable"); +#endif + +int main() +{ +    using std::any; +    { +        static_assert( +            std::is_nothrow_default_constructible<any>::value +          , "Must be default constructible" +          ); +    } +    { +        DisableAllocationGuard g; ((void)g); +        any const a; +        assertEmpty(a); +    } +} diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp new file mode 100644 index 00000000000..949c105f988 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class T, class ...Args> any(in_place_type_t<T>, Args&&...); +// template <class T, class U, class ...Args> +// any(in_place_type_t<T>, initializer_list<U>, Args&&...); + +// Test construction from a value. +// Concerns: +// --------- +// 1. The value is properly move/copied depending on the value category. +// 2. Both small and large values are properly handled. + + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" +#include "test_convertible.hpp" + +using std::any; +using std::any_cast; + +template <class Type> +void test_in_place_type() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Type>); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 0); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Type>, 101); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 101); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Type>, -1, 42, -1); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +} + +template <class Type> +void test_in_place_type_tracked() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    { +        any a(std::in_place<Type>); +        assertArgsMatch<Type>(a); +    } +    { +        any a(std::in_place<Type>, -1, 42, -1); +        assertArgsMatch<Type, int, int, int>(a); +    } +    // initializer_list constructor tests +    { +        any a(std::in_place<Type>, {-1, 42, -1}); +        assertArgsMatch<Type, std::initializer_list<int>>(a); +    } +    { +        int x = 42; +        any a(std::in_place<Type>, {-1, 42, -1}, x); +        assertArgsMatch<Type, std::initializer_list<int>, int&>(a); +    } +} + +void test_ctor_sfinae() { +    { +        // Test that the init-list ctor SFINAE's away properly when +        // construction would be ill-formed. +        using IL = std::initializer_list<int>; +        static_assert(!std::is_constructible<std::any, +                      std::in_place_type_t<int>, IL>::value, ""); +        static_assert(std::is_constructible<std::any, +            std::in_place_type_t<small_tracked_t>, IL>::value, ""); +    } +    { +        // Test that the tagged dispatch constructor SFINAE's away when the +        // argument is non-copyable +        struct NoCopy { +          NoCopy() = default; +          NoCopy(NoCopy const&) = delete; +          NoCopy(int) {} +          NoCopy(std::initializer_list<int>, int) {} +        }; +        using Tag = std::in_place_type_t<NoCopy>; +        using IL = std::initializer_list<int>; +        static_assert(!std::is_constructible<std::any, Tag>::value, ""); +        static_assert(!std::is_constructible<std::any, Tag, int>::value, ""); +        static_assert(!std::is_constructible<std::any, Tag, IL, int>::value, ""); +    } +} + +struct Implicit { +  Implicit(int) {} +  Implicit(int, int, int) {} +  Implicit(std::initializer_list<int>, int) {} +}; + +void test_constructor_explicit() { +    using I = Implicit; +    using IT = std::in_place_type_t<I>; +    static_assert(!test_convertible<std::any, IT, int>(), ""); +    static_assert(std::is_constructible<std::any, IT, int>::value, ""); +    static_assert(!test_convertible<std::any, IT, int, int, int>(), ""); +    static_assert(std::is_constructible<std::any, IT, int, int, int>::value, ""); +    static_assert(!test_convertible<std::any, IT, std::initializer_list<int>&, int>(), ""); +    static_assert(std::is_constructible<std::any, IT, std::initializer_list<int>&, int>::value, ""); +} + +int main() { +    test_in_place_type<small>(); +    test_in_place_type<large>(); +    test_in_place_type<small_throws_on_copy>(); +    test_in_place_type<large_throws_on_copy>(); +    test_in_place_type<throws_on_move>(); +    test_in_place_type_tracked<small_tracked_t>(); +    test_in_place_type_tracked<large_tracked_t>(); +    test_ctor_sfinae(); +    test_constructor_explicit(); +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp new file mode 100644 index 00000000000..9a83e66ab8a --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any(any &&) noexcept; + +#include <any> +#include <utility> +#include <type_traits> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +// Moves are always noexcept. The throws_on_move object +// must be stored dynamically so the pointer is moved and +// not the stored object. +void test_move_does_not_throw() +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    assert(throws_on_move::count == 0); +    { +        throws_on_move v(42); +        any a(v); +        assert(throws_on_move::count == 2); +        // No allocations should be performed after this point. +        DisableAllocationGuard g; ((void)g); +        try { +            any const a2(std::move(a)); +            assertEmpty(a); +            assertContains<throws_on_move>(a2, 42); +        } catch (...) { +            assert(false); +        } +        assert(throws_on_move::count == 1); +        assertEmpty(a); +    } +    assert(throws_on_move::count == 0); +#endif +} + +void test_move_empty() { +    DisableAllocationGuard g; ((void)g); // no allocations should be performed. + +    any a1; +    any a2(std::move(a1)); + +    assertEmpty(a1); +    assertEmpty(a2); +} + +template <class Type> +void test_move() { +    assert(Type::count == 0); +    Type::reset(); +    { +        any a((Type(42))); +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); + +        // Moving should not perform allocations since it must be noexcept. +        DisableAllocationGuard g; ((void)g); + +        any a2(std::move(a)); + +        assert(Type::moved >= 1); // zero or more move operations can be performed. +        assert(Type::copied == 0); // no copies can be performed. +        assert(Type::count == 1); +        assertEmpty(a); // Moves are always destructive. +        assertContains<Type>(a2, 42); +    } +    assert(Type::count == 0); +} + +int main() +{ +    // noexcept test +    { +        static_assert( +            std::is_nothrow_move_constructible<any>::value +          , "any must be nothrow move constructible" +          ); +    } +    test_move<small>(); +    test_move<large>(); +    test_move_empty(); +    test_move_does_not_throw(); +} diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp new file mode 100644 index 00000000000..ba5419b1245 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp @@ -0,0 +1,184 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class Value> any(Value &&) + +// Test construction from a value. +// Concerns: +// --------- +// 1. The value is properly move/copied depending on the value category. +// 2. Both small and large values are properly handled. + + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + + +template <class Type> +void test_copy_value_throws() +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    assert(Type::count == 0); +    { +        Type const t(42); +        assert(Type::count == 1); +        try { +            any const a2(t); +            assert(false); +        } catch (my_any_exception const &) { +            // do nothing +        } catch (...) { +            assert(false); +        } +        assert(Type::count == 1); +        assert(t.value == 42); +    } +    assert(Type::count == 0); +#endif +} + +void test_move_value_throws() +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    assert(throws_on_move::count == 0); +    { +        throws_on_move v; +        assert(throws_on_move::count == 1); +        try { +            any const a(std::move(v)); +            assert(false); +        } catch (my_any_exception const &) { +            // do nothing +        } catch (...) { +            assert(false); +        } +        assert(throws_on_move::count == 1); +    } +    assert(throws_on_move::count == 0); +#endif +} + +template <class Type> +void test_copy_move_value() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    assert(Type::count == 0); +    Type::reset(); +    { +        Type t(42); +        assert(Type::count == 1); + +        any a(t); + +        assert(Type::count == 2); +        assert(Type::copied == 1); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        Type t(42); +        assert(Type::count == 1); + +        any a(std::move(t)); + +        assert(Type::count == 2); +        assert(Type::copied == 0); +        assert(Type::moved == 1); +        assertContains<Type>(a, 42); +    } +} + +void test_non_moveable_type() +{ +    using Type = deleted_move; +    { +        deleted_move mv(42); +        std::any a(mv); +        assert(Type::count == 2); +        assert(Type::copied == 1); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        deleted_move mv(42); +        std::any a(std::move(mv)); +        assert(Type::count == 2); +        assert(Type::copied == 1); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +} + + + +// Test that any(ValueType&&) is *never* selected for a std::in_place type. +void test_sfinae_constraints() { +    using Tag = std::in_place_type_t<int>; +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif +    static_assert(std::is_same<Tag, const Tag>::value, ""); +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +    // Test that the tag type is properly handled in SFINAE +    Tag t = std::in_place; +    { +        std::any a(t); +        assertContains<int>(a, 0); +    } +    { +        std::any a(std::move(t)); +        assertContains<int>(a, 0); +    } +    { +        struct Dummy { Dummy() = delete; }; +        using T = std::in_place_type_t<Dummy>; +        static_assert(!std::is_constructible<std::any, T>::value, ""); +    } +    { +        // Test that the ValueType&& constructor SFINAE's away when the +        // argument is non-copyable +        struct NoCopy { +          NoCopy() = default; +          NoCopy(NoCopy const&) = delete; +          NoCopy(int) {} +        }; +        static_assert(!std::is_constructible<std::any, NoCopy>::value, ""); +        static_assert(!std::is_convertible<NoCopy, std::any>::value, ""); +    } +} + +int main() { +    test_copy_move_value<small>(); +    test_copy_move_value<large>(); +    test_copy_value_throws<small_throws_on_copy>(); +    test_copy_value_throws<large_throws_on_copy>(); +    test_move_value_throws(); +    test_non_moveable_type(); +    test_sfinae_constraints(); +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000..fa8b093d304 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp @@ -0,0 +1,255 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class T, class ...Args> emplace(Args&&...); +// template <class T, class U, class ...Args> +// void emplace(initializer_list<U>, Args&&...); + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +struct Tracked { +  static int count; +  Tracked()  {++count;} +  ~Tracked() { --count; } +}; +int Tracked::count = 0; + +template <class Type> +void test_emplace_type() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); + +        a.emplace<Type>(); + +        assert(Tracked::count == 0); +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 0); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); + +        a.emplace<Type>(101); + +        assert(Tracked::count == 0); +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 101); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); + +        a.emplace<Type>(-1, 42, -1); + +        assert(Tracked::count == 0); +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +} + +template <class Type> +void test_emplace_type_tracked() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); +        a.emplace<Type>(); +        assert(Tracked::count == 0); +        assertArgsMatch<Type>(a); +    } +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); +        a.emplace<Type>(-1, 42, -1); +        assert(Tracked::count == 0); +        assertArgsMatch<Type, int, int, int>(a); +    } +    // initializer_list constructor tests +    { +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); +        a.emplace<Type>({-1, 42, -1}); +        assert(Tracked::count == 0); +        assertArgsMatch<Type, std::initializer_list<int>>(a); +    } +    { +        int x = 42; +        any a(std::in_place<Tracked>); +        assert(Tracked::count == 1); +        a.emplace<Type>({-1, 42, -1}, x); +        assert(Tracked::count == 0); +        assertArgsMatch<Type, std::initializer_list<int>, int&>(a); +    } +} + +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct SmallThrows { +  SmallThrows(int) { throw 42; } +  SmallThrows(std::initializer_list<int>, int) { throw 42; } +}; +static_assert(IsSmallObject<SmallThrows>::value, ""); + +struct LargeThrows { +  LargeThrows(int) { throw 42; } +  LargeThrows(std::initializer_list<int>, int) { throw 42; } +  int data[10]; +}; +static_assert(!IsSmallObject<LargeThrows>::value, ""); + +template <class Type> +void test_emplace_throws() +{ +    // any stores small type +    { +        std::any a(small{42}); +        assert(small::count == 1); +        try { +            a.emplace<Type>(101); +            assert(false); +        } catch (int const&) { +        } +        assert(small::count == 0); +    } +    { +        std::any a(small{42}); +        assert(small::count == 1); +        try { +            a.emplace<Type>({1, 2, 3}, 101); +            assert(false); +        } catch (int const&) { +        } +        assert(small::count == 0); +    } +    // any stores large type +    { +        std::any a(large{42}); +        assert(large::count == 1); +        try { +            a.emplace<Type>(101); +            assert(false); +        } catch (int const&) { +        } +        assert(large::count == 0); +    } +    { +        std::any a(large{42}); +        assert(large::count == 1); +        try { +            a.emplace<Type>({1, 2, 3}, 101); +            assert(false); +        } catch (int const&) { +        } +        assert(large::count == 0); +    } +} + +#endif + +template <class T, class ...Args> +constexpr auto has_emplace(int) +    -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; } + +template <class ...Args> +constexpr bool has_emplace(long) { return false; } + +template <class ...Args> +constexpr bool has_emplace() { return has_emplace<Args...>(0); } + + +template <class T, class IT, class ...Args> +constexpr auto has_emplace_init_list(int) +    -> decltype(std::any{}.emplace<T>( +        {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()}, +        std::declval<Args>()...), true) { return true; } + +template <class ...Args> +constexpr bool has_emplace_init_list(long) { return false; } + +template <class ...Args> +constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); } + + +void test_emplace_sfinae_constraints() { +    { +        static_assert(has_emplace<int>(), ""); +        static_assert(has_emplace<int, int>(), ""); +        static_assert(!has_emplace<int, int, int>(), "not constructible"); +        static_assert(!has_emplace_init_list<int, int>(), "not constructible from il"); +    } +    { +        static_assert(has_emplace<small>(), ""); +        static_assert(has_emplace<large>(), ""); +        static_assert(!has_emplace<small, void*>(), ""); +        static_assert(!has_emplace<large, void*>(), ""); + +        static_assert(has_emplace_init_list<small, int>(), ""); +        static_assert(has_emplace_init_list<large, int>(), ""); +        static_assert(!has_emplace_init_list<small, void*>(), ""); +        static_assert(!has_emplace_init_list<large, void*>(), ""); +    } +    { +        // Test that the emplace SFINAE's away when the +        // argument is non-copyable +        struct NoCopy { +          NoCopy() = default; +          NoCopy(NoCopy const&) = delete; +          NoCopy(int) {} +          NoCopy(std::initializer_list<int>, int, int) {} +        }; +        static_assert(!has_emplace<NoCopy>(), ""); +        static_assert(!has_emplace<NoCopy, int>(), ""); +        static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), ""); +    } +} + +int main() { +    test_emplace_type<small>(); +    test_emplace_type<large>(); +    test_emplace_type<small_throws_on_copy>(); +    test_emplace_type<large_throws_on_copy>(); +    test_emplace_type<throws_on_move>(); +    test_emplace_type_tracked<small_tracked_t>(); +    test_emplace_type_tracked<large_tracked_t>(); +    test_emplace_sfinae_constraints(); +#ifndef TEST_HAS_NO_EXCEPTIONS +    test_emplace_throws<SmallThrows>(); +    test_emplace_throws<LargeThrows>(); +#endif +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.class/any.modifiers/reset.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.modifiers/reset.pass.cpp new file mode 100644 index 00000000000..31648a04e1a --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.modifiers/reset.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any::reset() noexcept + +#include <any> +#include <cassert> + +#include "any_helpers.h" + +int main() +{ +    using std::any; +    using std::any_cast; +    // empty +    { +        any a; + +        // noexcept check +        static_assert( +            noexcept(a.reset()) +          , "any.reset() must be noexcept" +          ); + +        assertEmpty(a); + +        a.reset(); + +        assertEmpty(a); +    } +    // small object +    { +        any a((small(1))); +        assert(small::count == 1); +        assertContains<small>(a, 1); + +        a.reset(); + +        assertEmpty<small>(a); +        assert(small::count == 0); +    } +    // large object +    { +        any a(large(1)); +        assert(large::count == 1); +        assertContains<large>(a); + +        a.reset(); + +        assertEmpty<large>(a); +        assert(large::count == 0); +    } +} diff --git a/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp new file mode 100644 index 00000000000..013982478ee --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any::swap(any &) noexcept + +// Test swap(large, small) and swap(small, large) + +#include <any> +#include <cassert> + +#include "any_helpers.h" + +using std::any; +using std::any_cast; + +template <class LHS, class RHS> +void test_swap() { +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    { +        any a1((LHS(1))); +        any a2(RHS{2}); +        assert(LHS::count == 1); +        assert(RHS::count == 1); + +        a1.swap(a2); + +        assert(LHS::count == 1); +        assert(RHS::count == 1); + +        assertContains<RHS>(a1, 2); +        assertContains<LHS>(a2, 1); +    } +    assert(LHS::count == 0); +    assert(RHS::count == 0); +    assert(LHS::copied == 0); +    assert(RHS::copied == 0); +} + +template <class Tp> +void test_swap_empty() { +    assert(Tp::count == 0); +    { +        any a1((Tp(1))); +        any a2; +        assert(Tp::count == 1); + +        a1.swap(a2); + +        assert(Tp::count == 1); + +        assertContains<Tp>(a2, 1); +        assertEmpty(a1); +    } +    assert(Tp::count == 0); +    { +        any a1((Tp(1))); +        any a2; +        assert(Tp::count == 1); + +        a2.swap(a1); + +        assert(Tp::count == 1); + +        assertContains<Tp>(a2, 1); +        assertEmpty(a1); +    } +    assert(Tp::count == 0); +    assert(Tp::copied == 0); +} + +void test_noexcept() +{ +    any a1; +    any a2; +    static_assert( +        noexcept(a1.swap(a2)) +      , "any::swap(any&) must be noexcept" +      ); +} + +int main() +{ +    test_noexcept(); +    test_swap_empty<small>(); +    test_swap_empty<large>(); +    test_swap<small1, small2>(); +    test_swap<large1, large2>(); +    test_swap<small, large>(); +    test_swap<large, small>(); +} diff --git a/libcxx/test/std/utilities/any/any.class/any.observers/has_value.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.observers/has_value.pass.cpp new file mode 100644 index 00000000000..072ac06776c --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.observers/has_value.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// any::has_value() noexcept + +#include <any> +#include <cassert> + +#include "any_helpers.h" + +int main() +{ +    using std::any; +    // noexcept test +    { +        any a; +        static_assert(noexcept(a.has_value()), "any::has_value() must be noexcept"); +    } +    // empty +    { +        any a; +        assert(!a.has_value()); + +        a.reset(); +        assert(!a.has_value()); + +        a = 42; +        assert(a.has_value()); +    } +    // small object +    { +        small const s(1); +        any a(s); +        assert(a.has_value()); + +        a.reset(); +        assert(!a.has_value()); + +        a = s; +        assert(a.has_value()); +    } +    // large object +    { +        large const l(1); +        any a(l); +        assert(a.has_value()); + +        a.reset(); +        assert(!a.has_value()); + +        a = l; +        assert(a.has_value()); +    } +} diff --git a/libcxx/test/std/utilities/any/any.class/any.observers/type.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.observers/type.pass.cpp new file mode 100644 index 00000000000..984c4137db0 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/any.observers/type.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// XFAIL: libcpp-no-rtti + +// <any> + +// any::type() noexcept + +#include <any> +#include <cassert> +#include "any_helpers.h" + +int main() +{ +    using std::any; +    { +        any const a; +        assert(a.type() == typeid(void)); +        static_assert(noexcept(a.type()), "any::type() must be noexcept"); +    } +    { +        small const s(1); +        any const a(s); +        assert(a.type() == typeid(small)); + +    } +    { +        large const l(1); +        any const a(l); +        assert(a.type() == typeid(large)); +    } +} diff --git a/libcxx/test/std/utilities/any/any.class/not_literal_type.pass.cpp b/libcxx/test/std/utilities/any/any.class/not_literal_type.pass.cpp new file mode 100644 index 00000000000..91ef5c970a2 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.class/not_literal_type.pass.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// [Note any is a not a literal type --end note] + +#include <any> +#include <type_traits> + +int main () { +    static_assert(!std::is_literal_type<std::any>::value, ""); +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp new file mode 100644 index 00000000000..0f4fc6ab7eb --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class ValueType> +// ValueType const* any_cast(any const *) noexcept; +// +// template <class ValueType> +// ValueType * any_cast(any *) noexcept; + +#include <any> +#include <type_traits> +#include <cassert> + +#include "any_helpers.h" + +using std::any; +using std::any_cast; + +// Test that the operators are properly noexcept. +void test_cast_is_noexcept() { +    any a; +    static_assert(noexcept(any_cast<int>(&a)), ""); + +    any const& ca = a; +    static_assert(noexcept(any_cast<int>(&ca)), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { +    any a; +    static_assert(std::is_same<decltype(any_cast<int>(&a)), int*>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const>(&a)), int const*>::value, ""); + +    any const& ca = a; +    static_assert(std::is_same<decltype(any_cast<int>(&ca)), int const*>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const>(&ca)), int const*>::value, ""); +} + +// Test that any_cast handles null pointers. +void test_cast_nullptr() { +    any* a = nullptr; +    assert(nullptr == any_cast<int>(a)); +    assert(nullptr == any_cast<int const>(a)); + +    any const* ca = nullptr; +    assert(nullptr == any_cast<int>(ca)); +    assert(nullptr == any_cast<int const>(ca)); +} + +// Test casting an empty object. +void test_cast_empty() { +    { +        any a; +        assert(nullptr == any_cast<int>(&a)); +        assert(nullptr == any_cast<int const>(&a)); + +        any const& ca = a; +        assert(nullptr == any_cast<int>(&ca)); +        assert(nullptr == any_cast<int const>(&ca)); +    } +    // Create as non-empty, then make empty and run test. +    { +        any a(42); +        a.reset(); +        assert(nullptr == any_cast<int>(&a)); +        assert(nullptr == any_cast<int const>(&a)); + +        any const& ca = a; +        assert(nullptr == any_cast<int>(&ca)); +        assert(nullptr == any_cast<int const>(&ca)); +    } +} + +template <class Type> +void test_cast() { +    assert(Type::count == 0); +    Type::reset(); +    { +        any a((Type(42))); +        any const& ca = a; +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); + +        // Try a cast to a bad type. +        // NOTE: Type cannot be an int. +        assert(any_cast<int>(&a) == nullptr); +        assert(any_cast<int const>(&a) == nullptr); +        assert(any_cast<int const volatile>(&a) == nullptr); + +        // Try a cast to the right type, but as a pointer. +        assert(any_cast<Type*>(&a) == nullptr); +        assert(any_cast<Type const*>(&a) == nullptr); + +        // Check getting a unqualified type from a non-const any. +        Type* v = any_cast<Type>(&a); +        assert(v != nullptr); +        assert(v->value == 42); + +        // change the stored value and later check for the new value. +        v->value = 999; + +        // Check getting a const qualified type from a non-const any. +        Type const* cv = any_cast<Type const>(&a); +        assert(cv != nullptr); +        assert(cv == v); +        assert(cv->value == 999); + +        // Check getting a unqualified type from a const any. +        cv = any_cast<Type>(&ca); +        assert(cv != nullptr); +        assert(cv == v); +        assert(cv->value == 999); + +        // Check getting a const-qualified type from a const any. +        cv = any_cast<Type const>(&ca); +        assert(cv != nullptr); +        assert(cv == v); +        assert(cv->value == 999); + +        // Check that no more objects were created, copied or moved. +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); +    } +    assert(Type::count == 0); +} + +void test_cast_non_copyable_type() +{ +    // Even though 'any' never stores non-copyable types +    // we still need to support any_cast<NoCopy>(ptr) +    struct NoCopy { NoCopy(NoCopy const&) = delete; }; +    std::any a(42); +    std::any const& ca = a; +    assert(std::any_cast<NoCopy>(&a) == nullptr); +    assert(std::any_cast<NoCopy>(&ca) == nullptr); +} + +int main() { +    test_cast_is_noexcept(); +    test_cast_return_type(); +    test_cast_nullptr(); +    test_cast_empty(); +    test_cast<small>(); +    test_cast<large>(); +    test_cast_non_copyable_type(); +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp new file mode 100644 index 00000000000..852e776ce2d --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -0,0 +1,396 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class ValueType> +// ValueType const any_cast(any const&); +// +// template <class ValueType> +// ValueType any_cast(any &); +// +// template <class ValueType> +// ValueType any_cast(any &&); + +#include <any> +#include <type_traits> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; +using std::bad_any_cast; + + +// Test that the operators are NOT marked noexcept. +void test_cast_is_not_noexcept() { +    any a; +    static_assert(!noexcept(any_cast<int>(static_cast<any&>(a))), ""); +    static_assert(!noexcept(any_cast<int>(static_cast<any const&>(a))), ""); +    static_assert(!noexcept(any_cast<int>(static_cast<any &&>(a))), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { +    any a; +    static_assert(std::is_same<decltype(any_cast<int>(a)), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const>(a)), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int&>(a)), int&>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const&>(a)), int const&>::value, ""); + +    static_assert(std::is_same<decltype(any_cast<int&&>(a)), int&&>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const&&>(a)), int const&&>::value, ""); + +    static_assert(std::is_same<decltype(any_cast<int>(std::move(a))), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const>(std::move(a))), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int&>(std::move(a))), int&>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const&>(std::move(a))), int const&>::value, ""); + +    static_assert(std::is_same<decltype(any_cast<int&&>(std::move(a))), int&&>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const&&>(std::move(a))), int const&&>::value, ""); + +    any const& ca = a; +    static_assert(std::is_same<decltype(any_cast<int>(ca)), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const>(ca)), int>::value, ""); +    static_assert(std::is_same<decltype(any_cast<int const&>(ca)), int const&>::value, ""); + +    static_assert(std::is_same<decltype(any_cast<int const&&>(ca)), int const&&>::value, ""); +} + +template <class Type, class ConstT = Type> +void checkThrows(any& a) +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) +    try { +        any_cast<Type>(a); +        assert(false); +    } catch (bad_any_cast const &) { +            // do nothing +    } catch (...) { +        assert(false); +    } + +    try { +        any_cast<ConstT>(static_cast<any const&>(a)); +        assert(false); +    } catch (bad_any_cast const &) { +            // do nothing +    } catch (...) { +        assert(false); +    } + +    try { +        any_cast<Type>(static_cast<any&&>(a)); +        assert(false); +    } catch (bad_any_cast const &) { +            // do nothing +    } catch (...) { +        assert(false); +    } +#endif +} + +void test_cast_empty() { +    // None of these operations should allocate. +    DisableAllocationGuard g; ((void)g); +    any a; +    checkThrows<int>(a); +} + +template <class Type> +void test_cast_to_reference() { +    assert(Type::count == 0); +    Type::reset(); +    { +        any a((Type(42))); +        any const& ca = a; +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); + +        // Try a cast to a bad type. +        // NOTE: Type cannot be an int. +        checkThrows<int>(a); +        checkThrows<int&, int const&>(a); +        checkThrows<Type*, Type const*>(a); +        checkThrows<Type const*>(a); + +        // Check getting a type by reference from a non-const lvalue any. +        { +            Type& v = any_cast<Type&>(a); +            assert(v.value == 42); + +            Type const &cv = any_cast<Type const&>(a); +            assert(&cv == &v); +        } +        // Check getting a type by reference from a const lvalue any. +        { +            Type const& v = any_cast<Type const&>(ca); +            assert(v.value == 42); + +            Type const &cv = any_cast<Type const&>(ca); +            assert(&cv == &v); +        } +        // Check getting a type by reference from a non-const rvalue +        { +            Type& v = any_cast<Type&>(std::move(a)); +            assert(v.value == 42); + +            Type const &cv = any_cast<Type const&>(std::move(a)); +            assert(&cv == &v); +        } +        // Check getting a type by reference from a const rvalue any. +        { +            Type const& v = any_cast<Type const&>(std::move(ca)); +            assert(v.value == 42); + +            Type const &cv = any_cast<Type const&>(std::move(ca)); +            assert(&cv == &v); +        } +        // Check getting a type by reference from a const rvalue any. +        { +            Type&& v = any_cast<Type&&>(std::move(a)); +            assert(v.value == 42); +            assert(any_cast<Type&>(a).value == 42); + +            Type&& cv = any_cast<Type&&>(std::move(a)); +            assert(&cv == &v); +            assert(any_cast<Type&>(a).value == 42); +        } +        // Check getting a type by reference from a const rvalue any. +        { +            Type const&& v = any_cast<Type const&&>(std::move(a)); +            assert(v.value == 42); +            assert(any_cast<Type&>(a).value == 42); + +            Type const&& cv = any_cast<Type const&&>(std::move(a)); +            assert(&cv == &v); +            assert(any_cast<Type&>(a).value == 42); +        } +        // Check that the original object hasn't been changed. +        assertContains<Type>(a, 42); + +        // Check that no objects have been created/copied/moved. +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); +    } +    assert(Type::count == 0); +} + +template <class Type> +void test_cast_to_value() { +    assert(Type::count == 0); +    Type::reset(); +    { +        any a((Type(42))); +        any const& ca = a; +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 1); + +        // Try a cast to a bad type. +        // NOTE: Type cannot be an int. +        checkThrows<int>(a); +        checkThrows<int&, int const&>(a); +        checkThrows<Type*, Type const*>(a); +        checkThrows<Type const*>(a); + +        Type::reset(); // NOTE: reset does not modify Type::count +        // Check getting Type by value from a non-const lvalue any. +        // This should cause the non-const copy constructor to be called. +        { +            Type t = any_cast<Type>(a); + +            assert(Type::count == 2); +            assert(Type::copied == 1); +            assert(Type::const_copied == 0); +            assert(Type::non_const_copied == 1); +            assert(Type::moved == 0); +            assert(t.value == 42); +        } +        assert(Type::count == 1); +        Type::reset(); +        // Check getting const Type by value from a non-const lvalue any. +        // This should cause the const copy constructor to be called. +        { +            Type t = any_cast<Type const>(a); + +            assert(Type::count == 2); +            assert(Type::copied == 1); +            assert(Type::const_copied == 1); +            assert(Type::non_const_copied == 0); +            assert(Type::moved == 0); +            assert(t.value == 42); +        } +        assert(Type::count == 1); +        Type::reset(); +        // Check getting Type by value from a non-const lvalue any. +        // This should cause the const copy constructor to be called. +        { +            Type t = any_cast<Type>(static_cast<any const&>(a)); + +            assert(Type::count == 2); +            assert(Type::copied == 1); +            assert(Type::const_copied == 1); +            assert(Type::non_const_copied == 0); +            assert(Type::moved == 0); +            assert(t.value == 42); +        } +        assert(Type::count == 1); +        Type::reset(); +        // Check getting Type by value from a non-const rvalue any. +        // This should cause the non-const copy constructor to be called. +        { +            Type t = any_cast<Type>(static_cast<any &&>(a)); + +            assert(Type::count == 2); +            assert(Type::moved == 1); +            assert(Type::copied == 0); +            assert(Type::const_copied == 0); +            assert(Type::non_const_copied == 0); +            assert(t.value == 42); +            assert(any_cast<Type&>(a).value == 0); +            any_cast<Type&>(a).value = 42; // reset the value +        } +        assert(Type::count == 1); +        Type::reset(); +        // Check getting const Type by value from a non-const rvalue any. +        // This should cause the const copy constructor to be called. +        { +            Type t = any_cast<Type const>(static_cast<any &&>(a)); + +            assert(Type::count == 2); +            assert(Type::copied == 1); +            assert(Type::const_copied == 1); +            assert(Type::non_const_copied == 0); +            assert(Type::moved == 0); +            assert(t.value == 42); +            assert(any_cast<Type&>(a).value == 42); +        } +        assert(Type::count == 1); +        Type::reset(); +        // Check getting Type by value from a const rvalue any. +        // This should cause the const copy constructor to be called. +        { +            Type t = any_cast<Type>(static_cast<any const&&>(a)); + +            assert(Type::count == 2); +            assert(Type::copied == 1); +            assert(Type::const_copied == 1); +            assert(Type::non_const_copied == 0); +            assert(Type::moved == 0); +            assert(t.value == 42); +            assert(any_cast<Type&>(a).value == 42); +        } +        // Ensure we still only have 1 Type object alive. +        assert(Type::count == 1); + +        // Check that the original object hasn't been changed. +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +} + +void test_cast_to_value_deleted_move() +{ +    using Type = deleted_move; +    { +        std::any a(deleted_move(42)); +        assert(Type::count == 1); +        assert(Type::copied == 1); +        assert(Type::moved == 0); + +        Type const& t = any_cast<Type>(a); +        assert(Type::count == 2); +        assert(Type::copied == 2); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        std::any a(deleted_move(42)); +        std::any const& ca = a; +        assert(Type::count == 1); +        assert(Type::copied == 1); +        assert(Type::moved == 0); + +        Type const& t = any_cast<Type>(ca); +        assert(Type::count == 2); +        assert(Type::copied == 2); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        std::any a(deleted_move(42)); +        assert(Type::count == 1); +        assert(Type::copied == 1); +        assert(Type::moved == 0); + +        Type&& t = any_cast<Type>(std::move(a)); +        assert(Type::count == 2); +        assert(Type::copied == 2); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        std::any a(deleted_move(42)); +        std::any const& ca = a; +        assert(Type::count == 1); +        assert(Type::copied == 1); +        assert(Type::moved == 0); + +        Type&& t = any_cast<Type>(std::move(ca)); +        assert(Type::count == 2); +        assert(Type::copied == 2); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +} + +// Even though you can't get a non-copyable class into std::any +// the standard requires that these overloads compile and function. +void test_non_copyable_ref() { +    struct no_copy +    { +        no_copy() {} +        no_copy(no_copy &&) {} +    private: +        no_copy(no_copy const &); +    }; + +    any a; +    checkThrows<no_copy &, no_copy const&>(a); +    checkThrows<no_copy const&>(a); +    assertEmpty(a); +} + +int main() { +    test_cast_is_not_noexcept(); +    test_cast_return_type(); +    test_cast_empty(); +    test_cast_to_reference<small>(); +    test_cast_to_reference<large>(); +    test_cast_to_value<small>(); +    test_cast_to_value<large>(); +    test_cast_to_value_deleted_move(); +    test_non_copyable_ref(); +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp new file mode 100644 index 00000000000..a141b05ef7c --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class ValueType> +// ValueType any_cast(any const &); + +// Try and cast away const. + +#include <any> + +struct TestType {}; +struct TestType2 {}; + +int main() +{ +    using std::any; +    using std::any_cast; + +    any a; + +    // expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType') to reference to type 'TestType' drops 'const' qualifier}} +    any_cast<TestType &>(static_cast<any const&>(a)); // expected-note {{requested here}} +    any_cast<TestType &&>(static_cast<any const&>(a)); // expected-note {{requested here}} + +    // expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType2') to reference to type 'TestType2' drops 'const' qualifier}} +    any_cast<TestType2 &>(static_cast<any const&&>(a)); // expected-note {{requested here}} +    any_cast<TestType2 &&>(static_cast<any const&&>(a)); // expected-note {{requested here}} +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp new file mode 100644 index 00000000000..415da8396db --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class ValueType> +// ValueType const any_cast(any const&); +// +// template <class ValueType> +// ValueType any_cast(any &); +// +// template <class ValueType> +// ValueType any_cast(any &&); + +// Test instantiating the any_cast with a non-copyable type. + +#include <any> + +using std::any; +using std::any_cast; + +struct no_copy +{ +    no_copy() {} +    no_copy(no_copy &&) {} +private: +    no_copy(no_copy const &); +}; + +int main() { +    any a; +    any_cast<no_copy>(static_cast<any&>(a)); // expected-note {{requested here}} +    any_cast<no_copy>(static_cast<any const&>(a)); // expected-note {{requested here}} +    any_cast<no_copy>(static_cast<any &&>(a)); // expected-note {{requested here}} +    // expected-error@any:* 3 {{static_assert failed "_ValueType is required to be a reference or a CopyConstructible type."}} +    // expected-error@any:* 2 {{calling a private constructor of class 'no_copy'}} +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/reference_types.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/reference_types.fail.cpp new file mode 100644 index 00000000000..99cc029971a --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/reference_types.fail.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class ValueType> +// ValueType const* any_cast(any const *) noexcept; +// +// template <class ValueType> +// ValueType * any_cast(any *) noexcept; + +#include <any> + +using std::any; +using std::any_cast; + +int main() +{ +    any a(1); +    any_cast<int &>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int &&>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int const &>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int const&&>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any const& a2 = a; +    any_cast<int &>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int &&>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int const &>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +    any_cast<int const &&>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp new file mode 100644 index 00000000000..143b60dd864 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +//                     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, c++11, c++14 + +// <any> + +// template <class T, class ...Args> any make_any(Args&&...); +// template <class T, class U, class ...Args> +// any make_any(initializer_list<U>, Args&&...); + +#include <any> +#include <cassert> + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + + +template <class Type> +void test_make_any_type() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    assert(Type::count == 0); +    Type::reset(); +    { +        any a = std::make_any<Type>(); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 0); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a = std::make_any<Type>(101); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 101); +    } +    assert(Type::count == 0); +    Type::reset(); +    { +        any a = std::make_any<Type>(-1, 42, -1); + +        assert(Type::count == 1); +        assert(Type::copied == 0); +        assert(Type::moved == 0); +        assertContains<Type>(a, 42); +    } +    assert(Type::count == 0); +    Type::reset(); +} + +template <class Type> +void test_make_any_type_tracked() { +    // constructing from a small type should perform no allocations. +    DisableAllocationGuard g(isSmallType<Type>()); ((void)g); +    { +        any a = std::make_any<Type>(); +        assertArgsMatch<Type>(a); +    } +    { +        any a = std::make_any<Type>(-1, 42, -1); +        assertArgsMatch<Type, int, int, int>(a); +    } +    // initializer_list constructor tests +    { +        any a = std::make_any<Type>({-1, 42, -1}); +        assertArgsMatch<Type, std::initializer_list<int>>(a); +    } +    { +        int x = 42; +        any a  = std::make_any<Type>({-1, 42, -1}, x); +        assertArgsMatch<Type, std::initializer_list<int>, int&>(a); +    } +} + +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct SmallThrows { +  SmallThrows(int) { throw 42; } +  SmallThrows(std::initializer_list<int>, int) { throw 42; } +}; +static_assert(IsSmallObject<SmallThrows>::value, ""); + +struct LargeThrows { +  LargeThrows(int) { throw 42; } +  LargeThrows(std::initializer_list<int>, int) { throw 42; } +  int data[10]; +}; +static_assert(!IsSmallObject<LargeThrows>::value, ""); + +template <class Type> +void test_make_any_throws() +{ +    { +        try { +            std::make_any<Type>(101); +            assert(false); +        } catch (int const&) { +        } +    } +    { +        try { +            std::make_any<Type>({1, 2, 3}, 101); +            assert(false); +        } catch (int const&) { +        } +    } +} + +#endif + +int main() { +    test_make_any_type<small>(); +    test_make_any_type<large>(); +    test_make_any_type<small_throws_on_copy>(); +    test_make_any_type<large_throws_on_copy>(); +    test_make_any_type<throws_on_move>(); +    test_make_any_type_tracked<small_tracked_t>(); +    test_make_any_type_tracked<large_tracked_t>(); +#ifndef TEST_HAS_NO_EXCEPTIONS +    test_make_any_throws<SmallThrows>(); +    test_make_any_throws<LargeThrows>(); + +#endif +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.nonmembers/swap.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/swap.pass.cpp new file mode 100644 index 00000000000..1b3785bb1c6 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/swap.pass.cpp @@ -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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <any> + +// void swap(any &, any &) noexcept + +// swap(...) just wraps any::swap(...). That function is tested elsewhere. + +#include <any> +#include <cassert> + +using std::any; +using std::any_cast; + +int main() +{ + +    { // test noexcept +        any a; +        static_assert(noexcept(swap(a, a)), "swap(any&, any&) must be noexcept"); +    } +    { +        any a1(1); +        any a2(2); + +        swap(a1, a2); + +        assert(any_cast<int>(a1) == 2); +        assert(any_cast<int>(a2) == 1); +    } +} diff --git a/libcxx/test/support/any_helpers.h b/libcxx/test/support/any_helpers.h index bb1ad175c1f..a0ff8dbc1f9 100644 --- a/libcxx/test/support/any_helpers.h +++ b/libcxx/test/support/any_helpers.h @@ -9,12 +9,14 @@  #ifndef ANY_HELPERS_H  #define ANY_HELPERS_H -#include <experimental/any>  #include <typeinfo>  #include <type_traits>  #include <cassert> +namespace std { namespace experimental {} } +  #include "test_macros.h" +#include "type_id.h"  #if !defined(TEST_HAS_NO_RTTI)  #define RTTI_ASSERT(X) assert(X) @@ -32,42 +34,55 @@ template <class _Tp>          >    {}; +template <class T> +bool containsType(std::any const& a) { +#if !defined(TEST_HAS_NO_RTTI) +    return a.type() == typeid(T); +#else +    return a.has_value() && std::any_cast<T>(&a) != nullptr; +#endif +}  // Return 'true' if 'Type' will be considered a small type by 'any'  template <class Type>  bool isSmallType() { -#if defined(_LIBCPP_VERSION) -    return std::experimental::__any_imp::_IsSmallObject<Type>::value; -#else      return IsSmallObject<Type>::value; -#endif -  }  // Assert that an object is empty. If the object used to contain an object  // of type 'LastType' check that it can no longer be accessed.  template <class LastType = int> -void assertEmpty(std::experimental::any const& a) { -    assert(a.empty()); +void assertEmpty(std::any const& a) { +    using namespace std; +    assert(!a.has_value());      RTTI_ASSERT(a.type() == typeid(void)); -    assert(std::experimental::any_cast<LastType const>(&a) == nullptr); +    assert(any_cast<LastType const>(&a) == nullptr);  }  // Assert that an 'any' object stores the specified 'Type' and 'value'.  template <class Type> -void assertContains(std::experimental::any const& a, int value = 1) { -    assert(!a.empty()); -    RTTI_ASSERT(a.type() == typeid(Type)); -    assert(std::experimental::any_cast<Type const &>(a).value == value); +void assertContains(std::any const& a, int value = 1) { +    assert(a.has_value()); +    assert(containsType<Type>(a)); +    assert(std::any_cast<Type const &>(a).value == value); +} + +template <> +void assertContains<int>(std::any const& a, int value) { +    assert(a.has_value()); +    assert(containsType<int>(a)); +    assert(std::any_cast<int const &>(a) == value);  }  // Modify the value of a "test type" stored within an any to the specified  // 'value'.  template <class Type> -void modifyValue(std::experimental::any& a, int value) { -    assert(!a.empty()); -    RTTI_ASSERT(a.type() == typeid(Type)); -    std::experimental::any_cast<Type&>(a).value = value; +void modifyValue(std::any& a, int value) { +    using namespace std; +    using namespace std::experimental; +    assert(a.has_value()); +    assert(containsType<Type>(a)); +    any_cast<Type&>(a).value = value;  }  // A test type that will trigger the small object optimization within 'any'. @@ -89,25 +104,31 @@ struct small_type      int value; -    explicit small_type(int val) : value(val) { +    explicit small_type(int val = 0) : value(val) { +        ++count; +    } +    explicit small_type(int, int val, int) : value(val) { +        ++count; +    } +    small_type(std::initializer_list<int> il) : value(*il.begin()) {          ++count;      } -    small_type(small_type const & other) throw() { +    small_type(small_type const & other) noexcept {          value = other.value;          ++count;          ++copied;          ++const_copied;      } -    small_type(small_type& other) throw() { +    small_type(small_type& other) noexcept {          value = other.value;          ++count;          ++copied;          ++non_const_copied;      } -    small_type(small_type && other) throw() { +    small_type(small_type && other) noexcept {          value = other.value;          other.value = 0;          ++count; @@ -163,11 +184,17 @@ struct large_type      int value; -    large_type(int val) : value(val) { +    large_type(int val = 0) : value(val) {          ++count;          data[0] = 0;      } - +    large_type(int, int val, int) : value(val) { +        ++count; +        data[0] = 0; +    } +    large_type(std::initializer_list<int> il) : value(*il.begin()) { +        ++count; +    }      large_type(large_type const & other) {          value = other.value;          ++count; @@ -219,6 +246,67 @@ typedef large_type<> large;  typedef large_type<1> large1;  typedef large_type<2> large2; + +struct deleted_move +{ +    static int count; +    static int copied; +    static int moved; +    static int const_copied; +    static int non_const_copied; + +    static void reset() { +        deleted_move::copied = 0; +        deleted_move::moved = 0; +        deleted_move::const_copied = 0; +        deleted_move::non_const_copied = 0; +    } + +    int value; + +    explicit deleted_move(int val = 0) : value(val) { +        ++count; +    } +    explicit deleted_move(int, int val, int) : value(val) { +        ++count; +    } +    deleted_move(std::initializer_list<int> il) : value(*il.begin()) { +        ++count; +    } + +    deleted_move(deleted_move const & other) noexcept { +        value = other.value; +        ++count; +        ++copied; +        ++const_copied; +    } + +    deleted_move(deleted_move& other) noexcept { +        value = other.value; +        ++count; +        ++copied; +        ++non_const_copied; +    } + +    deleted_move(deleted_move && other) = delete; + +    ~deleted_move() { +        value = -1; +        --count; +    } + +private: +    deleted_move& operator=(deleted_move const&) = delete; +    deleted_move& operator=(deleted_move&&) = delete; +}; + +int deleted_move::count = 0; +int deleted_move::copied = 0; +int deleted_move::moved = 0; +int deleted_move::const_copied = 0; +int deleted_move::non_const_copied = 0; + +  // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'  // and 'throws_on_move'.  struct my_any_exception {}; @@ -236,19 +324,24 @@ void throwMyAnyExpression() {  struct small_throws_on_copy  {      static int count; +    static int copied; +    static int moved; +    static void reset() { count = copied = moved = 0; }      int value;      explicit small_throws_on_copy(int val = 0) : value(val) {          ++count;      } - +    explicit small_throws_on_copy(int, int val, int) : value(val) { +        ++count; +    }      small_throws_on_copy(small_throws_on_copy const &) {          throwMyAnyExpression();      }      small_throws_on_copy(small_throws_on_copy && other) throw() {          value = other.value; -        ++count; +        ++count; ++moved;      }      ~small_throws_on_copy() { @@ -260,26 +353,35 @@ private:  };  int small_throws_on_copy::count = 0; +int small_throws_on_copy::copied = 0; +int small_throws_on_copy::moved = 0; +  // A test type that will NOT trigger the small object optimization within 'any'.  // this type throws if it is copied.  struct large_throws_on_copy  {      static int count; +    static int copied; +    static int moved; +    static void reset() { count = copied = moved = 0; }      int value = 0;      explicit large_throws_on_copy(int val = 0) : value(val) {          data[0] = 0;          ++count;      } - +    explicit large_throws_on_copy(int, int val, int) : value(val) { +        data[0] = 0; +        ++count; +    }      large_throws_on_copy(large_throws_on_copy const &) {           throwMyAnyExpression();      }      large_throws_on_copy(large_throws_on_copy && other) throw() {          value = other.value; -        ++count; +        ++count; ++moved;      }      ~large_throws_on_copy() { @@ -293,19 +395,24 @@ private:  };  int large_throws_on_copy::count = 0; +int large_throws_on_copy::copied = 0; +int large_throws_on_copy::moved = 0;  // A test type that throws when it is moved. This object will NOT trigger  // the small object optimization in 'any'.  struct throws_on_move  {      static int count; +    static int copied; +    static int moved; +    static void reset() { count = copied = moved = 0; }      int value;      explicit throws_on_move(int val = 0) : value(val) { ++count; } - +    explicit throws_on_move(int, int val, int) : value(val) { ++count; }      throws_on_move(throws_on_move const & other) {          value = other.value; -        ++count; +        ++count; ++copied;      }      throws_on_move(throws_on_move &&) { @@ -321,6 +428,56 @@ private:  };  int throws_on_move::count = 0; +int throws_on_move::copied = 0; +int throws_on_move::moved = 0; + +struct small_tracked_t { +  small_tracked_t() +      : arg_types(&makeArgumentID<>()) {} +  small_tracked_t(small_tracked_t const&) noexcept +      : arg_types(&makeArgumentID<small_tracked_t const&>()) {} +  small_tracked_t(small_tracked_t &&) noexcept +      : arg_types(&makeArgumentID<small_tracked_t &&>()) {} +  template <class ...Args> +  explicit small_tracked_t(Args&&...) +      : arg_types(&makeArgumentID<Args...>()) {} +  template <class ...Args> +  explicit small_tracked_t(std::initializer_list<int>, Args&&...) +      : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {} + +  TypeID const* arg_types; +}; +static_assert(IsSmallObject<small_tracked_t>::value, "must be small"); + +struct large_tracked_t { +  large_tracked_t() +      : arg_types(&makeArgumentID<>()) { dummy[0] = 42; } +  large_tracked_t(large_tracked_t const&) noexcept +      : arg_types(&makeArgumentID<large_tracked_t const&>()) {} +  large_tracked_t(large_tracked_t &&) noexcept +      : arg_types(&makeArgumentID<large_tracked_t &&>()) {} +  template <class ...Args> +  explicit large_tracked_t(Args&&...) +      : arg_types(&makeArgumentID<Args...>()) {} +  template <class ...Args> +  explicit large_tracked_t(std::initializer_list<int>, Args&&...) +      : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {} + +  TypeID const* arg_types; +  int dummy[10]; +}; + +static_assert(!IsSmallObject<large_tracked_t>::value, "must be small"); + + +template <class Type, class ...Args> +void assertArgsMatch(std::any const& a) { +    using namespace std; +    using namespace std::experimental; +    assert(a.has_value()); +    assert(containsType<Type>(a)); +    assert(any_cast<Type const &>(a).arg_types == &makeArgumentID<Args...>()); +};  #endif diff --git a/libcxx/test/support/experimental_any_helpers.h b/libcxx/test/support/experimental_any_helpers.h new file mode 100644 index 00000000000..50bd6d68fba --- /dev/null +++ b/libcxx/test/support/experimental_any_helpers.h @@ -0,0 +1,326 @@ +//===----------------------------------------------------------------------===// +// +//                     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. +// +//===----------------------------------------------------------------------===// +#ifndef EXPERIMENTAL_ANY_HELPERS_H +#define EXPERIMENTAL_ANY_HELPERS_H + +#include <experimental/any> +#include <typeinfo> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" + +#if !defined(TEST_HAS_NO_RTTI) +#define RTTI_ASSERT(X) assert(X) +#else +#define RTTI_ASSERT(X) +#endif + +template <class _Tp> +  struct IsSmallObject +    : public std::integral_constant<bool +        , sizeof(_Tp) <= (sizeof(void*)*3) +          && std::alignment_of<void*>::value +             % std::alignment_of<_Tp>::value == 0 +          && std::is_nothrow_move_constructible<_Tp>::value +        > +  {}; + + +// Return 'true' if 'Type' will be considered a small type by 'any' +template <class Type> +bool isSmallType() { +#if defined(_LIBCPP_VERSION) +    return std::experimental::__any_imp::_IsSmallObject<Type>::value; +#else +    return IsSmallObject<Type>::value; +#endif + +} + +// Assert that an object is empty. If the object used to contain an object +// of type 'LastType' check that it can no longer be accessed. +template <class LastType = int> +void assertEmpty(std::experimental::any const& a) { +    assert(a.empty()); +    RTTI_ASSERT(a.type() == typeid(void)); +    assert(std::experimental::any_cast<LastType const>(&a) == nullptr); +} + +// Assert that an 'any' object stores the specified 'Type' and 'value'. +template <class Type> +void assertContains(std::experimental::any const& a, int value = 1) { +    assert(!a.empty()); +    RTTI_ASSERT(a.type() == typeid(Type)); +    assert(std::experimental::any_cast<Type const &>(a).value == value); +} + +// Modify the value of a "test type" stored within an any to the specified +// 'value'. +template <class Type> +void modifyValue(std::experimental::any& a, int value) { +    assert(!a.empty()); +    RTTI_ASSERT(a.type() == typeid(Type)); +    std::experimental::any_cast<Type&>(a).value = value; +} + +// A test type that will trigger the small object optimization within 'any'. +template <int Dummy = 0> +struct small_type +{ +    static int count; +    static int copied; +    static int moved; +    static int const_copied; +    static int non_const_copied; + +    static void reset() { +        small_type::copied = 0; +        small_type::moved = 0; +        small_type::const_copied = 0; +        small_type::non_const_copied = 0; +    } + +    int value; + +    explicit small_type(int val) : value(val) { +        ++count; +    } + +    small_type(small_type const & other) throw() { +        value = other.value; +        ++count; +        ++copied; +        ++const_copied; +    } + +    small_type(small_type& other) throw() { +        value = other.value; +        ++count; +        ++copied; +        ++non_const_copied; +    } + +    small_type(small_type && other) throw() { +        value = other.value; +        other.value = 0; +        ++count; +        ++moved; +    } + +    ~small_type() { +        value = -1; +        --count; +    } + +private: +    small_type& operator=(small_type const&) = delete; +    small_type& operator=(small_type&&) = delete; +}; + +template <int Dummy> +int small_type<Dummy>::count = 0; + +template <int Dummy> +int small_type<Dummy>::copied = 0; + +template <int Dummy> +int small_type<Dummy>::moved = 0; + +template <int Dummy> +int small_type<Dummy>::const_copied = 0; + +template <int Dummy> +int small_type<Dummy>::non_const_copied = 0; + +typedef small_type<> small; +typedef small_type<1> small1; +typedef small_type<2> small2; + + +// A test type that will NOT trigger the small object optimization in any. +template <int Dummy = 0> +struct large_type +{ +    static int count; +    static int copied; +    static int moved; +    static int const_copied; +    static int non_const_copied; + +    static void reset() { +        large_type::copied = 0; +        large_type::moved  = 0; +        large_type::const_copied = 0; +        large_type::non_const_copied = 0; +    } + +    int value; + +    large_type(int val) : value(val) { +        ++count; +        data[0] = 0; +    } + +    large_type(large_type const & other) { +        value = other.value; +        ++count; +        ++copied; +        ++const_copied; +    } + +    large_type(large_type & other) { +        value = other.value; +        ++count; +        ++copied; +        ++non_const_copied; +    } + +    large_type(large_type && other) { +        value = other.value; +        other.value = 0; +        ++count; +        ++moved; +    } + +    ~large_type()  { +        value = 0; +        --count; +    } + +private: +    large_type& operator=(large_type const&) = delete; +    large_type& operator=(large_type &&) = delete; +    int data[10]; +}; + +template <int Dummy> +int large_type<Dummy>::count = 0; + +template <int Dummy> +int large_type<Dummy>::copied = 0; + +template <int Dummy> +int large_type<Dummy>::moved = 0; + +template <int Dummy> +int large_type<Dummy>::const_copied = 0; + +template <int Dummy> +int large_type<Dummy>::non_const_copied = 0; + +typedef large_type<> large; +typedef large_type<1> large1; +typedef large_type<2> large2; + +// The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy' +// and 'throws_on_move'. +struct my_any_exception {}; + +void throwMyAnyExpression() { +#if !defined(TEST_HAS_NO_EXCEPTIONS) +        throw my_any_exception(); +#else +        assert(false && "Exceptions are disabled"); +#endif +} + +// A test type that will trigger the small object optimization within 'any'. +// this type throws if it is copied. +struct small_throws_on_copy +{ +    static int count; +    int value; + +    explicit small_throws_on_copy(int val = 0) : value(val) { +        ++count; +    } + +    small_throws_on_copy(small_throws_on_copy const &) { +        throwMyAnyExpression(); +    } + +    small_throws_on_copy(small_throws_on_copy && other) throw() { +        value = other.value; +        ++count; +    } + +    ~small_throws_on_copy() { +        --count; +    } +private: +    small_throws_on_copy& operator=(small_throws_on_copy const&) = delete; +    small_throws_on_copy& operator=(small_throws_on_copy &&) = delete; +}; + +int small_throws_on_copy::count = 0; + +// A test type that will NOT trigger the small object optimization within 'any'. +// this type throws if it is copied. +struct large_throws_on_copy +{ +    static int count; +    int value = 0; + +    explicit large_throws_on_copy(int val = 0) : value(val) { +        data[0] = 0; +        ++count; +    } + +    large_throws_on_copy(large_throws_on_copy const &) { +         throwMyAnyExpression(); +    } + +    large_throws_on_copy(large_throws_on_copy && other) throw() { +        value = other.value; +        ++count; +    } + +    ~large_throws_on_copy() { +        --count; +    } + +private: +    large_throws_on_copy& operator=(large_throws_on_copy const&) = delete; +    large_throws_on_copy& operator=(large_throws_on_copy &&) = delete; +    int data[10]; +}; + +int large_throws_on_copy::count = 0; + +// A test type that throws when it is moved. This object will NOT trigger +// the small object optimization in 'any'. +struct throws_on_move +{ +    static int count; +    int value; + +    explicit throws_on_move(int val = 0) : value(val) { ++count; } + +    throws_on_move(throws_on_move const & other) { +        value = other.value; +        ++count; +    } + +    throws_on_move(throws_on_move &&) { +        throwMyAnyExpression(); +    } + +    ~throws_on_move() { +        --count; +    } +private: +    throws_on_move& operator=(throws_on_move const&) = delete; +    throws_on_move& operator=(throws_on_move &&) = delete; +}; + +int throws_on_move::count = 0; + + +#endif diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index 3e4400af00e..752bcdaecdd 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -33,6 +33,13 @@  #else  #define TEST_HAS_BUILTIN(X) 0  #endif +#ifdef __is_identifier +// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by +// the compiler and '1' otherwise. +#define TEST_HAS_BUILTIN_IDENTIFIER(X) !__is_identifier(X) +#else +#define TEST_HAS_BUILTIN_IDENTIFIER(X) 0 +#endif  #if defined(__apple_build_version__)  #define TEST_APPLE_CLANG_VER (__clang_major__ * 100) + __clang_minor__  | 

