Skip to content

Commit a159636

Browse files
authored
Merge pull request #60666 from hyp/eng/circular-structs
[interop][SwiftToCxx] fix the circular depedency issue for struct emi…
2 parents 390d8cc + 489c16e commit a159636

14 files changed

+315
-254
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ class DeclAndTypePrinter::Implementation
114114

115115
SmallVector<const FunctionType *, 4> openFunctionTypes;
116116

117-
std::string outOfLineDefinitions;
118-
119117
ASTContext &getASTContext() const {
120118
return owningPrinter.M.getASTContext();
121119
}
@@ -218,7 +216,6 @@ class DeclAndTypePrinter::Implementation
218216
template <bool AllowDelayed = false, typename R>
219217
void printMembers(R &&members) {
220218
bool protocolMembersOptional = false;
221-
assert(outOfLineDefinitions.empty());
222219
for (const Decl *member : members) {
223220
auto VD = dyn_cast<ValueDecl>(member);
224221
if (!VD || !shouldInclude(VD) || isa<TypeDecl>(VD))
@@ -302,8 +299,6 @@ class DeclAndTypePrinter::Implementation
302299
// FIXME: Print availability.
303300
ClangClassTypePrinter(os).printClassTypeDecl(
304301
CD, [&]() { printMembers(CD->getMembers()); });
305-
os << outOfLineDefinitions;
306-
outOfLineDefinitions.clear();
307302
return;
308303
}
309304

@@ -356,8 +351,6 @@ class DeclAndTypePrinter::Implementation
356351
owningPrinter.interopContext);
357352
printer.printValueTypeDecl(
358353
SD, /*bodyPrinter=*/[&]() { printMembers(SD->getMembers()); });
359-
os << outOfLineDefinitions;
360-
outOfLineDefinitions.clear();
361354
}
362355

363356
void visitExtensionDecl(ExtensionDecl *ED) {
@@ -580,8 +573,6 @@ class DeclAndTypePrinter::Implementation
580573
os << " }\n"; // operator cases()'s closing bracket
581574
os << "\n";
582575
});
583-
os << outOfLineDefinitions;
584-
outOfLineDefinitions.clear();
585576
}
586577

587578
void visitEnumDecl(EnumDecl *ED) {
@@ -767,10 +758,9 @@ class DeclAndTypePrinter::Implementation
767758
/*isDefinition=*/false);
768759
}
769760

770-
llvm::raw_string_ostream defOS(outOfLineDefinitions);
771761
DeclAndTypeClangFunctionPrinter defPrinter(
772-
defOS, owningPrinter.prologueOS, owningPrinter.typeMapping,
773-
owningPrinter.interopContext);
762+
owningPrinter.outOfLineDefinitionsOS, owningPrinter.prologueOS,
763+
owningPrinter.typeMapping, owningPrinter.interopContext);
774764

