diff --git a/libcxx/include/any b/libcxx/include/any new file mode 100644 index 000000000000..d6ae06345b3d --- /dev/null +++ b/libcxx/include/any @@ -0,0 +1,658 @@ +// -*- C++ -*- +//===------------------------------ any -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_ANY +#define _LIBCPP_ANY + +/* + any synopsis + +namespace std { + + class bad_any_cast : public bad_cast + { + public: + virtual const char* what() const noexcept; + }; + + class any + { + public: + + // 6.3.1 any construct/destruct + any() noexcept; + + any(const any& other); + any(any&& other) noexcept; + + template + any(ValueType&& value); + + ~any(); + + // 6.3.2 any assignments + any& operator=(const any& rhs); + any& operator=(any&& rhs) noexcept; + + template + any& operator=(ValueType&& rhs); + + // 6.3.3 any modifiers + void reset() noexcept; + void swap(any& rhs) noexcept; + + // 6.3.4 any observers + bool has_value() const noexcept; + const type_info& type() const noexcept; + }; + + // 6.4 Non-member functions + void swap(any& x, any& y) noexcept; + + template + any make_any(Args&& ...args); + template + any make_any(initializer_list, Args&& ...args); + + template + ValueType any_cast(const any& operand); + template + ValueType any_cast(any& operand); + template + ValueType any_cast(any&& operand); + + template + const ValueType* any_cast(const any* operand) noexcept; + template + ValueType* any_cast(any* operand) noexcept; + +} // namespace fundamentals_v1 +} // namespace experimental +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +namespace std { +class _LIBCPP_EXCEPTION_ABI bad_any_cast : public bad_cast +{ +public: + virtual const char* what() const _NOEXCEPT; +}; +} // namespace std + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 14 + +// Forward declarations +class _LIBCPP_TYPE_VIS_ONLY any; + +template +_LIBCPP_INLINE_VISIBILITY +add_pointer_t> +any_cast(any const *) _NOEXCEPT; + +template +_LIBCPP_INLINE_VISIBILITY +add_pointer_t<_ValueType> any_cast(any *) _NOEXCEPT; + +namespace __any_imp +{ + using _Buffer = aligned_storage_t<3*sizeof(void*), alignment_of::value>; + + template + using _IsSmallObject = integral_constant::value + % alignment_of<_Tp>::value == 0 + && is_nothrow_move_constructible<_Tp>::value + >; + + enum class _Action { + _Destroy, + _Copy, + _Move, + _Get, + _TypeInfo + }; + + template struct _SmallHandler; + template struct _LargeHandler; + + template + struct _LIBCPP_TYPE_VIS_ONLY __unique_typeinfo { static constexpr int __id = 0; }; + template constexpr int __unique_typeinfo<_Tp>::__id; + + template + inline _LIBCPP_INLINE_VISIBILITY + constexpr const void* __get_fallback_typeid() { + return &__unique_typeinfo>::__id; + } + + template + inline _LIBCPP_INLINE_VISIBILITY + bool __compare_typeid(type_info const* __id, const void* __fallback_id) + { +#if !defined(_LIBCPP_NO_RTTI) + if (__id && *__id == typeid(_Tp)) + return true; +#endif + if (!__id && __fallback_id == __any_imp::__get_fallback_typeid<_Tp>()) + return true; + return false; + } + + template + using _Handler = conditional_t< + _IsSmallObject<_Tp>::value, _SmallHandler<_Tp>, _LargeHandler<_Tp>>; + +} // namespace __any_imp + +class _LIBCPP_TYPE_VIS_ONLY any +{ +public: + // construct/destruct + _LIBCPP_INLINE_VISIBILITY + constexpr any() _NOEXCEPT : __h(nullptr) {} + + _LIBCPP_INLINE_VISIBILITY + any(any const & __other) : __h(nullptr) + { + if (__other.__h) __other.__call(_Action::_Copy, this); + } + + _LIBCPP_INLINE_VISIBILITY + any(any && __other) _NOEXCEPT : __h(nullptr) + { + if (__other.__h) __other.__call(_Action::_Move, this); + } + + template < + class _ValueType + , class = enable_if_t< + !is_same, any>::value && + !__is_inplace_type<_ValueType>::value && + is_copy_constructible<_ValueType>::value> + > + _LIBCPP_INLINE_VISIBILITY + any(_ValueType && __value); + + template ::value && + is_copy_constructible<_Tp>::value + > + > + _LIBCPP_INLINE_VISIBILITY + explicit any(in_place_type_t<_Tp>, _Args&&... __args); + + template &, _Args...>::value && + is_copy_constructible<_Tp>::value> + > + _LIBCPP_INLINE_VISIBILITY + explicit any(in_place_type_t<_Tp>, initializer_list<_Up>, _Args&&... __args); + + _LIBCPP_INLINE_VISIBILITY + ~any() { this->reset(); } + + // assignments + _LIBCPP_INLINE_VISIBILITY + any & operator=(any const & __rhs) { + any(__rhs).swap(*this); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + any & operator=(any && __rhs) _NOEXCEPT { + any(_VSTD::move(__rhs)).swap(*this); + return *this; + } + + // TODO: Should this be constrained to disallow in_place types like the + // ValueType constructor? + template < + class _ValueType + , class = enable_if_t< + !is_same, any>::value + && is_copy_constructible<_ValueType>::value + && !__is_inplace_type<_ValueType>::value> + > + _LIBCPP_INLINE_VISIBILITY + any & operator=(_ValueType && __rhs); + + template ::value && + is_copy_constructible<_Tp>::value> + > + _LIBCPP_INLINE_VISIBILITY + void emplace(_Args&&... args); + + template &, _Args...>::value && + is_copy_constructible<_Tp>::value> + > + _LIBCPP_INLINE_VISIBILITY + void emplace(initializer_list<_Up>, _Args&&...); + + // 6.3.3 any modifiers + _LIBCPP_INLINE_VISIBILITY + void reset() _NOEXCEPT { if (__h) this->__call(_Action::_Destroy); } + + _LIBCPP_INLINE_VISIBILITY + void swap(any & __rhs) _NOEXCEPT; + + // 6.3.4 any observers + _LIBCPP_INLINE_VISIBILITY + bool has_value() const _NOEXCEPT { return __h != nullptr; } + +#if !defined(_LIBCPP_NO_RTTI) + _LIBCPP_INLINE_VISIBILITY + const type_info & type() const _NOEXCEPT { + if (__h) { + return *static_cast(this->__call(_Action::_TypeInfo)); + } else { + return typeid(void); + } + } +#endif + +private: + typedef __any_imp::_Action _Action; + using _HandleFuncPtr = void* (*)(_Action, any const *, any *, const type_info *, + const void* __fallback_info); + + union _Storage { + constexpr _Storage() : __ptr(nullptr) {} + void * __ptr; + __any_imp::_Buffer __buf; + }; + + _LIBCPP_ALWAYS_INLINE + void * __call(_Action __a, any * __other = nullptr, + type_info const * __info = nullptr, + const void* __fallback_info = nullptr) const + { + return __h(__a, this, __other, __info, __fallback_info); + } + + _LIBCPP_ALWAYS_INLINE + void * __call(_Action __a, any * __other = nullptr, + type_info const * __info = nullptr, + const void* __fallback_info = nullptr) + { + return __h(__a, this, __other, __info, __fallback_info); + } + + template + friend struct __any_imp::_SmallHandler; + template + friend struct __any_imp::_LargeHandler; + + template + friend add_pointer_t> + any_cast(any const *) _NOEXCEPT; + + template + friend add_pointer_t<_ValueType> + any_cast(any *) _NOEXCEPT; + + _HandleFuncPtr __h = nullptr; + _Storage __s; +}; + +namespace __any_imp +{ + template + struct _LIBCPP_TYPE_VIS_ONLY _SmallHandler + { + _LIBCPP_INLINE_VISIBILITY + static void* __handle(_Action __act, any const * __this, any * __other, + type_info const * __info, const void* __fallback_info) + { + switch (__act) + { + case _Action::_Destroy: + __destroy(const_cast(*__this)); + return nullptr; + case _Action::_Copy: + __copy(*__this, *__other); + return nullptr; + case _Action::_Move: + __move(const_cast(*__this), *__other); + return nullptr; + case _Action::_Get: + return __get(const_cast(*__this), __info, __fallback_info); + case _Action::_TypeInfo: + return __type_info(); + } + } + + template + _LIBCPP_INLINE_VISIBILITY + static void __create(any & __dest, _Args&&... __args) { + ::new (static_cast(&__dest.__s.__buf)) _Tp(_VSTD::forward<_Args>(__args)...); + __dest.__h = &_SmallHandler::__handle; + } + + private: + _LIBCPP_INLINE_VISIBILITY + static void __destroy(any & __this) { + _Tp & __value = *static_cast<_Tp *>(static_cast(&__this.__s.__buf)); + __value.~_Tp(); + __this.__h = nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + static void __copy(any const & __this, any & __dest) { + _SmallHandler::__create(__dest, *static_cast<_Tp const *>( + static_cast(&__this.__s.__buf))); + } + + _LIBCPP_INLINE_VISIBILITY + static void __move(any & __this, any & __dest) { + _SmallHandler::__create(__dest, _VSTD::move( + *static_cast<_Tp*>(static_cast(&__this.__s.__buf)))); + __destroy(__this); + } + + _LIBCPP_INLINE_VISIBILITY + static void* __get(any & __this, + type_info const * __info, + const void* __fallback_id) + { + if (__any_imp::__compare_typeid<_Tp>(__info, __fallback_id)) + return static_cast(&__this.__s.__buf); + return nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + static void* __type_info() + { +#if !defined(_LIBCPP_NO_RTTI) + return const_cast(static_cast(&typeid(_Tp))); +#else + return nullptr; +#endif + } + }; + + template + struct _LIBCPP_TYPE_VIS_ONLY _LargeHandler + { + _LIBCPP_INLINE_VISIBILITY + static void* __handle(_Action __act, any const * __this, + any * __other, type_info const * __info, + void const* __fallback_info) + { + switch (__act) + { + case _Action::_Destroy: + __destroy(const_cast(*__this)); + return nullptr; + case _Action::_Copy: + __copy(*__this, *__other); + return nullptr; + case _Action::_Move: + __move(const_cast(*__this), *__other); + return nullptr; + case _Action::_Get: + return __get(const_cast(*__this), __info, __fallback_info); + case _Action::_TypeInfo: + return __type_info(); + } + } + + template + _LIBCPP_INLINE_VISIBILITY + static void __create(any & __dest, _Args&&... __args) { + typedef allocator<_Tp> _Alloc; + typedef __allocator_destructor<_Alloc> _Dp; + _Alloc __a; + unique_ptr<_Tp, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); + ::new ((void*)__hold.get()) _Tp(_VSTD::forward<_Args>(__args)...); + __dest.__s.__ptr = __hold.release(); + __dest.__h = &_LargeHandler::__handle; + } + + private: + + _LIBCPP_INLINE_VISIBILITY + static void __destroy(any & __this){ + delete static_cast<_Tp*>(__this.__s.__ptr); + __this.__h = nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + static void __copy(any const & __this, any & __dest) { + _LargeHandler::__create(__dest, *static_cast<_Tp const *>(__this.__s.__ptr)); + } + + _LIBCPP_INLINE_VISIBILITY + static void __move(any & __this, any & __dest) { + __dest.__s.__ptr = __this.__s.__ptr; + __dest.__h = &_LargeHandler::__handle; + __this.__h = nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + static void* __get(any & __this, type_info const * __info, + void const* __fallback_info) + { + if (__any_imp::__compare_typeid<_Tp>(__info, __fallback_info)) + return static_cast(__this.__s.__ptr); + return nullptr; + + } + + _LIBCPP_INLINE_VISIBILITY + static void* __type_info() + { +#if !defined(_LIBCPP_NO_RTTI) + return const_cast(static_cast(&typeid(_Tp))); +#else + return nullptr; +#endif + } + }; + +} // namespace __any_imp + + +template +any::any(_ValueType && __v) : __h(nullptr) +{ + typedef typename decay<_ValueType>::type _Tp; + static_assert(is_copy_constructible<_Tp>::value, + "_ValueType must be CopyConstructible."); + using _ForwardTp = conditional_t< + is_move_constructible<_Tp>::value, _ValueType, _ValueType&>; + typedef __any_imp::_Handler<_Tp> _HandlerType; + _HandlerType::__create(*this, _VSTD::forward<_ForwardTp>(__v)); +} + +template +any::any(in_place_type_t<_Tp>, _Args&&... __args) { + using _Hp = __any_imp::_Handler<_Tp>; + _Hp::__create(*this, _VSTD::forward<_Args>(__args)...); +}; + +template +any::any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) { + using _Hp = __any_imp::_Handler<_Tp>; + _Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +any & any::operator=(_ValueType && __v) +{ + typedef typename decay<_ValueType>::type _Tp; + static_assert(is_copy_constructible<_Tp>::value, + "_ValueType must be CopyConstructible."); + any(_VSTD::forward<_ValueType>(__v)).swap(*this); + return *this; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void any::emplace(_Args&&... __args) { + using _Hp = __any_imp::_Handler<_Tp>; + reset(); + _Hp::__create(*this, _VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void any::emplace(initializer_list<_Up> __il, _Args&&... __args) { + using _Hp = __any_imp::_Handler<_Tp>; + reset(); + _Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...); +} + +inline _LIBCPP_INLINE_VISIBILITY +void any::swap(any & __rhs) _NOEXCEPT +{ + if (__h && __rhs.__h) { + any __tmp; + __rhs.__call(_Action::_Move, &__tmp); + this->__call(_Action::_Move, &__rhs); + __tmp.__call(_Action::_Move, this); + } + else if (__h) { + this->__call(_Action::_Move, &__rhs); + } + else if (__rhs.__h) { + __rhs.__call(_Action::_Move, this); + } +} + +// 6.4 Non-member functions + +inline _LIBCPP_INLINE_VISIBILITY +void swap(any & __lhs, any & __rhs) _NOEXCEPT +{ + __lhs.swap(__rhs); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +any make_any(_Args&&... __args) { + return any(in_place<_Tp>, _VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +any make_any(initializer_list<_Up> __il, _Args&&... __args) { + return any(in_place<_Tp>, __il, _VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ValueType any_cast(any const & __v) +{ + static_assert( + is_reference<_ValueType>::value + || is_copy_constructible<_ValueType>::value, + "_ValueType is required to be a reference or a CopyConstructible type."); + using _Tp = add_const_t>; + _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __libcpp_throw(bad_any_cast()); + return *__tmp; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ValueType any_cast(any & __v) +{ + static_assert( + is_reference<_ValueType>::value + || is_copy_constructible<_ValueType>::value, + "_ValueType is required to be a reference or a CopyConstructible type."); + typedef typename remove_reference<_ValueType>::type _Tp; + _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __libcpp_throw(bad_any_cast()); + return *__tmp; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ValueType any_cast(any && __v) +{ + static_assert( + is_reference<_ValueType>::value + || is_copy_constructible<_ValueType>::value, + "_ValueType is required to be a reference or a CopyConstructible type."); + typedef typename remove_reference<_ValueType>::type _Tp; + using _ForwardTp = conditional_t< + is_reference<_ValueType>::value, + _ValueType, + conditional_t::value, _Tp, _Tp&> + >; + _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __libcpp_throw(bad_any_cast()); + return _VSTD::forward<_ForwardTp>(*__tmp); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +add_pointer_t> +any_cast(any const * __any) _NOEXCEPT +{ + static_assert(!is_reference<_ValueType>::value, + "_ValueType may not be a reference."); + return _VSTD::any_cast<_ValueType>(const_cast(__any)); +} + +template +add_pointer_t<_ValueType> +any_cast(any * __any) _NOEXCEPT +{ + using __any_imp::_Action; + static_assert(!is_reference<_ValueType>::value, + "_ValueType may not be a reference."); + typedef typename add_pointer<_ValueType>::type _ReturnType; + if (__any && __any->__h) { + return static_cast<_ReturnType>( + __any->__call(_Action::_Get, nullptr, +#if !defined(_LIBCPP_NO_RTTI) + &typeid(_ValueType), +#else + nullptr, +#endif + __any_imp::__get_fallback_typeid<_ValueType>() + )); + } + return nullptr; +} + +#endif // _LIBCPP_STD_VER > 14 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_ANY diff --git a/libcxx/src/any.cpp b/libcxx/src/any.cpp index f77684578905..45b2337eb353 100644 --- a/libcxx/src/any.cpp +++ b/libcxx/src/any.cpp @@ -7,12 +7,17 @@ // //===----------------------------------------------------------------------===// +#include "any" #include "experimental/any" -_LIBCPP_BEGIN_NAMESPACE_LFTS - +namespace std { const char* bad_any_cast::what() const _NOEXCEPT { return "bad any cast"; } +} +_LIBCPP_BEGIN_NAMESPACE_LFTS +const char* bad_any_cast::what() const _NOEXCEPT { + return "bad any cast"; +} _LIBCPP_END_NAMESPACE_LFTS diff --git a/libcxx/test/libcxx/experimental/any/small_type.pass.cpp b/libcxx/test/libcxx/experimental/any/small_type.pass.cpp index e6595d4a4ab3..96754126c996 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 -#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 000000000000..55b6b38d0f09 --- /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 + +// + +// Check that the size and alignment of any are what we expect. + +#include + +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 000000000000..34d57c705731 --- /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 + +// + +// Check that the size and alignment of any are what we expect. + +#include +#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::value, ""); + static_assert(_IsSmallObject::value, ""); + static_assert(!_IsSmallObject::value, ""); + static_assert(!_IsSmallObject::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::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::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::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::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::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::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 000000000000..5edee710d585 --- /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. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#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 8ee575c408f9..17b01fe630bf 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 #include -#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 0a2d71967cd4..49508febd941 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 #include -#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 8262990523c3..b42a4ba2b050 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 #include -#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 3d0b34b27406..69341ca6b801 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 #include -#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 b52c83fc3881..3839e3afc81d 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 #include -#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 40534cb55066..2a050946afab 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 #include -#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 7bb134efd28a..a3ab0edc8b6b 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 #include -#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 603490cef43d..781ed73f2b33 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 #include -#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 064935167eb5..b1d315468968 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 #include -#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 8c681f37017f..bdf0d511b811 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 #include -#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 682b73bc98c4..6d0048403677 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 #include -#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 9d9a5cdb4726..46ddbe5b05a1 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 #include -#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 e97560937fb0..7efbafff83cc 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 #include -#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 000000000000..fc76a2d8b954 --- /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& operator=(any const &); + +// Test copy assignment + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template +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(lhs, 2); + assertContains(rhs, 2); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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, 42); + assertContains(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); + 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(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(a, 1); + assert(globalMemCounter.checkOutstandingNewEq(1)); + } + assert(large::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +template +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(lhs); + assertContains(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(lhs, 2); + assertContains(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(lhs, 2); + assertContains(rhs); + } +#endif +} + +int main() { + test_copy_assign(); + test_copy_assign(); + test_copy_assign(); + test_copy_assign(); + test_copy_assign_empty(); + test_copy_assign_empty(); + test_copy_assign_self(); + test_copy_assign_throws(); + test_copy_assign_throws(); +} 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 000000000000..bac3edb7cdb0 --- /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& operator=(any &&); + +// Test move assignment. + +#include +#include + +#include "any_helpers.h" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template +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(a, 2); + assertEmpty(a2); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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(a, 1); + assertEmpty(a2); + } + assert(LHS::count == 0); + { + any a((LHS(1))); + any a2; + + assert(LHS::count == 1); + + a = std::move(a2); + + assert(LHS::count == 0); + + assertEmpty(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(); + test_move_assign(); + test_move_assign(); + test_move_assign(); + test_move_assign_empty(); + test_move_assign_empty(); +} 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 000000000000..d844fcfaa7c3 --- /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& operator=(any const &); + +// Test value copy and move assignment. + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template +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(lhs, 2); + assertContains(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(lhs, 2); + assertEmpty(rhs); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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(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(lhs, 42); + } + assert(RHS::count == 0); + RHS::reset(); +} + + +template +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(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(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(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; + using RawTag = std::remove_reference_t; + static_assert(!std::is_assignable::value, ""); + } + { + struct Dummy { Dummy() = delete; }; + using T = std::in_place_type_t; + static_assert(!std::is_assignable::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::value, ""); + } +} + +int main() { + test_assign_value(); + test_assign_value(); + test_assign_value(); + test_assign_value(); + test_assign_value_empty(); + test_assign_value_empty(); + test_assign_throws(); + test_assign_throws(); + test_assign_throws(); + 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 000000000000..03870caa531b --- /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 const &); + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +template +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(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 +void test_copy() +{ + // Copying small types should not perform any allocations. + DisableAllocationGuard g(isSmallType()); ((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(a, 42); + assertContains(a, 42); + + // Modify a and check that a2 is unchanged + modifyValue(a, -1); + assertContains(a, -1); + assertContains(a2, 42); + + // modify a2 and check that a is unchanged + modifyValue(a2, 999); + assertContains(a, -1); + assertContains(a2, 999); + + // clear a and check that a2 is unchanged + a.reset(); + assertEmpty(a); + assertContains(a2, 999); + } + assert(Type::count == 0); +} + +int main() { + test_copy(); + test_copy(); + test_copy_empty(); + test_copy_throws(); + test_copy_throws(); +} 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 000000000000..9f9b826b6121 --- /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() noexcept; + +#include +#include +#include + +#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::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 000000000000..949c105f9886 --- /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 + +// + +// template any(in_place_type_t, Args&&...); +// template +// any(in_place_type_t, initializer_list, 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 +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" +#include "test_convertible.hpp" + +using std::any; +using std::any_cast; + +template +void test_in_place_type() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 0); + } + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place, 101); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 101); + } + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place, -1, 42, -1); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 42); + } + assert(Type::count == 0); + Type::reset(); +} + +template +void test_in_place_type_tracked() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + { + any a(std::in_place); + assertArgsMatch(a); + } + { + any a(std::in_place, -1, 42, -1); + assertArgsMatch(a); + } + // initializer_list constructor tests + { + any a(std::in_place, {-1, 42, -1}); + assertArgsMatch>(a); + } + { + int x = 42; + any a(std::in_place, {-1, 42, -1}, x); + assertArgsMatch, 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; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(std::is_constructible, 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) {} + }; + using Tag = std::in_place_type_t; + using IL = std::initializer_list; + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + } +} + +struct Implicit { + Implicit(int) {} + Implicit(int, int, int) {} + Implicit(std::initializer_list, int) {} +}; + +void test_constructor_explicit() { + using I = Implicit; + using IT = std::in_place_type_t; + static_assert(!test_convertible(), ""); + static_assert(std::is_constructible::value, ""); + static_assert(!test_convertible(), ""); + static_assert(std::is_constructible::value, ""); + static_assert(!test_convertible&, int>(), ""); + static_assert(std::is_constructible&, int>::value, ""); +} + +int main() { + test_in_place_type(); + test_in_place_type(); + test_in_place_type(); + test_in_place_type(); + test_in_place_type(); + test_in_place_type_tracked(); + test_in_place_type_tracked(); + 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 000000000000..9a83e66ab8a6 --- /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 &&) noexcept; + +#include +#include +#include +#include + +#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(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 +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(a2, 42); + } + assert(Type::count == 0); +} + +int main() +{ + // noexcept test + { + static_assert( + std::is_nothrow_move_constructible::value + , "any must be nothrow move constructible" + ); + } + test_move(); + test_move(); + 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 000000000000..ba5419b12454 --- /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 + +// + +// template 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 +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + + +template +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 +void test_copy_move_value() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((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(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(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(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(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; +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif + static_assert(std::is_same::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(a, 0); + } + { + std::any a(std::move(t)); + assertContains(a, 0); + } + { + struct Dummy { Dummy() = delete; }; + using T = std::in_place_type_t; + static_assert(!std::is_constructible::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::value, ""); + static_assert(!std::is_convertible::value, ""); + } +} + +int main() { + test_copy_move_value(); + test_copy_move_value(); + test_copy_value_throws(); + test_copy_value_throws(); + 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 000000000000..fa8b093d3048 --- /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 + +// + +// template emplace(Args&&...); +// template +// void emplace(initializer_list, Args&&...); + +#include +#include + +#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 +void test_emplace_type() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place); + assert(Tracked::count == 1); + + a.emplace(); + + assert(Tracked::count == 0); + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 0); + } + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place); + assert(Tracked::count == 1); + + a.emplace(101); + + assert(Tracked::count == 0); + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 101); + } + assert(Type::count == 0); + Type::reset(); + { + any a(std::in_place); + assert(Tracked::count == 1); + + a.emplace(-1, 42, -1); + + assert(Tracked::count == 0); + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 42); + } + assert(Type::count == 0); + Type::reset(); +} + +template +void test_emplace_type_tracked() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + { + any a(std::in_place); + assert(Tracked::count == 1); + a.emplace(); + assert(Tracked::count == 0); + assertArgsMatch(a); + } + { + any a(std::in_place); + assert(Tracked::count == 1); + a.emplace(-1, 42, -1); + assert(Tracked::count == 0); + assertArgsMatch(a); + } + // initializer_list constructor tests + { + any a(std::in_place); + assert(Tracked::count == 1); + a.emplace({-1, 42, -1}); + assert(Tracked::count == 0); + assertArgsMatch>(a); + } + { + int x = 42; + any a(std::in_place); + assert(Tracked::count == 1); + a.emplace({-1, 42, -1}, x); + assert(Tracked::count == 0); + assertArgsMatch, int&>(a); + } +} + +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct SmallThrows { + SmallThrows(int) { throw 42; } + SmallThrows(std::initializer_list, int) { throw 42; } +}; +static_assert(IsSmallObject::value, ""); + +struct LargeThrows { + LargeThrows(int) { throw 42; } + LargeThrows(std::initializer_list, int) { throw 42; } + int data[10]; +}; +static_assert(!IsSmallObject::value, ""); + +template +void test_emplace_throws() +{ + // any stores small type + { + std::any a(small{42}); + assert(small::count == 1); + try { + a.emplace(101); + assert(false); + } catch (int const&) { + } + assert(small::count == 0); + } + { + std::any a(small{42}); + assert(small::count == 1); + try { + a.emplace({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(101); + assert(false); + } catch (int const&) { + } + assert(large::count == 0); + } + { + std::any a(large{42}); + assert(large::count == 1); + try { + a.emplace({1, 2, 3}, 101); + assert(false); + } catch (int const&) { + } + assert(large::count == 0); + } +} + +#endif + +template +constexpr auto has_emplace(int) + -> decltype(std::any{}.emplace(std::declval()...), true) { return true; } + +template +constexpr bool has_emplace(long) { return false; } + +template +constexpr bool has_emplace() { return has_emplace(0); } + + +template +constexpr auto has_emplace_init_list(int) + -> decltype(std::any{}.emplace( + {std::declval(), std::declval(), std::declval()}, + std::declval()...), true) { return true; } + +template +constexpr bool has_emplace_init_list(long) { return false; } + +template +constexpr bool has_emplace_init_list() { return has_emplace_init_list(0); } + + +void test_emplace_sfinae_constraints() { + { + static_assert(has_emplace(), ""); + static_assert(has_emplace(), ""); + static_assert(!has_emplace(), "not constructible"); + static_assert(!has_emplace_init_list(), "not constructible from il"); + } + { + static_assert(has_emplace(), ""); + static_assert(has_emplace(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace(), ""); + + static_assert(has_emplace_init_list(), ""); + static_assert(has_emplace_init_list(), ""); + static_assert(!has_emplace_init_list(), ""); + static_assert(!has_emplace_init_list(), ""); + } + { + // 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) {} + }; + static_assert(!has_emplace(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace_init_list(), ""); + } +} + +int main() { + test_emplace_type(); + test_emplace_type(); + test_emplace_type(); + test_emplace_type(); + test_emplace_type(); + test_emplace_type_tracked(); + test_emplace_type_tracked(); + test_emplace_sfinae_constraints(); +#ifndef TEST_HAS_NO_EXCEPTIONS + test_emplace_throws(); + test_emplace_throws(); +#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 000000000000..31648a04e1ab --- /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::reset() noexcept + +#include +#include + +#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(a, 1); + + a.reset(); + + assertEmpty(a); + assert(small::count == 0); + } + // large object + { + any a(large(1)); + assert(large::count == 1); + assertContains(a); + + a.reset(); + + assertEmpty(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 000000000000..013982478eeb --- /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::swap(any &) noexcept + +// Test swap(large, small) and swap(small, large) + +#include +#include + +#include "any_helpers.h" + +using std::any; +using std::any_cast; + +template +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(a1, 2); + assertContains(a2, 1); + } + assert(LHS::count == 0); + assert(RHS::count == 0); + assert(LHS::copied == 0); + assert(RHS::copied == 0); +} + +template +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(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(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(); + test_swap_empty(); + test_swap(); + test_swap(); + test_swap(); + test_swap(); +} 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 000000000000..072ac06776c1 --- /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::has_value() noexcept + +#include +#include + +#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 000000000000..984c4137db09 --- /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::type() noexcept + +#include +#include +#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 000000000000..91ef5c970a22 --- /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 + +// + +// [Note any is a not a literal type --end note] + +#include +#include + +int main () { + static_assert(!std::is_literal_type::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 000000000000..0f4fc6ab7eb0 --- /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 + +// + +// template +// ValueType const* any_cast(any const *) noexcept; +// +// template +// ValueType * any_cast(any *) noexcept; + +#include +#include +#include + +#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(&a)), ""); + + any const& ca = a; + static_assert(noexcept(any_cast(&ca)), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { + any a; + static_assert(std::is_same(&a)), int*>::value, ""); + static_assert(std::is_same(&a)), int const*>::value, ""); + + any const& ca = a; + static_assert(std::is_same(&ca)), int const*>::value, ""); + static_assert(std::is_same(&ca)), int const*>::value, ""); +} + +// Test that any_cast handles null pointers. +void test_cast_nullptr() { + any* a = nullptr; + assert(nullptr == any_cast(a)); + assert(nullptr == any_cast(a)); + + any const* ca = nullptr; + assert(nullptr == any_cast(ca)); + assert(nullptr == any_cast(ca)); +} + +// Test casting an empty object. +void test_cast_empty() { + { + any a; + assert(nullptr == any_cast(&a)); + assert(nullptr == any_cast(&a)); + + any const& ca = a; + assert(nullptr == any_cast(&ca)); + assert(nullptr == any_cast(&ca)); + } + // Create as non-empty, then make empty and run test. + { + any a(42); + a.reset(); + assert(nullptr == any_cast(&a)); + assert(nullptr == any_cast(&a)); + + any const& ca = a; + assert(nullptr == any_cast(&ca)); + assert(nullptr == any_cast(&ca)); + } +} + +template +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(&a) == nullptr); + assert(any_cast(&a) == nullptr); + assert(any_cast(&a) == nullptr); + + // Try a cast to the right type, but as a pointer. + assert(any_cast(&a) == nullptr); + assert(any_cast(&a) == nullptr); + + // Check getting a unqualified type from a non-const any. + Type* v = any_cast(&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(&a); + assert(cv != nullptr); + assert(cv == v); + assert(cv->value == 999); + + // Check getting a unqualified type from a const any. + cv = any_cast(&ca); + assert(cv != nullptr); + assert(cv == v); + assert(cv->value == 999); + + // Check getting a const-qualified type from a const any. + cv = any_cast(&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(ptr) + struct NoCopy { NoCopy(NoCopy const&) = delete; }; + std::any a(42); + std::any const& ca = a; + assert(std::any_cast(&a) == nullptr); + assert(std::any_cast(&ca) == nullptr); +} + +int main() { + test_cast_is_noexcept(); + test_cast_return_type(); + test_cast_nullptr(); + test_cast_empty(); + test_cast(); + test_cast(); + 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 000000000000..852e776ce2d2 --- /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 + +// + +// template +// ValueType const any_cast(any const&); +// +// template +// ValueType any_cast(any &); +// +// template +// ValueType any_cast(any &&); + +#include +#include +#include + +#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(static_cast(a))), ""); + static_assert(!noexcept(any_cast(static_cast(a))), ""); + static_assert(!noexcept(any_cast(static_cast(a))), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { + any a; + static_assert(std::is_same(a)), int>::value, ""); + static_assert(std::is_same(a)), int>::value, ""); + static_assert(std::is_same(a)), int&>::value, ""); + static_assert(std::is_same(a)), int const&>::value, ""); + + static_assert(std::is_same(a)), int&&>::value, ""); + static_assert(std::is_same(a)), int const&&>::value, ""); + + static_assert(std::is_same(std::move(a))), int>::value, ""); + static_assert(std::is_same(std::move(a))), int>::value, ""); + static_assert(std::is_same(std::move(a))), int&>::value, ""); + static_assert(std::is_same(std::move(a))), int const&>::value, ""); + + static_assert(std::is_same(std::move(a))), int&&>::value, ""); + static_assert(std::is_same(std::move(a))), int const&&>::value, ""); + + any const& ca = a; + static_assert(std::is_same(ca)), int>::value, ""); + static_assert(std::is_same(ca)), int>::value, ""); + static_assert(std::is_same(ca)), int const&>::value, ""); + + static_assert(std::is_same(ca)), int const&&>::value, ""); +} + +template +void checkThrows(any& a) +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) + try { + any_cast(a); + assert(false); + } catch (bad_any_cast const &) { + // do nothing + } catch (...) { + assert(false); + } + + try { + any_cast(static_cast(a)); + assert(false); + } catch (bad_any_cast const &) { + // do nothing + } catch (...) { + assert(false); + } + + try { + any_cast(static_cast(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(a); +} + +template +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(a); + checkThrows(a); + checkThrows(a); + checkThrows(a); + + // Check getting a type by reference from a non-const lvalue any. + { + Type& v = any_cast(a); + assert(v.value == 42); + + Type const &cv = any_cast(a); + assert(&cv == &v); + } + // Check getting a type by reference from a const lvalue any. + { + Type const& v = any_cast(ca); + assert(v.value == 42); + + Type const &cv = any_cast(ca); + assert(&cv == &v); + } + // Check getting a type by reference from a non-const rvalue + { + Type& v = any_cast(std::move(a)); + assert(v.value == 42); + + Type const &cv = any_cast(std::move(a)); + assert(&cv == &v); + } + // Check getting a type by reference from a const rvalue any. + { + Type const& v = any_cast(std::move(ca)); + assert(v.value == 42); + + Type const &cv = any_cast(std::move(ca)); + assert(&cv == &v); + } + // Check getting a type by reference from a const rvalue any. + { + Type&& v = any_cast(std::move(a)); + assert(v.value == 42); + assert(any_cast(a).value == 42); + + Type&& cv = any_cast(std::move(a)); + assert(&cv == &v); + assert(any_cast(a).value == 42); + } + // Check getting a type by reference from a const rvalue any. + { + Type const&& v = any_cast(std::move(a)); + assert(v.value == 42); + assert(any_cast(a).value == 42); + + Type const&& cv = any_cast(std::move(a)); + assert(&cv == &v); + assert(any_cast(a).value == 42); + } + // Check that the original object hasn't been changed. + assertContains(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 +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(a); + checkThrows(a); + checkThrows(a); + checkThrows(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(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(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(static_cast(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(static_cast(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(a).value == 0); + any_cast(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(static_cast(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(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(static_cast(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(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(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(a); + assert(Type::count == 2); + assert(Type::copied == 2); + assert(Type::moved == 0); + assertContains(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(ca); + assert(Type::count == 2); + assert(Type::copied == 2); + assert(Type::moved == 0); + assertContains(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(std::move(a)); + assert(Type::count == 2); + assert(Type::copied == 2); + assert(Type::moved == 0); + assertContains(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(std::move(ca)); + assert(Type::count == 2); + assert(Type::copied == 2); + assert(Type::moved == 0); + assertContains(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(a); + checkThrows(a); + assertEmpty(a); +} + +int main() { + test_cast_is_not_noexcept(); + test_cast_return_type(); + test_cast_empty(); + test_cast_to_reference(); + test_cast_to_reference(); + test_cast_to_value(); + test_cast_to_value(); + 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 000000000000..a141b05ef7cd --- /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 + +// + +// template +// ValueType any_cast(any const &); + +// Try and cast away const. + +#include + +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(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(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(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(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 000000000000..415da8396db9 --- /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 + +// + +// template +// ValueType const any_cast(any const&); +// +// template +// ValueType any_cast(any &); +// +// template +// ValueType any_cast(any &&); + +// Test instantiating the any_cast with a non-copyable type. + +#include + +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(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(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 000000000000..99cc029971a8 --- /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 + +// + +// template +// ValueType const* any_cast(any const *) noexcept; +// +// template +// ValueType * any_cast(any *) noexcept; + +#include + +using std::any; +using std::any_cast; + +int main() +{ + any a(1); + any_cast(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any const& a2 = a; + any_cast(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&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 000000000000..143b60dd8648 --- /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 + +// + +// template any make_any(Args&&...); +// template +// any make_any(initializer_list, Args&&...); + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + + +template +void test_make_any_type() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + assert(Type::count == 0); + Type::reset(); + { + any a = std::make_any(); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 0); + } + assert(Type::count == 0); + Type::reset(); + { + any a = std::make_any(101); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 101); + } + assert(Type::count == 0); + Type::reset(); + { + any a = std::make_any(-1, 42, -1); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 42); + } + assert(Type::count == 0); + Type::reset(); +} + +template +void test_make_any_type_tracked() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((void)g); + { + any a = std::make_any(); + assertArgsMatch(a); + } + { + any a = std::make_any(-1, 42, -1); + assertArgsMatch(a); + } + // initializer_list constructor tests + { + any a = std::make_any({-1, 42, -1}); + assertArgsMatch>(a); + } + { + int x = 42; + any a = std::make_any({-1, 42, -1}, x); + assertArgsMatch, int&>(a); + } +} + +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct SmallThrows { + SmallThrows(int) { throw 42; } + SmallThrows(std::initializer_list, int) { throw 42; } +}; +static_assert(IsSmallObject::value, ""); + +struct LargeThrows { + LargeThrows(int) { throw 42; } + LargeThrows(std::initializer_list, int) { throw 42; } + int data[10]; +}; +static_assert(!IsSmallObject::value, ""); + +template +void test_make_any_throws() +{ + { + try { + std::make_any(101); + assert(false); + } catch (int const&) { + } + } + { + try { + std::make_any({1, 2, 3}, 101); + assert(false); + } catch (int const&) { + } + } +} + +#endif + +int main() { + test_make_any_type(); + test_make_any_type(); + test_make_any_type(); + test_make_any_type(); + test_make_any_type(); + test_make_any_type_tracked(); + test_make_any_type_tracked(); +#ifndef TEST_HAS_NO_EXCEPTIONS + test_make_any_throws(); + test_make_any_throws(); + +#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 000000000000..1b3785bb1c66 --- /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 + +// + +// void swap(any &, any &) noexcept + +// swap(...) just wraps any::swap(...). That function is tested elsewhere. + +#include +#include + +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(a1) == 2); + assert(any_cast(a2) == 1); + } +} diff --git a/libcxx/test/support/any_helpers.h b/libcxx/test/support/any_helpers.h index bb1ad175c1f2..a0ff8dbc1f9a 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 #include #include #include +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 > {}; +template +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(&a) != nullptr; +#endif +} // Return 'true' if 'Type' will be considered a small type by 'any' template bool isSmallType() { -#if defined(_LIBCPP_VERSION) - return std::experimental::__any_imp::_IsSmallObject::value; -#else return IsSmallObject::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 -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(&a) == nullptr); + assert(any_cast(&a) == nullptr); } // Assert that an 'any' object stores the specified 'Type' and 'value'. template -void assertContains(std::experimental::any const& a, int value = 1) { - assert(!a.empty()); - RTTI_ASSERT(a.type() == typeid(Type)); - assert(std::experimental::any_cast(a).value == value); +void assertContains(std::any const& a, int value = 1) { + assert(a.has_value()); + assert(containsType(a)); + assert(std::any_cast(a).value == value); +} + +template <> +void assertContains(std::any const& a, int value) { + assert(a.has_value()); + assert(containsType(a)); + assert(std::any_cast(a) == value); } // Modify the value of a "test type" stored within an any to the specified // 'value'. template -void modifyValue(std::experimental::any& a, int value) { - assert(!a.empty()); - RTTI_ASSERT(a.type() == typeid(Type)); - std::experimental::any_cast(a).value = value; +void modifyValue(std::any& a, int value) { + using namespace std; + using namespace std::experimental; + assert(a.has_value()); + assert(containsType(a)); + any_cast(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 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 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 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(small_tracked_t &&) noexcept + : arg_types(&makeArgumentID()) {} + template + explicit small_tracked_t(Args&&...) + : arg_types(&makeArgumentID()) {} + template + explicit small_tracked_t(std::initializer_list, Args&&...) + : arg_types(&makeArgumentID, Args...>()) {} + + TypeID const* arg_types; +}; +static_assert(IsSmallObject::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(large_tracked_t &&) noexcept + : arg_types(&makeArgumentID()) {} + template + explicit large_tracked_t(Args&&...) + : arg_types(&makeArgumentID()) {} + template + explicit large_tracked_t(std::initializer_list, Args&&...) + : arg_types(&makeArgumentID, Args...>()) {} + + TypeID const* arg_types; + int dummy[10]; +}; + +static_assert(!IsSmallObject::value, "must be small"); + + +template +void assertArgsMatch(std::any const& a) { + using namespace std; + using namespace std::experimental; + assert(a.has_value()); + assert(containsType(a)); + assert(any_cast(a).arg_types == &makeArgumentID()); +}; #endif diff --git a/libcxx/test/support/experimental_any_helpers.h b/libcxx/test/support/experimental_any_helpers.h new file mode 100644 index 000000000000..50bd6d68fba5 --- /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 +#include +#include +#include + +#include "test_macros.h" + +#if !defined(TEST_HAS_NO_RTTI) +#define RTTI_ASSERT(X) assert(X) +#else +#define RTTI_ASSERT(X) +#endif + +template + struct IsSmallObject + : public std::integral_constant::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 +bool isSmallType() { +#if defined(_LIBCPP_VERSION) + return std::experimental::__any_imp::_IsSmallObject::value; +#else + return IsSmallObject::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 +void assertEmpty(std::experimental::any const& a) { + assert(a.empty()); + RTTI_ASSERT(a.type() == typeid(void)); + assert(std::experimental::any_cast(&a) == nullptr); +} + +// Assert that an 'any' object stores the specified 'Type' and 'value'. +template +void assertContains(std::experimental::any const& a, int value = 1) { + assert(!a.empty()); + RTTI_ASSERT(a.type() == typeid(Type)); + assert(std::experimental::any_cast(a).value == value); +} + +// Modify the value of a "test type" stored within an any to the specified +// 'value'. +template +void modifyValue(std::experimental::any& a, int value) { + assert(!a.empty()); + RTTI_ASSERT(a.type() == typeid(Type)); + std::experimental::any_cast(a).value = value; +} + +// A test type that will trigger the small object optimization within 'any'. +template +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 small_type::count = 0; + +template +int small_type::copied = 0; + +template +int small_type::moved = 0; + +template +int small_type::const_copied = 0; + +template +int small_type::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 +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 large_type::count = 0; + +template +int large_type::copied = 0; + +template +int large_type::moved = 0; + +template +int large_type::const_copied = 0; + +template +int large_type::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 3e4400af00ee..752bcdaecddb 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__ diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html index e85f91e4fb2b..7c67de789a02 100644 --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -271,7 +271,7 @@ 2436Comparators for associative containers should always be CopyConstructibleOuluComplete 2441Exact-width atomic typedefs should be providedOuluComplete 2451[fund.ts.v2] optional should 'forward' T's implicit conversionsOulu - 2509[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value targetOulu + 2509[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value targetOuluComplete 2516[fund.ts.v2] Public "exposition only" members in observer_ptrOulu 2542Missing const requirements for associative containersOulu 2549Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling referencesOuluComplete