mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 23:06:34 +00:00

In the MS C++ ABI, the complete destructor variant for a class with virtual bases is emitted whereever it is needed, instead of directly alongside the base destructor variant. The complete destructor calls the base destructor of the current class and the base destructors of each virtual base. In order for this to work reliably, translation units that use the destructor of a class also need to mark destructors of virtual bases of that class used. Fixes PR38521 Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D77081
52 lines
1.8 KiB
C++
52 lines
1.8 KiB
C++
// RUN: %clang_cc1 -std=c++17 -verify -Wno-defaulted-function-deleted %s -triple x86_64-windows-msvc
|
|
|
|
// MSVC emits the complete destructor as if it were its own special member.
|
|
// Clang attempts to do the same. This affects the diagnostics clang emits,
|
|
// because deleting a type with a user declared constructor implicitly
|
|
// references the destructors of virtual bases, which might be deleted or access
|
|
// controlled.
|
|
|
|
namespace t1 {
|
|
struct A {
|
|
~A() = delete; // expected-note {{deleted here}}
|
|
};
|
|
struct B {
|
|
B() = default;
|
|
A o; // expected-note {{destructor of 'B' is implicitly deleted because field 'o' has a deleted destructor}}
|
|
};
|
|
struct C : virtual B {
|
|
~C(); // expected-error {{attempt to use a deleted function}}
|
|
};
|
|
void delete1(C *p) { delete p; } // expected-note {{in implicit destructor for 't1::C' first required here}}
|
|
void delete2(C *p) { delete p; }
|
|
}
|
|
|
|
namespace t2 {
|
|
struct A {
|
|
private:
|
|
~A();
|
|
};
|
|
struct B {
|
|
B() = default;
|
|
A o; // expected-note {{destructor of 'B' is implicitly deleted because field 'o' has an inaccessible destructor}}
|
|
};
|
|
struct C : virtual B {
|
|
~C(); // expected-error {{attempt to use a deleted function}}
|
|
};
|
|
void useCompleteDtor(C *p) { delete p; } // expected-note {{in implicit destructor for 't2::C' first required here}}
|
|
}
|
|
|
|
namespace t3 {
|
|
template <unsigned N>
|
|
class Base { ~Base(); }; // expected-note 1{{declared private here}}
|
|
// No diagnostic.
|
|
class Derived0 : virtual Base<0> { ~Derived0(); };
|
|
class Derived1 : virtual Base<1> {};
|
|
// Emitting complete dtor causes a diagnostic.
|
|
struct Derived2 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}}
|
|
virtual Base<2> {
|
|
~Derived2();
|
|
};
|
|
void useCompleteDtor(Derived2 *p) { delete p; } // expected-note {{in implicit destructor for 't3::Derived2' first required here}}
|
|
}
|