summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-09-22 05:58:42 +1000
committer Vas Crabb <vas@vastheman.com>2021-09-22 05:58:42 +1000
commit2bfa21eb2a6fd9af7429a347026c50aec045f590 (patch)
tree9565dec73cad2451237a8fcd7e1570c0164ec072 /src/lib
parent86c005377d62adf7996f3d6def3046e3fde1da27 (diff)
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.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/util/delegate.h35
1 files changed, 32 insertions, 3 deletions
diff --git a/src/lib/util/delegate.h b/src/lib/util/delegate.h
index f79f8a110ad..223467d2fbc 100644
--- a/src/lib/util/delegate.h
+++ b/src/lib/util/delegate.h
@@ -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; }