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((void*)__p, /*__size*/0, __alignof(_Tp)); } #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) Index: include/new =================================================================== --- include/new +++ include/new @@ -239,7 +239,7 @@ #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_ALIGNED_OPERATOR_NEW_DELETE +# ifdef _LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE return ::operator new(__size, __align_val); # else return __builtin_operator_new(__size, __align_val); @@ -255,24 +255,78 @@ #endif } -inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) { +struct _DeallocateCaller { + static inline _LIBCPP_INLINE_VISIBILITY + void __do_it(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 + } + + private: + static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) { +#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION + ((void)__size); + __do_call(__ptr); +#else + if (__size == 0) + return __do_call(__ptr); + 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); + __do_call(__ptr, __align); +#else + if (__size == 0) + return __do_call(__ptr, __align); + return __do_call(__ptr, __size, __align); +#endif } +#endif + + 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_it(__ptr, __size, __align); } #ifdef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED Index: include/valarray =================================================================== --- include/valarray +++ include/valarray @@ -3733,7 +3733,7 @@ { while (__end_ != __begin_) (--__end_)->~value_type(); - _VSTD::__libcpp_deallocate(__begin_, __alignof(value_type)); + _VSTD::__libcpp_deallocate(__begin_, /*__size*/0, __alignof(value_type)); __begin_ = __end_ = nullptr; } } 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,166 @@ +//===----------------------------------------------------------------------===// +// +// 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) noexcept { + ::free(p); + ++plain_called; + last_size = last_align = -1; +} + +void operator delete(void *p, size_t n) noexcept { + ::free(p); + ++sized_called; + last_size = n; + last_align = -1; +} + +#ifndef NO_ALIGN +void operator delete(void *p, std::align_val_t a) 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) 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 = alignof(std::max_align_t) * 2; + size_t under_align_val = alignof(int); + size_t no_size_val = 0; + size_t with_size_val = 2; + + { + std::__libcpp_deallocate(p, no_size_val, 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(p, no_size_val, 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 +}