diff --git a/include/new b/include/new index 7268b4bd..29c1a839 100644 --- a/include/new +++ b/include/new @@ -139,9 +139,11 @@ _LIBCPP_NEW_DELETE_VIS void* operator new(std::size_t __sz) ; _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, std::size_t __sz) _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, 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) ; _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, std::size_t __sz) _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, 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;} diff --git a/src/new.cpp b/src/new.cpp index a9b3733d..c46d073f 100644 --- a/src/new.cpp +++ b/src/new.cpp @@ -124,13 +124,6 @@ operator delete(void* ptr) _NOEXCEPT ::free(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS -void -operator delete(void* ptr, size_t) _NOEXCEPT -{ - ::operator delete(ptr); -} - _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT @@ -140,11 +133,18 @@ operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete(void* ptr, size_t, 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& nt) _NOEXCEPT +{ + ::operator delete(ptr, nt); +} + _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void operator delete[] (void* ptr) _NOEXCEPT @@ -152,13 +152,6 @@ operator delete[] (void* ptr) _NOEXCEPT ::operator delete(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS -void -operator delete[] (void* ptr, size_t) _NOEXCEPT -{ - ::operator delete[](ptr); -} - _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT @@ -168,11 +161,18 @@ operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS void -operator delete[] (void* ptr, size_t, 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& nt) _NOEXCEPT +{ + ::operator delete[](ptr, nt); +} + #endif // !__GLIBCXX__ namespace std diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp new file mode 100644 index 00000000..57e6cd6f --- /dev/null +++ b/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); +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow.pass.cpp new file mode 100644 index 00000000..05dc013a --- /dev/null +++ b/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); + } +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow_replace.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_nothrow_replace.pass.cpp new file mode 100644 index 00000000..6a5320bf --- /dev/null +++ b/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); + } +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_replace.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array_replace.pass.cpp new file mode 100644 index 00000000..752cd70d --- /dev/null +++ b/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); +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp new file mode 100644 index 00000000..6e3a2352 --- /dev/null +++ b/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); +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow.pass.cpp new file mode 100644 index 00000000..690e8afe --- /dev/null +++ b/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); + } +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow_replace.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_nothrow_replace.pass.cpp new file mode 100644 index 00000000..b5eb9f25 --- /dev/null +++ b/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); + } +} diff --git a/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_replace.pass.cpp b/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete_replace.pass.cpp new file mode 100644 index 00000000..4e0d7c7a --- /dev/null +++ b/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); +}