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())
}
}
- 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 (ImplicitVirtualDtor)
- NewVirtualFunctions.push_back(ImplicitVirtualDtor);
+ if (MD->isImplicit())
+ NewImplicitVirtualFunctions.push_back(MD);
+ else
+ NewVirtualFunctions.push_back(MD);
+ }
+
+ 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.
--- /dev/null
+// 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: @_ZThn8_N1AD1Ev
+// CHECK-SAME: @_ZThn8_N1AD0Ev
+// virtual ~Y();
+
+// CHECK-SAME: @_ZThn8_N1AaSERKS_
+// virtual A &operator=(const A &);
+
+void A::f() {}