[PATCH] libstdc++: Value-initialize hashtable helper objects [PR126949]

Tomasz Kaminski tkaminsk@redhat.com
Thu Sep 10 08:42:33 GMT 2026


On Mon, Aug 31, 2026 at 5:58 PM Marco Falke <falke.marco@gmail.com> wrote:

> 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 <falke.marco@gmail.com>
> 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{};
>
This is not value-initialization, but aggregate initialization (there are
observable
differences in corner cases). I would prefer that we actually use an
value-init
here and say = _Tp().

> +
> +      _Hashtable_ebo_helper() = default;
>
This constructor will no longer be trivial if the _Tp has trivial
constructor, so
I need to take a look to see if that may have ABI impact.

> +
> +      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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260910/185cbdea/attachment.htm>


More information about the Libstdc++ mailing list