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

This commit is contained in:
susmonteiro
2025-06-10 12:15:21 +01:00
parent d00a3b5764
commit 848fad0021
13 changed files with 242 additions and 4 deletions

View File

@@ -210,7 +210,8 @@ private:
// whether they need them or not.
asImpl().noteStartOfFieldOffsets(theClass);
forEachField(IGM, theClass, [&](Field field) {
asImpl().addFieldEntries(field);
if (isExportableField(field))
asImpl().addFieldEntries(field);
});
asImpl().noteEndOfFieldOffsets(theClass);

View File

@@ -2415,7 +2415,7 @@ namespace {
B.addInt32(numImmediateMembers);
// uint32_t NumFields;
B.addInt32(getNumFields(getType()));
B.addInt32(countExportableFields(IGM, getType()));
// uint32_t FieldOffsetVectorOffset;
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());

View File

@@ -158,7 +158,7 @@ public enum _DebuggerSupport {
default:
return value.map(String.init(reflecting:))
}
case .`class`?:
case .`class`?, .foreignReference?:
switch value {
case let x as CustomDebugStringConvertible:
return x.debugDescription

View File

@@ -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 foreignReference
}
internal static func _noSuperclassMirror() -> Mirror? { return nil }
@@ -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 foreignReference
}
public init<Subject, C: Collection>(
_ subject: Subject,

View File

@@ -381,6 +381,10 @@ internal func _adHocPrint_unlocked<T, TargetStream: TextOutputStream>(
target.write(")")
}
}
case .foreignReference:
printTypeName(mirror.subjectType)
// FRT has no children
target.write("()")
default:
target.write(_typeName(mirror.subjectType))
}
@@ -526,7 +530,7 @@ internal func _dumpPrint_unlocked<T, TargetStream: TextOutputStream>(
if let displayStyle = mirror.displayStyle {
switch displayStyle {
case .`class`, .`struct`:
case .`class`, .`struct`, .foreignReference:
// Classes and structs without custom representations are displayed as
// their fully qualified type name
target.write(_typeName(mirror.subjectType, qualified: true))

View File

@@ -172,6 +172,12 @@ extension Mirror {
case "e": self.displayStyle = .enum
case "s": self.displayStyle = .struct
case "t": self.displayStyle = .tuple
case "f":
if #available(SwiftStdlib 6.2, *) {
self.displayStyle = .foreignReference
} else {
self.displayStyle = nil
}
case "\0": self.displayStyle = nil
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
}

View File

@@ -0,0 +1,49 @@
#ifndef TEST_INTEROP_CXX_METADATA_INPUTS_MIRROR_H
#define TEST_INTEROP_CXX_METADATA_INPUTS_MIRROR_H
struct EmptyStruct {};
struct BaseStruct {
private:
int priv;
public:
int publ;
protected:
int prot;
public:
BaseStruct(int i1, int i2, int i3) : priv(i1), publ(i2), prot(i3) {}
};
class EmptyClass {};
struct OuterStruct {
private:
BaseStruct privStruct;
public:
BaseStruct publStruct;
OuterStruct() : privStruct(1, 2, 3), publStruct(4, 5, 6) {}
};
struct FRTStruct {
private:
int priv = 1;
public:
int publ = 2;
} __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:retain")))
__attribute__((swift_attr("release:release")));
void retain(FRTStruct *v) {};
void release(FRTStruct *v) {};
class FRTImmortalClass {} __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")));
#endif

View File

@@ -158,3 +158,9 @@ module SimpleStructs {
requires cplusplus
export *
}
module Mirror {
header "mirror.h"
requires cplusplus
export *
}

View File

@@ -52,4 +52,38 @@ public:
Outer() : privStruct(1, 2, 3, 4, 5, 6), publStruct(7, 8, 9, 10, 11, 12) {}
};
struct ImmortalFRT {
private:
int priv = 1;
public:
int publ = 2;
} __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")));
struct FRTCustomStringConvertible {
public:
private:
int priv = 1;
public:
int publ = 2;
} __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:immortal")))
__attribute__((swift_attr("release:immortal")));
struct FRType {
private:
int priv = 1;
public:
int publ = 2;
} __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:retain")))
__attribute__((swift_attr("release:release")));
void retain(FRType *v) {};
void release(FRType *v) {};
#endif

View File

@@ -0,0 +1,97 @@
// RUN: %target-run-simple-swift(-cxx-interoperability-mode=default -I %S/Inputs)
// REQUIRES: executable_test
// Metadata for foreign reference types is not supported on Windows.
// UNSUPPORTED: OS=windows-msvc
import StdlibUnittest
import Mirror
var MirrorTestSuite = TestSuite("Mirrors")
MirrorTestSuite.test("EmptyCxxStruct") {
let s = EmptyStruct()
let m = Mirror(reflecting: s)
expectEqual(.`struct`, m.displayStyle)
expectTrue(m.subjectType == EmptyStruct.self)
expectEqual(0, m.children.count)
var output = ""
dump(s, to: &output)
expectEqual("- __C.EmptyStruct\n", output)
}
MirrorTestSuite.test("EmptyCxxClass") {
let s = EmptyClass()
let m = Mirror(reflecting: s)
expectEqual(.`struct`, m.displayStyle)
expectTrue(m.subjectType == EmptyClass.self)
expectEqual(0, m.children.count)
var output = ""
dump(s, to: &output)
expectEqual("- __C.EmptyClass\n", output)
}
MirrorTestSuite.test("CxxStructWithFields") {
let s = BaseStruct(1, 2, 3)
let m = Mirror(reflecting: s)
expectEqual(.`struct`, m.displayStyle)
expectTrue(m.subjectType == BaseStruct.self)
expectEqual(1, m.children.count)
expectEqual("publ", m.children.first!.label)
expectEqual(2, m.children.first!.value as? Int32)
var output = ""
dump(s, to: &output)
let expected =
"▿ __C.BaseStruct\n" +
" - publ: 2\n"
expectEqual(expected, output)
}
MirrorTestSuite.test("CxxStructWithStructsAsFields") {
let s = OuterStruct()
let m = Mirror(reflecting: s)
expectEqual(.`struct`, m.displayStyle)
expectTrue(m.subjectType == OuterStruct.self)
expectEqual(1, m.children.count)
expectEqual("publStruct", m.children.first!.label)
var output = ""
dump(s, to: &output)
let expected =
"▿ __C.OuterStruct\n" +
" ▿ publStruct: __C.BaseStruct\n" +
" - publ: 5\n"
expectEqual(expected, output)
}
if #available(SwiftStdlib 6.2, *) {
MirrorTestSuite.test("CxxFRTStruct") {
let s = FRTStruct()
let m = Mirror(reflecting: s)
expectEqual(.foreignReference, m.displayStyle)
expectTrue(m.subjectType == FRTStruct.self)
expectEqual(0, m.children.count)
var output = ""
dump(s, to: &output)
expectEqual("- __C.FRTStruct\n", output)
}
MirrorTestSuite.test("CxxFRTImmortalClass") {
let s = FRTImmortalClass()
let m = Mirror(reflecting: s)
expectEqual(.foreignReference, m.displayStyle)
expectTrue(m.subjectType == FRTImmortalClass.self)
expectEqual(0, m.children.count)
var output = ""
dump(s, to: &output)
expectEqual("- __C.FRTImmortalClass\n", output)
}
}
runAllTests()

