[SILGen] Fix the type of closure thunks that are passed const reference structs

This PR is another attempt at landing #76903. The changes compared to
the original PR:
* Instead of increasing the size of SILDeclRef, store the necessary type
  information in a side channel using withClosureTypeInfo.
* Rely on SGFContext to get the right ClangType
* Extend BridgingConversion with an AbstractionPattern to store the
  original clang type.
* The PR above introduced a crash during indexing system modules that
  references foreign types coming from modules imported as
  implementation only. These entities are implementation details so they
  do not need to be included during serialization. This PR adds a test
  and adds logic to exclude such clang types in the serialization
  process.

rdar://131321096&141786724
This commit is contained in:
Gabor Horvath
2025-03-20 15:27:33 +00:00
parent b72ef8eb88
commit f26749245b
16 changed files with 365 additions and 83 deletions

View File

@@ -17,6 +17,7 @@
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/AutoDiff.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/Expr.h"
@@ -41,6 +42,7 @@
#include "swift/AST/SynthesizedFileUnit.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/FileSystem.h"
@@ -5567,6 +5569,31 @@ static TypeAliasDecl *findTypeAliasForBuiltin(ASTContext &Ctx, Type T) {
return cast<TypeAliasDecl>(CurModuleResults[0]);
}
namespace {
struct ImplementationOnlyWalker : TypeWalker {
bool hadImplementationOnlyDecl = false;
const ModuleDecl *currentModule;
ImplementationOnlyWalker(const ModuleDecl *M) : currentModule(M) {}
Action walkToTypePre(Type ty) override {
if (auto *typeAlias = dyn_cast<TypeAliasType>(ty)) {
if (importedImplementationOnly(typeAlias->getDecl()))
return Action::Stop;
} else if (auto *nominal = ty->getAs<NominalType>()) {
if (importedImplementationOnly(nominal->getDecl()))
return Action::Stop;
}
return Action::Continue;
}
bool importedImplementationOnly(const Decl *D) {
if (currentModule->isImportedImplementationOnly(D->getModuleContext())) {
hadImplementationOnlyDecl = true;
return true;
}
return false;
}
};
} // namespace
class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {
Serializer &S;
@@ -5920,10 +5947,23 @@ public:
using namespace decls_block;
auto resultType = S.addTypeRef(fnTy->getResult());
auto clangType =
S.getASTContext().LangOpts.UseClangFunctionTypes
? S.addClangTypeRef(fnTy->getClangTypeInfo().getType())
: ClangTypeID(0);
bool shouldSerializeClangType = true;
if (S.hadImplementationOnlyImport && S.M &&
S.M->getResilienceStrategy() != ResilienceStrategy::Resilient) {
// Deserializing clang types from implementation only modules could crash
// as the transitive clang module might not be available to retrieve the
// declarations from. In an optimal world we would make the deseriaization
// more resilient to these problems but the failure is in Clang's
// deserialization code path that is not architected with potentially
// missing declarations in mind.
ImplementationOnlyWalker walker{S.M};
Type(const_cast<FunctionType *>(fnTy)).walk(walker);
if (walker.hadImplementationOnlyDecl)
shouldSerializeClangType = false;
}
auto clangType = shouldSerializeClangType
? S.addClangTypeRef(fnTy->getClangTypeInfo().getType())
: ClangTypeID(0);
auto isolation = encodeIsolation(fnTy->getIsolation());
@@ -7005,8 +7045,13 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
nextFile->getTopLevelDeclsWithAuxiliaryDecls(fileDecls);
for (auto D : fileDecls) {
if (isa<ImportDecl>(D) || isa<MacroExpansionDecl>(D) ||
isa<TopLevelCodeDecl>(D) || isa<UsingDecl>(D)) {
if (const auto *ID = dyn_cast<ImportDecl>(D)) {
if (ID->getAttrs().hasAttribute<ImplementationOnlyAttr>())
hadImplementationOnlyImport = true;
continue;
}
if (isa<MacroExpansionDecl>(D) || isa<TopLevelCodeDecl>(D) ||
isa<UsingDecl>(D)) {
continue;
}