diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index aa90b20410d..fd547e26039 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,31 @@ +2018-08-10 Jonathan Wakely + + PR libstdc++/68210 + * doc/xml/manual/intro.xml: Document LWG 206 change. + * libsupc++/del_op.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept. + * libsupc++/del_opa.cc: Likewise. + * libsupc++/del_opant.cc: Likewise. + * libsupc++/del_opnt.cc: Likewise. Call operator delete(ptr) instead + of free(ptr). + * libsupc++/del_ops.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept. + * libsupc++/del_opsa.cc: Likewise. + * libsupc++/del_opva.cc: Likewise. + * libsupc++/del_opvant.cc: Likewise. + * libsupc++/del_opvnt.cc: Likewise. Call operator delete[](ptr) + instead of operator delete(ptr). + * libsupc++/del_opvs.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept. + * libsupc++/del_opvsa.cc: Likewise. + * libsupc++/new_op.cc: Use __builtin_expect in check for zero size. + * libsupc++/new_opa.cc: Use nullptr instead of literal 0. + * libsupc++/new_opant.cc: Likewise. Replace _GLIBCXX_USE_NOEXCEPT + with noexcept. + * libsupc++/new_opnt.cc: Likewise. Call operator new(sz) instead of + malloc(sz). + * libsupc++/new_opvant.cc: Use nullptr and noexcept. + * libsupc++/new_opvnt.cc: Likewise. Call operator new[](sz) instead of + operator new(sz, nothrow). + * testsuite/18_support/new_nothrow.cc: New test. + 2018-08-10 Martin Liska * libsupc++/new_op.cc (new): Remove __builtin_expect as malloc diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index fea07e2bb5f..cb187e1a2ed 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -440,6 +440,17 @@ requirements of the license of GCC. Yes, it can, specifically if EOF is reached while skipping whitespace. + 206: + operator new(size_t, nothrow) may become + unlinked to ordinary operator new if ordinary + version replaced + + + The nothrow forms of new and delete were + changed to call the throwing forms, handling any exception by + catching it and returning a null pointer. + + 211: operator>>(istream&, string&) doesn't set failbit diff --git a/libstdc++-v3/libsupc++/del_op.cc b/libstdc++-v3/libsupc++/del_op.cc index 9a5cb82fdf0..ab3b617afa7 100644 --- a/libstdc++-v3/libsupc++/del_op.cc +++ b/libstdc++-v3/libsupc++/del_op.cc @@ -44,7 +44,7 @@ _GLIBCXX_END_NAMESPACE_VERSION #pragma GCC diagnostic ignored "-Wsized-deallocation" _GLIBCXX_WEAK_DEFINITION void -operator delete(void* ptr) _GLIBCXX_USE_NOEXCEPT +operator delete(void* ptr) noexcept { std::free(ptr); } diff --git a/libstdc++-v3/libsupc++/del_opa.cc b/libstdc++-v3/libsupc++/del_opa.cc index 71f384df661..2a1f0aba3a1 100644 --- a/libstdc++-v3/libsupc++/del_opa.cc +++ b/libstdc++-v3/libsupc++/del_opa.cc @@ -44,7 +44,7 @@ _GLIBCXX_END_NAMESPACE_VERSION #pragma GCC diagnostic ignored "-Wsized-deallocation" _GLIBCXX_WEAK_DEFINITION void -operator delete(void* ptr, std::align_val_t) _GLIBCXX_USE_NOEXCEPT +operator delete(void* ptr, std::align_val_t) noexcept { #if _GLIBCXX_HAVE_ALIGNED_ALLOC || _GLIBCXX_HAVE_POSIX_MEMALIGN \ || _GLIBCXX_HAVE_MEMALIGN diff --git a/libstdc++-v3/libsupc++/del_opant.cc b/libstdc++-v3/libsupc++/del_opant.cc index a4305a3146a..603d9f2e9d2 100644 --- a/libstdc++-v3/libsupc++/del_opant.cc +++ b/libstdc++-v3/libsupc++/del_opant.cc @@ -27,7 +27,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete (void *ptr, std::align_val_t al, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT +operator delete (void *ptr, std::align_val_t al, const std::nothrow_t&) noexcept { ::operator delete (ptr, al); } diff --git a/libstdc++-v3/libsupc++/del_opnt.cc b/libstdc++-v3/libsupc++/del_opnt.cc index 2bbcdc3dceb..a2762659d9f 100644 --- a/libstdc++-v3/libsupc++/del_opnt.cc +++ b/libstdc++-v3/libsupc++/del_opnt.cc @@ -41,7 +41,10 @@ _GLIBCXX_END_NAMESPACE_VERSION #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete (void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT +operator delete (void *ptr, const std::nothrow_t&) noexcept { - std::free(ptr); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 206. operator new(size_t, nothrow) may become unlinked to ordinary + // operator new if ordinary version replaced + ::operator delete (ptr); } diff --git a/libstdc++-v3/libsupc++/del_ops.cc b/libstdc++-v3/libsupc++/del_ops.cc index 1fa24f22dc3..e452c7cf19e 100644 --- a/libstdc++-v3/libsupc++/del_ops.cc +++ b/libstdc++-v3/libsupc++/del_ops.cc @@ -28,7 +28,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete(void* ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT +operator delete(void* ptr, std::size_t) noexcept { ::operator delete (ptr); } diff --git a/libstdc++-v3/libsupc++/del_opsa.cc b/libstdc++-v3/libsupc++/del_opsa.cc index 1984fce9c90..2cadb4b6ae4 100644 --- a/libstdc++-v3/libsupc++/del_opsa.cc +++ b/libstdc++-v3/libsupc++/del_opsa.cc @@ -27,7 +27,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete(void* ptr, std::size_t, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT +operator delete(void* ptr, std::size_t, std::align_val_t al) noexcept { ::operator delete (ptr, al); } diff --git a/libstdc++-v3/libsupc++/del_opva.cc b/libstdc++-v3/libsupc++/del_opva.cc index dc727b38c24..a539ccc8187 100644 --- a/libstdc++-v3/libsupc++/del_opva.cc +++ b/libstdc++-v3/libsupc++/del_opva.cc @@ -30,7 +30,7 @@ #pragma GCC diagnostic ignored "-Wsized-deallocation" _GLIBCXX_WEAK_DEFINITION void -operator delete[] (void *ptr, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT +operator delete[] (void *ptr, std::align_val_t al) noexcept { ::operator delete (ptr, al); } diff --git a/libstdc++-v3/libsupc++/del_opvant.cc b/libstdc++-v3/libsupc++/del_opvant.cc index 86406b253b1..892c8b7999b 100644 --- a/libstdc++-v3/libsupc++/del_opvant.cc +++ b/libstdc++-v3/libsupc++/del_opvant.cc @@ -27,7 +27,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete[] (void *ptr, std::align_val_t al, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT +operator delete[] (void *ptr, std::align_val_t al, const std::nothrow_t&) noexcept { ::operator delete[] (ptr, al); } diff --git a/libstdc++-v3/libsupc++/del_opvnt.cc b/libstdc++-v3/libsupc++/del_opvnt.cc index ed06d2e82d5..f050526093b 100644 --- a/libstdc++-v3/libsupc++/del_opvnt.cc +++ b/libstdc++-v3/libsupc++/del_opvnt.cc @@ -27,7 +27,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete[] (void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT +operator delete[] (void *ptr, const std::nothrow_t&) noexcept { - ::operator delete (ptr); + ::operator delete[] (ptr); } diff --git a/libstdc++-v3/libsupc++/del_opvs.cc b/libstdc++-v3/libsupc++/del_opvs.cc index 2be94d6562c..4b1e161fb25 100644 --- a/libstdc++-v3/libsupc++/del_opvs.cc +++ b/libstdc++-v3/libsupc++/del_opvs.cc @@ -28,7 +28,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete[] (void *ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT +operator delete[] (void *ptr, std::size_t) noexcept { ::operator delete[] (ptr); } diff --git a/libstdc++-v3/libsupc++/del_opvsa.cc b/libstdc++-v3/libsupc++/del_opvsa.cc index 02f18452462..00ea369ee69 100644 --- a/libstdc++-v3/libsupc++/del_opvsa.cc +++ b/libstdc++-v3/libsupc++/del_opvsa.cc @@ -27,7 +27,7 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void -operator delete[] (void *ptr, std::size_t, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT +operator delete[] (void *ptr, std::size_t, std::align_val_t al) noexcept { ::operator delete[] (ptr, al); } diff --git a/libstdc++-v3/libsupc++/new_op.cc b/libstdc++-v3/libsupc++/new_op.cc index 3caa0bab2ea..df77950cd97 100644 --- a/libstdc++-v3/libsupc++/new_op.cc +++ b/libstdc++-v3/libsupc++/new_op.cc @@ -44,7 +44,7 @@ operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc) void *p; /* malloc (0) is unpredictable; avoid it. */ - if (sz == 0) + if (__builtin_expect (sz == 0, false)) sz = 1; while ((p = malloc (sz)) == 0) diff --git a/libstdc++-v3/libsupc++/new_opa.cc b/libstdc++-v3/libsupc++/new_opa.cc index a27ff843ca1..aa3e5dc4ce5 100644 --- a/libstdc++-v3/libsupc++/new_opa.cc +++ b/libstdc++-v3/libsupc++/new_opa.cc @@ -101,7 +101,6 @@ aligned_alloc (std::size_t al, std::size_t sz) _GLIBCXX_WEAK_DEFINITION void * operator new (std::size_t sz, std::align_val_t al) { - void *p; std::size_t align = (std::size_t)al; /* Alignment must be a power of two. */ @@ -125,8 +124,9 @@ operator new (std::size_t sz, std::align_val_t al) sz += align - rem; #endif - using __gnu_cxx::aligned_alloc; - while ((p = aligned_alloc (align, sz)) == 0) + void *p; + + while ((p = __gnu_cxx::aligned_alloc (align, sz)) == nullptr) { new_handler handler = std::get_new_handler (); if (! handler) diff --git a/libstdc++-v3/libsupc++/new_opant.cc b/libstdc++-v3/libsupc++/new_opant.cc index b4458402d02..f08ae0c2ac4 100644 --- a/libstdc++-v3/libsupc++/new_opant.cc +++ b/libstdc++-v3/libsupc++/new_opant.cc @@ -29,7 +29,7 @@ _GLIBCXX_WEAK_DEFINITION void* operator new(std::size_t sz, std::align_val_t al, const std::nothrow_t&) - _GLIBCXX_USE_NOEXCEPT + noexcept { __try { @@ -37,6 +37,6 @@ operator new(std::size_t sz, std::align_val_t al, const std::nothrow_t&) } __catch(...) { - return 0; + return nullptr; } } diff --git a/libstdc++-v3/libsupc++/new_opnt.cc b/libstdc++-v3/libsupc++/new_opnt.cc index faab44e66c2..ffe44b939bb 100644 --- a/libstdc++-v3/libsupc++/new_opnt.cc +++ b/libstdc++-v3/libsupc++/new_opnt.cc @@ -32,28 +32,17 @@ using std::bad_alloc; extern "C" void *malloc (std::size_t); _GLIBCXX_WEAK_DEFINITION void * -operator new (std::size_t sz, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT +operator new (std::size_t sz, const std::nothrow_t&) noexcept { - void *p; - - /* malloc (0) is unpredictable; avoid it. */ - if (sz == 0) - sz = 1; - - while ((p = malloc (sz)) == 0) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 206. operator new(size_t, nothrow) may become unlinked to ordinary + // operator new if ordinary version replaced + __try { - new_handler handler = std::get_new_handler (); - if (! handler) - return 0; - __try - { - handler (); - } - __catch(const bad_alloc&) - { - return 0; - } + return ::operator new(sz); + } + __catch (...) + { + return nullptr; } - - return p; } diff --git a/libstdc++-v3/libsupc++/new_opvant.cc b/libstdc++-v3/libsupc++/new_opvant.cc index faeb4dc2cb2..4ba1268fbe9 100644 --- a/libstdc++-v3/libsupc++/new_opvant.cc +++ b/libstdc++-v3/libsupc++/new_opvant.cc @@ -29,7 +29,7 @@ _GLIBCXX_WEAK_DEFINITION void* operator new[] (std::size_t sz, std::align_val_t al, const std::nothrow_t&) - _GLIBCXX_USE_NOEXCEPT + noexcept { __try { @@ -37,6 +37,6 @@ operator new[] (std::size_t sz, std::align_val_t al, const std::nothrow_t&) } __catch(...) { - return 0; + return nullptr; } } diff --git a/libstdc++-v3/libsupc++/new_opvnt.cc b/libstdc++-v3/libsupc++/new_opvnt.cc index 828a971dafb..3678b8e1ac9 100644 --- a/libstdc++-v3/libsupc++/new_opvnt.cc +++ b/libstdc++-v3/libsupc++/new_opvnt.cc @@ -27,8 +27,17 @@ #include "new" _GLIBCXX_WEAK_DEFINITION void* -operator new[] (std::size_t sz, const std::nothrow_t& nothrow) - _GLIBCXX_USE_NOEXCEPT +operator new[] (std::size_t sz, const std::nothrow_t&) noexcept { - return ::operator new(sz, nothrow); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 206. operator new(size_t, nothrow) may become unlinked to ordinary + // operator new if ordinary version replaced + __try + { + return ::operator new[](sz); + } + __catch (...) + { + return nullptr; + } } diff --git a/libstdc++-v3/testsuite/18_support/new_nothrow.cc b/libstdc++-v3/testsuite/18_support/new_nothrow.cc new file mode 100644 index 00000000000..362dabf2bcf --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/new_nothrow.cc @@ -0,0 +1,183 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run } + +#include +#include +#include + +// PR libstdc++/68210 + +struct MyBadAlloc: std::bad_alloc { }; + +static bool new_fail; +static bool bad_alloc_thrown; +static unsigned new_called; +static unsigned delete_called; +static unsigned new_vec_called; +static unsigned delete_vec_called; +static unsigned new_handler_called; + +static void new_handler () +{ + if (new_handler_called++) + throw MyBadAlloc (); +} + +void* operator new (size_t n) +{ + static size_t cntr; + + ++new_called; + + for ( ; ; ) { + if (void *p = new_fail ? 0 : malloc (n + sizeof n)) { + *static_cast(p) = ++cntr; + return static_cast(p) + 1; + } + + if (std::new_handler h = std::set_new_handler (0)) { + std::set_new_handler (h); + h (); + } + else { + bad_alloc_thrown = true; + throw MyBadAlloc (); + } + } +} + +void operator delete (void *p) +{ + ++delete_called; + if (p) + free (static_cast(p) - 1); +} + +void* operator new[] (size_t n) +{ + ++new_vec_called; + return operator new(n); +} + +void operator delete[] (void *p) +{ + ++delete_vec_called; + operator delete(p); +} + +#if __cplusplus >= 201402L +void operator delete (void *p, std::size_t) +{ + ::operator delete(p); +} +void operator delete[] (void *p, std::size_t) +{ + ::operator delete[](p); +} +#endif + +void init() +{ + new_fail = false; + new_called = 0; + delete_called = 0; + new_vec_called = 0; + delete_vec_called = 0; + new_handler_called = 0; + std::set_new_handler (0); +} + +void +test01() +{ + init (); + + void *p = operator new (1, std::nothrow); + + VERIFY (p != 0); + VERIFY (1 == new_called); + VERIFY (0 == new_handler_called); + VERIFY (!bad_alloc_thrown); + + operator delete (p, std::nothrow); + VERIFY( 1 == delete_called ); + + new_fail = true; + p = operator new (1, std::nothrow); + + VERIFY (0 == p); + VERIFY (2 == new_called); + VERIFY (0 == new_handler_called); + VERIFY (bad_alloc_thrown); + + new_fail = true; + bad_alloc_thrown = false; + std::set_new_handler (new_handler); + p = operator new (1, std::nothrow); + + VERIFY (0 == p); + VERIFY (3 == new_called); + VERIFY (2 == new_handler_called); + VERIFY (!bad_alloc_thrown); +} + +void +test02() +{ + init (); + + void *p = operator new[] (1, std::nothrow); + + VERIFY (p != 0); + VERIFY (1 == new_called); + VERIFY (1 == new_vec_called); + VERIFY (0 == new_handler_called); + VERIFY (!bad_alloc_thrown); + + operator delete[] (p, std::nothrow); + VERIFY( 1 == delete_called ); + VERIFY( 1 == delete_vec_called ); + + new_fail = true; + p = operator new[] (1, std::nothrow); + + VERIFY (0 == p); + VERIFY (2 == new_called); + VERIFY (2 == new_vec_called); + VERIFY (0 == new_handler_called); + VERIFY (bad_alloc_thrown); + + new_fail = true; + bad_alloc_thrown = false; + std::set_new_handler (new_handler); + p = operator new[] (1, std::nothrow); + + VERIFY (0 == p); + VERIFY (3 == new_called); + VERIFY (3 == new_vec_called); + VERIFY (2 == new_handler_called); + VERIFY (!bad_alloc_thrown); +} + + +int main() +{ + test01(); + test02(); +}