[PATCHv3] libstdc++: container erasure overloads (P2077) [PR117404]

Nathan Myers ncm@cantrip.org
Sat Jan 24 01:05:59 GMT 2026


Thank you.

On 1/23/26 12:48 PM, Jonathan Wakely wrote:
> On Thu, 11 Dec 2025 at 13:19 -0500, Nathan Myers wrote:
>> ...
>> libstdc++-v3/ChangeLog:
>>     PR libstdc++/117404
>>     * include/bits/version.def: Add feature macro
>>     __cpplib_heterogeneous_erasure.
> 
> Please name the thing being added using the usual ChangeLog format
> described at https://www.gnu.org/prep/standards/html_node/Style-of- 
> Change-Logs.html
> 
>      * filename (name_of_thing): Define.
> 
> But also __cpplib_heterogeneous_erasure isn't the right name.
> 
> So:
> 
>      * include/bits/version.def (associative_heterogeneous_erasure):
>      Define.

OK.

>>     * include/bits/version.h: Regenerate.
>>     * include/std/map: Request new feature from version.h.
>>     * include/std/set: Same.
>>     * include/std/unordered_map: Same.
>>     * include/std/unordered_set: Same.
>>     * include/bits/stl_map.h: Add specified new overloads.
> 
> This should say which overloads.

OK.

>>     * include/bits/stl_set.h: Same.
>>     * include/bits/stl_multimap.h: Same.
>>     * include/bits/stl_multiset.h: Same.
>>     * include/bits/unordered_map.h: Same.
>>     * include/bits/unordered_set.h: Same.
>>     * include/bits/hashtable.h: Add supporting overloads, new concept
>>     __heterogeneous_hash_key.
> 
> Ditto, and then add:
> 
>      (__heterogeneous_hash_key): New concept.

OK

>>     * include/bits/stl_tree.h: Add supporting overloads, new concept
>>     __heterogeneous_tree_key.
>>     * include/bits/stl_function.h: Add concepts 
>> __not_container_iterator and
>>     __heterogeneous_key.
>>     * testsuite/23_containers/map/modifiers/hetero/erase.cc: New test.
>>     * testsuite/23_containers/multimap/modifiers/hetero/erase.cc: Same.
>>     * testsuite/23_containers/multiset/modifiers/hetero/erase.cc: Same.
>>     * testsuite/23_containers/set/modifiers/hetero/erase.cc: Same.
>>     * testsuite/23_containers/unordered_map/modifiers/hetero/erase.cc: 
>> Same.
>>     * testsuite/23_containers/unordered_multimap/modifiers/hetero/ 
>> erase.cc:
>>     Same.
>>     * testsuite/23_containers/unordered_multiset/modifiers/hetero/ 
>> erase.cc:
>>     Same.
>>     * testsuite/23_containers/unordered_set/modifiers/hetero/erase.cc: 
>> Same.
>> ---
>> libstdc++-v3/include/bits/hashtable.h         | 182 +++++++++++++++---
>> libstdc++-v3/include/bits/stl_function.h      |  12 ++
>> libstdc++-v3/include/bits/stl_map.h           |  20 ++
>> libstdc++-v3/include/bits/stl_multimap.h      |  15 ++
>> libstdc++-v3/include/bits/stl_multiset.h      |  15 ++
>> libstdc++-v3/include/bits/stl_set.h           |  18 ++
>> libstdc++-v3/include/bits/stl_tree.h          |  96 ++++++++-
>> libstdc++-v3/include/bits/unordered_map.h     |  28 +++
>> libstdc++-v3/include/bits/unordered_set.h     |  28 +++
>> libstdc++-v3/include/bits/version.def         |   8 +
>> libstdc++-v3/include/bits/version.h           |  12 +-
>> libstdc++-v3/include/std/map                  |  22 +--
>> libstdc++-v3/include/std/set                  |  19 +-
>> libstdc++-v3/include/std/unordered_map        |  19 +-
>> libstdc++-v3/include/std/unordered_set        |  17 +-
>> .../map/modifiers/hetero/erase.cc             |  95 +++++++++
>> .../multimap/modifiers/hetero/erase.cc        |  95 +++++++++
>> .../multiset/modifiers/hetero/erase.cc        |  88 +++++++++
>> .../set/modifiers/hetero/erase.cc             |  88 +++++++++
>> .../unordered_map/modifiers/hetero/erase.cc   |  76 ++++++++
>> .../modifiers/hetero/erase.cc                 |  75 ++++++++
>> .../modifiers/hetero/erase.cc                 |  73 +++++++
>> .../unordered_set/modifiers/hetero/erase.cc   |  73 +++++++
>> 23 files changed, 1102 insertions(+), 72 deletions(-)
>> create mode 100644 libstdc++-v3/testsuite/23_containers/map/modifiers/ 
>> hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/multimap/ 
>> modifiers/hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/multiset/ 
>> modifiers/hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/set/modifiers/ 
>> hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/unordered_map/ 
>> modifiers/hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/ 
>> unordered_multimap/modifiers/hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/ 
>> unordered_multiset/modifiers/hetero/erase.cc
>> create mode 100644 libstdc++-v3/testsuite/23_containers/unordered_set/ 
>> modifiers/hetero/erase.cc
>>
>> diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/ 
>> include/bits/hashtable.h
>> index 06cc51ac4a0..bd5c9dc64e5 100644
>> --- a/libstdc++-v3/include/bits/hashtable.h
>> +++ b/libstdc++-v3/include/bits/hashtable.h
>> @@ -905,6 +905,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       __location_type
>>       _M_locate(const key_type& __k) const;
>>
>> +      // We would like to extend _M_locate for heterogeneous
>> +      // keys, and use try_emplace as is, but ABI forbids it.
> 
> Why? Because of explicit instantiations, or something else?

