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

[cxx-interop] Add support for custom C++ destructors. #32291

Merged
merged 1 commit into from
Jan 28, 2021

Conversation

zoecarver
Copy link
Contributor

This patch adds support for custom C++ destructors. The most notable thing here, I think, is that this is the first place a struct type has a custom destructor. I suspect with more code we will expose a few places where optimization passes need to be fixed to account for this.

One of many patches to fix SR-12797.

@zoecarver zoecarver added the c++ interop Feature: Interoperability with C++ label Jun 10, 2020
@zoecarver zoecarver requested review from gribozavr and MForster June 10, 2020 02:58
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from fcee2ad to 2a6fc7e Compare June 10, 2020 02:59
test/Interop/Cxx/destructor/Inputs/basic.h Outdated Show resolved Hide resolved
lib/AST/ASTVerifier.cpp Outdated Show resolved Hide resolved
lib/ClangImporter/ImportDecl.cpp Outdated Show resolved Hide resolved
@@ -1455,6 +1455,13 @@ namespace {
properties.setAddressOnly();
}

// If a struct has a destructor, it's not trivial. Currently this is only
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is redundant with the code right above -- if (D->isCxxNotTriviallyCopyable()). However, you're raising a good point -- should we also set the non-trivial flag? Seems like trivial and address-only is an invalid combination of flags, and we are setting that combination now. If you agree, could you send that fix as a separate PR?

On the other hand, if we are building towards the future Swift feature of move-only structs then checking for the destructor makes sense. However, I'm not sure that Swift move-only structs would necessarily be non-trivial. They can be certainly trivial to move (imagine a Swift equivalent of std::unique_ptr). So I'm reluctant to add code that checks for non-C++ destructors at this point, we know too little about the future Swift feature yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we also set the non-trivial flag?

Yes. This is very important. Otherwise, the compiler won't create or will remove calls to destroy_addr which will mean the destructor will not be invoked.

Seems like trivial and address-only is an invalid combination of flags

I don't think this is the case. I don't see any reason we couldn't have a trivial, address-only type.

So I'm reluctant to add code that checks for non-C++ destructors at this point, we know too little about the future Swift feature yet.

I see the concern but, I think the risk of omitting destroy_addr calls is greater than the risk of uncertainty in the future. If and when Swift changes its mind about structs with custom destructors, there's no reason this code couldn't be updated.

That being said, it might just be easier to set the properties flag based on isCxxNotTriviallyCopyable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I'm reluctant to add code that checks for non-C++ destructors at this point, we know too little about the future Swift feature yet.

Thinking about this more, I think you're right. I'll update this to check isCxxNotTriviallyCopyable and remove the llvm::any_of.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is the case. I don't see any reason we couldn't have a trivial, address-only type.

Could you provide a sample use case? What would prevent a trivial type from being loadable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here's an example:

struct Foo { unsigned x : 3; };

That type is trivial and also address-only. If you remove the bitfield you'll see the SIL gen produces a builtin "zeroInitializer"<Foo>() : $Foo instruction whereas with the bitfield (as above) it is stored on the stack.

However, there are no destory_addrs indicating that this type is trivial (and if you want, I suspect the compiler would confirm this if I add an assertion or something to double-check).

