| Issue |
74282
|
| Summary |
[Clang] Possible miscompilation of the destructor of a class with a virtual base class
|
| Labels |
clang
|
| Assignees |
|
| Reporter |
frederick-vs-ja
|
The following program attempts to destroy a **mediate base class subobject whose type has a virtual base class**.
(Skipping the side effects of a destructor is made well-defined via [CWG2523](https://cplusplus.github.io/CWG/issues/2523.html).)
```C++
#include <cstdio>
struct B {
B() { std::printf("B::B %p\n", static_cast<const void*>(this)); }
B(const B&) = delete;
B &operator=(const B&) = delete;
~B() { std::printf("B::~B %p\n", static_cast<const void*>(this)); }
};
struct DX : virtual B {
DX() { std::printf("DX::DX %p\n", static_cast<const void*>(this)); }
DX(const DX&) = delete;
DX &operator=(const DX&) = delete;
~DX() { std::printf("DX::~DX %p\n", static_cast<const void*>(this)); }
};
struct DY : virtual B {
DY() { std::printf("DY::DY %p\n", static_cast<const void*>(this)); }
DY(const DY&) = delete;
DY &operator=(const DY&) = delete;
~DY() { std::printf("DY::~DY %p\n", static_cast<const void*>(this)); }
};
struct DZ : DX, DY {
DZ() { std::printf("DZ::DZ %p\n", static_cast<const void*>(this)); }
DZ(const DZ&) = delete;
DZ &operator=(const DZ&) = delete;
~DZ() { std::printf("DZ::~DZ %p\n", static_cast<const void*>(this)); }
};
template<class T>
union NoDestroy {
T val;
NoDestroy() : val() {}
NoDestroy(const NoDestroy&) = delete;
NoDestroy &operator=(const NoDestroy&) = delete;
~NoDestroy() {}
};
int main()
{
NoDestroy<DZ> d{};
static_cast<DY&>(d.val).~DY();
}
```
When using Clang (same for GCC), the addresses printed after `B::B` and `B::~B` are always different ([Godbolt link](https://godbolt.org/z/q4sYoWhTx)). Clang (and GCC) seems to emit miscalculation of the offset of the `B` base class subobject in `DY::~DY` (possibly due to early setting vptr), which is likely wrong when the `DY` object is not a most derived object.
MSVC seems to calculate the offset correctly.
There doesn't seem anything in the C++ standard indicating that "destructing a mediate base class subobject whose type has a virtual base class" is undefined behavior. However, [[class.dtor]/13](https://eel.is/c++draft/class.dtor#13) says
> [...] and, if `X` is the most derived class ([class.base.init]), its destructor calls the destructors for `X`'s virtual base classes. [...]
which looks defective as it possibly requires additional metadata to tell whether a class object whose type has a virtual base class is a most derived object.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs