On 08/04/21 17:50 +0100, Jonathan Wakely wrote:
This puts the logic for the noexcept-specifier in one place, and then
reuses it elsewhere. This means checking whether the move constructor
can throw doesn't need to do overload resolution and then check whether
some other constructor can throw, we just get the answer directly.
libstdc++-v3/ChangeLog:
* include/bits/hashtable.h (_Hashtable::_S_nothrow_move()):
New function to determine noexcept-specifier for move
constructors.
(_Hashtable): Use _S_nothrow_move() on move constructors.
* testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc:
Correct static assertion message.
*
testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc:
Likewise.
*
testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc:
Likewise.
* testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc:
Likewise.
I keep forgetting that a constexpr function in C++11 has to be a single
return statement.
I'm testing this patch now and will push to trunk and backport to the
branches where I already backported the breakage (facepalm).
commit ea14e090ebfa8bb52583ccc1a78db06a759a63ef
Author: Jonathan Wakely <jwak...@redhat.com>
Date: Fri Apr 9 12:05:39 2021
libstdc++: Fix invalid constexpr function in C++11 mode [PR 99985]
I keep forgetting that a constexpr function in C++11 has to be a single
return statement.
libstdc++-v3/ChangeLog:
PR libstdc++/99985
* include/bits/hashtable.h (_Hashtable::_S_nothrow_move()): Fix
to be a valid constexpr function in C++11.
* testsuite/23_containers/unordered_set/cons/99985.cc: New test.
diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 39872ce5342..6711d08e6b8 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -476,10 +476,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static constexpr bool
_S_nothrow_move()
{
- if _GLIBCXX17_CONSTEXPR (_No_realloc)
- if _GLIBCXX17_CONSTEXPR (is_nothrow_copy_constructible<_Hash>())
+#if __cplusplus <= 201402L
+ return __and_<__bool_constant<_No_realloc>,
+ is_nothrow_copy_constructible<_Hash>,
+ is_nothrow_copy_constructible<_Equal>>::value;
+#else
+ if constexpr (_No_realloc)
+ if constexpr (is_nothrow_copy_constructible<_Hash>())
return is_nothrow_copy_constructible<_Equal>();
return false;
+#endif
}
_Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/99985.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/99985.cc
new file mode 100644
index 00000000000..b209f7627f5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/99985.cc
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 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-options "-std=gnu++11" }
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+#include <testsuite_allocator.h>
+
+template<typename Alloc, typename T = typename Alloc::value_type>
+ using Set = std::unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;
+
+// PR libstdc++/99985 - invalid constexpr function in C++11 mode
+
+void
+test01()
+{
+ using A = std::allocator<int>;
+ A a;
+ Set<A> s;
+ static_assert( noexcept( Set<A>(std::move(s)) ), "non-throwing" );
+ static_assert( noexcept( Set<A>(std::move(s), a) ), "non-throwing" );
+}
+
+void
+test02()
+{
+ using A = __gnu_test::uneq_allocator<long>;
+ A a;
+ Set<A> s;
+ static_assert( noexcept( Set<A>(std::move(s)) ), "non-throwing" );
+ static_assert( ! noexcept( Set<A>(std::move(s), a) ), "throwing" );
+}