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>