#include <experimental/__config>
#include <memory>
-#include <new>
#include <typeinfo>
#include <type_traits>
#include <cstdlib>
template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY
static _Tp& __create(any & __dest, _Args&&... __args) {
- _Tp* __ret = ::new (static_cast<void*>(&__dest.__s.__buf)) _Tp(_VSTD::forward<_Args>(__args)...);
+ typedef allocator<_Tp> _Alloc;
+ typedef allocator_traits<_Alloc> _ATraits;
+ _Alloc __a;
+ _Tp * __ret = static_cast<_Tp*>(static_cast<void*>(&__dest.__s.__buf));
+ _ATraits::construct(__a, __ret, _VSTD::forward<_Args>(__args)...);
__dest.__h = &_SmallHandler::__handle;
return *__ret;
}
private:
_LIBCPP_INLINE_VISIBILITY
static void __destroy(any & __this) {
- _Tp & __value = *static_cast<_Tp *>(static_cast<void*>(&__this.__s.__buf));
- __value.~_Tp();
+ typedef allocator<_Tp> _Alloc;
+ typedef allocator_traits<_Alloc> _ATraits;
+ _Alloc __a;
+ _Tp * __p = static_cast<_Tp *>(static_cast<void*>(&__this.__s.__buf));
+ _ATraits::destroy(__a, __p);
__this.__h = nullptr;
}
_LIBCPP_INLINE_VISIBILITY
static _Tp& __create(any & __dest, _Args&&... __args) {
typedef allocator<_Tp> _Alloc;
+ typedef allocator_traits<_Alloc> _ATraits;
typedef __allocator_destructor<_Alloc> _Dp;
_Alloc __a;
- unique_ptr<_Tp, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
- _Tp* __ret = ::new ((void*)__hold.get()) _Tp(_VSTD::forward<_Args>(__args)...);
+ unique_ptr<_Tp, _Dp> __hold(_ATraits::allocate(__a, 1), _Dp(__a, 1));
+ _Tp * __ret = __hold.get();
+ _ATraits::construct(__a, __ret, _VSTD::forward<_Args>(__args)...);
__dest.__s.__ptr = __hold.release();
__dest.__h = &_LargeHandler::__handle;
return *__ret;
_LIBCPP_INLINE_VISIBILITY
static void __destroy(any & __this){
- delete static_cast<_Tp*>(__this.__s.__ptr);
+ typedef allocator<_Tp> _Alloc;
+ typedef allocator_traits<_Alloc> _ATraits;
+ _Alloc __a;
+ _Tp * __p = static_cast<_Tp *>(__this.__s.__ptr);
+ _ATraits::destroy(__a, __p);
+ _ATraits::deallocate(__a, __p, 1);
__this.__h = nullptr;
}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <any>
+
+// Check that we're consistently using std::allocator_traits to
+// allocate/deallocate/construct/destroy objects in std::any.
+// See https://llvm.org/PR45099 for details.
+
+#include <any>
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+
+// Make sure we don't fit in std::any's SBO
+struct Large { char big[sizeof(std::any) + 1]; };
+
+// Make sure we fit in std::any's SBO
+struct Small { };
+
+bool Large_was_allocated = false;
+bool Large_was_constructed = false;
+bool Large_was_destroyed = false;
+bool Large_was_deallocated = false;
+
+bool Small_was_allocated = false;
+bool Small_was_constructed = false;
+bool Small_was_destroyed = false;
+bool Small_was_deallocated = false;
+
+namespace std {
+ template <>
+ struct allocator<Large> {
+ using value_type = Large;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using propagate_on_container_move_assignment = std::true_type;
+ using is_always_equal = std::true_type;
+
+ Large* allocate(std::size_t n) {
+ Large_was_allocated = true;
+ return static_cast<Large*>(::operator new(n));
+ }
+
+ template <typename ...Args>
+ void construct(Large* p, Args&& ...args) {
+ new (p) Large(std::forward<Args>(args)...);
+ Large_was_constructed = true;
+ }
+
+ void destroy(Large* p) {
+ p->~Large();
+ Large_was_destroyed = true;
+ }
+
+ void deallocate(Large* p, std::size_t) {
+ Large_was_deallocated = true;
+ return ::operator delete(p);
+ }
+ };
+
+ template <>
+ struct allocator<Small> {
+ using value_type = Small;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using propagate_on_container_move_assignment = std::true_type;
+ using is_always_equal = std::true_type;
+
+ Small* allocate(std::size_t n) {
+ Small_was_allocated = true;
+ return static_cast<Small*>(::operator new(n));
+ }
+
+ template <typename ...Args>
+ void construct(Small* p, Args&& ...args) {
+ new (p) Small(std::forward<Args>(args)...);
+ Small_was_constructed = true;
+ }
+
+ void destroy(Small* p) {
+ p->~Small();
+ Small_was_destroyed = true;
+ }
+
+ void deallocate(Small* p, std::size_t) {
+ Small_was_deallocated = true;
+ return ::operator delete(p);
+ }
+ };
+} // end namespace std
+
+
+int main(int, char**) {
+ // Test large types
+ {
+ {
+ std::any a = Large();
+ (void)a;
+
+ assert(Large_was_allocated);
+ assert(Large_was_constructed);
+ }
+
+ assert(Large_was_destroyed);
+ assert(Large_was_deallocated);
+ }
+
+ // Test small types
+ {
+ {
+ std::any a = Small();
+ (void)a;
+
+ assert(!Small_was_allocated);
+ assert(Small_was_constructed);
+ }
+
+ assert(Small_was_destroyed);
+ assert(!Small_was_deallocated);
+ }
+
+ return 0;
+}