Skip to content

Commit 68fb206

Browse files
committed
[cxx-interop] Support from printing C++ foreign references
1 parent d00a3b5 commit 68fb206

File tree

13 files changed

+236
-4
lines changed

13 files changed

+236
-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
@@ -147,7 +147,7 @@ public enum _DebuggerSupport {
147147
return value.map(String.init(reflecting:))
148148
case .collection?, .dictionary?, .set?, .tuple?:
149149
return count == 1 ? "1 element" : "\(count) elements"
150-
case .`struct`?, .`enum`?, nil:
150+
case .`struct`?, .`enum`?, .foreign?, nil:
151151
switch value {
152152
case let x as CustomDebugStringConvertible:
153153
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 foreign
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 foreign
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 .foreign:
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`, .foreign:
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 = .foreign
178+
} else {
179+
self.displayStyle = nil
180+
}
175181
case "\0": self.displayStyle = nil
176182
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
177183
}

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/print-simple-structs.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,28 @@ func printCxxStructNested() {
2424
print(s)
2525
}
2626

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

@@ -35,3 +57,12 @@ printCxxStructPrivatePublicProtectedFields()
3557

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

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+
// rdar://124164228: 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+
// rdar://124164228: printing foreign reference types requires a new displayStyle: .foreign
1090+
Added: _$ss6MirrorV12DisplayStyleO7foreignyA2DmFWC

0 commit comments

Comments
 (0)