Index: include/__sso_allocator =================================================================== --- include/__sso_allocator +++ include/__sso_allocator @@ -57,12 +57,12 @@ } return static_cast(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp))); } - _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) + _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) { if (__p == (pointer)&buf_) __allocated_ = false; else - _VSTD::__libcpp_deallocate(__p, __alignof(_Tp)); + _VSTD::__libcpp_deallocate(__p, __n * sizeof(_Tp), __alignof(_Tp)); } _LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);} Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -1799,8 +1799,8 @@ " 'n' exceeds maximum supported size"); return static_cast(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp))); } - _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT - {_VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));} + _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT + {_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), __alignof(_Tp));} _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) @@ -1900,8 +1900,8 @@ " 'n' exceeds maximum supported size"); return static_cast(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp))); } - _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT - {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __alignof(_Tp));} + _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT + {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), __alignof(_Tp));} _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) @@ -2052,7 +2052,7 @@ inline _LIBCPP_INLINE_VISIBILITY void return_temporary_buffer(_Tp* __p) _NOEXCEPT { - _VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp)); + _VSTD::__libcpp_deallocate_unsized((void*)__p, __alignof(_Tp)); } #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) Index: include/new =================================================================== --- include/new +++ include/new @@ -104,12 +104,17 @@ #pragma GCC system_header #endif -#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14 +#if !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation < 201309L +#define _LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION +#endif + +#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14 && \ + defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION) # define _LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION #endif #if defined(_LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION) || \ - !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation < 201309 + defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION) # define _LIBCPP_HAS_NO_SIZED_DEALLOCATION #endif @@ -255,24 +260,94 @@ #endif } -inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) { +struct _DeallocateCaller { + static inline _LIBCPP_INLINE_VISIBILITY + void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) { +#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + ((void)__align); + return __do_deallocate_handle_size(__ptr, __size); +#else + if (__is_overaligned_for_new(__align)) { + const align_val_t __align_val = static_cast(__align); + return __do_deallocate_handle_size(__ptr, __size, __align_val); + } else { + return __do_deallocate_handle_size(__ptr, __size); + } +#endif + } + + static inline _LIBCPP_INLINE_VISIBILITY + void __do_deallocate_handle_align(void *__ptr, size_t __align) { +#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + ((void)__align); + return __do_call(__ptr); +#else + if (__is_overaligned_for_new(__align)) { + const align_val_t __align_val = static_cast(__align); + return __do_call(__ptr, __align_val); + } else { + return __do_call(__ptr); + } +#endif + } + + private: + static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) { +#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION + ((void)__size); + return __do_call(__ptr); +#else + return __do_call(__ptr, __size); +#endif + } + #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION - if (__is_overaligned_for_new(__align)) { - const align_val_t __align_val = static_cast(__align); -# ifdef _LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE - return ::operator delete(__ptr, __align_val); -# else - return __builtin_operator_delete(__ptr, __align_val); -# endif + static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) { +#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION + ((void)__size); + return __do_call(__ptr, __align); +#else + return __do_call(__ptr, __size, __align); +#endif } +#endif + +private: + template + static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) { +#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ + defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) + return ::operator delete(__ptr, __a1, __a2); #else - ((void)__align); + return __builtin_operator_delete(__ptr, __a1, __a2); #endif + } + + template + static inline void __do_call(void *__ptr, _A1 __a1) { +#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ + defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) + return ::operator delete(__ptr, __a1); +#else + return __builtin_operator_delete(__ptr, __a1); +#endif + } + + static inline void __do_call(void *__ptr) { #ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE - return ::operator delete(__ptr); + return ::operator delete(__ptr); #else - return __builtin_operator_delete(__ptr); + return __builtin_operator_delete(__ptr); #endif + } +}; + +inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) { + _DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align); +} + +inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate_unsized(void* __ptr, size_t __align) { + _DeallocateCaller::__do_deallocate_handle_align(__ptr, __align); } #ifdef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED Index: include/valarray =================================================================== --- include/valarray +++ include/valarray @@ -1054,7 +1054,7 @@ const _Up* end(const valarray<_Up>& __v); - void __clear(); + void __clear(size_t __capacity); valarray& __assign_range(const value_type* __f, const value_type* __l); }; @@ -2762,13 +2762,13 @@ try { #endif // _LIBCPP_NO_EXCEPTIONS - for (; __n; --__n, ++__end_) + for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) ::new (__end_) value_type(); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2797,13 +2797,13 @@ try { #endif // _LIBCPP_NO_EXCEPTIONS - for (; __n; ++__end_, ++__p, --__n) + for (size_t __n_left = __n; __n_left; ++__end_, ++__p, --__n_left) ::new (__end_) value_type(*__p); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2829,7 +2829,7 @@ } catch (...) { - __clear(); + __clear(__v.size()); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2852,7 +2852,7 @@ : __begin_(0), __end_(0) { - size_t __n = __il.size(); + const size_t __n = __il.size(); if (__n) { __begin_ = __end_ = static_cast( @@ -2861,13 +2861,14 @@ try { #endif // _LIBCPP_NO_EXCEPTIONS - for (const value_type* __p = __il.begin(); __n; ++__end_, ++__p, --__n) + size_t __n_left = __n; + for (const value_type* __p = __il.begin(); __n_left; ++__end_, ++__p, --__n_left) ::new (__end_) value_type(*__p); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2881,7 +2882,7 @@ : __begin_(0), __end_(0) { - size_t __n = __sa.__size_; + const size_t __n = __sa.__size_; if (__n) { __begin_ = __end_ = static_cast( @@ -2890,13 +2891,14 @@ try { #endif // _LIBCPP_NO_EXCEPTIONS - for (const value_type* __p = __sa.__vp_; __n; ++__end_, __p += __sa.__stride_, --__n) + size_t __n_left = __n; + for (const value_type* __p = __sa.__vp_; __n_left; ++__end_, __p += __sa.__stride_, --__n_left) ::new (__end_) value_type(*__p); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2908,7 +2910,7 @@ : __begin_(0), __end_(0) { - size_t __n = __ga.__1d_.size(); + const size_t __n = __ga.__1d_.size(); if (__n) { __begin_ = __end_ = static_cast( @@ -2926,7 +2928,7 @@ } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2938,7 +2940,7 @@ : __begin_(0), __end_(0) { - size_t __n = __ma.__1d_.size(); + const size_t __n = __ma.__1d_.size(); if (__n) { __begin_ = __end_ = static_cast( @@ -2956,7 +2958,7 @@ } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2968,7 +2970,7 @@ : __begin_(0), __end_(0) { - size_t __n = __ia.__1d_.size(); + const size_t __n = __ia.__1d_.size(); if (__n) { __begin_ = __end_ = static_cast( @@ -2986,7 +2988,7 @@ } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS @@ -2997,7 +2999,7 @@ inline valarray<_Tp>::~valarray() { - __clear(); + __clear(size()); } template @@ -3007,7 +3009,7 @@ size_t __n = __l - __f; if (size() != __n) { - __clear(); + __clear(size()); __begin_ = static_cast( _VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type))); __end_ = __begin_ + __n; @@ -3034,7 +3036,7 @@ valarray<_Tp>& valarray<_Tp>::operator=(valarray&& __v) _NOEXCEPT { - __clear(); + __clear(size()); __begin_ = __v.__begin_; __end_ = __v.__end_; __v.__begin_ = nullptr; @@ -3726,23 +3728,23 @@ } template -void -valarray<_Tp>::__clear() +inline _LIBCPP_INLINE_VISIBILITY +void valarray<_Tp>::__clear(size_t __capacity) { - if (__begin_ != nullptr) - { - while (__end_ != __begin_) - (--__end_)->~value_type(); - _VSTD::__libcpp_deallocate(__begin_, __alignof(value_type)); - __begin_ = __end_ = nullptr; - } + if (__begin_ != nullptr) + { + while (__end_ != __begin_) + (--__end_)->~value_type(); + _VSTD::__libcpp_deallocate(__begin_, __capacity * sizeof(value_type), __alignof(value_type)); + __begin_ = __end_ = nullptr; + } } template void valarray<_Tp>::resize(size_t __n, value_type __x) { - __clear(); + __clear(size()); if (__n) { __begin_ = __end_ = static_cast( @@ -3751,13 +3753,13 @@ try { #endif // _LIBCPP_NO_EXCEPTIONS - for (; __n; --__n, ++__end_) + for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) ::new (__end_) value_type(__x); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - __clear(); + __clear(__n); throw; } #endif // _LIBCPP_NO_EXCEPTIONS Index: src/experimental/memory_resource.cpp =================================================================== --- src/experimental/memory_resource.cpp +++ src/experimental/memory_resource.cpp @@ -33,8 +33,8 @@ virtual void* do_allocate(size_t __size, size_t __align) { return _VSTD::__libcpp_allocate(__size, __align); /* FIXME */} - virtual void do_deallocate(void * __p, size_t, size_t __align) - { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ } + virtual void do_deallocate(void * __p, size_t __n, size_t __align) + { _VSTD::__libcpp_deallocate(__p, __n, __align); /* FIXME */ } virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT { return &__other == this; } Index: test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp =================================================================== --- /dev/null +++ test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp @@ -0,0 +1,165 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// test libc++'s implementation of align_val_t, and the relevent new/delete +// overloads in all dialects when -faligned-allocation is present. + +// Libc++ defers to the underlying MSVC library to provide the new/delete +// definitions, which does not yet provide aligned allocation +// XFAIL: LIBCXX-WINDOWS-FIXME + +// XFAIL: with_system_cxx_lib=macosx10.12 +// XFAIL: with_system_cxx_lib=macosx10.11 +// XFAIL: with_system_cxx_lib=macosx10.10 +// XFAIL: with_system_cxx_lib=macosx10.9 +// XFAIL: with_system_cxx_lib=macosx10.7 +// XFAIL: with_system_cxx_lib=macosx10.8 + +// RUN: %build -faligned-allocation -fsized-deallocation +// RUN: %run +// RUN: %build -faligned-allocation -fno-sized-deallocation -DNO_SIZE +// RUN: %run +// RUN: %build -fno-aligned-allocation -fsized-deallocation -DNO_ALIGN +// RUN: %run +// RUN: %build -fno-aligned-allocation -fno-sized-deallocation -DNO_ALIGN -DNO_SIZE +// RUN: %run + + +#include +#include +#include +#include + +#include "test_macros.h" + +int aligned_sized_called = 0; +int aligned_called = 0; +int sized_called = 0; +int plain_called = 0; +int last_size = -1; +int last_align = -1; + +void reset_state() { + aligned_sized_called = aligned_called = sized_called = plain_called = 0; + last_size = last_align = -1; +} + +void operator delete(void *p) TEST_NOEXCEPT { + ::free(p); + ++plain_called; + last_size = last_align = -1; +} + +void operator delete(void *p, size_t n) TEST_NOEXCEPT { + ::free(p); + ++sized_called; + last_size = n; + last_align = -1; +} + +#ifndef NO_ALIGN +void operator delete(void *p, std::align_val_t a) TEST_NOEXCEPT { + ::free(p); + ++aligned_called; + last_align = static_cast(a); + last_size = -1; +} + +void operator delete(void * p, size_t n, std::align_val_t a) TEST_NOEXCEPT { + ::free(p); + ++aligned_sized_called; + last_align = static_cast(a); + last_size = n; +} +#endif + +bool expect_plain() { + assert(aligned_sized_called == 0); + assert(aligned_called == 0); + assert(sized_called == 0); + assert(last_size == -1); + assert(last_align == -1); + return plain_called == 1; +} + +bool expect_size(int n) { + assert(plain_called == 0); + assert(aligned_sized_called == 0); + assert(aligned_called == 0); + assert(last_size == n); + assert(last_align == -1); + return sized_called == 1; +} + +bool expect_align(int a) { + assert(plain_called == 0); + assert(aligned_sized_called == 0); + assert(sized_called == 0); + assert(last_size == -1); + assert(last_align == a); + return aligned_called == 1; +} + +bool expect_size_align(int n, int a) { + assert(plain_called == 0); + assert(sized_called == 0); + assert(aligned_called == 0); + assert(last_size == n); + assert(last_align == a); + return aligned_sized_called == 1; +} + +int main() { + void *p = nullptr; + size_t over_align_val = TEST_ALIGNOF(std::max_align_t) * 2; + size_t under_align_val = TEST_ALIGNOF(int); + size_t with_size_val = 2; + + { + std::__libcpp_deallocate_unsized(p, under_align_val); + assert(expect_plain()); + } + reset_state(); + +#if defined(NO_SIZE) && defined(NO_ALIGN) + { + std::__libcpp_deallocate(p, with_size_val, over_align_val); + assert(expect_plain()); + } + reset_state(); +#elif defined(NO_SIZE) + { + std::__libcpp_deallocate(p, with_size_val, over_align_val); + assert(expect_align(over_align_val)); + } + reset_state(); +#elif defined(NO_ALIGN) + { + std::__libcpp_deallocate(p, with_size_val, over_align_val); + assert(expect_size(with_size_val)); + } + reset_state(); +#else + { + std::__libcpp_deallocate(p, with_size_val, over_align_val); + assert(expect_size_align(with_size_val, over_align_val)); + } + reset_state(); + { + std::__libcpp_deallocate_unsized(p, over_align_val); + assert(expect_align(over_align_val)); + } + reset_state(); + { + std::__libcpp_deallocate(p, with_size_val, under_align_val); + assert(expect_size(with_size_val)); + } + reset_state(); +#endif +}