List implicit operator== after implicit destructors in a vtable.

Summary:
We previously listed first declared members, then implicit operator=,
then implicit operator==, then implicit destructors. Per discussion on
https://github.com/itanium-cxx-abi/cxx-abi/issues/88, put the implicit
equality comparison operators at the very end, after all special member
functions.

This reinstates add2b7e44a, reverted in
commit 89e43f04ba, with a fix for 32-bit
targets.

Reviewers: rjmccall

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D72897
This commit is contained in:
Richard Smith 2020-01-21 15:52:15 -08:00
parent fa001767f0
commit 6e73fee780
2 changed files with 77 additions and 18 deletions

View File

@ -1474,11 +1474,11 @@ void ItaniumVTableBuilder::AddMethods(
llvm_unreachable("Found a duplicate primary base!");
}
const CXXDestructorDecl *ImplicitVirtualDtor = nullptr;
typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
NewVirtualFunctionsTy NewVirtualFunctions;
llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions;
// Now go through all virtual member functions and add them.
for (const auto *MD : RD->methods()) {
if (!MD->isVirtual())
@ -1542,24 +1542,30 @@ void ItaniumVTableBuilder::AddMethods(
}
}
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
if (MD->isImplicit()) {
// Itanium C++ ABI 2.5.2:
// If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers.
assert(!ImplicitVirtualDtor &&
"Did already see an implicit virtual dtor!");
ImplicitVirtualDtor = DD;
continue;
}
}
NewVirtualFunctions.push_back(MD);
if (MD->isImplicit())
NewImplicitVirtualFunctions.push_back(MD);
else
NewVirtualFunctions.push_back(MD);
}
if (ImplicitVirtualDtor)
NewVirtualFunctions.push_back(ImplicitVirtualDtor);
std::stable_sort(
NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
[](const CXXMethodDecl *A, const CXXMethodDecl *B) {
if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
return A->isCopyAssignmentOperator();
if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
return A->isMoveAssignmentOperator();
if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
return isa<CXXDestructorDecl>(A);
assert(A->getOverloadedOperator() == OO_EqualEqual &&
B->getOverloadedOperator() == OO_EqualEqual &&
"unexpected or duplicate implicit virtual function");
// We rely on Sema to have declared the operator== members in the
// same order as the corresponding operator<=> members.
return false;
});
NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
NewImplicitVirtualFunctions.end());
for (const CXXMethodDecl *MD : NewVirtualFunctions) {
// Get the final overrider.

View File

@ -0,0 +1,53 @@
// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
#include "Inputs/std-compare.h"
// CHECK: @_ZTV1A =
struct A;
struct X {
// CHECK-SAME: @_ZN1X1xEv
virtual void x();
friend auto operator<=>(X, X) = default;
};
struct Y {
virtual ~Y();
virtual A &operator=(const A &);
friend auto operator<=>(Y, Y) = default;
};
struct A : X, Y {
// CHECK-SAME: @_ZN1A1fEv
virtual void f();
// CHECK-SAME: @_ZNKR1AssERKS_
virtual std::strong_ordering operator<=>(const A &) const & = default;
// CHECK-SAME: @_ZN1A1gEv
virtual void g();
// CHECK-SAME: @_ZNKO1AssERKS_
virtual std::strong_ordering operator<=>(const A &) const && = default;
// CHECK-SAME: @_ZN1A1hEv
virtual void h();
// CHECK-SAME: @_ZN1AaSERKS_
// implicit virtual A &operator=(const A&) = default;
// CHECK-SAME: @_ZN1AD1Ev
// CHECK-SAME: @_ZN1AD0Ev
// implicit virtual ~A();
// CHECK-SAME: @_ZNKR1AeqERKS_
// implicit virtual A &operator==(const A&) const & = default;
// CHECK-SAME: @_ZNKO1AeqERKS_
// implicit virtual A &operator==(const A&) const && = default;
};
// For Y:
// CHECK-SAME: @_ZTI1A
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AD1Ev
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AD0Ev
// virtual ~Y();
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AaSERKS_
// virtual A &operator=(const A &);
void A::f() {}