Index: include/new =================================================================== --- include/new +++ include/new @@ -139,9 +139,11 @@ ; _LIBCPP_NEW_DELETE_VIS void* operator new(std::size_t __sz, const std::nothrow_t&) _NOEXCEPT _NOALIAS; _LIBCPP_NEW_DELETE_VIS void operator delete(void* __p) _NOEXCEPT; +_LIBCPP_NEW_DELETE_VIS void operator delete(void* __p, const std::nothrow_t&) _NOEXCEPT; +#if defined(_LIBCPP_BUILDING_NEW) || _LIBCPP_STD_VER >= 14 _LIBCPP_NEW_DELETE_VIS void operator delete(void* __p, std::size_t __sz) _NOEXCEPT; -_LIBCPP_NEW_DELETE_VIS void operator delete(void* __p, const std::nothrow_t&) _NOEXCEPT; _LIBCPP_NEW_DELETE_VIS void operator delete(void* __p, std::size_t __sz, const std::nothrow_t&) _NOEXCEPT; +#endif _LIBCPP_NEW_DELETE_VIS void* operator new[](std::size_t __sz) #if !__has_feature(cxx_noexcept) @@ -150,9 +152,11 @@ ; _LIBCPP_NEW_DELETE_VIS void* operator new[](std::size_t __sz, const std::nothrow_t&) _NOEXCEPT _NOALIAS; _LIBCPP_NEW_DELETE_VIS void operator delete[](void* __p) _NOEXCEPT; +_LIBCPP_NEW_DELETE_VIS void operator delete[](void* __p, const std::nothrow_t&) _NOEXCEPT; +#if defined(_LIBCPP_BUILDING_NEW) || _LIBCPP_STD_VER >= 14 _LIBCPP_NEW_DELETE_VIS void operator delete[](void* __p, std::size_t __sz) _NOEXCEPT; -_LIBCPP_NEW_DELETE_VIS void operator delete[](void* __p, const std::nothrow_t&) _NOEXCEPT; _LIBCPP_NEW_DELETE_VIS void operator delete[](void* __p, std::size_t __sz, const std::nothrow_t&) _NOEXCEPT; +#endif inline _LIBCPP_INLINE_VISIBILITY void* operator new (std::size_t, void* __p) _NOEXCEPT {return __p;} inline _LIBCPP_INLINE_VISIBILITY void* operator new[](std::size_t, void* __p) _NOEXCEPT {return __p;} Index: src/new.cpp =================================================================== --- src/new.cpp +++ src/new.cpp @@ -126,23 +126,23 @@ _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete(void* ptr, size_t) _NOEXCEPT +operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT { ::operator delete(ptr); } _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT +operator delete(void* ptr, size_t) _NOEXCEPT { ::operator delete(ptr); } _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete(void* ptr, size_t, const std::nothrow_t&) _NOEXCEPT +operator delete(void* ptr, size_t, const std::nothrow_t& nt) _NOEXCEPT { - ::operator delete(ptr); + ::operator delete(ptr, nt); } _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS @@ -154,23 +154,23 @@ _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete[] (void* ptr, size_t) _NOEXCEPT +operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT { ::operator delete[](ptr); } _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT +operator delete[] (void* ptr, size_t) _NOEXCEPT { ::operator delete[](ptr); } _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete[] (void* ptr, size_t, const std::nothrow_t&) _NOEXCEPT +operator delete[] (void* ptr, size_t, const std::nothrow_t& nt) _NOEXCEPT { - ::operator delete[](ptr); + ::operator delete[](ptr, nt); } #endif // !__GLIBCXX__ Index: test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 sized operator delete[] by replacing unsized operator delete[]. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int delete_called = 0; +int delete_nothrow_called = 0; + +void operator delete[](void* p) throw() +{ + ++delete_called; + delete_nothrow_called; + std::free(p); +} + +void operator delete[](void* p, const std::nothrow_t&) throw() +{ + ++delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +int A_constructed = 0; + +struct A +{ + A() {++A_constructed;} + ~A() {--A_constructed;} +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void* vp = operator new [] (std::numeric_limits::max()); + assert(false); + } + catch (std::bad_alloc&) + { + assert(new_handler_called == 1); + } + catch (...) + { + assert(false); + } + A* ap = new A[3]; + assert(ap); + assert(A_constructed == 3); + assert(!delete_called); + assert(!delete_nothrow_called); + delete [] ap; + assert(A_constructed == 0); + assert(delete_called == 1); + assert(!delete_nothrow_called); +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 nothrow sized operator delete[] by replacing +// nothrow unsized operator delete[]. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int delete_called = 0; +int delete_nothrow_called = 0; + +void operator delete[](void* p) throw() +{ + ++delete_called; + std::free(p); +} + +void operator delete[](void* p, const std::nothrow_t&) throw() +{ + ++delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +struct BadA : public A { + BadA() { throw std::bad_alloc(); } +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void*volatile vp = operator new [] (std::numeric_limits::max(), std::nothrow); + assert(new_handler_called == 1); + assert(vp == 0); + } + catch (...) + { + assert(false); + } + try + { + A* ap = new(std::nothrow) BadA [3]; + assert(false); + } + catch (...) + { + assert(!A_constructed); + assert(!delete_called); + assert(delete_nothrow_called == 1); + } +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow_replace.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow_replace.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow_replace.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 nothrow sized operator delete[] replacement. + +// Note that sized delete operator definitions below are simply ignored +// when sized deallocation is not supported, e.g., prior to C++14. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int unsized_delete_called = 0; +int unsized_delete_nothrow_called = 0; +int sized_delete_called = 0; +int sized_delete_nothrow_called = 0; + +void operator delete[](void* p) throw() +{ + ++unsized_delete_called; + std::free(p); +} + +void operator delete[](void* p, const std::nothrow_t&) throw() +{ + ++unsized_delete_nothrow_called; + std::free(p); +} + +void operator delete[](void* p, std::size_t) throw() +{ + ++sized_delete_called; + std::free(p); +} + +void operator delete[](void* p, std::size_t, const std::nothrow_t&) throw() +{ + ++sized_delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +struct BadA : public A { + BadA() { throw std::bad_alloc(); } +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void*volatile vp = operator new [] (std::numeric_limits::max(), std::nothrow); + assert(new_handler_called == 1); + assert(vp == 0); + } + catch (...) + { + assert(false); + } + try + { + A* ap = new(std::nothrow) BadA [3]; + assert(false); + } + catch (...) + { + assert(!A_constructed); +#if _LIBCPP_STD_VER >= 14 + // FIXME: Do we need a version of [Expr.Delete]#10 for nothrow + // deallocation functions (selecting sized ones whenever available)? + // It is not required by the standard. If it were, the following would + // be the expected behaviour (instead of the current one): + // assert(!unsized_delete_nothrow_called); + // assert(sized_delete_nothrow_called == 1); + assert(unsized_delete_nothrow_called == 1); + assert(!sized_delete_nothrow_called); +#else // if _LIBCPP_STD_VER < 14 + assert(unsized_delete_nothrow_called == 1); + assert(!sized_delete_nothrow_called); +#endif + assert(!unsized_delete_called); + assert(!sized_delete_called); + } +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_replace.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_replace.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_replace.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. +// +//===----------------------------------------------------------------------===// + +// test sized operator delete[] replacement. + +// Note that sized delete operator definitions below are simply ignored +// when sized deallocation is not supported, e.g., prior to C++14. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int unsized_delete_called = 0; +int unsized_delete_nothrow_called = 0; +int sized_delete_called = 0; +int sized_delete_nothrow_called = 0; + +void operator delete[](void* p) throw() +{ + ++unsized_delete_called; + std::free(p); +} + +void operator delete[](void* p, const std::nothrow_t&) throw() +{ + ++unsized_delete_nothrow_called; + std::free(p); +} + +void operator delete[](void* p, std::size_t) throw() +{ + ++sized_delete_called; + std::free(p); +} + +void operator delete[](void* p, std::size_t, const std::nothrow_t&) throw() +{ + ++sized_delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +int A_constructed = 0; + +struct A +{ + A() {++A_constructed;} + ~A() {--A_constructed;} +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void* vp = operator new [] (std::numeric_limits::max()); + assert(false); + } + catch (std::bad_alloc&) + { + assert(new_handler_called == 1); + } + catch (...) + { + assert(false); + } + A* ap = new A[3]; + assert(ap); + assert(A_constructed == 3); + assert(!unsized_delete_called); + assert(!unsized_delete_nothrow_called); + assert(!sized_delete_called); + assert(!sized_delete_nothrow_called); + delete [] ap; + assert(A_constructed == 0); +#if _LIBCPP_STD_VER >= 14 + assert(!unsized_delete_called); + assert(sized_delete_called == 1); +#else // if _LIBCPP_STD_VER < 14 + assert(unsized_delete_called == 1); + assert(!sized_delete_called); +#endif + assert(!unsized_delete_nothrow_called); + assert(!sized_delete_nothrow_called); +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 sized operator delete by replacing unsized operator delete. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int delete_called = 0; +int delete_nothrow_called = 0; + +void operator delete(void* p) throw() +{ + ++delete_called; + delete_nothrow_called; + std::free(p); +} + +void operator delete(void* p, const std::nothrow_t&) throw() +{ + ++delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void* vp = operator new (std::numeric_limits::max()); + assert(false); + } + catch (std::bad_alloc&) + { + assert(new_handler_called == 1); + } + catch (...) + { + assert(false); + } + A* ap = new A; + assert(ap); + assert(A_constructed); + assert(!delete_called); + assert(!delete_nothrow_called); + delete ap; + assert(!A_constructed); + assert(delete_called == 1); + assert(!delete_nothrow_called); +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 nothrow sized operator delete by replacing +// nothrow unsized operator delete. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int delete_called = 0; +int delete_nothrow_called = 0; + +void operator delete(void* p) throw() +{ + ++delete_called; + std::free(p); +} + +void operator delete(void* p, const std::nothrow_t&) throw() +{ + ++delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +struct BadA : public A { + BadA() { throw std::bad_alloc(); } +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void* volatile vp = operator new (std::numeric_limits::max(), std::nothrow); + assert(new_handler_called == 1); + assert(vp == 0); + } + catch (...) + { + assert(false); + } + try + { + A* ap = new(std::nothrow) BadA; + assert(false); + } + catch (...) + { + assert(!A_constructed); + assert(!delete_called); + assert(delete_nothrow_called == 1); + } +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow_replace.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow_replace.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow_replace.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 nothrow sized operator delete replacement. + +// Note that sized delete operator definitions below are simply ignored +// when sized deallocation is not supported, e.g., prior to C++14. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int unsized_delete_called = 0; +int unsized_delete_nothrow_called = 0; +int sized_delete_called = 0; +int sized_delete_nothrow_called = 0; + +void operator delete(void* p) throw() +{ + ++unsized_delete_called; + std::free(p); +} + +void operator delete(void* p, const std::nothrow_t&) throw() +{ + ++unsized_delete_nothrow_called; + std::free(p); +} + +void operator delete(void* p, std::size_t) throw() +{ + ++sized_delete_called; + std::free(p); +} + +void operator delete(void* p, std::size_t, const std::nothrow_t&) throw() +{ + ++sized_delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +struct BadA : public A { + BadA() { throw std::bad_alloc(); } +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void*volatile vp = operator new (std::numeric_limits::max(), std::nothrow); + assert(new_handler_called == 1); + assert(vp == 0); + } + catch (...) + { + assert(false); + } + try + { + A* ap = new(std::nothrow) BadA; + assert(false); + } + catch (...) + { + assert(!A_constructed); +#if _LIBCPP_STD_VER >= 14 + // FIXME: Do we need a version of [Expr.Delete]#10 for nothrow + // deallocation functions (selecting sized ones whenever available)? + // It is not required by the standard. If it were, the following would + // be the expected behaviour (instead of the current one): + // assert(!unsized_delete_nothrow_called); + // assert(sized_delete_nothrow_called == 1); + assert(unsized_delete_nothrow_called == 1); + assert(!sized_delete_nothrow_called); +#else // if _LIBCPP_STD_VER < 14 + assert(unsized_delete_nothrow_called == 1); + assert(!sized_delete_nothrow_called); +#endif + assert(!unsized_delete_called); + assert(!sized_delete_called); + } +} Index: test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_replace.pass.cpp =================================================================== --- test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_replace.pass.cpp +++ test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_replace.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. +// +//===----------------------------------------------------------------------===// + +// test sized operator delete replacement. + +// Note that sized delete operator definitions below are simply ignored +// when sized deallocation is not supported, e.g., prior to C++14. + +// UNSUPPORTED: asan, msan + +#include +#include +#include +#include +#include + +int unsized_delete_called = 0; +int unsized_delete_nothrow_called = 0; +int sized_delete_called = 0; +int sized_delete_nothrow_called = 0; + +void operator delete(void* p) throw() +{ + ++unsized_delete_called; + std::free(p); +} + +void operator delete(void* p, const std::nothrow_t&) throw() +{ + ++unsized_delete_nothrow_called; + std::free(p); +} + +void operator delete(void* p, std::size_t) throw() +{ + ++sized_delete_called; + std::free(p); +} + +void operator delete(void* p, std::size_t, const std::nothrow_t&) throw() +{ + ++sized_delete_nothrow_called; + std::free(p); +} + +int new_handler_called = 0; + +void new_handler() +{ + ++new_handler_called; + std::set_new_handler(0); +} + +bool A_constructed = false; + +struct A +{ + A() {A_constructed = true;} + ~A() {A_constructed = false;} +}; + +int main() +{ + std::set_new_handler(new_handler); + try + { + void* vp = operator new (std::numeric_limits::max()); + assert(false); + } + catch (std::bad_alloc&) + { + assert(new_handler_called == 1); + } + catch (...) + { + assert(false); + } + A* ap = new A; + assert(ap); + assert(A_constructed); + assert(!unsized_delete_called); + assert(!unsized_delete_nothrow_called); + assert(!sized_delete_called); + assert(!sized_delete_nothrow_called); + delete ap; + assert(!A_constructed); +#if _LIBCPP_STD_VER >= 14 + assert(!unsized_delete_called); + assert(sized_delete_called == 1); +#else // if _LIBCPP_STD_VER < 14 + assert(unsized_delete_called == 1); + assert(!sized_delete_called); +#endif + assert(!unsized_delete_nothrow_called); + assert(!sized_delete_nothrow_called); +}