diff options
-rw-r--r-- | libstdc++-v3/ChangeLog | 17 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/alloc_traits.h | 7 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/allocator.h | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/ext/malloc_allocator.h | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/ext/new_allocator.h | 5 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/allocator/89510.cc | 147 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc | 149 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/ext/new_allocator/89510.cc | 149 |
8 files changed, 471 insertions, 13 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2032e90..b21c44f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2020-04-30 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/89510 + * include/bits/alloc_traits.h (allocator_traits::_S_construct) + (allocator_traits::_S_destroy) + (allocator_traits<allocator<T>>::construct): Use traits in + noexcept-specifiers. + * include/bits/allocator.h (allocator<void>::construct) + (allocator<void>::destroy): Likewise. + * include/ext/malloc_allocator.h (malloc_allocator::construct) + (malloc_allocator::destroy): Likewise. + * include/ext/new_allocator.h (new_allocator::construct) + (new_allocator::destroy): Likewise. + * testsuite/20_util/allocator/89510.cc: New test. + * testsuite/ext/malloc_allocator/89510.cc: New test. + * testsuite/ext/new_allocator/89510.cc: New test. + 2020-04-29 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/94854 diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h index 6066f48..86d8ed2 100644 --- a/libstdc++-v3/include/bits/alloc_traits.h +++ b/libstdc++-v3/include/bits/alloc_traits.h @@ -251,8 +251,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Require<__and_<__not_<__has_construct<_Tp, _Args...>>, is_constructible<_Tp, _Args...>>> _S_construct(_Alloc&, _Tp* __p, _Args&&... __args) - noexcept(noexcept(::new((void*)__p) - _Tp(std::forward<_Args>(__args)...))) + noexcept(std::is_nothrow_constructible<_Tp, _Args...>::value) { #if __cplusplus <= 201703L ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); @@ -271,7 +270,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Alloc2, typename _Tp> static _GLIBCXX14_CONSTEXPR void _S_destroy(_Alloc2&, _Tp* __p, ...) - noexcept(noexcept(__p->~_Tp())) + noexcept(std::is_nothrow_destructible<_Tp>::value) { std::_Destroy(__p); } template<typename _Alloc2> @@ -507,7 +506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static _GLIBCXX20_CONSTEXPR void construct(allocator_type& __a __attribute__((__unused__)), _Up* __p, _Args&&... __args) - noexcept(noexcept(::new((void*)__p) _Up(std::declval<_Args>()...))) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { #if __cplusplus <= 201703L __a.construct(__p, std::forward<_Args>(__args)...); diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index dcca769..d224aa3 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -93,14 +93,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) - noexcept(noexcept(::new((void *)__p) - _Up(std::forward<_Args>(__args)...))) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } template<typename _Up> void destroy(_Up* __p) - noexcept(noexcept(__p->~_Up())) + noexcept(std::is_nothrow_destructible<_Up>::value) { __p->~_Up(); } #endif // C++11 to C++17 }; diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h index 1f41660..366c766 100644 --- a/libstdc++-v3/include/ext/malloc_allocator.h +++ b/libstdc++-v3/include/ext/malloc_allocator.h @@ -147,14 +147,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) - noexcept(noexcept(::new((void *)__p) - _Up(std::forward<_Args>(__args)...))) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } template<typename _Up> void destroy(_Up* __p) - noexcept(noexcept(__p->~_Up())) + noexcept(std::is_nothrow_destructible<_Up>::value) { __p->~_Up(); } #else // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 959d688..131718b 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -146,14 +146,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) - noexcept(noexcept(::new((void *)__p) - _Up(std::forward<_Args>(__args)...))) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } template<typename _Up> void destroy(_Up* __p) - noexcept(noexcept( __p->~_Up())) + noexcept(std::is_nothrow_destructible<_Up>::value) { __p->~_Up(); } #else // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/testsuite/20_util/allocator/89510.cc b/libstdc++-v3/testsuite/20_util/allocator/89510.cc new file mode 100644 index 0000000..a3100a2 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/89510.cc @@ -0,0 +1,147 @@ +// Copyright (C) 2020 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 +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++11 } } + +#include <memory> + +using AT = std::allocator_traits<std::allocator<int>>; + +template<typename...> using void_t = void; + +template<typename T, typename U, typename = void> +struct has_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_construct<T, U, + void_t<decltype(std::declval<T&>().construct(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_destroy<T, U, + void_t<decltype(std::declval<T&>().destroy(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_construct<T, U, + void_t<decltype(AT::construct(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_destroy<T, U, + void_t<decltype(AT::destroy(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +struct NoDefault { NoDefault(int); }; +struct NoDest { private: ~NoDest(); }; + +// Whether true or false, this should not give an error: +constexpr bool c = has_construct<std::allocator<NoDefault>, NoDefault>::value; +constexpr bool cv = has_construct<std::allocator<void>, NoDefault>::value; +constexpr bool c2 = has_traits_construct<std::allocator<int>, NoDefault>::value; +constexpr bool d = has_destroy<std::allocator<NoDest>, NoDest>::value; +constexpr bool d2 = has_traits_destroy<std::allocator<int>, NoDest>::value; + +std::allocator<int> a; + +long* lp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(lp)), "" ); +static_assert( noexcept(a.construct(lp, 1L)), "" ); +static_assert( noexcept(a.construct(lp, 2)), "" ); +static_assert( noexcept(a.construct(lp, 2U)), "" ); +static_assert( noexcept(a.destroy(lp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, lp)), "" ); +static_assert( noexcept(AT::construct(a, lp, 1L)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2U)), "" ); +static_assert( noexcept(AT::destroy(a, lp)), "" ); + +struct X +{ + X() noexcept; + X(int) noexcept; + ~X() noexcept; +}; + +X* xp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(xp)), "" ); +static_assert( noexcept(a.construct(xp, 1)), "" ); +static_assert( noexcept(a.destroy(xp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, xp)), "" ); +static_assert( noexcept(AT::construct(a, xp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, xp)), "" ); + +struct Y +{ + Y() noexcept; + Y(int) noexcept(false); + ~Y() noexcept; +}; + +Y* yp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(yp)), "" ); +static_assert( ! noexcept(a.construct(yp, 1)), "" ); +static_assert( noexcept(a.destroy(yp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, yp)), "" ); +static_assert( ! noexcept(AT::construct(a, yp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, yp)), "" ); + +struct Z +{ + Z() noexcept; + Z(int) noexcept; + ~Z() noexcept(false); +}; + +Z* zp; +// These construct calls should be noexcept, but they are false because +// they use is_nothrow_constructible which depends on is_nothrow_destructible. +#if __cplusplus <= 201703L +static_assert( ! noexcept(a.construct(zp)), "wrong" ); +static_assert( ! noexcept(a.construct(zp, 1)), "wrong" ); +static_assert( ! noexcept(a.destroy(zp)), "" ); +#endif +static_assert( ! noexcept(AT::construct(a, zp)), "" ); +static_assert( ! noexcept(AT::construct(a, zp, 1)), "" ); +static_assert( ! noexcept(AT::destroy(a, zp)), "" ); diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc new file mode 100644 index 0000000..f2ab25a --- /dev/null +++ b/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc @@ -0,0 +1,149 @@ +// Copyright (C) 2020 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 +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++11 } } + +#include <ext/malloc_allocator.h> +#include <memory> +#include <type_traits> + +using __gnu_cxx::malloc_allocator; +using AT = std::allocator_traits<malloc_allocator<int>>; + +template<typename...> using void_t = void; + +template<typename T, typename U, typename = void> +struct has_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_construct<T, U, + void_t<decltype(std::declval<T&>().construct(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_destroy<T, U, + void_t<decltype(std::declval<T&>().destroy(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_construct<T, U, + void_t<decltype(AT::construct(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_destroy<T, U, + void_t<decltype(AT::destroy(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +struct NoDefault { NoDefault(int); }; +struct NoDest { private: ~NoDest(); }; + +// Whether true or false, these should not give errors: +constexpr bool c = has_construct<malloc_allocator<NoDefault>, NoDefault>::value; +constexpr bool c2 = has_traits_construct<malloc_allocator<int>, NoDefault>::value; +constexpr bool d = has_destroy<malloc_allocator<NoDest>, NoDest>::value; +constexpr bool b2 = has_traits_destroy<malloc_allocator<int>, NoDest>::value; + +malloc_allocator<int> a; + +long* lp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(lp)), "" ); +static_assert( noexcept(a.construct(lp, 1L)), "" ); +static_assert( noexcept(a.construct(lp, 2)), "" ); +static_assert( noexcept(a.construct(lp, 2U)), "" ); +static_assert( noexcept(a.destroy(lp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, lp)), "" ); +static_assert( noexcept(AT::construct(a, lp, 1L)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2U)), "" ); +static_assert( noexcept(AT::destroy(a, lp)), "" ); + +struct X +{ + X() noexcept; + X(int) noexcept; + ~X() noexcept; +}; + +X* xp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(xp)), "" ); +static_assert( noexcept(a.construct(xp, 1)), "" ); +static_assert( noexcept(a.destroy(xp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, xp)), "" ); +static_assert( noexcept(AT::construct(a, xp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, xp)), "" ); + +struct Y +{ + Y() noexcept; + Y(int) noexcept(false); + ~Y() noexcept; +}; + +Y* yp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(yp)), "" ); +static_assert( ! noexcept(a.construct(yp, 1)), "" ); +static_assert( noexcept(a.destroy(yp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, yp)), "" ); +static_assert( ! noexcept(AT::construct(a, yp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, yp)), "" ); + +struct Z +{ + Z() noexcept; + Z(int) noexcept; + ~Z() noexcept(false); +}; + +Z* zp; +// These construct calls should be noexcept, but they are false because +// they use is_nothrow_constructible which depends on is_nothrow_destructible. +#if __cplusplus <= 201703L +static_assert( ! noexcept(a.construct(zp)), "wrong" ); +static_assert( ! noexcept(a.construct(zp, 1)), "wrong" ); +static_assert( ! noexcept(a.destroy(zp)), "" ); +#endif +static_assert( ! noexcept(AT::construct(a, zp)), "" ); +static_assert( ! noexcept(AT::construct(a, zp, 1)), "" ); +static_assert( ! noexcept(AT::destroy(a, zp)), "" ); diff --git a/libstdc++-v3/testsuite/ext/new_allocator/89510.cc b/libstdc++-v3/testsuite/ext/new_allocator/89510.cc new file mode 100644 index 0000000..f684a9c --- /dev/null +++ b/libstdc++-v3/testsuite/ext/new_allocator/89510.cc @@ -0,0 +1,149 @@ +// Copyright (C) 2020 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 +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++11 } } + +#include <ext/new_allocator.h> +#include <memory> +#include <type_traits> + +using __gnu_cxx::new_allocator; +using AT = std::allocator_traits<new_allocator<int>>; + +template<typename...> using void_t = void; + +template<typename T, typename U, typename = void> +struct has_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_construct<T, U, + void_t<decltype(std::declval<T&>().construct(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_destroy<T, U, + void_t<decltype(std::declval<T&>().destroy(std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_construct +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_construct<T, U, + void_t<decltype(AT::construct(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +template<typename T, typename U, typename = void> +struct has_traits_destroy +: std::false_type +{ }; + +template<typename T, typename U> +struct has_traits_destroy<T, U, + void_t<decltype(AT::destroy(std::declval<T&>(), std::declval<U*>()))>> +: std::true_type +{ }; + +struct NoDefault { NoDefault(int); }; +struct NoDest { private: ~NoDest(); }; + +// Whether true or false, these should not give errors: +constexpr bool c = has_construct<new_allocator<NoDefault>, NoDefault>::value; +constexpr bool c2 = has_traits_construct<new_allocator<int>, NoDefault>::value; +constexpr bool d = has_destroy<new_allocator<NoDest>, NoDest>::value; +constexpr bool d2 = has_traits_destroy<new_allocator<int>, NoDest>::value; + +new_allocator<int> a; + +long* lp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(lp)), "" ); +static_assert( noexcept(a.construct(lp, 1L)), "" ); +static_assert( noexcept(a.construct(lp, 2)), "" ); +static_assert( noexcept(a.construct(lp, 2U)), "" ); +static_assert( noexcept(a.destroy(lp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, lp)), "" ); +static_assert( noexcept(AT::construct(a, lp, 1L)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2)), "" ); +static_assert( noexcept(AT::construct(a, lp, 2U)), "" ); +static_assert( noexcept(AT::destroy(a, lp)), "" ); + +struct X +{ + X() noexcept; + X(int) noexcept; + ~X() noexcept; +}; + +X* xp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(xp)), "" ); +static_assert( noexcept(a.construct(xp, 1)), "" ); +static_assert( noexcept(a.destroy(xp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, xp)), "" ); +static_assert( noexcept(AT::construct(a, xp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, xp)), "" ); + +struct Y +{ + Y() noexcept; + Y(int) noexcept(false); + ~Y() noexcept; +}; + +Y* yp; +#if __cplusplus <= 201703L +static_assert( noexcept(a.construct(yp)), "" ); +static_assert( ! noexcept(a.construct(yp, 1)), "" ); +static_assert( noexcept(a.destroy(yp)), "" ); +#endif +static_assert( noexcept(AT::construct(a, yp)), "" ); +static_assert( ! noexcept(AT::construct(a, yp, 1)), "" ); +static_assert( noexcept(AT::destroy(a, yp)), "" ); + +struct Z +{ + Z() noexcept; + Z(int) noexcept; + ~Z() noexcept(false); +}; + +Z* zp; +// These construct calls should be noexcept, but they are false because +// they use is_nothrow_constructible which depends on is_nothrow_destructible. +#if __cplusplus <= 201703L +static_assert( ! noexcept(a.construct(zp)), "wrong" ); +static_assert( ! noexcept(a.construct(zp, 1)), "wrong" ); +static_assert( ! noexcept(a.destroy(zp)), "" ); +#endif +static_assert( ! noexcept(AT::construct(a, zp)), "" ); +static_assert( ! noexcept(AT::construct(a, zp, 1)), "" ); +static_assert( ! noexcept(AT::destroy(a, zp)), "" ); |