Skip to content

[cxx-interop] Support for printing C++ foreign references #81832

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

Merged
merged 1 commit into from
Jun 11, 2025

Conversation

susmonteiro
Copy link
Contributor

@susmonteiro susmonteiro commented May 29, 2025

Adds support for printing a C++ foreign reference in Swift.

Also skips metadata of private fields in C++ records imported as Swift classes, following up on #81035

Resolves rdar://124164228

@susmonteiro susmonteiro added the c++ interop Feature: Interoperability with C++ label May 29, 2025
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro force-pushed the susmonteiro/class-metadata-private-fields branch from 4aadc58 to ebdea6a Compare June 4, 2025 12:08
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro force-pushed the susmonteiro/class-metadata-private-fields branch from ebdea6a to 68fb206 Compare June 4, 2025 15:54
@susmonteiro susmonteiro changed the title [cxx-interop] Skip metadata of C++ private fields in ClassContextDescriptorBuilder [cxx-interop] Support from printing C++ foreign references Jun 4, 2025
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro marked this pull request as ready for review June 4, 2025 16:02
Copy link
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

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

Looks great! Some minor nits inline.

@@ -381,6 +381,10 @@ internal func _adHocPrint_unlocked<T, TargetStream: TextOutputStream>(
target.write(")")
}
}
case .foreign:
printTypeName(mirror.subjectType)
// FRT has no children
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to print the (public) fields similar to structs in the future? I think it is fine to not do it in this PR but we might want to have a rdar for it if this is planned and possible to achieve?

Copy link
Contributor Author

@susmonteiro susmonteiro Jun 4, 2025

Choose a reason for hiding this comment

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

At the moment, we don't emit field metadata for FRT, so we don't have any field information at runtime:

swift/lib/IRGen/GenMeta.cpp

Lines 2006 to 2009 in 68fb206

if (getType()->isForeign())
return;
MetadataLayout = &IGM.getClassMetadataLayout(Type);

swift/lib/IRGen/GenMeta.cpp

Lines 2120 to 2125 in 68fb206

Size getFieldVectorOffset() {
if (!MetadataLayout) return Size(0);
return (MetadataLayout->hasResilientSuperclass()
? MetadataLayout->getRelativeFieldOffsetVectorOffset()
: MetadataLayout->getStaticFieldOffsetVectorOffset());
}

I'm not sure if this is on purpose or it's simply not yet implemented, but I agree it would be useful to figure this out and, potentially, print more information in the future

@@ -147,7 +147,7 @@ public enum _DebuggerSupport {
return value.map(String.init(reflecting:))
case .collection?, .dictionary?, .set?, .tuple?:
return count == 1 ? "1 element" : "\(count) elements"
case .`struct`?, .`enum`?, nil:
case .`struct`?, .`enum`?, .foreign?, nil:
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if foreign reference types should behave more like classes and print the memory address.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

asObjectAddress(...) of a FRT returns 0, so for now I think we shouldn't print the memory address. Most likely this happens for the same reason that we don't have metadata about the fields of FRTs at runtime.

If in the future we decide to work on emitting more metadata for FRTs, it could make sense to add .foreign to the same case as classes. For now, I would keep it as is, if you agree?

Copy link
Contributor

Choose a reason for hiding this comment

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

If supporting this requires additional work I am fine to leave this as is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed that we should ideally print an address, also agreed that it doesn't have to be in this PR 😉

@susmonteiro susmonteiro changed the title [cxx-interop] Support from printing C++ foreign references [cxx-interop] Support for printing C++ foreign references Jun 5, 2025
@susmonteiro susmonteiro force-pushed the susmonteiro/class-metadata-private-fields branch from 68fb206 to 3ec1479 Compare June 5, 2025 13:51
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro
Copy link
Contributor Author

@swift-ci please test Windows platform

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

Thanks! Just a couple of minor comments, and then this should be good to go.

@@ -147,7 +147,7 @@ public enum _DebuggerSupport {
return value.map(String.init(reflecting:))
case .collection?, .dictionary?, .set?, .tuple?:
return count == 1 ? "1 element" : "\(count) elements"
case .`struct`?, .`enum`?, nil:
case .`struct`?, .`enum`?, .foreign?, nil:
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed that we should ideally print an address, also agreed that it doesn't have to be in this PR 😉

@@ -313,6 +313,7 @@ extension Mirror {
public enum DisplayStyle: Sendable {
case `struct`, `class`, `enum`, tuple, optional, collection
case dictionary, `set`
@available(SwiftStdlib 6.2, *) case foreign
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 we should call this foreignReference to make it clear that this is about foreign reference types specifically. IRGen uses the term "foreign" to refer to C structs that are imported as value types, and here this means something different.

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 see, thanks!

@@ -481,6 +482,7 @@ public struct Mirror {
public enum DisplayStyle: Sendable {
case `struct`, `class`, `enum`, tuple, optional, collection
case dictionary, `set`
@available(SwiftStdlib 6.2, *) case foreign
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto

@susmonteiro
Copy link
Contributor Author

susmonteiro commented Jun 9, 2025

Agreed that we should ideally print an address, also agreed that it doesn't have to be in this PR 😉

As this isn't a trivial change, I think we could do it in another PR 🙂

@susmonteiro susmonteiro force-pushed the susmonteiro/class-metadata-private-fields branch from 3ec1479 to 9975ac8 Compare June 9, 2025 15:10
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro force-pushed the susmonteiro/class-metadata-private-fields branch from 9975ac8 to 848fad0 Compare June 10, 2025 11:15
@susmonteiro
Copy link
Contributor Author

@swift-ci please smoke test

@susmonteiro susmonteiro merged commit 6164af2 into main Jun 11, 2025
3 checks passed
@susmonteiro susmonteiro deleted the susmonteiro/class-metadata-private-fields branch June 11, 2025 10:58
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.

3 participants