Teach canImport to reject modules that mismatch on Embedded vs. normal Swift

Check for Embedded/normal Swift mismatches as part of module
validation, rather than after loading. Do this check as part of
canImport, so that canImport will evaluate false when there is a mismatch.

This will produce a warning in this case, because it's often a mistake
to have a module visible that isn't actually usable. However, don't
break the build over it.

Fixes #86419 / rdar://167851189
This commit is contained in:
Doug Gregor
2026-04-02 18:28:07 -07:00
parent 6e2eaee27a
commit 169561851d
8 changed files with 81 additions and 21 deletions
+16 -3
View File
@@ -250,6 +250,7 @@ static ValidationInfo validateControlBlock(
bool requiresRevisionMatch,
StringRef requiredSDK,
std::optional<llvm::Triple> target,
std::optional<bool> isEmbedded,
ExtendedValidationInfo *extendedInfo,
PathObfuscator &pathRecoverer) {
// The control block is malformed until we've at least read a major version
@@ -287,6 +288,13 @@ static ValidationInfo validateControlBlock(
result.status = Status::Malformed;
return result;
}
// Validate extended options.
if (isEmbedded &&
extendedInfo->isEmbeddedSwiftModule() != *isEmbedded) {
result.status = Status::EmbeddedMismatch;
return result;
}
} else {
// Unknown metadata sub-block, possibly for use by a future version of
// the module format.
@@ -673,6 +681,7 @@ std::string serialization::StatusToString(Status S) {
case Status::TargetIncompatible: return "TargetIncompatible";
case Status::TargetTooNew: return "TargetTooNew";
case Status::SDKMismatch: return "SDKMismatch";
case Status::EmbeddedMismatch: return "EmbeddedMismatch";
}
llvm_unreachable("The switch should cover all cases");
}
@@ -689,7 +698,8 @@ ValidationInfo serialization::validateSerializedAST(
SmallVectorImpl<SearchPath> *searchPaths,
ExplicitSwiftModuleMap *explicitSwiftModuleMap,
ExplicitClangModuleMap *explicitClangModuleMap,
std::optional<llvm::Triple> target) {
std::optional<llvm::Triple> target,
std::optional<bool> isEmbedded) {
ValidationInfo result;
// Check 32-bit alignment.
@@ -731,7 +741,7 @@ ValidationInfo serialization::validateSerializedAST(
cursor, scratch,
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
/*requiresRevisionMatch=*/true,
requiredSDK, target,
requiredSDK, target, isEmbedded,
extendedInfo, localObfuscator);
if (result.status != Status::Valid)
return result;
@@ -1284,6 +1294,7 @@ bool ModuleFileSharedCore::readModuleDocIfPresent(PathObfuscator &pathRecoverer)
docCursor, scratch, {SWIFTDOC_VERSION_MAJOR, SWIFTDOC_VERSION_MINOR},
/*requiresRevisionMatch*/false,
/*requiredSDK*/StringRef(), /*target*/std::nullopt,
/*isEmbedded*/std::nullopt,
/*extendedInfo*/nullptr, pathRecoverer);
if (info.status != Status::Valid)
return false;
@@ -1429,6 +1440,7 @@ bool ModuleFileSharedCore::readModuleSourceInfoIfPresent(PathObfuscator &pathRec
{SWIFTSOURCEINFO_VERSION_MAJOR, SWIFTSOURCEINFO_VERSION_MINOR},
/*requiresRevisionMatch*/false,
/*requiredSDK*/StringRef(), /*target*/std::nullopt,
/*isEmbedded*/std::nullopt,
/*extendedInfo*/nullptr, pathRecoverer);
if (info.status != Status::Valid)
return false;
@@ -1508,6 +1520,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
bool isFramework,
StringRef requiredSDK,
std::optional<llvm::Triple> target,
std::optional<bool> isEmbedded,
serialization::ValidationInfo &info, PathObfuscator &pathRecoverer)
: ModuleInputBuffer(std::move(moduleInputBuffer)),
ModuleDocInputBuffer(std::move(moduleDocInputBuffer)),
@@ -1558,7 +1571,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
info = validateControlBlock(
cursor, scratch,
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
/*requiresRevisionMatch=*/true, requiredSDK, target,
/*requiresRevisionMatch=*/true, requiredSDK, target, isEmbedded,
&extInfo, pathRecoverer);
if (info.status != Status::Valid) {
error(info.status);