tupleInit->SubInitializations.push_back(std::move(eltInit));
}
// If this is an empty tuple, we don't want to decompose it.
if (resultTupleType.getElementTypes().size()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you provide some information about why this change was needed? Was it necessary for destructors to work (if so, how does it come up?), or is it just a drive-by peephole optimization? From my reading of TupleInitialization it seems like it should handle the empty tuple.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, this as actually causing issues (probably should have put that in the comment). When we have an empty tuple, we get the wrong return type later on. Because the value is returned with an indirect result, the return type should be @out Foo but instead is () (because that's what's returned).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this should now be part of #32402. I'll leave it in this PR too (just so the tests don't crash) but, I think #32402 is where review/discussion should happen.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! Now that the other PR is merged, could you rebase to eliminate this diff from this PR?

lib/SIL/IR/SILDeclRef.cpp Outdated Show resolved Hide resolved
test/Interop/Cxx/destructor/Inputs/basic.h Outdated Show resolved Hide resolved
test/Interop/Cxx/destructor/Inputs/basic.h Outdated Show resolved Hide resolved
test/Interop/Cxx/destructor/basic.swift Outdated Show resolved Hide resolved
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch 2 times, most recently from 7ec0794 to 77463ea Compare June 10, 2020 17:50
@zoecarver zoecarver requested review from gottesmm and gribozavr June 10, 2020 18:04
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from 77463ea to 6aaf4a3 Compare June 10, 2020 18:04
@@ -1453,6 +1453,7 @@ namespace {

if (D->isCxxNotTriviallyCopyable()) {
properties.setAddressOnly();
properties.setNonTrivial();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to factor out this fix into a separate PR and write a test for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#32402 done :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! Now that PR is merged, would you mind rebasing to minimize the diff?

lib/AST/ASTVerifier.cpp Outdated Show resolved Hide resolved
lib/AST/ASTVerifier.cpp Outdated Show resolved Hide resolved
lib/IRGen/GenStruct.h Outdated Show resolved Hide resolved
lib/IRGen/GenStruct.h Outdated Show resolved Hide resolved
lib/IRGen/GenStruct.h Outdated Show resolved Hide resolved
@@ -0,0 +1,61 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -fno-rtti)
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for repeating the comment. Each file will likely live its own life, and figuring out a couple of years from now why there is an -fno-rtti in one of the files but not in others would be difficult if we didn't have local comments.

// we try to delete the base object. Until we can link against libc++, use
// this dummy implementation.
static void operator delete(void *p) { __builtin_unreachable(); }
virtual ~HasVirtualDestructor(){};
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
virtual ~HasVirtualDestructor(){};
virtual ~HasVirtualDestructor() {}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. I agree that this is better, but I also like to use clang-format on all my changes, and clang-format seems to disagree about this. I'm going to look into fixing our clang-format config so that this is formatted correctly.

test/Interop/Cxx/class/destructor-correct-abi-irgen.swift Outdated Show resolved Hide resolved
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from 5f3d55a to 4b6f93f Compare January 17, 2021 20:20
@zoecarver
Copy link
Contributor Author

@swift-ci please smoke test.

@@ -0,0 +1,41 @@
// RUN: %target-swift-frontend -enable-cxx-interop -I %S/Inputs %s -emit-ir | %FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

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

Assuming you rename the other test to custom-destructors-virtual-irgen.swift, please rename this one to custom-destructors-non-virtual-irgen.swift.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to do the same thing with custom-destructors.swift -> custom-destructors-non-virtual.swift

@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from 4b6f93f to 2fff450 Compare January 19, 2021 20:34
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from 2fff450 to a49aef2 Compare January 19, 2021 20:37
@zoecarver
Copy link
Contributor Author

@swift-ci please test.

@zoecarver
Copy link
Contributor Author

@swift-ci please test Windows.

1 similar comment
@zoecarver
Copy link
Contributor Author

@swift-ci please test Windows.

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - a49aef2d5c3dd1a17ca4b513fe740002900b7706

@zoecarver
Copy link
Contributor Author

@swift-ci please test Windows.

@zoecarver
Copy link
Contributor Author

@swift-ci please test Linux.

1 similar comment
@zoecarver
Copy link
Contributor Author

@swift-ci please test Linux.

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - a49aef2d5c3dd1a17ca4b513fe740002900b7706

@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch 2 times, most recently from 6454b74 to 36eb6c9 Compare January 27, 2021 07:33
This patch adds support for custom C++ destructors. The most notable thing here, I think, is that this is the first place a struct type has a custom destructor. I suspect with more code we will expose a few places where optimization passes need to be fixed to account for this.

One of many patches to fix SR-12797.
@zoecarver zoecarver force-pushed the cxx/irgen/destructor branch from 36eb6c9 to ffa0d1c Compare January 27, 2021 20:55
@zoecarver
Copy link
Contributor Author

@swift-ci please test Linux.

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - ffa0d1c

@zoecarver
Copy link
Contributor Author

@swift-ci please test Linux.

@zoecarver
Copy link
Contributor Author

@swift-ci please test macOS.

@zoecarver
Copy link
Contributor Author

@swift-ci please test Windows.

1 similar comment
@zoecarver
Copy link
Contributor Author

@swift-ci please test Windows.

@zoecarver
Copy link
Contributor Author

I'm going to land this as soon as the Windows bot finishes.

@zoecarver zoecarver merged commit b5d59ed into swiftlang:main Jan 28, 2021
mem-frob pushed a commit to draperlaboratory/hope-llvm-project that referenced this pull request Oct 7, 2022
Adds `CodeGen::getCXXDestructorImplicitParam`, to retrieve a C++ destructor's implicit parameter (after the "this" pointer) based on the ABI in the given CodeGenModule.

This will allow other frontends (Swift, for example) to easily emit calls to object destructors with correct ABI semantics and calling convetions.

This is needed for Swift C++ interop. Here's the corresponding Swift change: swiftlang/swift#32291

Differential Revision: https://reviews.llvm.org/D82392
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants