Skip to content

Commit 623e284

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 93f9a17 commit 623e284

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 78 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,76 @@ static void emitDynamicSelfMetadata(IRGenSILFunction &IGF) {
24722476
IGF.setDynamicSelfMetadata(selfTy, isExact, value, selfKind);
24732477
}
24742478

2479+
namespace {
2480+
// Notes the use of foreign types in generic arguments for C++ interop.
2481+
class NoteUseOfForeignTypeMetadata
2482+
: public TypeVisitor<NoteUseOfForeignTypeMetadata, void, bool> {
2483+
public:
2484+
NoteUseOfForeignTypeMetadata(IRGenerator &IRGen) : IRGen(IRGen) {}
2485+
2486+
void visitType(TypeBase *, bool) {}
2487+
2488+
void visitTupleType(TupleType *TT, bool isInGenericArgument) {
2489+
for (auto type : TT->getElementTypes())
2490+
TypeVisitor::visit(type, isInGenericArgument);
2491+
}
2492+
2493+
void visitSugarType(SugarType *sugarTy, bool isInGenericArgument) {
2494+
TypeVisitor::visit(sugarTy->getSinglyDesugaredType(), isInGenericArgument);
2495+
}
2496+
2497+
void visitClassType(ClassType *CT, bool isInGenericArgument) {
2498+
noteUseOfTypeMetadata(CT->getDecl(), isInGenericArgument);
2499+
}
2500+
2501+
void visitEnumType(EnumType *ET, bool isInGenericArgument) {
2502+
noteUseOfTypeMetadata(ET->getDecl(), isInGenericArgument);
2503+
}
2504+
2505+
void visitStructType(StructType *ST, bool isInGenericArgument) {
2506+
noteUseOfTypeMetadata(ST->getDecl(), isInGenericArgument);
2507+
}
2508+
2509+
void visitBoundGenericType(BoundGenericType *BGT, bool isInGenericArgument) {
2510+
for (auto type : BGT->getGenericArgs())
2511+
TypeVisitor::visit(type, true);
2512+
}
2513+
2514+
void visitDynamicSelfType(DynamicSelfType *ds, bool isInGenericArgument) {
2515+
TypeVisitor::visit(ds->getSelfType(), isInGenericArgument);
2516+
}
2517+
2518+
private:
2519+
void noteUseOfTypeMetadata(NominalTypeDecl *type, bool isInGenericArgument) {
2520+
if (!isInGenericArgument)
2521+
return;
2522+
if (!IRGen.hasLazyMetadata(type) || !type->hasClangNode())
2523+
return;
2524+
IRGen.noteUseOfTypeMetadata(type);
2525+
}
2526+
IRGenerator &IRGen;
2527+
};
2528+
} // namespace
2529+
2530+
/// C++ interop might refer to the type metadat in some scenarios.
2531+
/// This function covers those cases and makes sure metadata is emitted
2532+
/// for the foreing types.
2533+
static void noteUseOfMetadataByCXXInterop(IRGenerator &IRGen,
2534+
const SILFunction *f,
2535+
const TypeExpansionContext &context) {
2536+
auto type = f->getLoweredFunctionType();
2537+
2538+
auto processType = [&](CanType type) {
2539+
NoteUseOfForeignTypeMetadata visitor(IRGen);
2540+
visitor.visit(type, false);
2541+
};
2542+
2543+
for (const auto &param : type->getParameters())
2544+
processType(param.getArgumentType(IRGen.SIL, type, context));
2545+
for (const auto &result : type->getResultsWithError())
2546+
processType(result.getReturnValueType(IRGen.SIL, type, context));
2547+
}
2548+
24752549
/// Emit the definition for the given SIL constant.
24762550
void IRGenModule::emitSILFunction(SILFunction *f) {
24772551
if (f->isExternalDeclaration())
@@ -2487,6 +2561,10 @@ void IRGenModule::emitSILFunction(SILFunction *f) {
24872561
f->isAvailableExternally())
24882562
return;
24892563

2564+
if (Context.LangOpts.EnableCXXInterop &&
2565+
f->getLinkage() == SILLinkage::Public)
2566+
noteUseOfMetadataByCXXInterop(IRGen, f, TypeExpansionContext(*f));
2567+
24902568
PrettyStackTraceSILFunction stackTrace("emitting IR", f);
24912569
IRGenSILFunction(*this, f).emitSILFunction();
24922570
}

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

Lines changed: 13 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,10 @@ public func retCxxStruct() -> CxxStruct {
3038
return CxxStruct(2)
3139
}
3240

41+
public func retCxxStruct2() -> CxxStruct2? {
42+
return CxxStruct2(2)
43+
}
44+
3345
//--- use-swift-cxx-types.cpp
3446

3547
#include "header.h"
@@ -38,5 +50,6 @@ public func retCxxStruct() -> CxxStruct {
3850

3951
int main() {
4052
auto x = UseCxx::retCxxStruct();
53+
auto y = UseCxx::retCxxStruct2();
4154
return 0;
4255
}

0 commit comments

Comments
 (0)