Guessing that CUs built before this may have it as a global symbol
reference. If not, I am happy to remove it.

>> +      template <typename _HetKey>
> 
> We use _Kt everywhere else for heterogeneous key parameters. The fact
> it's a template parameter (rather than just using _Key or key_type)
> already implies it's a heterogeneous key type.

OK.

>> +    __location_type
>> +    _M_locate_tr(const _HetKey& __k) const;
> 
> Should this be guarded by __glibcxx_associative_heterogeneous_erasure ?
> Patch v2 called _M_locate_tr from pre-C++23 code, but v3 doesn't seem
> to.

P2363 updates various existing members to use _M_locate_tr with
the regular key, in an effort to minimize code duplication.

>> +
>>       __node_ptr
>>       _M_find_node(size_type __bkt, const key_type& __key,
>>            __hash_code __c) const
>> @@ -1016,6 +1022,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       iterator
>>       _M_erase(size_type __bkt, __node_base_ptr __prev_n, __node_ptr 
>> __n);
>>
>> +      size_type
>> +      _M_erase_some(size_type __bkt, __node_base_ptr __prev_n, 
>> __node_ptr __n);
>> +
>>       template<typename _InputIterator>
>>     void
>>     _M_insert_range_multi(_InputIterator __first, _InputIterator __last);
>> @@ -1163,6 +1172,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       size_type
>>       erase(const key_type& __k);
>>
>> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077
> 
> We don't put the paper number on these feature test checks anywhere
> else in our headers.

OK, removing.

>> +      template <typename _HetKey>
>> +    size_type
>> +    _M_erase_tr(const _HetKey& __k);
>> +#endif
>> ...
 >> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077>> 
+  template<typename _Key, typename _Value, typename _Alloc,
>> +       typename _ExtractKey, typename _Equal,
>> +       typename _Hash, typename _RangeHash, typename _Unused,
>> +       typename _RehashPolicy, typename _Traits>
>> +    template <typename _HetKey>
>> +      auto
>> +      _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
>> +         _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
>> +      _M_erase_tr(const _HetKey& __k)
>> +    -> size_type
>> +      {
>> +    auto __loc = _M_locate_tr(__k);
>> +    if (!__loc)
>> +      return 0;
>> +
>> +    __node_base_ptr __prev_n = __loc._M_before;
>> +    __node_ptr __n = __loc._M_node();
>> +    auto __bkt = __loc._M_bucket_index;
>> +    if (__bkt == size_type(-1))
>> +      __bkt = _M_bucket_index(*__n);
>> +    if constexpr (__unique_keys::value)
>> +      {
>> +        _M_erase(__bkt, __prev_n, __n);
>> +        return 1;
>> +      }
>> +    else
>> +      return _M_erase_some(__bkt, __prev_n, __n);
>> +      }
>> +#endif // P2207
> 
> This should definitely not be the paper number here, but the macro
> name (omitting the prefix if you want to keep it brief):
> 
> # endif // associative_heterogeneous_erasure

