Skip to content

Commit 6e73fee

Browse files
committed
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 itanium-cxx-abi/cxx-abi#88, put the implicit equality comparison operators at the very end, after all special member functions. This reinstates add2b7e, reverted in commit 89e43f0, with a fix for 32-bit targets. Reviewers: rjmccall Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72897
1 parent fa00176 commit 6e73fee

File tree

2 files changed

+79
-20
lines changed

2 files changed

+79
-20
lines changed

clang/lib/AST/VTableBuilder.cpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,11 +1474,11 @@ void ItaniumVTableBuilder::AddMethods(
14741474
llvm_unreachable("Found a duplicate primary base!");
14751475
}
14761476

1477-
const CXXDestructorDecl *ImplicitVirtualDtor = nullptr;
1478-
14791477
typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
14801478
NewVirtualFunctionsTy NewVirtualFunctions;
14811479

1480+
llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions;
1481+
14821482
// Now go through all virtual member functions and add them.
14831483
for (const auto *MD : RD->methods()) {
14841484
if (!MD->isVirtual())
@@ -1542,24 +1542,30 @@ void ItaniumVTableBuilder::AddMethods(
15421542
}
15431543
}
15441544

1545-
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
1546-
if (MD->isImplicit()) {
1547-
// Itanium C++ ABI 2.5.2:
1548-
// If a class has an implicitly-defined virtual destructor,
1549-
// its entries come after the declared virtual function pointers.
1550-
1551-
assert(!ImplicitVirtualDtor &&
1552-
"Did already see an implicit virtual dtor!");
1553-
ImplicitVirtualDtor = DD;
1554-
continue;
1555-
}
1556-
}
1557-
1558-
NewVirtualFunctions.push_back(MD);
1559-
}
1560-
1561-
if (ImplicitVirtualDtor)
1562-
NewVirtualFunctions.push_back(ImplicitVirtualDtor);
1545+
if (MD->isImplicit())
1546+
NewImplicitVirtualFunctions.push_back(MD);
1547+
else
1548+
NewVirtualFunctions.push_back(MD);
1549+
}
1550+
1551+
std::stable_sort(
1552+
NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
1553+
[](const CXXMethodDecl *A, const CXXMethodDecl *B) {
1554+
if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
1555+
return A->isCopyAssignmentOperator();
1556+
if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
1557+
return A->isMoveAssignmentOperator();
1558+
if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
1559+
return isa<CXXDestructorDecl>(A);
1560+
assert(A->getOverloadedOperator() == OO_EqualEqual &&
1561+
B->getOverloadedOperator() == OO_EqualEqual &&
1562+
"unexpected or duplicate implicit virtual function");
1563+
// We rely on Sema to have declared the operator== members in the
1564+
// same order as the corresponding operator<=> members.
1565+
return false;
1566+
});
1567+
NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1568+
NewImplicitVirtualFunctions.end());
15631569

15641570
for (const CXXMethodDecl *MD : NewVirtualFunctions) {
15651571
// Get the final overrider.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
2+
3+
#include "Inputs/std-compare.h"
4+
5+
// CHECK: @_ZTV1A =
6+
struct A;
7+
struct X {
8+
// CHECK-SAME: @_ZN1X1xEv
9+
virtual void x();
10+
friend auto operator<=>(X, X) = default;
11+
};
12+
struct Y {
13+
virtual ~Y();
14+
virtual A &operator=(const A &);
15+
friend auto operator<=>(Y, Y) = default;
16+
};
17+
struct A : X, Y {
18+
// CHECK-SAME: @_ZN1A1fEv
19+
virtual void f();
20+
// CHECK-SAME: @_ZNKR1AssERKS_
21+
virtual std::strong_ordering operator<=>(const A &) const & = default;
22+
// CHECK-SAME: @_ZN1A1gEv
23+
virtual void g();
24+
// CHECK-SAME: @_ZNKO1AssERKS_
25+
virtual std::strong_ordering operator<=>(const A &) const && = default;
26+
// CHECK-SAME: @_ZN1A1hEv
27+
virtual void h();
28+
29+
// CHECK-SAME: @_ZN1AaSERKS_
30+
// implicit virtual A &operator=(const A&) = default;
31+
32+
// CHECK-SAME: @_ZN1AD1Ev
33+
// CHECK-SAME: @_ZN1AD0Ev
34+
// implicit virtual ~A();
35+
36+
// CHECK-SAME: @_ZNKR1AeqERKS_
37+
// implicit virtual A &operator==(const A&) const & = default;
38+
39+
// CHECK-SAME: @_ZNKO1AeqERKS_
40+
// implicit virtual A &operator==(const A&) const && = default;
41+
};
42+
43+
// For Y:
44+
// CHECK-SAME: @_ZTI1A
45+
46+
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AD1Ev
47+
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AD0Ev
48+
// virtual ~Y();
49+
50+
// CHECK-SAME: @_ZThn{{[0-9]*}}_N1AaSERKS_
51+
// virtual A &operator=(const A &);
52+
53+
void A::f() {}

0 commit comments

Comments
 (0)