diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 2032e90abebec9f5216369a08e56ad3adb85b982..b21c44fc0b8cee04cfe7a132822cfd2e62771765 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 6066f48d24cc031a69848ce328111c2ad42c4e8d..86d8ed221ff8d312aada579600b6543997f1fcc3 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 dcca769938c40ee83dfae8dc92372329e34c55b6..d224aa3ec5ec807dad60ec4c70810cca07a383b1 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 1f41660fac7e9676cbdcfc9fc5f6beafd8668bdf..366c766f25b56533100a8b53d7ce9283b594c004 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 959d6880276892d12e171c9a67403a6267c0e21f..131718b8b2ff68ff6db77d854378bb342cbc5477 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 0000000000000000000000000000000000000000..a3100a2b062da4685e781ee09a015a446a9cb4e1
--- /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 0000000000000000000000000000000000000000..f2ab25adb74c40e400a8bc714d39992b59413cd1
--- /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 0000000000000000000000000000000000000000..f684a9c157da7e098a6cef915860c198d033044f
--- /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)), "" );