-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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] Use user defined copy constructor to copy C++ objects. #32378
Conversation
lib/AST/ClangTypeConverter.cpp
Outdated
@@ -410,7 +410,19 @@ clang::QualType ClangTypeConverter::visitProtocolType(ProtocolType *type) { | |||
// Metatypes can be converted to Class when they are metatypes for concrete |
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.
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. |
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.
if (ctor->isDeleted()) | ||
return nullptr; | ||
} | ||
if (ctor->getAccess() != clang::AS_public) { |
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.
@@ -0,0 +1,21 @@ | |||
// Target-specific tests for C++ copy constructor code generation. |
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.
// RUN: %target-swift-frontend -enable-cxx-interop -I %S/Inputs %s -emit-ir | %FileCheck %s | ||
|
||
// REQUIRES: CPU=x86_64 | ||
// REQUIRES: objc_interop |
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
@@ -18,7 +18,7 @@ | |||
// This definition is a placeholder for importing into Swift. | |||
// It provides size and alignment but cannot be manipulated safely there. | |||
typedef struct { | |||
__swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE; |
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 |
if (ctor->isDeleted()) | ||
return nullptr; | ||
} | ||
if (ctor->getAccess() != clang::AS_public) { |
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.
@@ -54,17 +54,17 @@ func pass(s: StructWithSubobjectDefaultedCopyConstructor) { | |||
|
|||
// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithPrivateDefaultedCopyConstructor) | |||
func pass(s: StructWithPrivateDefaultedCopyConstructor) { | |||
// CHECK: bb0(%0 : $*StructWithPrivateDefaultedCopyConstructor): |
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?
} | ||
|
||
// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithInheritedPrivateDefaultedCopyConstructor) | ||
func pass(s: StructWithInheritedPrivateDefaultedCopyConstructor) { | ||
// CHECK: bb0(%0 : $*StructWithInheritedPrivateDefaultedCopyConstructor): | ||
// CHECK: bb0(%0 : $StructWithInheritedPrivateDefaultedCopyConstructor): |
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?
@@ -18,7 +18,7 @@ | |||
// This definition is a placeholder for importing into Swift. | |||
// It provides size and alignment but cannot be manipulated safely there. | |||
typedef struct { | |||
__swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE; |
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).