Skip to content

Commit cdbe999

Browse files
author
Gabor Horvath
committed
[cxx-interop] Emit type metadata for foreign types more often
Metadata for foreign types are emitted lazily, when SILGen generates a reference to it. Unfortunately, C++ reverse interop can also introduce references to such metadata in the generated header when types are used as generic arguments. This adds a type visitor to make note of the type metadata use for those generic arguments in public APIs when C++ interop is enabled. rdar://132925256
1 parent f6791a2 commit cdbe999

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "GenKeyPath.h"
1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/ASTMangler.h"
21+
#include "swift/AST/Decl.h"
2122
#include "swift/AST/DiagnosticsIRGen.h"
2223
#include "swift/AST/ExtInfo.h"
2324
#include "swift/AST/GenericEnvironment.h"
@@ -26,6 +27,9 @@
2627
#include "swift/AST/Pattern.h"
2728
#include "swift/AST/SemanticAttrs.h"
2829
#include "swift/AST/SubstitutionMap.h"
30+
#include "swift/AST/Type.h"
31+
#include "swift/AST/TypeExpansionContext.h"
32+
#include "swift/AST/TypeVisitor.h"
2933
#include "swift/AST/Types.h"
3034
#include "swift/Basic/Assertions.h"
3135
#include "swift/Basic/ExternalUnion.h"
@@ -2472,6 +2476,53 @@ static void emitDynamicSelfMetadata(IRGenSILFunction &IGF) {
24722476
IGF.setDynamicSelfMetadata(selfTy, isExact, value, selfKind);
24732477
}
24742478

2479+
/// C++ interop might refer to the type metadata in some scenarios.
2480+
/// This function covers those cases and makes sure metadata is emitted
2481+
/// for the foreign types.
2482+
static void noteUseOfMetadataByCXXInterop(IRGenerator &IRGen,
2483+
const SILFunction *f,
2484+
const TypeExpansionContext &context) {
2485+
auto type = f->getLoweredFunctionType();
2486+
2487+
// Notes the use of foreign types in generic arguments for C++ interop.
2488+
auto processType = [&](CanType type) {
2489+
struct Walker : TypeWalker {
2490+
Walker(IRGenerator &IRGen) : IRGen(IRGen) {}
2491+
2492+
Action walkToTypePre(Type ty) override {
2493+
if (auto *BGT = ty->getAs<BoundGenericType>())
2494+
genericDepth++;
2495+
else if (auto *nominal = ty->getAs<NominalType>())
2496+
noteUseOfTypeMetadata(nominal->getDecl());
2497+
return Action::Continue;
2498+
}
2499+
2500+
Action walkToTypePost(Type ty) override {
2501+
if (auto *BGT = ty->getAs<BoundGenericType>())
2502+
genericDepth--;
2503+
2504+
return Action::Continue;
2505+
}
2506+
2507+
void noteUseOfTypeMetadata(NominalTypeDecl *type) {
2508+
if (genericDepth == 0)
2509+
return;
2510+
if (!IRGen.hasLazyMetadata(type) || !type->hasClangNode())
2511+
return;
2512+
IRGen.noteUseOfTypeMetadata(type);
2513+
}
2514+
IRGenerator &IRGen;
2515+
int genericDepth = 0;
2516+
} walker{IRGen};
2517+
type.walk(walker);
2518+
};
2519+
2520+
for (const auto &param : type->getParameters())
2521+
processType(param.getArgumentType(IRGen.SIL, type, context));
2522+
for (const auto &result : type->getResultsWithError())
2523+
processType(result.getReturnValueType(IRGen.SIL, type, context));
2524+
}
2525+
24752526
/// Emit the definition for the given SIL constant.
24762527
void IRGenModule::emitSILFunction(SILFunction *f) {
24772528
if (f->isExternalDeclaration())
@@ -2487,6 +2538,12 @@ void IRGenModule::emitSILFunction(SILFunction *f) {
24872538
f->isAvailableExternally())
24882539
return;
24892540

2541+
// Type metadata for foreign references is not yet supported on Windows. Bug #76168.
2542+
if (Context.LangOpts.EnableCXXInterop &&
2543+
f->getLinkage() == SILLinkage::Public &&
2544+
!Context.LangOpts.Target.isOSWindows())
2545+
noteUseOfMetadataByCXXInterop(IRGen, f, TypeExpansionContext(*f));
2546+
24902547
PrettyStackTraceSILFunction stackTrace("emitting IR", f);
24912548
IRGenSILFunction(*this, f).emitSILFunction();
24922549
}

test/Interop/CxxToSwiftToCxx/link-cxx-type-metadata-accessor.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ struct CxxStruct {
1717
int x;
1818
};
1919

20+
struct CxxStruct2 {
21+
inline CxxStruct2(int x) : x(x) {}
22+
inline CxxStruct2(const CxxStruct &other) : x(other.x) {}
23+
inline ~CxxStruct2() {}
24+
25+
int x;
26+
};
27+
2028
//--- module.modulemap
2129
module CxxTest {
2230
header "header.h"
@@ -30,6 +38,12 @@ public func retCxxStruct() -> CxxStruct {
3038
return CxxStruct(2)
3139
}
3240

41+
#if !os(Windows)
42+
public func retCxxStruct2() -> CxxStruct2? {
43+
return CxxStruct2(2)
44+
}
45+
#endif
46+
3347
//--- use-swift-cxx-types.cpp
3448

3549
#include "header.h"
@@ -38,5 +52,8 @@ public func retCxxStruct() -> CxxStruct {
3852

3953
int main() {
4054
auto x = UseCxx::retCxxStruct();
55+
#ifndef _WIN32
56+
auto y = UseCxx::retCxxStruct2();
57+
#endif
4158
return 0;
4259
}

0 commit comments

Comments
 (0)