[NCGenerics] trigger module mismatch

A swiftmodule can only be correctly ingested by a compiler
that has a matching state of using or not-using
NoncopyableGenerics.

The reason for this is fundamental: the absence of a Copyable
conformance in the swiftmodule indicates that a type is
noncopyable. Thus, if a compiler with NoncopyableGenerics
reads a swiftmodule that was not compiled with that feature,
it will think every type in that module is noncopyable.

Similarly, if a compiler with NoncopyableGenerics produces a
swiftmodule, there will be Copyable requirements on each
generic parameter that the compiler without the feature will
become confused about.

The solution here is to trigger a module mismatch, so that
the compiler re-generates the swiftmodule file using the
swiftinterface, which has been kept compatible with the compiler
regardless of whether the feature is enabled.
This commit is contained in:
Kavon Farvardin
2023-12-15 00:49:32 -08:00
parent 54dff6fb17
commit 483b569bc8
21 changed files with 323 additions and 67 deletions

View File

@@ -209,7 +209,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
static ValidationInfo validateControlBlock(
llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch,
std::pair<uint16_t, uint16_t> expectedVersion, bool requiresOSSAModules,
std::pair<uint16_t, uint16_t> expectedVersion,
bool requiresOSSAModules,
bool requiresNoncopyableGenerics,
bool requiresRevisionMatch,
StringRef requiredSDK,
ExtendedValidationInfo *extendedInfo,
@@ -422,6 +424,12 @@ static ValidationInfo validateControlBlock(
result.status = Status::NotInOSSA;
break;
}
case control_block::HAS_NONCOPYABLE_GENERICS: {
auto hasNoncopyableGenerics = scratch[0];
if (requiresNoncopyableGenerics && !hasNoncopyableGenerics)
result.status = Status::NotUsingNoncopyableGenerics;
break;
}
default:
// Unknown metadata record, possibly for use by a future version of the
// module format.
@@ -525,6 +533,8 @@ std::string serialization::StatusToString(Status S) {
case Status::FormatTooNew: return "FormatTooNew";
case Status::RevisionIncompatible: return "RevisionIncompatible";
case Status::NotInOSSA: return "NotInOSSA";
case Status::NotUsingNoncopyableGenerics:
return "NotUsingNoncopyableGenerics";
case Status::MissingDependency: return "MissingDependency";
case Status::MissingUnderlyingModule: return "MissingUnderlyingModule";
case Status::CircularDependency: return "CircularDependency";
@@ -546,7 +556,8 @@ bool serialization::isSerializedAST(StringRef data) {
}
ValidationInfo serialization::validateSerializedAST(
StringRef data, bool requiresOSSAModules, StringRef requiredSDK,
StringRef data, bool requiresOSSAModules, bool requiresNoncopyableGenerics,
StringRef requiredSDK,
ExtendedValidationInfo *extendedInfo,
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies,
SmallVectorImpl<SearchPath> *searchPaths) {
@@ -590,7 +601,9 @@ ValidationInfo serialization::validateSerializedAST(
result = validateControlBlock(
cursor, scratch,
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
requiresOSSAModules, /*requiresRevisionMatch=*/true,
requiresOSSAModules,
requiresNoncopyableGenerics,
/*requiresRevisionMatch=*/true,
requiredSDK,
extendedInfo, localObfuscator);
if (result.status != Status::Valid)
@@ -1122,7 +1135,9 @@ bool ModuleFileSharedCore::readModuleDocIfPresent(PathObfuscator &pathRecoverer)
info = validateControlBlock(
docCursor, scratch, {SWIFTDOC_VERSION_MAJOR, SWIFTDOC_VERSION_MINOR},
RequiresOSSAModules, /*requiresRevisionMatch*/false,
RequiresOSSAModules,
RequiresNoncopyableGenerics,
/*requiresRevisionMatch*/false,
/*requiredSDK*/StringRef(), /*extendedInfo*/nullptr, pathRecoverer);
if (info.status != Status::Valid)
return false;
@@ -1266,7 +1281,9 @@ bool ModuleFileSharedCore::readModuleSourceInfoIfPresent(PathObfuscator &pathRec
info = validateControlBlock(
infoCursor, scratch,
{SWIFTSOURCEINFO_VERSION_MAJOR, SWIFTSOURCEINFO_VERSION_MINOR},
RequiresOSSAModules, /*requiresRevisionMatch*/false,
RequiresOSSAModules,
RequiresNoncopyableGenerics,
/*requiresRevisionMatch*/false,
/*requiredSDK*/StringRef(), /*extendedInfo*/nullptr, pathRecoverer);
if (info.status != Status::Valid)
return false;
@@ -1341,12 +1358,16 @@ ModuleFileSharedCore::ModuleFileSharedCore(
std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
std::unique_ptr<llvm::MemoryBuffer> moduleSourceInfoInputBuffer,
bool isFramework, bool requiresOSSAModules, StringRef requiredSDK,
bool isFramework,
bool requiresOSSAModules,
bool requiresNoncopyableGenerics,
StringRef requiredSDK,
serialization::ValidationInfo &info, PathObfuscator &pathRecoverer)
: ModuleInputBuffer(std::move(moduleInputBuffer)),
ModuleDocInputBuffer(std::move(moduleDocInputBuffer)),
ModuleSourceInfoInputBuffer(std::move(moduleSourceInfoInputBuffer)),
RequiresOSSAModules(requiresOSSAModules) {
RequiresOSSAModules(requiresOSSAModules),
RequiresNoncopyableGenerics(requiresNoncopyableGenerics) {
assert(!hasError());
Bits.IsFramework = isFramework;
@@ -1393,7 +1414,9 @@ ModuleFileSharedCore::ModuleFileSharedCore(
info = validateControlBlock(
cursor, scratch,
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
RequiresOSSAModules, /*requiresRevisionMatch=*/true, requiredSDK,
RequiresOSSAModules,
RequiresNoncopyableGenerics,
/*requiresRevisionMatch=*/true, requiredSDK,
&extInfo, pathRecoverer);
if (info.status != Status::Valid) {
error(info.status);