Fix #22709 - Use of extern(C++) destructor is hidden#22931
Fix #22709 - Use of extern(C++) destructor is hidden#22931dkorpel wants to merge 1 commit intodlang:masterfrom
Conversation
|
Thanks for your pull request and interest in making D better, @dkorpel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
|
thewilsonator
left a comment
There was a problem hiding this comment.
What exactly was "hidden" about this? along explanation about this in the commit message would be good.
Also that test case doesn't seem to test for much I would expect that level of brevity for an ICE. Is it possible to test observed behaviour, with possibly one of the classes implemented in C++ (or several permutations of implementation on C++/D)?
|
When you add a method to a derived class with the exact same signature, you must add the override keyword to specify it will override the vtbl entry of the base class: class C {
int f(int x) => 3;
}
class D : C {
override int f(int x) => 4;
}
// vtbl = [int f(int x)]When the signature is different, instead of overriding you can add a new method with the same name as a different overload: class C {
int f(int x) => 3;
}
class D : C {
int f(string x) => 4;
}
// vtbl = [int f(int x), int f(string x)]But what if the parameter types implicitly convert? class C {
int f(uint x) => 3;
}
class D : C {
int f(int x) => 4;
}
// vtbl = [int f(uint x), int f(int x)]Even an exact match Now with C++ destructors, from what I gather, the intention is that ~this() implicitly overrides the parent destructor. But this search is shallow, so in the issues test case with classes A, B and C, the resulting vtable is: extern(C++):
class A
{
~this();
}
class B : A
{
}
class C : B
{
~this();
}
// vtbl = [A.~this, C.~this]And then dmd considers That makes sense to me, but I'm not familiar with the exact C++ destructor overriding / chaining semantics hence my question for review. I had Claude write a cxx-runnable test, but it's currently hard-coded for the itanium C++ abi, so I'll try to make a cross-platform test case that doesn't pry in vtbl internals. |
|
The change looks good. I think there could be other problems, if cppDtorVtblIndex is not set for C++ classes without explicit destructor, like this: import std.stdio;
extern(C++):
struct S
{
~this()
{
writeln("S.~this");
}
}
class A
{
~this()
{
writeln("A.~this");
}
}
class B : A
{
S s;
}
void main()
{
A x = new B;
x.destroy();
}It only runs the destructor for A and does not run the destructor for S, because B has no explicit destructor. See dmd/compiler/src/dmd/dsymbolsem.d Lines 5842 to 5854 in 1133fe0 It could be better, if the semantic analysis for C++ classes without destructor also sets cppDtorVtblIndex if a base class has it set. Maybe the loop over all base classes would then not be needed. but I'm not sure, if the order of semantic analysis always allows this. |
Previously, the implicit override of a base class destructor for C++ classes was shallow, so with an empty class B sitting inbetween A and C you would get a vtbl = [A.~this, C.~this], where dmd considers A.~this hidden by C.~this. Now, C finds the vtable index of A resulting in vtbl = [C.~this]. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for the review @tim-dlang, is that field destructor issue filed already? |
I have created an issue now: #22942 |
Closes #22709
The initial fix was simply "if (extern(c++) destructor) continue;" on the hidden method check, but that felt odd because it's a weirdly special case, and the bug only manifests with the empty B class inbetween. So after asking Claude to investigate, this deeper bug surfaced where the search for an inherited destructor is too shallow.
The correction looks right to me, but could really use a review from someone with C++ experience.