OK.

>> +
>> #pragma GCC diagnostic pop
>>
>>   template<typename _Key, typename _Value, typename _Alloc,
>> @@ -2977,6 +3087,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       = __enable_if_t<!__or_<is_integral<_Hash>, 
>> __is_allocator<_Hash>>::value>;
>> #endif
>>
>> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077
>> +template <typename _Kt, typename _Container>
>> +  concept __heterogeneous_hash_key =
>> +    __transparent_comparator<typename _Container::hasher> &&
>> +    __transparent_comparator<typename _Container::key_equal> &&
>> +    __heterogeneous_key<_Kt, _Container>;
>> +#endif
>> +
>> /// @endcond
>> _GLIBCXX_END_NAMESPACE_VERSION
>> } // namespace std
>> diff --git a/libstdc++-v3/include/bits/stl_function.h b/libstdc++-v3/ 
>> include/bits/stl_function.h
>> index ff3f8f4c6e7..7f99ffe1566 100644
>> --- a/libstdc++-v3/include/bits/stl_function.h
>> +++ b/libstdc++-v3/include/bits/stl_function.h
>> @@ -1486,6 +1486,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> #endif
>> #endif
>>
>> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077
>> +template <typename _Kt, typename _Container>
>> +  concept __not_container_iterator =
>> +    (!is_convertible_v<_Kt&&, typename _Container::iterator> &&
>> +     !is_convertible_v<_Kt&&, typename _Container::const_iterator>);
>> +
>> +template <typename _Kt, typename _Container>
>> +  concept __heterogeneous_key =
>> +    (!is_same_v<typename _Container::key_type, remove_cvref_t<_Kt>>) &&
>> +    __not_container_iterator<_Kt&&, _Container>;
> 
> Do you need to add the && here when __not_container_iterator
> explicitly adds it again?

OK.

>> +#endif
>> +
>> _GLIBCXX_END_NAMESPACE_VERSION
>> } // namespace
>>
>> diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/ 
>> include/bits/stl_map.h
>> index 62d66cef6b2..686ab792399 100644
>> --- a/libstdc++-v3/include/bits/stl_map.h
>> +++ b/libstdc++-v3/include/bits/stl_map.h
>> @@ -65,6 +65,7 @@
>> #if __glibcxx_containers_ranges // C++ >= 23
>> # include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
>> #endif
>> +#include <bits/stl_tree.h>
> 
> If this is included here, it doesn't need to be included in <regex>
> prior to including stl_map.h.

Is this a suggestion to patch std/regex too?
Ready to do, if so.