View File

@@ -1,6 +1,8 @@
// RUN: %target-run-simple-swift(-cxx-interoperability-mode=default -Xfrontend -disable-availability-checking -I %S/Inputs) | %FileCheck %s
// REQUIRES: executable_test
// Metadata for foreign reference types is not supported on Windows.
// UNSUPPORTED: OS=windows-msvc
import SimpleStructs
@@ -24,6 +26,28 @@ func printCxxStructNested() {
print(s)
}
func printCxxImmortalFRT() {
let s = ImmortalFRT()
print(s)
}
extension FRTCustomStringConvertible : CustomStringConvertible {
public var description: String {
return "FRTCustomStringConvertible(publ: \(publ))"
}
}
func printCxxFRTCustomStringConvertible() {
let s = FRTCustomStringConvertible()
print(s)
}
func printCxxFRType() {
let s = FRType()
print(s)
}
printCxxStructPrivateFields()
// CHECK: HasPrivateFieldsOnly()
@@ -35,3 +59,12 @@ printCxxStructPrivatePublicProtectedFields()
printCxxStructNested()
// CHECK: Outer(publStruct: {{.*}}.HasPrivatePublicProtectedFields(publ1: 8, publ2: 12))
printCxxImmortalFRT()
// CHECK: ImmortalFRT()
printCxxFRTCustomStringConvertible()
// CHECK: FRTCustomStringConvertible(publ: 2)
printCxxFRType()
// CHECK: FRType()

View File

@@ -1085,3 +1085,6 @@ Added: _$ss8UTF8SpanV10_countMasks6UInt64VvpZMV
Added: _$ss8UTF8SpanV10_flagsMasks6UInt64VvpZMV
Added: _$ss8UTF8SpanV7_nfcBits6UInt64VvpZMV
Added: _$ss8UTF8SpanV9_asciiBits6UInt64VvpZMV
// printing foreign reference types requires a new displayStyle: .foreign
Added: _$ss6MirrorV12DisplayStyleO16foreignReferenceyA2DmFWC

View File

@@ -1085,3 +1085,6 @@ Added: _$ss8UTF8SpanV10_countMasks6UInt64VvpZMV
Added: _$ss8UTF8SpanV10_flagsMasks6UInt64VvpZMV
Added: _$ss8UTF8SpanV7_nfcBits6UInt64VvpZMV
Added: _$ss8UTF8SpanV9_asciiBits6UInt64VvpZMV
// printing foreign reference types requires a new displayStyle: .foreign
Added: _$ss6MirrorV12DisplayStyleO16foreignReferenceyA2DmFWC