-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[cxx-interop] Use user defined copy constructor to copy C++ objects. #32378
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
Conversation
lib/AST/ClangTypeConverter.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case it wasn't clear from the summary, most of the changes here are from #30630.
martinboehme
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I was going to do this at some point, but hadn't gotten round to it yet.
8a28baa to
36d8c28
Compare
|
Thanks for the reviews! I fixed a few of the comments. I'll fix the rest tomorrow (and add some related witness table changes from #32291). |
e4fb5c4 to
1ef546b
Compare
1ef546b to
dbddd9d
Compare
|
@gribozavr and @martinboehme thank you for your comments and patience. I think I've (finally) resolved all the comments (except for the thunk/Microsoft ABI issue). Sorry for the delay. |
martinboehme
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Responding to one of your code-level comments here, as github apparently won't allow me to respond to the comment thread any more:
We could also import it as a __double_underscore method which should help with overload resolution. Then just use it's function signature and ignore it.
Yes, something like that I think. I'm not super-familiar with the rules that Swift has here (to make sure we're not generating a name that could conflict with anything else) -- @gribozavr can probably say more about this.
Alternatively, we could try to build the "correct" function type in IRGen and then use that in the signature argument.
Yes, that's what we would need to do. But I think that would end up being quite a bit more code than the alternative we're discussing above. I've also pointed out an additional name-mangling issue in one of my new comments.
I think it's easier to just import the copy constructor as a SIL function, emit a call to that, and have the existing code take care of the rest.
lib/ClangImporter/ImportDecl.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to admit I don't understand the logic that existed here before this PR, and which was introduced by #31707.
AFAICT, the definition of "trivially copyable" says nothing about the access level of the copy constructor. It does say something about the copy constructor being deleted, namely that this is compatible with the class being trivially copyable.
Beyond that, I'm not sure why simply taking the result of cxxRecordDecl->isTriviallyCopyable() isn't sufficient here.
@MForster I think you introduced this logic -- can you comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[class.prop]/p1 defines a trivially copyable class as a class, "that has at least one eligible copy constructor..." I think the important word there is eligible. A private copy constructor is not eligible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's how C++ defines "eligible":
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. However, I think we have to still check for public access level, since it would be otherwise quite weird that Swift can use a private constructor -- even if it is trivial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gribozavr Did you really intend that this test should be in the class (not value-witness-table) directory?
This forces us to duplicate the definitions of the C++ classes between the two directories, which seems suboptimal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a shame that this test needs to be so platform-specific.
If you change the definitions of your C++ test classes a bit, I think you should be able to use a strategy similar to the one used here:
https://github.com/apple/swift/pull/30630/files#diff-496932cc8ce48ca2aa1c0a25fd7d1d8b
This would then also allow you to tests for platforms that require implicit parameters to be inserted.
I think the main obstacle to importing your current C++ classes without a stdlib present is that they use the C++ type int in the interface, and the corresponding CInt is defined in stdlib. So I'd suggest defining variants of these classes that don't use int in the interface, and using them for this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even without an int member, they need the stdlib to represent the reference types (with an UnsafePointer). I tried updating this test for multiple targets but, I don't think this will work (without the stdlib). I even tried mocking up a basic UnsafePointer in the test file but, that didn't seem to work either (and it seems very fragile).
Another possibility is I could duplicate this test and have a REQUIRES comment for each target (i.e., have three tests for three targets). WDTY the best solution is?
4b87be5 to
ecd1674
Compare
I figured out all we really need to do is create the SIL function type and that didn't seem to be too much work. I also got it working by importing the constructor like any other, so if you'd rather we can do that (but I like this way better). FWIW one issue I ran into when importing the constructor as a SIL function is that Swift will try to remove the function unless there is a use of it (or maybe it just lazily SILGens it-- either way it doesn't seem to exist when I dump the SIL if I don't explicitly call it somewhere). |
|
@swift-ci please smoke test Linux platform. |
2b5e0ef to
11c8898
Compare
|
@swift-ci please test |
11c8898 to
1d2ac78
Compare
|
@swift-ci please test |
|
@hlopko and @gribozavr friendly ping. This is ready for review when you're ready to review it :) |
|
Build failed |
|
Build failed |
1d2ac78 to
4e6e029
Compare
stdlib/public/SwiftShims/RefCount.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, in C-mode this attribute is meaningless which is why we didn't see the error before now. If we want to make sure that in runtime mode we don't use this type, I'll need to create a separate and more involved fix. Let me know if that needs to be done.
Another "fix" could be to only add SWIFT_ATTRIBUTE_UNAVAILABLE when ifndef __swift__ .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, in C-mode this attribute is meaningless which is why we didn't see the error before now.
Which error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we have a reference type, for example an array, we try to add an implicit copy constructor in C++ mode. When we try to do this, we get an error that refCounts is unreachable:
swift-source/build/Ninja-ReleaseAssert/swift-macosx-arm64/lib/swift/shims/RefCount.h:20:9: error: 'refCounts' is unavailable
typedef struct {
^
swift-source/build/Ninja-ReleaseAssert/swift-macosx-arm64/lib/swift/shims/HeapObject.h:45:8: note: in implicit copy constructor for 'InlineRefCountsPlaceholder' first required here
struct HeapObject {
^
swift-source/build/Ninja-ReleaseAssert/swift-macosx-arm64/lib/swift/shims/GlobalObjects.h:38:8: note: in implicit copy constructor for 'HeapObject' first required here
struct _SwiftEmptyArrayStorage {
^
<unknown>:0: note: in implicit copy constructor for '_SwiftEmptyArrayStorage' first required here
swift-source/build/Ninja-ReleaseAssert/swift-macosx-arm64/lib/swift/shims/RefCount.h:21:21: note: 'refCounts' has been explicitly marked unavailable here
__swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE;
|
@swift-ci please test |
lib/ClangImporter/ImportDecl.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. However, I think we have to still check for public access level, since it would be otherwise quite weird that Swift can use a private constructor -- even if it is trivial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. However, you added this code:
if (ctor->isDeleted() || ctor->getAccess() != clang::AS_public)
return nullptr;
shouldn't it take care of rejecting it based on the access control level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's code in the importer that should make a type address-only if there is any private constructor, do you know why that is not kicking in?
stdlib/public/SwiftShims/RefCount.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, in C-mode this attribute is meaningless which is why we didn't see the error before now.
Which error?
test/Interop/Cxx/value-witness-table/copy-constructor-irgen.swift
Outdated
Show resolved
Hide resolved
4e6e029 to
c33e672
Compare
|
@swift-ci please smoke test. |
|
@swift-ci please smoke test macOS. |
|
@swift-ci please smoke test Windows. |
c33e672 to
4b11c54
Compare
|
@swift-ci please smoke test Windows. |
|
@swift-ci please smoke test. |
4b11c54 to
de4e80e
Compare
|
@swift-ci please smoke test Windows. |
de4e80e to
825342d
Compare
|
@swift-ci please smoke test. |
|
@gribozavr tests are passing and suggestions have been applied. Any more comments? |
test/Interop/Cxx/class/type-classification-module-interface.swift
Outdated
Show resolved
Hide resolved
If a user-defined copy constructor exists, use that to copy imported C++ types.
825342d to
b2b7f7b
Compare
|
@swift-ci please test. |
|
@swift-ci please test Windows platform. |
Calls user-defined copy constructor when present. Based on #30630 (probably best to wait until that lands to review this).