>>
>> +      ///@{
>>       /**
>>        *  @brief Erases elements according to the provided key.
>>        *  @param  __x  Key of element to be erased.
>> @@ -1158,6 +1167,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>       erase(const key_type& __x)
>>       { return _M_t._M_erase_unique(__x); }
>>
>> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077
>> +      // Note that for some types _Kt this may erase more than
>> +      // one element, such as if _Kt::operator< checks only part
>> +      // of the key.
>> +      template <__heterogeneous_tree_key<map> _Kt>
>> +    size_type
>> +    erase(_Kt&& __x)
>> +    { return _M_t._M_erase_tr(__x); }
>> +#endif
>> +      ///@}
>> +
>> #if __cplusplus >= 201103L
>>       // _GLIBCXX_RESOLVE_LIB_DEFECTS
>>       // DR 130. Associative erase should return an iterator.
>> diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/ 
>> include/bits/stl_multimap.h
>> index b2ae2bae745..7576653c8b9 100644
>> --- a/libstdc++-v3/include/bits/stl_multimap.h
>> +++ b/libstdc++-v3/include/bits/stl_multimap.h
>> @@ -63,6 +63,7 @@
>> #if __glibcxx_containers_ranges // C++ >= 23
>> # include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
>> #endif
>> +#include <bits/stl_tree.h>
> 
> Adding this is redundant. stl_multimap.h is included in exactly one
> file, <map>, and that includes stl_tree.h before it includes stl_map.h
> and stl_multimap.h

OK.

> Although GCC optimizes includes to avoid reopening the file on disk,
> we now do #include <bits/stl_tree.h> three times in <set> and three
> times in <map>.
> 
> The only reason that a "single use" header like stl_set.h needs to be
> self-sufficient in terms of "include what you use" is if you are
> compiling individual bits/*.h headers as header units so they can be
> imported, which Nathan Sidwell was at one time making changes to
> support.
> 
> I have a weak preference for not adding these redundant includes.
> 
> P.S. oh I see later in the patch that including bits/stl_tree.h is
> removed from <map> and <set>, so it's only being included twice now,
> not three times as I said above. So that's less bad.

I will clean up redundant includes.

>> ...
>> --- a/libstdc++-v3/include/bits/stl_tree.h
>> +++ b/libstdc++-v3/include/bits/stl_tree.h
>> @@ -1399,8 +1399,8 @@ namespace __rb_tree
>> #if __cplusplus >= 201103L
>>       // Enforce this here with a user-friendly message.
>>       static_assert(
>> -        __is_invocable<const _Compare&, const _Key&, const 
>> _Key&>::value,
>> -        "comparison object must be invocable with two arguments of 
>> key type"
>> +        __is_invocable<const _Compare&, const _Key1&, const 
>> _Key2&>::value,
>> +        "comparison object must be invocable with key types used"
> 
> IIRC I made this function a template so the static_assert would only
> be checked if a comparison was actually performed (so not checked for
> the default constructor and destructor, for example). But the fact
> that it tested invocation with _Key not with _Key1 and _Key2 was
> intentional. The point of this static_assert is to check that _Compare
> accepts arguments of type const _Key& because those are the template
> parameters of the whole class.
> 
> Specifically, it was for diagnosing Gaby's example in
> https://gcc.gnu.org/PR48101
> 
> So I'm not sure we need to generalize the assertion for all uses of
> transparent comparators, but I suppose it doesn't hurt.

Taking this as permission to retain the change...
Clear error messages in more use cases seems like a benefit.

>>       );
>> #endif
>>       return _M_impl._M_key_compare(__k1, __k2);
>> @@ -1539,10 +1539,24 @@ namespace __rb_tree
>>       _M_lower_bound(_Base_ptr __x, _Base_ptr __y,
>>              const _Key& __k) const;
>>
>> +#if __glibcxx_associative_heterogeneous_erasure // C++23, P2077
>> +      template <typename _HetKey>
> 
> Again, we just use _Kt for e.g. _Rb_tree::_M_find_tr

OK.

>> ...
 >> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/ 
 >> include/bits/version.def
>> index 04232187965..e3b9627b022 100644
>> --- a/libstdc++-v3/include/bits/version.def
>> +++ b/libstdc++-v3/include/bits/version.def
>> @@ -1589,6 +1589,14 @@ ftms = {
>>   };
>> };
>>
>> +ftms = {
>> +  name = associative_heterogeneous_erasure;
>> +  values = {
>> +    v = 202110;
>> +    cxxmin = 23;
>> +  };
>> +};
>> +
>> ftms = {
>>   name = is_scoped_enum;
>>   values = {
>> diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/ 
>> include/bits/version.h
>> index df7a291b05f..39f5d462550 100644
>> --- a/libstdc++-v3/include/bits/version.h
>> +++ b/libstdc++-v3/include/bits/version.h
>> @@ -1756,6 +1756,16 @@
>> #endif /* !defined(__cpp_lib_invoke_r) */
>> #undef __glibcxx_want_invoke_r
>>
>> +#if !defined(__cpp_lib_associative_heterogeneous_erasure)
>> +# if (__cplusplus >= 202100L)
>> +#  define __glibcxx_associative_heterogeneous_erasure 202110L
>> +#  if defined(__glibcxx_want_all) || 
>> defined(__glibcxx_want_associative_heterogeneous_erasure)
>> +#   define __cpp_lib_associative_heterogeneous_erasure 202110L
>> +#  endif
>> +# endif
>> +#endif /* !defined(__cpp_lib_associative_heterogeneous_erasure) */
>> +#undef __glibcxx_want_associative_heterogeneous_erasure
>> +
>> #if !defined(__cpp_lib_is_scoped_enum)
>> # if (__cplusplus >= 202100L)
>> #  define __glibcxx_is_scoped_enum 202011L
>> @@ -2198,7 +2208,7 @@
>> #   define __cpp_lib_observable_checkpoint 202506L
>> #  endif
>> # endif
>> -#endif /* !defined(__cpp_lib_observable_checkpoint) && 
>> defined(__glibcxx_want_observable_checkpoint) */
>> +#endif /* !defined(__cpp_lib_observable_checkpoint) */
> 
> This was already removed in late October. Please be sure to rebase
> this patch to make sure it applies to current trunk.

