]> git.ipfire.org Git - thirdparty/gcc.git/commit
libstdc++: Add _M_key_compare helper to associative containers
authorJonathan Wakely <jwakely@redhat.com>
Thu, 24 Apr 2025 13:58:58 +0000 (14:58 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 25 Apr 2025 10:47:12 +0000 (11:47 +0100)
commit876d1a22dfaf873d167bd2ffad190a1d07a81b22
treea21244a9d63262874fe067602b75a14a5148456b
parentaafe942227baf8c2bcd4cac2cb150e49a4b895a9
libstdc++: Add _M_key_compare helper to associative containers

In r10-452-ge625ccc21a91f3 I noted that we don't have an accessor for
invoking _M_impl._M_key_compare in the associative containers. That
meant that the static assertions to check for valid comparison functions
were squirrelled away in _Rb_tree::_S_key instead. As Jason noted in
https://gcc.gnu.org/pipermail/gcc-patches/2025-April/681436.html this
means that the static assertions fail later than we'd like.

This change adds a new _Rb_tree::_M_key_compare member function which
invokes the _M_impl._M_key_compare function object, and then moves the
static_assert from _S_key into _M_key_compare. Now if the static_assert
fails, that's the first error we get, before the "no match for call" and
and "invalid conversion" errors.

Because the new function is const-qualified, we now treat LWG 2542 as a
DR for older standards, requiring the comparison function to be const
invocable. Previously we only enforced the LWG 2542 rule for C++17 and
later.

I did consider deprecating support for comparisons which aren't const
invocable, something like this:

  // Before LWG 2542 it wasn't strictly necessary for _Compare to be
  // const invocable, if you only used non-const container members.
  // Define a non-const overload for pre-C++17, deprecated for C++11/14.
  #if __cplusplus < 201103L
  bool
  _M_key_compare(const _Key& __k1, const _Key& __k2)
  { return _M_impl._M_key_compare(__k1, __k2); }
  #elif __cplusplus < 201703L
  template<typename _Key1, typename _Key2>
    [[__deprecated__("support for comparison functions that are not "
                     "const invocable is deprecated")]]
    __enable_if_t<
    __and_<__is_invocable<_Compare&, const _Key1&, const _Key2&>,
           __not_<__is_invocable<const _Compare&, const _Key1&, const _Key2&>>>::value,
           bool>
    _M_key_compare(const _Key1& __k1, const _Key2& __k2)
    {
      static_assert(
        __is_invocable<_Compare&, const _Key&, const _Key&>::value,
        "comparison object must be invocable with two arguments of key type"
      );
      return _M_impl._M_key_compare(__k1, __k2);
    }
  #endif

But I decided that this isn't necessary, because we've been enforcing
the C++17 rule since GCC 8.4 and 9.2, and C++17 has been the default
since GCC 11.1. Users have had plenty of time to fix their invalid
comparison functions.

libstdc++-v3/ChangeLog:

* include/bits/stl_tree.h (_Rb_tree::_M_key_compare): New member
function to invoke comparison function.
(_Rb_tree): Use new member function instead of accessing the
comparison function directly.

Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
libstdc++-v3/include/bits/stl_tree.h