Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call #12265

Merged
merged 3 commits into from Mar 15, 2021

Conversation

MoonlightSentinel
Copy link
Contributor

@MoonlightSentinel MoonlightSentinel commented Mar 11, 2021

Ensures proper RAII behaviour for stack allocated instances but doesn't affect the behaviour for heap allocated instances.

The previous rewrite used delete which relies on TypeInfo and crashed at runtime. Using object.destroy circumvents this issue (and is also beneficial due to the deprecation of delete).

destroy can be used instead of delete because the instances live on the heap and hence don't need to be deallocated.

@MoonlightSentinel MoonlightSentinel changed the base branch from master to stable March 11, 2021 00:48
@MoonlightSentinel MoonlightSentinel changed the title Scoped destruction Issue 21693 - Lower scoped destruction of extern(C++) class to destroy Mar 11, 2021
@MoonlightSentinel MoonlightSentinel marked this pull request as ready for review March 11, 2021 01:40
@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @MoonlightSentinel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

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 references

Auto-close Bugzilla Severity Description
21693 critical extern(C++) class instance dtors are never called, breaking RAII

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "stable + dmd#12265"

@MoonlightSentinel MoonlightSentinel added the extern (C/C++) interfacing to C and C++ label Mar 11, 2021
if (mynew || onstack) // if any destructors
{
// delete'ing C++ classes crashes (and delete is deprecated anyway)
if (cd.classKind == ClassKind.cpp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy should be used instead of delete for for D classes, too: https://issues.dlang.org/show_bug.cgi?id=21692

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy doesn't work for const/immutable either (unless we insert an explicit cast to mutable)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented another approach, it's now directly calling the dtor (effectively inlining the call to destroy).
This matches the implementation for structs and allows the hack to call dtors on immutable instances.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy doesn't work for const/immutable either (unless we insert an explicit cast to mutable)

Seems like it does (tested with v2.096.0). Anyway, the direct dtor call is better. Is there a reason you don't use it for D classes too? I find it inconsistent (can use scope const/immutable with C++ classes, but not with D ones) and don't really like deprecated expressions in compiler-generated AST nodes. ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it does (tested with v2.096.0).

Nevermind, seems like it was an issue with the lowering.

Is there a reason you don't use it for D classes too? I find it inconsistent (can use scope const/immutable with C++ classes, but not with D ones) and don't really like deprecated expressions in compiler-generated AST nodes. ;)

Mostly because destroy (and delete IIRC) refer to rt_finalize2 which does more cleanup than just calling the dtor. Not sure if those additional steps are required for stack allocated instances...

But lowering to destroy would still work for D classes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But lowering to destroy would still work for D classes.

Yeah that'd be great.

You're right, for D classes, there's apparently the need to descend to all base classes and invoke the dtors manually (via TypeInfo... argh), and the monitor might need cleanup too. LDC has a special case for these delete expressions for scope classes and tries to avoid calling druntime if the class has no finalizer and the monitor is null: https://github.com/ldc-developers/ldc/blob/937c57b8354d4821daededb35abdb77d16ce3737/gen/classes.cpp#L200-L222

Doing this here in the frontend directly would obviously be much nicer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the best way forward is to replace the TypeInfo based dtor-loop in DRuntime with a real dtor chain as done for C++ classes and to move the cleanup into `Object.~this()). That would cause less (magic) code scattered across dmd/druntime/ldc/... .

Anyway, lowering to destroy doesn't work yet.

  • it isn't alway @nogc
  • CTFE cannot handle destroy (it needs some special casing as done for delete)

@MoonlightSentinel MoonlightSentinel force-pushed the scoped-destruction branch 2 times, most recently from 98de8e4 to da70229 Compare March 11, 2021 15:04
@MoonlightSentinel MoonlightSentinel changed the title Issue 21693 - Lower scoped destruction of extern(C++) class to destroy Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call Mar 12, 2021
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.

The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).

`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
Call the destructor directly instead of referring to object.destroy
@Geod24 Geod24 merged commit 939778e into dlang:stable Mar 15, 2021
@MoonlightSentinel MoonlightSentinel deleted the scoped-destruction branch June 20, 2021 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extern (C/C++) interfacing to C and C++
Projects
None yet
6 participants