Skip to content

Commit 9975ac8

Browse files
committed
[cxx-interop] Support for printing C++ foreign references
1 parent d00a3b5 commit 9975ac8

File tree

13 files changed

+242
-4
lines changed

13 files changed

+242
-4
lines changed

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ template <class Impl> class ClassMetadataVisitor
210210
// whether they need them or not.
211211
asImpl().noteStartOfFieldOffsets(theClass);
212212
forEachField(IGM, theClass, [&](Field field) {
213-
asImpl().addFieldEntries(field);
213+
if (isExportableField(field))
214+
asImpl().addFieldEntries(field);
214215
});
215216
asImpl().noteEndOfFieldOffsets(theClass);
216217

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2415,7 +2415,7 @@ namespace {
24152415
B.addInt32(numImmediateMembers);
24162416

24172417
// uint32_t NumFields;
2418-
B.addInt32(getNumFields(getType()));
2418+
B.addInt32(countExportableFields(IGM, getType()));
24192419

24202420
// uint32_t FieldOffsetVectorOffset;
24212421
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());

stdlib/public/core/DebuggerSupport.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public enum _DebuggerSupport {
158158
default:
159159
return value.map(String.init(reflecting:))
160160
}
161-
case .`class`?:
161+
case .`class`?, .foreignReference?:
162162
switch value {
163163
case let x as CustomDebugStringConvertible:
164164
return x.debugDescription

stdlib/public/core/Mirror.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ extension Mirror {
313313
public enum DisplayStyle: Sendable {
314314
case `struct`, `class`, `enum`, tuple, optional, collection
315315
case dictionary, `set`
316+
@available(SwiftStdlib 6.2, *) case foreignReference
316317
}
317318

318319
internal static func _noSuperclassMirror() -> Mirror? { return nil }
@@ -481,6 +482,7 @@ public struct Mirror {
481482
public enum DisplayStyle: Sendable {
482483
case `struct`, `class`, `enum`, tuple, optional, collection
483484
case dictionary, `set`
485+
@available(SwiftStdlib 6.2, *) case foreignReference
484486
}
485487
public init<Subject, C: Collection>(
486488
_ subject: Subject,

stdlib/public/core/OutputStream.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ internal func _adHocPrint_unlocked<T, TargetStream: TextOutputStream>(
381381
target.write(")")
382382
}
383383
}
384+
case .foreignReference:
385+
printTypeName(mirror.subjectType)
386+
// FRT has no children
387+
target.write("()")
384388
default:
385389
target.write(_typeName(mirror.subjectType))
386390
}
@@ -526,7 +530,7 @@ internal func _dumpPrint_unlocked<T, TargetStream: TextOutputStream>(
526530

527531
if let displayStyle = mirror.displayStyle {
528532
switch displayStyle {
529-
case .`class`, .`struct`:
533+
case .`class`, .`struct`, .foreignReference:
530534
// Classes and structs without custom representations are displayed as
531535
// their fully qualified type name
532536
target.write(_typeName(mirror.subjectType, qualified: true))

stdlib/public/core/ReflectionMirror.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ extension Mirror {
172172
case "e": self.displayStyle = .enum
173173
case "s": self.displayStyle = .struct
174174
case "t": self.displayStyle = .tuple
175+
case "f":
176+
if #available(SwiftStdlib 6.2, *) {
177+
self.displayStyle = .foreignReference
178+
} else {
179+
self.displayStyle = nil
180+
}
175181
case "\0": self.displayStyle = nil
176182
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
177183
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef TEST_INTEROP_CXX_METADATA_INPUTS_MIRROR_H
2+
#define TEST_INTEROP_CXX_METADATA_INPUTS_MIRROR_H
3+
4+
struct EmptyStruct {};
5+
6+
struct BaseStruct {
7+
private:
8+
int priv;
9+
10+
public:
11+
int publ;
12+
13+
protected:
14+
int prot;
15+
16+
public:
17+
BaseStruct(int i1, int i2, int i3) : priv(i1), publ(i2), prot(i3) {}
18+
};
19+
20+
class EmptyClass {};
21+
22+
struct OuterStruct {
23+
private:
24+
BaseStruct privStruct;
25+
26+
public:
27+
BaseStruct publStruct;
28+
29+
OuterStruct() : privStruct(1, 2, 3), publStruct(4, 5, 6) {}
30+
};
31+
32+
struct FRTStruct {
33+
private:
34+
int priv = 1;
35+
36+
public:
37+
int publ = 2;
38+
} __attribute__((swift_attr("import_reference")))
39+
__attribute__((swift_attr("retain:retain")))
40+
__attribute__((swift_attr("release:release")));
41+
42+
void retain(FRTStruct *v) {};
43+
void release(FRTStruct *v) {};
44+
45+
class FRTImmortalClass {} __attribute__((swift_attr("import_reference")))
46+
__attribute__((swift_attr("retain:immortal")))
47+
__attribute__((swift_attr("release:immortal")));
48+
49+
#endif

test/Interop/Cxx/class/Inputs/module.modulemap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,9 @@ module SimpleStructs {
158158
requires cplusplus
159159
export *
160160
}
161+
162+
module Mirror {
163+
header "mirror.h"
164+
requires cplusplus
165+
export *
166+
}

test/Interop/Cxx/class/Inputs/simple-structs.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,38 @@ struct Outer {
5252
Outer() : privStruct(1, 2, 3, 4, 5, 6), publStruct(7, 8, 9, 10, 11, 12) {}
5353
};
5454

55+
struct ImmortalFRT {
56+
private:
57+
int priv = 1;
58+
59+
public:
60+
int publ = 2;
61+
} __attribute__((swift_attr("import_reference")))
62+
__attribute__((swift_attr("retain:immortal")))
63+
__attribute__((swift_attr("release:immortal")));
64+
65+
struct FRTCustomStringConvertible {
66+
public:
67+
private:
68+
int priv = 1;
69+
70+
public:
71+
int publ = 2;
72+
} __attribute__((swift_attr("import_reference")))
73+
__attribute__((swift_attr("retain:immortal")))
74+
__attribute__((swift_attr("release:immortal")));
75+
76+
struct FRType {
77+
private:
78+
int priv = 1;
79+
80+
public:
81+
int publ = 2;
82+
} __attribute__((swift_attr("import_reference")))
83+
__attribute__((swift_attr("retain:retain")))
84+
__attribute__((swift_attr("release:release")));
85+
86+
void retain(FRType *v) {};
87+
void release(FRType *v) {};
88+
5589
#endif

test/Interop/Cxx/class/mirror.swift

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// RUN: %target-run-simple-swift(-cxx-interoperability-mode=default -I %S/Inputs)
2+
3+
// REQUIRES: executable_test
4+
// Metadata for foreign reference types is not supported on Windows.
5+
// UNSUPPORTED: OS=windows-msvc
6+
7+
import StdlibUnittest
8+
import Mirror
9+
10+
var MirrorTestSuite = TestSuite("Mirrors")
11+
12+
MirrorTestSuite.test("EmptyCxxStruct") {
13+
let s = EmptyStruct()
14+
let m = Mirror(reflecting: s)
15+
expectEqual(.`struct`, m.displayStyle)
16+
expectTrue(m.subjectType == EmptyStruct.self)
17+
expectEqual(0, m.children.count)
18+
19+
var output = ""
20+
dump(s, to: &output)
21+
expectEqual("- __C.EmptyStruct\n", output)
22+
}
23+
24+
MirrorTestSuite.test("EmptyCxxClass") {
25+
let s = EmptyClass()
26+
let m = Mirror(reflecting: s)
27+
expectEqual(.`struct`, m.displayStyle)
28+
expectTrue(m.subjectType == EmptyClass.self)
29+
expectEqual(0, m.children.count)
30+
31+
var output = ""
32+
dump(s, to: &output)
33+
expectEqual("- __C.EmptyClass\n", output)
34+
}
35+
36+
MirrorTestSuite.test("CxxStructWithFields") {
37+
let s = BaseStruct(1, 2, 3)
38+
let m = Mirror(reflecting: s)
39+
expectEqual(.`struct`, m.displayStyle)
40+
expectTrue(m.subjectType == BaseStruct.self)
41+
expectEqual(1, m.children.count)
42+
43+
expectEqual("publ", m.children.first!.label)
44+
expectEqual(2, m.children.first!.value as? Int32)
45+
46+
var output = ""
47+
dump(s, to: &output)
48+
let expected =
49+
"▿ __C.BaseStruct\n" +
50+
" - publ: 2\n"
51+
expectEqual(expected, output)
52+
}
53+
54+
MirrorTestSuite.test("CxxStructWithStructsAsFields") {
55+
let s = OuterStruct()
56+
let m = Mirror(reflecting: s)
57+
expectEqual(.`struct`, m.displayStyle)
58+
expectTrue(m.subjectType == OuterStruct.self)
59+
expectEqual(1, m.children.count)
60+
expectEqual("publStruct", m.children.first!.label)
61+
62+
var output = ""
63+
dump(s, to: &output)
64+
let expected =
65+
"▿ __C.OuterStruct\n" +
66+
" ▿ publStruct: __C.BaseStruct\n" +
67+
" - publ: 5\n"
68+
expectEqual(expected, output)
69+
}
70+
71+
if #available(SwiftStdlib 6.2, *) {
72+
MirrorTestSuite.test("CxxFRTStruct") {
73+
let s = FRTStruct()
74+
let m = Mirror(reflecting: s)
75+
expectEqual(.foreignReference, m.displayStyle)
76+
expectTrue(m.subjectType == FRTStruct.self)
77+
expectEqual(0, m.children.count)
78+
79+
var output = ""
80+
dump(s, to: &output)
81+
expectEqual("- __C.FRTStruct\n", output)
82+
}
83+
84+
MirrorTestSuite.test("CxxFRTImmortalClass") {
85+
let s = FRTImmortalClass()
86+
let m = Mirror(reflecting: s)
87+
expectEqual(.foreignReference, m.displayStyle)
88+
expectTrue(m.subjectType == FRTImmortalClass.self)
89+
expectEqual(0, m.children.count)
90+
91+
var output = ""
92+
dump(s, to: &output)
93+
expectEqual("- __C.FRTImmortalClass\n", output)
94+
}
95+
}
96+
97+
runAllTests()

test/Interop/Cxx/class/print-simple-structs.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// RUN: %target-run-simple-swift(-cxx-interoperability-mode=default -Xfrontend -disable-availability-checking -I %S/Inputs) | %FileCheck %s
22

33
// REQUIRES: executable_test
4+
// Metadata for foreign reference types is not supported on Windows.
5+
// UNSUPPORTED: OS=windows-msvc
46

57
import SimpleStructs
68

@@ -24,6 +26,28 @@ func printCxxStructNested() {
2426
print(s)
2527
}
2628

29+
func printCxxImmortalFRT() {
30+
let s = ImmortalFRT()
31+
print(s)
32+
}
33+
34+
extension FRTCustomStringConvertible : CustomStringConvertible {
35+
public var description: String {
36+
return "FRTCustomStringConvertible(publ: \(publ))"
37+
}
38+
}
39+
40+
func printCxxFRTCustomStringConvertible() {
41+
let s = FRTCustomStringConvertible()
42+
print(s)
43+
}
44+
45+
func printCxxFRType() {
46+
let s = FRType()
47+
print(s)
48+
}
49+
50+
2751
printCxxStructPrivateFields()
2852
// CHECK: HasPrivateFieldsOnly()
2953

@@ -35,3 +59,12 @@ printCxxStructPrivatePublicProtectedFields()
3559

3660
printCxxStructNested()
3761
// CHECK: Outer(publStruct: {{.*}}.HasPrivatePublicProtectedFields(publ1: 8, publ2: 12))
62+
63+
printCxxImmortalFRT()
64+
// CHECK: ImmortalFRT()
65+
66+
printCxxFRTCustomStringConvertible()
67+
// CHECK: FRTCustomStringConvertible(publ: 2)
68+
69+
printCxxFRType()
70+
// CHECK: FRType()

test/abi/macOS/arm64/stdlib.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,3 +1085,6 @@ Added: _$ss8UTF8SpanV10_countMasks6UInt64VvpZMV
10851085
Added: _$ss8UTF8SpanV10_flagsMasks6UInt64VvpZMV
10861086
Added: _$ss8UTF8SpanV7_nfcBits6UInt64VvpZMV
10871087
Added: _$ss8UTF8SpanV9_asciiBits6UInt64VvpZMV
1088+
1089+
// printing foreign reference types requires a new displayStyle: .foreign
1090+
Added: _$ss6MirrorV12DisplayStyleO7foreignyA2DmFWC

test/abi/macOS/x86_64/stdlib.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,3 +1085,6 @@ Added: _$ss8UTF8SpanV10_countMasks6UInt64VvpZMV
10851085
Added: _$ss8UTF8SpanV10_flagsMasks6UInt64VvpZMV
10861086
Added: _$ss8UTF8SpanV7_nfcBits6UInt64VvpZMV
10871087
Added: _$ss8UTF8SpanV9_asciiBits6UInt64VvpZMV
1088+
1089+
// printing foreign reference types requires a new displayStyle: .foreign
1090+
Added: _$ss6MirrorV12DisplayStyleO7foreignyA2DmFWC

0 commit comments

Comments
 (0)