OK.

>> #undef __glibcxx_want_observable_checkpoint
>>
>> #if !defined(__cpp_lib_algorithm_default_value_type)
>> diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map
>> index 6bfb53848ba..efdf915f081 100644
>> --- a/libstdc++-v3/include/std/map
>> +++ b/libstdc++-v3/include/std/map
>> @@ -59,9 +59,19 @@
>> #pragma GCC system_header
>> #endif
>>
>> +#define __glibcxx_want_allocator_traits_is_always_equal
>> +#define __glibcxx_want_containers_ranges
>> +#define __glibcxx_want_erase_if
>> +#define __glibcxx_want_generic_associative_lookup
>> +#define __glibcxx_want_map_try_emplace
>> +#define __glibcxx_want_node_extract
>> +#define __glibcxx_want_nonmember_container_access
>> +#define __glibcxx_want_tuple_like
>> +#define __glibcxx_want_associative_heterogeneous_erasure
>> +#include <bits/version.h>
> 
> Is there a reason to move these earlier?
> 
> The downside of doing this is that the __cpp_lib_xxx forms of the
> macros are all defined while preprocessing the headers that follow,
> not *only* for the code that appears directly in *this* header.
 >
> That's not necessarily a problem, but it makes it easier to
> accidentally rely on #if __cpp_lib_xxx in other files which should
> be relying on the #if __glibcxx_xxx form instead.

Not seeing how __glibcxx_... would be defined without the
__glibcxx_want_... names defined here.

> With the current ordering, the effects of the "want" macros are
> limited to a smaller scope, just this file and user code that includes
> it, but not all the other library internals this this file includes.
> 
> So the current ordering is intentional, not accidental, and this patch
> doesn't mention any rationale for changing that.

I was having trouble with things I needed not being defined yet.
I will try to evolve a less intrusive change that works.

>> #include <bits/requires_hosted.h> // containers
> 
> This one should certainly be first, it just has a #error for
> non-hosted. We want the "die or continue" header to be first, before
> we waste time processing any other code.

OK.

