libstdc++15 and 16 do not allow to construct an unordered set with a hasher whose ctor is explicit.
This is an issue with Clang, or with GCC -Wsystem-headers. See https://godbolt.org/z/EGzKbjh84 Fix this by using value-init, similar to commit f8f0193b5b83f6e85d65015e79c803295baf5166. However, that likely regressed again in commit 689d4abc0b836aaf1c8ecd38091dde6b14373c60? patch is attached and copied later. I'd say the unit test could be expanded by adding // { dg-additional-options "-Werror -Wsystem-headers" } , but I wasn't sure if this is recommended. Best, Marco >From 2bd4a6218ff9ca10f1d11b6b19411c9556df90ed Mon Sep 17 00:00:00 2001 From: MarcoFalke <[email protected]> Date: Sun, 26 Jul 2026 14:30:58 +0000 Subject: [PATCH] libstdc++: Value-initialize hashtable helper objects [PR126949] Value-initialize the object stored in _Hashtable_ebo_helper so that hash containers can be default constructed when the hash function has an explicit default constructor. A default member initializer prevents aggregate initialization in C++11, so add constructors that preserve initialization from hash, equality, and allocator objects. libstdc++-v3/ChangeLog: PR libstdc++/126949 * include/bits/hashtable_policy.h (_Hashtable_ebo_helper): Value-initialize the stored object. Add default and forwarding constructors. * testsuite/23_containers/unordered_map/cons/default.cc: Check default construction with an explicit hash constructor. * testsuite/23_containers/unordered_set/cons/default.cc: Likewise. --- libstdc++-v3/include/bits/hashtable_policy.h | 18 ++++++++++++++++-- .../unordered_map/cons/default.cc | 15 +++++++++++++++ .../unordered_set/cons/default.cc | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index 6e4b365d592..396214ed4bb 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -1033,7 +1033,14 @@ namespace __detail bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> struct _Hashtable_ebo_helper { - [[__no_unique_address__]] _Tp _M_obj; + [[__no_unique_address__]] _Tp _M_obj{}; + + _Hashtable_ebo_helper() = default; + + template<typename _Up> + _Hashtable_ebo_helper(_Up&& __obj) + : _M_obj(std::forward<_Up>(__obj)) + { } }; #if ! _GLIBCXX_INLINE_VERSION @@ -1042,7 +1049,14 @@ namespace __detail template<typename _Tp> struct _Hashtable_ebo_helper<_Tp, false> { - _Tp _M_obj; + _Tp _M_obj{}; + + _Hashtable_ebo_helper() = default; + + template<typename _Up> + _Hashtable_ebo_helper(_Up&& __obj) + : _M_obj(std::forward<_Up>(__obj)) + { } }; #endif diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc index 7a785e980b1..07089c36bcf 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc @@ -49,3 +49,18 @@ Map4 m4{m}; Map4 m5{m, a}; Map4 m6{std::move(m)}; Map4 m7{std::move(m6), a}; + +// PR libstdc++/126949 +struct ExplicitHash +{ + explicit ExplicitHash(bool = false) { } + + std::size_t operator()(int value) const + { return value; } +}; + +void +test_explicit_hash() +{ + std::unordered_map<int, int, ExplicitHash> map; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc index fb87c96ce9d..8949b202125 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc @@ -48,3 +48,18 @@ Set4 s4{s}; Set4 s5{s, a}; Set4 s6{std::move(s)}; Set4 s7{std::move(s6), a}; + +// PR libstdc++/126949 +struct ExplicitHash +{ + explicit ExplicitHash(bool = false) { } + + std::size_t operator()(int value) const + { return value; } +}; + +void +test_explicit_hash() +{ + std::unordered_set<int, ExplicitHash> set; +} -- 2.53.0
From 2bd4a6218ff9ca10f1d11b6b19411c9556df90ed Mon Sep 17 00:00:00 2001 From: MarcoFalke <[email protected]> Date: Sun, 26 Jul 2026 14:30:58 +0000 Subject: [PATCH] libstdc++: Value-initialize hashtable helper objects [PR126949] Value-initialize the object stored in _Hashtable_ebo_helper so that hash containers can be default constructed when the hash function has an explicit default constructor. A default member initializer prevents aggregate initialization in C++11, so add constructors that preserve initialization from hash, equality, and allocator objects. libstdc++-v3/ChangeLog: PR libstdc++/126949 * include/bits/hashtable_policy.h (_Hashtable_ebo_helper): Value-initialize the stored object. Add default and forwarding constructors. * testsuite/23_containers/unordered_map/cons/default.cc: Check default construction with an explicit hash constructor. * testsuite/23_containers/unordered_set/cons/default.cc: Likewise. --- libstdc++-v3/include/bits/hashtable_policy.h | 18 ++++++++++++++++-- .../unordered_map/cons/default.cc | 15 +++++++++++++++ .../unordered_set/cons/default.cc | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index 6e4b365d592..396214ed4bb 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -1033,7 +1033,14 @@ namespace __detail bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> struct _Hashtable_ebo_helper { - [[__no_unique_address__]] _Tp _M_obj; + [[__no_unique_address__]] _Tp _M_obj{}; + + _Hashtable_ebo_helper() = default; + + template<typename _Up> + _Hashtable_ebo_helper(_Up&& __obj) + : _M_obj(std::forward<_Up>(__obj)) + { } }; #if ! _GLIBCXX_INLINE_VERSION @@ -1042,7 +1049,14 @@ namespace __detail template<typename _Tp> struct _Hashtable_ebo_helper<_Tp, false> { - _Tp _M_obj; + _Tp _M_obj{}; + + _Hashtable_ebo_helper() = default; + + template<typename _Up> + _Hashtable_ebo_helper(_Up&& __obj) + : _M_obj(std::forward<_Up>(__obj)) + { } }; #endif diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc index 7a785e980b1..07089c36bcf 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/default.cc @@ -49,3 +49,18 @@ Map4 m4{m}; Map4 m5{m, a}; Map4 m6{std::move(m)}; Map4 m7{std::move(m6), a}; + +// PR libstdc++/126949 +struct ExplicitHash +{ + explicit ExplicitHash(bool = false) { } + + std::size_t operator()(int value) const + { return value; } +}; + +void +test_explicit_hash() +{ + std::unordered_map<int, int, ExplicitHash> map; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc index fb87c96ce9d..8949b202125 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/default.cc @@ -48,3 +48,18 @@ Set4 s4{s}; Set4 s5{s, a}; Set4 s6{std::move(s)}; Set4 s7{std::move(s6), a}; + +// PR libstdc++/126949 +struct ExplicitHash +{ + explicit ExplicitHash(bool = false) { } + + std::size_t operator()(int value) const + { return value; } +}; + +void +test_explicit_hash() +{ + std::unordered_set<int, ExplicitHash> set; +} -- 2.53.0
