Commit add2b7e4 authored by Richard Smith's avatar Richard Smith
Browse files

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.

Reviewers: rjmccall

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D72897
parent 13fa4e2e
Loading
Loading
Loading
Loading
+26 −20
Original line number Diff line number Diff line
@@ -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;
      }
    }

    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.
+53 −0
Original line number Diff line number Diff line
// 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() {}