>>
>> -#include <bits/stl_tree.h>
>> #include <bits/stl_map.h>
>> #include <bits/stl_multimap.h>
>> #include <bits/range_access.h>
>> @@ -71,16 +81,6 @@
>> # include <debug/map>
>> #endif
>>
>> -#define __glibcxx_want_allocator_traits_is_always_equal
>> -#define __glibcxx_want_containers_ranges
>> -#define __glibcxx_want_erase_if
>> -#define __glibcxx_want_generic_associative_lookup
>> -#define __glibcxx_want_map_try_emplace
>> -#define __glibcxx_want_node_extract
>> -#define __glibcxx_want_nonmember_container_access
>> -#define __glibcxx_want_tuple_like
>> -#include <bits/version.h>
>> -
>> #if __cplusplus >= 201703L
>> #include <bits/memory_resource.h>
>> namespace std _GLIBCXX_VISIBILITY(default)
>> diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set
>> index cf7057aa6c6..0e6fb3e88c6 100644
>> --- a/libstdc++-v3/include/std/set
>> +++ b/libstdc++-v3/include/std/set
>> @@ -59,9 +59,18 @@
>> #pragma GCC system_header
>> #endif
>>
>> +#define __glibcxx_want_allocator_traits_is_always_equal
>> +#define __glibcxx_want_containers_ranges
>> +#define __glibcxx_want_erase_if
>> +#define __glibcxx_want_generic_associative_lookup
>> +#define __glibcxx_want_node_extract
>> +#define __glibcxx_want_nonmember_container_access
>> +#define __glibcxx_want_associative_heterogeneous_erasure
>> +#define __glibcxx_want_associative_heterogeneous_insertion
>> +#include <bits/version.h>
>> +
>> #include <bits/requires_hosted.h> // containers
>>
>> -#include <bits/stl_tree.h>
>> #include <bits/stl_set.h>
>> #include <bits/stl_multiset.h>
>> #include <bits/range_access.h>
>> @@ -71,14 +80,6 @@
>> # include <debug/set>
>> #endif
>>
>> -#define __glibcxx_want_allocator_traits_is_always_equal
>> -#define __glibcxx_want_containers_ranges
>> -#define __glibcxx_want_erase_if
>> -#define __glibcxx_want_generic_associative_lookup
>> -#define __glibcxx_want_node_extract
>> -#define __glibcxx_want_nonmember_container_access
>> -#include <bits/version.h>
>> -
>> #if __cplusplus >= 201703L
>> #include <bits/memory_resource.h>
>> namespace std _GLIBCXX_VISIBILITY(default)
>> diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/ 
>> include/std/unordered_map
>> index 3ae25d758ac..783ead99a4b 100644
>> --- a/libstdc++-v3/include/std/unordered_map
>> +++ b/libstdc++-v3/include/std/unordered_map
>> @@ -39,15 +39,6 @@
>> # include <bits/c++0x_warning.h>
>> #else
>>
>> -#include <initializer_list>
>> -#include <bits/unordered_map.h>
>> -#include <bits/range_access.h>
>> -#include <bits/erase_if.h>
>> -
>> -#ifdef _GLIBCXX_DEBUG
>> -# include <debug/unordered_map>
>> -#endif
>> -
>> #define __glibcxx_want_allocator_traits_is_always_equal
>> #define __glibcxx_want_containers_ranges
>> #define __glibcxx_want_erase_if
>> @@ -56,8 +47,18 @@
>> #define __glibcxx_want_nonmember_container_access
>> #define __glibcxx_want_unordered_map_try_emplace
>> #define __glibcxx_want_tuple_like
>> +#define __glibcxx_want_associative_heterogeneous_erasure
>> #include <bits/version.h>
>>
>> +#include <initializer_list>
>> +#include <bits/unordered_map.h>
>> +#include <bits/range_access.h>
>> +#include <bits/erase_if.h>
>> +
>> +#ifdef _GLIBCXX_DEBUG
>> +# include <debug/unordered_map>
>> +#endif
>> +
>> #if __cplusplus >= 201703L
>> #include <bits/memory_resource.h>
>> namespace std _GLIBCXX_VISIBILITY(default)
>> diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/ 
>> include/std/unordered_set
>> index b561163d31d..9dcecb050b0 100644
>> --- a/libstdc++-v3/include/std/unordered_set
>> +++ b/libstdc++-v3/include/std/unordered_set
>> @@ -39,6 +39,15 @@
>> # include <bits/c++0x_warning.h>
>> #else
>>
>> +#define __glibcxx_want_allocator_traits_is_always_equal
>> +#define __glibcxx_want_containers_ranges
>> +#define __glibcxx_want_erase_if
>> +#define __glibcxx_want_generic_unordered_lookup
>> +#define __glibcxx_want_node_extract
>> +#define __glibcxx_want_nonmember_container_access
>> +#define __glibcxx_want_associative_heterogeneous_erasure
>> +#include <bits/version.h>
>> +
>> #include <initializer_list>
>> #include <bits/unordered_set.h>
>> #include <bits/range_access.h>
>> @@ -48,14 +57,6 @@
>> # include <debug/unordered_set>
>> #endif
>>
>> -#define __glibcxx_want_allocator_traits_is_always_equal
>> -#define __glibcxx_want_containers_ranges
>> -#define __glibcxx_want_erase_if
>> -#define __glibcxx_want_generic_unordered_lookup
>> -#define __glibcxx_want_node_extract
>> -#define __glibcxx_want_nonmember_container_access
>> -#include <bits/version.h>
>> -
>> #if __cplusplus >= 201703L
>> #include <bits/memory_resource.h>
>> namespace std _GLIBCXX_VISIBILITY(default)
>> diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/ 
>> hetero/erase.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/ 
>> hetero/erase.cc
>> new file mode 100644
>> index 00000000000..711ba05952c
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/hetero/erase.cc
>> @@ -0,0 +1,95 @@
>> +// { dg-do compile { target c++23 } }
> 
> All these tests use dg-do compile but have main() functions. Those
> main functions aren't going to run, so you're only testing that the
> code compiles, not that it runs.
> 
> Presumably they should be dg-do run.

<grimace>
I was lucky the tests passed when actually run.

I had the same problem in the p2363 patch, with worse effect, fixed
in v3.


More information about the Libstdc++ mailing list