775765
if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
776766

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class DeclAndTypePrinter {
4242
ModuleDecl &M;
4343
raw_ostream &os;
4444
raw_ostream &prologueOS;
45+
raw_ostream &outOfLineDefinitionsOS;
4546
const DelayedMemberSet &delayedMembers;
4647
PrimitiveTypeMapping &typeMapping;
4748
SwiftToClangInteropContext &interopContext;
@@ -57,11 +58,13 @@ class DeclAndTypePrinter {
5758

5859
public:
5960
DeclAndTypePrinter(ModuleDecl &mod, raw_ostream &out, raw_ostream &prologueOS,
61+
raw_ostream &outOfLineDefinitionsOS,
6062
DelayedMemberSet &delayed,
6163
PrimitiveTypeMapping &typeMapping,
6264
SwiftToClangInteropContext &interopContext,
6365
AccessLevel access, OutputLanguageMode outputLang)
64-
: M(mod), os(out), prologueOS(prologueOS), delayedMembers(delayed),
66+
: M(mod), os(out), prologueOS(prologueOS),
67+
outOfLineDefinitionsOS(outOfLineDefinitionsOS), delayedMembers(delayed),
6568
typeMapping(typeMapping), interopContext(interopContext),
6669
minRequiredAccess(access), outputLang(outputLang) {}
6770

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "DeclAndTypePrinter.h"
1717
#include "OutputLanguageMode.h"
1818
#include "PrimitiveTypeMapping.h"
19+
#include "PrintClangValueType.h"
1920
#include "PrintSwiftToClangCoreScaffold.h"
2021

2122
#include "swift/AST/ExistentialLayout.h"
@@ -126,6 +127,8 @@ class ModuleWriter {
126127
std::vector<const Decl *> declsToWrite;
127128
DelayedMemberSet delayedMembers;
128129
PrimitiveTypeMapping typeMapping;
130+
std::string outOfLineDefinitions;
131+
llvm::raw_string_ostream outOfLineDefinitionsOS;
129132
DeclAndTypePrinter printer;
130133
OutputLanguageMode outputLangMode;
131134

@@ -135,8 +138,9 @@ class ModuleWriter {
135138
SwiftToClangInteropContext &interopContext, AccessLevel access,
136139
OutputLanguageMode outputLang)
137140
: os(os), imports(imports), M(mod),
138-
printer(M, os, prologueOS, delayedMembers, typeMapping, interopContext,
139-
access, outputLang),
141+
outOfLineDefinitionsOS(outOfLineDefinitions),
142+
printer(M, os, prologueOS, outOfLineDefinitionsOS, delayedMembers,
143+
typeMapping, interopContext, access, outputLang),
140144
outputLangMode(outputLang) {}
141145

142146
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
@@ -238,14 +242,8 @@ class ModuleWriter {
238242
os << "@protocol " << getNameForObjC(PD) << ";\n";
239243
});
240244
}
241-
242-
void forwardDeclare(const EnumDecl *ED) {
243-
// TODO: skip for now; will overhaul the forward decals for c++ in the
244-
// future
245-
if (outputLangMode == swift::OutputLanguageMode::Cxx) {
246-
return;
247-
}
248245

246+
void forwardDeclare(const EnumDecl *ED) {
249247
assert(ED->isObjC() || ED->hasClangNode());
250248

251249
forwardDeclare(ED, [&]{
@@ -256,6 +254,14 @@ class ModuleWriter {
256254
}
257255

258256
void forwardDeclareType(const TypeDecl *TD) {
257+
if (outputLangMode == OutputLanguageMode::Cxx) {
258+
if (isa<StructDecl>(TD) || isa<EnumDecl>(TD)) {
259+
auto *NTD = cast<NominalTypeDecl>(TD);
260+
forwardDeclare(
261+
NTD, [&]() { ClangValueTypePrinter::forwardDeclType(os, NTD); });
262+
}
263+
return;
264+
}
259265
if (auto CD = dyn_cast<ClassDecl>(TD)) {
260266
if (!forwardDeclare(CD)) {
261267
(void)addImport(CD);
@@ -274,9 +280,6 @@ class ModuleWriter {
274280
forwardDeclare(ED);
275281
} else if (isa<AbstractTypeParamDecl>(TD)) {
276282
llvm_unreachable("should not see type params here");
277-
} else if (isa<StructDecl>(TD)) {
278-
// FIXME: add support here.
279-
return;
280283
} else {
281284
assert(false && "unknown local type decl");
282285
}
@@ -290,6 +293,11 @@ class ModuleWriter {
290293
case DeclKind::Protocol:
291294
case DeclKind::Extension:
292295
break;
296+
case DeclKind::Struct:
297+
case DeclKind::Enum:
298+
if (outputLangMode == OutputLanguageMode::Cxx)
299+
break;
300+
LLVM_FALLTHROUGH;
293301
default:
294302
llvm_unreachable("unexpected container kind");
295303
}
@@ -346,11 +354,12 @@ class ModuleWriter {
346354
}
347355

348356
// Protocols should be delayed wholesale unless we might have a cycle.
349-
auto *proto = cast<ProtocolDecl>(container);
350-
if (!hasBeenRequested(proto) || !hasBeenRequested(TD)) {
351-
if (!require(TD))
352-
hadAnyDelayedMembers = true;
353-
return;
357+
if (auto *proto = dyn_cast<ProtocolDecl>(container)) {
358+
if (!hasBeenRequested(proto) || !hasBeenRequested(TD)) {
359+
if (!require(TD))
360+
hadAnyDelayedMembers = true;
361+
return;
362+
}
354363
}
355364

356365
// Otherwise, we have a cyclic dependency. Give up and continue with
@@ -426,6 +435,8 @@ class ModuleWriter {
426435
bool writeStruct(const StructDecl *SD) {
427436
if (addImport(SD))
428437
return true;
438+
if (outputLangMode == OutputLanguageMode::Cxx)
439+
(void)forwardDeclareMemberTypes(SD->getMembers(), SD);
429440
printer.print(SD);
430441
return true;
431442
}
@@ -646,6 +657,8 @@ class ModuleWriter {
646657
}
647658
printer.printAdHocCategory(make_range(groupBegin, delayedMembers.end()));
648659
}
660+
// Print any out of line definitions.
661+
os << outOfLineDefinitionsOS.str();
649662
}
650663
};
651664
} // end anonymous namespace

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
8080
os << "};\n\n";
8181
}
8282

83+
void ClangValueTypePrinter::forwardDeclType(raw_ostream &os,
84+
const NominalTypeDecl *typeDecl) {
85+
os << "class ";
86+
ClangSyntaxPrinter(os).printBaseName(typeDecl);
87+
os << ";\n";
88+
}
89+
8390
void ClangValueTypePrinter::printValueTypeDecl(
8491
const NominalTypeDecl *typeDecl,
8592
llvm::function_ref<void(void)> bodyPrinter) {

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class ClangValueTypePrinter {
9898
const NominalTypeDecl *typeDecl,
9999
StringRef typeMetadataFuncName);
100100

101+
static void forwardDeclType(raw_ostream &os, const NominalTypeDecl *typeDecl);
102+
101103
private:
102104
/// Prints out the C stub name used to pass/return value directly for the
103105
/// given value type.

test/Interop/SwiftToCxx/cross-module-refs/imported-enum-refs-in-cxx.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ public struct UsesEnumsLargeEnum {
2121
public let x: LargeEnum
2222
}
2323

24+
public func inoutLargeEnum(_ s: inout LargeEnum) {
25+
return s = LargeEnum.B
26+
}
27+
28+
// CHECK: inline void inoutLargeEnum(Enums::LargeEnum& s) noexcept {
29+
// CHECK-NEXT: return _impl::$s9UsesEnums14inoutLargeEnumyy0B00dE0OzF(Enums::_impl::_impl_LargeEnum::getOpaquePointer(s));
30+
// CHECK-NEXT: }
31+
2432
// CHECK: inline Enums::LargeEnum UsesEnumsLargeEnum::passThroughStructSeveralI64(const Enums::LargeEnum& y) const {
2533
// CHECK-NEXT: return Enums::_impl::_impl_LargeEnum::returnNewValue([&](void * _Nonnull result) {
2634
// CHECK-NEXT: _impl::$s9UsesEnums0aB9LargeEnumV27passThroughStructSeveralI64y0B00cD0OAGF(result, Enums::_impl::_impl_LargeEnum::getOpaquePointer(y), _getOpaquePointer());
@@ -31,12 +39,3 @@ public struct UsesEnumsLargeEnum {
3139
// CHECK-NEXT: _impl::$s9UsesEnums0aB9LargeEnumV1x0B00cD0Ovg(result, _getOpaquePointer());
3240
// CHECK-NEXT: });
3341
// CHECK-NEXT: }
34-
35-
36-
public func inoutLargeEnum(_ s: inout LargeEnum) {
37-
return s = LargeEnum.B
38-
}
39-
40-
// CHECK: inline void inoutLargeEnum(Enums::LargeEnum& s) noexcept {
41-
// CHECK-NEXT: return _impl::$s9UsesEnums14inoutLargeEnumyy0B00dE0OzF(Enums::_impl::_impl_LargeEnum::getOpaquePointer(s));
42-
// CHECK-NEXT: }

test/Interop/SwiftToCxx/cross-module-refs/imported-struct-refs-in-cxx.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,6 @@ public struct UsesStructsStruct {
2424
// CHECK: inline Structs::StructSeveralI64 passThroughStructSeveralI64(const Structs::StructSeveralI64& y) const;
2525
// CHECK-NEXT: inline Structs::StructSeveralI64 getX() const;
2626

27-
// CHECK: inline Structs::StructSeveralI64 UsesStructsStruct::passThroughStructSeveralI64(const Structs::StructSeveralI64& y) const {
28-
// CHECK-NEXT: return Structs::_impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
29-
// CHECK-NEXT: _impl::$s11UsesStructs0aB6StructV011passThroughC10SeveralI64y0B00cfG0VAGF(result, Structs::_impl::_impl_StructSeveralI64::getOpaquePointer(y), _getOpaquePointer());
30-
// CHECK-NEXT: });
31-
// CHECK-NEXT: }
32-
33-
// CHECK: inline Structs::StructSeveralI64 UsesStructsStruct::getX() const {
34-
// CHECK-NEXT: return Structs::_impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
35-
// CHECK-NEXT: _impl::$s11UsesStructs0aB6StructV1x0B00C10SeveralI64Vvg(result, _getOpaquePointer());
36-
// CHECK-NEXT: });
37-
// CHECK-NEXT: }
38-
3927

4028
public func passThroughStructSeveralI64(_ x: StructSeveralI64) -> StructSeveralI64 {
4129
return Structs.passThroughStructSeveralI64(i: 0, x, j: 2)
@@ -65,3 +53,15 @@ public func passThroughStructSmallDirect(_ x: SmallStructDirectPassing) -> Small
6553
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_SmallStructDirectPassing(result, _impl::$s11UsesStructs28passThroughStructSmallDirecty0B00feG7PassingVAEF(_impl::swift_interop_passDirect_Structs_SmallStructDirectPassing(Structs::_impl::_impl_SmallStructDirectPassing::getOpaquePointer(x))));
6654
// CHECK-NEXT: });
6755
// CHECK-NEXT: }
56+
57+
// CHECK: inline Structs::StructSeveralI64 UsesStructsStruct::passThroughStructSeveralI64(const Structs::StructSeveralI64& y) const {
58+
// CHECK-NEXT: return Structs::_impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
59+
// CHECK-NEXT: _impl::$s11UsesStructs0aB6StructV011passThroughC10SeveralI64y0B00cfG0VAGF(result, Structs::_impl::_impl_StructSeveralI64::getOpaquePointer(y), _getOpaquePointer());
60+
// CHECK-NEXT: });
61+
// CHECK-NEXT: }
62+
63+
// CHECK: inline Structs::StructSeveralI64 UsesStructsStruct::getX() const {
64+
// CHECK-NEXT: return Structs::_impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
65+
// CHECK-NEXT: _impl::$s11UsesStructs0aB6StructV1x0B00C10SeveralI64Vvg(result, _getOpaquePointer());
66+
// CHECK-NEXT: });
67+
// CHECK-NEXT: }

test/Interop/SwiftToCxx/initializers/init-in-cxx.swift

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,6 @@ public struct FirstSmallStruct {
3838
// CHECK-NEXT: static inline FirstSmallStruct init(swift::Int x);
3939
// CHECK-NEXT: private:
4040

41-
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
42-
// CHECK-NEXT: return _impl::$s4Init16FirstSmallStructV1xs6UInt32Vvg(_impl::swift_interop_passDirect_Init_FirstSmallStruct(_getOpaquePointer()));
43-
// CHECK-NEXT: }
44-
// CHECK-NEXT: inline FirstSmallStruct FirstSmallStruct::init() {
45-
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
46-
// CHECK-NEXT: _impl::swift_interop_returnDirect_Init_FirstSmallStruct(result, _impl::$s4Init16FirstSmallStructVACycfC());
47-
// CHECK-NEXT: });
48-
// CHECK-NEXT: }
49-
// CHECK-NEXT: inline FirstSmallStruct FirstSmallStruct::init(swift::Int x) {
50-
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
51-
// CHECK-NEXT: _impl::swift_interop_returnDirect_Init_FirstSmallStruct(result, _impl::$s4Init16FirstSmallStructVyACSicfC(x));
52-
// CHECK-NEXT: });
53-
// CHECK-NEXT: }
54-
5541
public struct LargeStruct {
5642
public let x1, x2, x3, x4, x5, x6: Int
5743

@@ -80,17 +66,6 @@ public struct LargeStruct {
8066
// CHECK-NEXT: static inline LargeStruct init(swift::Int x, const FirstSmallStruct& y);
8167
// CHECK-NEXT: private:
8268

83-
// CHECK: inline LargeStruct LargeStruct::init() {
84-
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
85-
// CHECK-NEXT: _impl::$s4Init11LargeStructVACycfC(result);
86-
// CHECK-NEXT: });
87-
// CHECK-NEXT: }
88-
// CHECK-NEXT: inline LargeStruct LargeStruct::init(swift::Int x, const FirstSmallStruct& y) {
89-
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
90-
// CHECK-NEXT: _impl::$s4Init11LargeStructV1x1yACSi_AA010FirstSmallC0VtcfC(result, x, _impl::swift_interop_passDirect_Init_FirstSmallStruct(_impl::_impl_FirstSmallStruct::getOpaquePointer(y)));
91-
// CHECK-NEXT: });
92-
// CHECK-NEXT: }
93-
9469
private class RefCountedClass {
9570
let x: Int
9671

@@ -118,6 +93,32 @@ public struct StructWithRefCountStoredProp {
11893
// CHECK: static inline StructWithRefCountStoredProp init();
11994
// CHECK-NEXT: static inline StructWithRefCountStoredProp init(swift::Int x);
12095

96+
97+
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
98+
// CHECK-NEXT: return _impl::$s4Init16FirstSmallStructV1xs6UInt32Vvg(_impl::swift_interop_passDirect_Init_FirstSmallStruct(_getOpaquePointer()));
99+
// CHECK-NEXT: }
100+
// CHECK-NEXT: inline FirstSmallStruct FirstSmallStruct::init() {
101+
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
102+
// CHECK-NEXT: _impl::swift_interop_returnDirect_Init_FirstSmallStruct(result, _impl::$s4Init16FirstSmallStructVACycfC());
103+
// CHECK-NEXT: });
104+
// CHECK-NEXT: }
105+
// CHECK-NEXT: inline FirstSmallStruct FirstSmallStruct::init(swift::Int x) {
106+
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
107+
// CHECK-NEXT: _impl::swift_interop_returnDirect_Init_FirstSmallStruct(result, _impl::$s4Init16FirstSmallStructVyACSicfC(x));
108+
// CHECK-NEXT: });
109+
// CHECK-NEXT: }
110+
111+
// CHECK: inline LargeStruct LargeStruct::init() {
112+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
113+
// CHECK-NEXT: _impl::$s4Init11LargeStructVACycfC(result);
114+
// CHECK-NEXT: });
115+
// CHECK-NEXT: }
116+
// CHECK-NEXT: inline LargeStruct LargeStruct::init(swift::Int x, const FirstSmallStruct& y) {
117+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
118+
// CHECK-NEXT: _impl::$s4Init11LargeStructV1x1yACSi_AA010FirstSmallC0VtcfC(result, x, _impl::swift_interop_passDirect_Init_FirstSmallStruct(_impl::_impl_FirstSmallStruct::getOpaquePointer(y)));
119+
// CHECK-NEXT: });
120+
// CHECK-NEXT: }
121+
121122
// CHECK: inline StructWithRefCountStoredProp StructWithRefCountStoredProp::init() {
122123
// CHECK-NEXT: return _impl::_impl_StructWithRefCountStoredProp::returnNewValue([&](char * _Nonnull result) {
123124
// CHECK-NEXT: _impl::swift_interop_returnDirect_Init_StructWithRefCountStoredProp(result, _impl::$s4Init28StructWithRefCountStoredPropVACycfC());

0 commit comments

Comments
 (0)