diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h index 765121a7b5ade..ff55aa8161f03 100644 --- a/lib/IRGen/ClassMetadataVisitor.h +++ b/lib/IRGen/ClassMetadataVisitor.h @@ -210,7 +210,8 @@ template class ClassMetadataVisitor // 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); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 834d67209d810..52c0482521ad9 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -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()); diff --git a/stdlib/public/core/DebuggerSupport.swift b/stdlib/public/core/DebuggerSupport.swift index 62a3fd5723675..93efe80075c8b 100644 --- a/stdlib/public/core/DebuggerSupport.swift +++ b/stdlib/public/core/DebuggerSupport.swift @@ -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 diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift index 5d94615ac7463..960652c6546b1 100644 --- a/stdlib/public/core/Mirror.swift +++ b/stdlib/public/core/Mirror.swift @@ -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: Subject, diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 9a2d4e1f00e79..448d5989a2c42 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -381,6 +381,10 @@ internal func _adHocPrint_unlocked( 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( 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)) diff --git a/stdlib/public/core/ReflectionMirror.swift b/stdlib/public/core/ReflectionMirror.swift index b4639050f61bf..73fa13048c0d9 100644 --- a/stdlib/public/core/ReflectionMirror.swift +++ b/stdlib/public/core/ReflectionMirror.swift @@ -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)'") } diff --git a/test/Interop/Cxx/class/Inputs/mirror.h b/test/Interop/Cxx/class/Inputs/mirror.h new file mode 100644 index 0000000000000..8d12ee09c8f5d --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/mirror.h @@ -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 diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index 46b4c801295b3..ab8bb3e04e78c 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -158,3 +158,9 @@ module SimpleStructs { requires cplusplus export * } + +module Mirror { + header "mirror.h" + requires cplusplus + export * +} diff --git a/test/Interop/Cxx/class/Inputs/simple-structs.h b/test/Interop/Cxx/class/Inputs/simple-structs.h index cdda0654dbb5f..b8a6a4f4d034f 100644 --- a/test/Interop/Cxx/class/Inputs/simple-structs.h +++ b/test/Interop/Cxx/class/Inputs/simple-structs.h @@ -52,4 +52,38 @@ struct Outer { 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 diff --git a/test/Interop/Cxx/class/mirror.swift b/test/Interop/Cxx/class/mirror.swift new file mode 100644 index 0000000000000..8b004a3946a4c --- /dev/null +++ b/test/Interop/Cxx/class/mirror.swift @@ -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() diff --git a/test/Interop/Cxx/class/print-simple-structs.swift b/test/Interop/Cxx/class/print-simple-structs.swift index 449177e0311ec..3bd7cef362440 100644 --- a/test/Interop/Cxx/class/print-simple-structs.swift +++ b/test/Interop/Cxx/class/print-simple-structs.swift @@ -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() diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index 9849f6933a921..1d6fffbc45e6e 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -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 diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index ad72435b1c73c..df564b00c92d6 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -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