util/delegate.h: Make comparison operators more technically correct.

For Itanium ABI, two null member function pointers should compare equal
even if the undefined bits differ.

For MSVC ABI, there's all sorts of complexity around what happens when
you compare pointers to member functions for different inheritance
types.

You'll still occasionally get weird results comparing pointers to
members of different classes.
This commit is contained in:
Vas Crabb 2021-09-22 05:58:42 +10:00
parent 86c005377d
commit 2bfa21eb2a

View file

@ -402,7 +402,7 @@ public:
// comparison helpers
bool operator==(const delegate_mfp_itanium &rhs) const
{
return (m_function == rhs.m_function) && (m_this_delta == rhs.m_this_delta);
return (isnull() && rhs.isnull()) || ((m_function == rhs.m_function) && (m_this_delta == rhs.m_this_delta));
}
bool isnull() const
@ -496,8 +496,37 @@ public:
}
// comparison helpers
bool operator==(const delegate_mfp_msvc &rhs) const { return m_function == rhs.m_function; }
bool isnull() const { return !reinterpret_cast<void (*)()>(m_function); }
bool operator==(const delegate_mfp_msvc &rhs) const
{
if (m_function != rhs.m_function)
{
return false;
}
else if (sizeof(single_base_equiv) == m_size)
{
return (sizeof(single_base_equiv) == rhs.m_size) || (!rhs.m_this_delta && ((sizeof(multi_base_equiv) == rhs.m_size) || !rhs.m_vt_index));
}
else if (sizeof(multi_base_equiv) == m_size)
{
if (sizeof(unknown_base_equiv) == rhs.m_size)
return (m_this_delta == rhs.m_this_delta) && !rhs.m_vt_index;
else
return (sizeof(single_base_equiv) == rhs.m_size) ? !m_this_delta : (m_this_delta == rhs.m_this_delta);
}
else if (sizeof(unknown_base_equiv) == rhs.m_size)
{
return (m_this_delta == rhs.m_this_delta) && (m_vt_index == rhs.m_vt_index) && (!m_vt_index || (m_vptr_offs == rhs.m_vptr_offs));
}
else
{
return !m_vt_index && ((sizeof(multi_base_equiv) == rhs.m_size) ? (m_this_delta == rhs.m_this_delta) : !m_this_delta);
}
}
bool isnull() const
{
return !reinterpret_cast<void (*)()>(m_function);
}
// getters
static delegate_generic_class *real_object(delegate_generic_class *original) { return original; }