Skip to content

[cxx-interop] Emit type metadata for foreign types more often #76011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "GenKeyPath.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsIRGen.h"
#include "swift/AST/ExtInfo.h"
#include "swift/AST/GenericEnvironment.h"
Expand All @@ -26,6 +27,9 @@
#include "swift/AST/Pattern.h"
#include "swift/AST/SemanticAttrs.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeExpansionContext.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/ExternalUnion.h"
Expand Down Expand Up @@ -2472,6 +2476,53 @@ static void emitDynamicSelfMetadata(IRGenSILFunction &IGF) {
IGF.setDynamicSelfMetadata(selfTy, isExact, value, selfKind);
}

/// C++ interop might refer to the type metadata in some scenarios.
/// This function covers those cases and makes sure metadata is emitted
/// for the foreign types.
static void noteUseOfMetadataByCXXInterop(IRGenerator &IRGen,
const SILFunction *f,
const TypeExpansionContext &context) {
auto type = f->getLoweredFunctionType();

// Notes the use of foreign types in generic arguments for C++ interop.
auto processType = [&](CanType type) {
struct Walker : TypeWalker {
Walker(IRGenerator &IRGen) : IRGen(IRGen) {}

Action walkToTypePre(Type ty) override {
if (auto *BGT = ty->getAs<BoundGenericType>())
genericDepth++;
else if (auto *nominal = ty->getAs<NominalType>())
noteUseOfTypeMetadata(nominal->getDecl());
return Action::Continue;
}

Action walkToTypePost(Type ty) override {
if (auto *BGT = ty->getAs<BoundGenericType>())
genericDepth--;

return Action::Continue;
}

void noteUseOfTypeMetadata(NominalTypeDecl *type) {
if (genericDepth == 0)
return;
if (!IRGen.hasLazyMetadata(type) || !type->hasClangNode())
return;
IRGen.noteUseOfTypeMetadata(type);
}
IRGenerator &IRGen;
int genericDepth = 0;
} walker{IRGen};
type.walk(walker);
};

for (const auto &param : type->getParameters())
processType(param.getArgumentType(IRGen.SIL, type, context));
for (const auto &result : type->getResultsWithError())
processType(result.getReturnValueType(IRGen.SIL, type, context));
}

/// Emit the definition for the given SIL constant.
void IRGenModule::emitSILFunction(SILFunction *f) {
if (f->isExternalDeclaration())
Expand All @@ -2487,6 +2538,12 @@ void IRGenModule::emitSILFunction(SILFunction *f) {
f->isAvailableExternally())
return;

// Type metadata for foreign references is not yet supported on Windows. Bug #76168.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that this is not supported on Windows?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that on Windows we end up requiring a metadata completion function for C++ foreign reference types. That logic just isn't implemented yet for C++ types.

swift/lib/IRGen/GenMeta.cpp

Lines 6636 to 6639 in bd313de

void emitInitializeMetadata(IRGenFunction &IGF, llvm::Value *metadata,
MetadataDependencyCollector *collector) {
llvm_unreachable("Not implemented for foreign reference types.");
}

if (Context.LangOpts.EnableCXXInterop &&
f->getLinkage() == SILLinkage::Public &&
!Context.LangOpts.Target.isOSWindows())
noteUseOfMetadataByCXXInterop(IRGen, f, TypeExpansionContext(*f));

PrettyStackTraceSILFunction stackTrace("emitting IR", f);
IRGenSILFunction(*this, f).emitSILFunction();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ struct CxxStruct {
int x;
};

struct CxxStruct2 {
inline CxxStruct2(int x) : x(x) {}
inline CxxStruct2(const CxxStruct &other) : x(other.x) {}
inline ~CxxStruct2() {}

int x;
};

//--- module.modulemap
module CxxTest {
header "header.h"
Expand All @@ -30,6 +38,12 @@ public func retCxxStruct() -> CxxStruct {
return CxxStruct(2)
}

#if !os(Windows)
public func retCxxStruct2() -> CxxStruct2? {
return CxxStruct2(2)
}
#endif

//--- use-swift-cxx-types.cpp

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

int main() {
auto x = UseCxx::retCxxStruct();
#ifndef _WIN32
auto y = UseCxx::retCxxStruct2();
#endif
return 0;
}