SILGen: Limit references to NSError in inlinable code optimization

Revisit the optimization that provides a fast path for instances of
`NSError` when erasing the `Error` type in `emitExistentialErasure`. It
generated references to `NSError` when the `Foundation` module was
loaded, no matter how it was imported. This lead to deserialization
failures at reading the swiftmodule when that reference was added to
inlinable code while `Foundation` was not a public dependency.

Fix this crash by limiting the optimization to all non-inlinable code
and only inlinable code from a module with a public dependency on
`Foundation`. This is the similar check we apply to user written
inlinable code, however here we use the module-wide dependency instead
of per file imports.

rdar://142438679
This commit is contained in:
Alexis Laferrière
2025-02-18 16:44:28 -08:00
parent a619daf12b
commit db7126c390
4 changed files with 200 additions and 1 deletions

View File

@@ -30,6 +30,7 @@
#include "swift/AST/FileUnit.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/ImportCache.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/SourceFile.h"
@@ -210,6 +211,35 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
llvm_unreachable("Unhandled SILDeclRefKind in switch.");
}
bool SILGenFunction::referenceAllowed(ValueDecl *decl) {
// Use in any non-fragile functions.
if (FunctionDC->getResilienceExpansion() == ResilienceExpansion::Maximal)
return true;
// Allow same-module references.
auto *targetMod = decl->getDeclContext()->getParentModule();
auto *thisMod = FunctionDC->getParentModule();
if (thisMod == targetMod)
return true;
ModuleDecl::ImportFilter filter = {
ModuleDecl::ImportFilterKind::Exported,
ModuleDecl::ImportFilterKind::Default,
ModuleDecl::ImportFilterKind::SPIOnly};
if (thisMod->getResilienceStrategy() != ResilienceStrategy::Resilient)
filter |= ModuleDecl::ImportFilterKind::InternalOrBelow;
// Look through public module local imports and their reexports.
llvm::SmallVector<ImportedModule, 8> imports;
thisMod->getImportedModules(imports, filter);
auto &importCache = getASTContext().getImportCache();
for (auto &import : imports) {
if (importCache.isImportedBy(targetMod, import.importedModule))
return true;
}
return false;
}
SILDebugLocation SILGenFunction::getSILDebugLocation(
SILBuilder &B, SILLocation Loc,
std::optional<SILLocation> CurDebugLocOverride, bool ForMetaInstruction) {