Skip to content

[Serialization] Write in the binary swiftmodule file whether it was rebuilt from a swiftinterface #61789

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 2 commits into from
Oct 29, 2022
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
6 changes: 5 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
HasAnyUnavailableValues : 1
);

SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1,
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1,
/// If the module is compiled as static library.
StaticLibrary : 1,

Expand All @@ -632,6 +632,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
/// \sa ResilienceStrategy
RawResilienceStrategy : 1,

/// Whether the module was rebuilt from a module interface instead of being
/// build from the full source.
IsBuiltFromInterface : 1,

/// Whether all imports have been resolved. Used to detect circular imports.
HasResolvedImports : 1,

Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,15 @@ class ModuleDecl
Bits.ModuleDecl.IsSystemModule = flag;
}

/// Returns true if the module was rebuilt from a module interface instead
/// of being build from the full source.
bool isBuiltFromInterface() const {
return Bits.ModuleDecl.IsBuiltFromInterface;
}
void setIsBuiltFromInterface(bool flag = true) {
Bits.ModuleDecl.IsBuiltFromInterface = flag;
}

/// Returns true if this module is a non-Swift module that was imported into
/// Swift.
///
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Serialization/Validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class ExtendedValidationInfo {
unsigned IsTestable : 1;
unsigned ResilienceStrategy : 2;
unsigned IsImplicitDynamicEnabled : 1;
unsigned IsBuiltFromInterface : 1;
unsigned IsAllowModuleWithCompilerErrorsEnabled : 1;
unsigned IsConcurrencyChecked : 1;
} Bits;
Expand Down Expand Up @@ -163,6 +164,10 @@ class ExtendedValidationInfo {
void setResilienceStrategy(ResilienceStrategy resilience) {
Bits.ResilienceStrategy = unsigned(resilience);
}
bool isBuiltFromInterface() const { return Bits.IsBuiltFromInterface; }
void setIsBuiltFromInterface(bool val) {
Bits.IsBuiltFromInterface = val;
}
bool isAllowModuleWithCompilerErrorsEnabled() {
return Bits.IsAllowModuleWithCompilerErrorsEnabled;
}
Expand Down
1 change: 1 addition & 0 deletions lib/Frontend/ModuleInterfaceBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface(

SILOptions &SILOpts = Invocation.getSILOptions();
auto Mod = Instance.getMainModule();
Mod->setIsBuiltFromInterface(true);
auto &TC = Instance.getSILTypes();
auto SILMod = performASTLowering(Mod, TC, SILOpts);
if (!SILMod) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,10 @@ class ModuleFile
return ResilienceStrategy(Core->Bits.ResilienceStrategy);
}

bool isBuiltFromInterface() const {
return Core->Bits.IsBuiltFromInterface;
}

/// Whether this module is compiled with implicit dynamic.
bool isImplicitDynamicEnabled() const {
return Core->Bits.IsImplicitDynamicEnabled;
Expand Down
17 changes: 13 additions & 4 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
options_block::ResilienceStrategyLayout::readRecord(scratch, Strategy);
extendedInfo.setResilienceStrategy(ResilienceStrategy(Strategy));
break;
case options_block::IS_BUILT_FROM_INTERFACE:
extendedInfo.setIsBuiltFromInterface(true);
break;
case options_block::IS_ALLOW_MODULE_WITH_COMPILER_ERRORS_ENABLED:
extendedInfo.setAllowModuleWithCompilerErrorsEnabled(true);
break;
Expand Down Expand Up @@ -581,12 +584,17 @@ void ModuleFileSharedCore::fatal(llvm::Error error) const {
}

void ModuleFileSharedCore::outputDiagnosticInfo(llvm::raw_ostream &os) const {
os << "module '" << Name << "' with full misc version '" << MiscVersion
<< "'";
bool resilient = ResilienceStrategy(Bits.ResilienceStrategy) ==
ResilienceStrategy::Resilient;
os << "module '" << Name
<< "', builder version '" << MiscVersion
<< "', built from "
<< (Bits.IsBuiltFromInterface? "swiftinterface": "source")
<< ", " << (resilient? "resilient": "non-resilient");
if (Bits.IsAllowModuleWithCompilerErrorsEnabled)
os << " (built with -experimental-allow-module-with-compiler-errors)";
os << ", built with -experimental-allow-module-with-compiler-errors";
if (ModuleInputBuffer)
os << " at '" << ModuleInputBuffer->getBufferIdentifier() << "'";
os << ", loaded from '" << ModuleInputBuffer->getBufferIdentifier() << "'";
}

ModuleFileSharedCore::~ModuleFileSharedCore() { }
Expand Down Expand Up @@ -1319,6 +1327,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
Bits.IsTestable = extInfo.isTestable();
Bits.ResilienceStrategy = unsigned(extInfo.getResilienceStrategy());
Bits.IsImplicitDynamicEnabled = extInfo.isImplicitDynamicEnabled();
Bits.IsBuiltFromInterface = extInfo.isBuiltFromInterface();
Bits.IsAllowModuleWithCompilerErrorsEnabled =
extInfo.isAllowModuleWithCompilerErrorsEnabled();
Bits.IsConcurrencyChecked = extInfo.isConcurrencyChecked();
Expand Down
6 changes: 5 additions & 1 deletion lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,10 @@ class ModuleFileSharedCore {
/// Discriminator for resilience strategy.
unsigned ResilienceStrategy : 2;

/// Whether the module was rebuilt from a module interface instead of being
/// build from the full source.
unsigned IsBuiltFromInterface: 1;

/// Whether this module is compiled with implicit dynamic.
unsigned IsImplicitDynamicEnabled: 1;

Expand All @@ -357,7 +361,7 @@ class ModuleFileSharedCore {
unsigned IsConcurrencyChecked: 1;

// Explicitly pad out to the next word boundary.
unsigned : 5;
unsigned : 4;
} Bits = {};
static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small");

Expand Down
7 changes: 6 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 718; // element archetype
const uint16_t SWIFTMODULE_VERSION_MINOR = 719; // isBuiltFromInterface

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -826,6 +826,7 @@ namespace options_block {
RESILIENCE_STRATEGY,
ARE_PRIVATE_IMPORTS_ENABLED,
IS_IMPLICIT_DYNAMIC_ENABLED,
IS_BUILT_FROM_INTERFACE,
IS_ALLOW_MODULE_WITH_COMPILER_ERRORS_ENABLED,
MODULE_ABI_NAME,
IS_CONCURRENCY_CHECKED,
Expand Down Expand Up @@ -871,6 +872,10 @@ namespace options_block {
BCFixed<2>
>;

using IsBuiltFromInterfaceLayout = BCRecordLayout<
IS_BUILT_FROM_INTERFACE
>;

using IsAllowModuleWithCompilerErrorsEnabledLayout = BCRecordLayout<
IS_ALLOW_MODULE_WITH_COMPILER_ERRORS_ENABLED
>;
Expand Down
5 changes: 5 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,11 @@ void Serializer::writeHeader(const SerializationOptions &options) {
Strategy.emit(ScratchRecord, unsigned(M->getResilienceStrategy()));
}

if (M->isBuiltFromInterface()) {
options_block::IsBuiltFromInterfaceLayout BuiltFromInterface(Out);
BuiltFromInterface.emit(ScratchRecord);
}

if (allowCompilerErrors()) {
options_block::IsAllowModuleWithCompilerErrorsEnabledLayout
AllowErrors(Out);
Expand Down
2 changes: 2 additions & 0 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
M.setImplicitDynamicEnabled();
if (loadedModuleFile->hasIncrementalInfo())
M.setHasIncrementalInfo();
if (loadedModuleFile->isBuiltFromInterface())
M.setIsBuiltFromInterface();
if (!loadedModuleFile->getModuleABIName().empty())
M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName()));
if (loadedModuleFile->isConcurrencyChecked())
Expand Down
2 changes: 1 addition & 1 deletion test/Serialization/Recovery/crash-recovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ public class Sub: Base {
// CHECK-CRASH-LABEL: *** DESERIALIZATION FAILURE ***
// CHECK-CRASH-LABEL: *** If any module named here was modified in the SDK, please delete the ***
// CHECK-CRASH-LABEL: *** new swiftmodule files from the SDK and keep only swiftinterfaces. ***
// CHECK-CRASH: module 'Lib' with full misc version {{.*}}4.1.50
// CHECK-CRASH: module 'Lib', builder version {{.*}}4.1.50
// CHECK-CRASH: could not find 'disappearingMethod()' in parent class
22 changes: 17 additions & 5 deletions test/Serialization/Recovery/crash-xref.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
// RUN: %empty-directory(%t/partials)
// RUN: %empty-directory(%t/normal)
// RUN: %empty-directory(%t/errors)
// RUN: %empty-directory(%t/cache)

/// Compile module A with a type and an empty module B.
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/A.swiftmodule -module-name A -D LIB
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/B.swiftmodule -module-name B
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/A.swiftmodule -module-name A -D LIB -enable-library-evolution
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/B.swiftmodule -module-name B -enable-library-evolution

/// Compile a client using the type from A.
// RUN: %target-swift-frontend %s -emit-module-path %t/normal/Client.swiftmodule -module-name Client -D CLIENT -I %t/partials
// RUN: %target-swift-frontend %s -emit-module-path %t/normal/Client.swiftmodule -module-name Client -D CLIENT -I %t/partials -enable-library-evolution -emit-module-interface-path %t/normal/Client.swiftinterface
// RUN: %target-swift-frontend %s -emit-module-path %t/errors/Client.swiftmodule -module-name Client -D CLIENT -I %t/partials -experimental-allow-module-with-compiler-errors

/// Force rebuilding from the swiftinterface.
// RUN: mv %t/normal/Client.swiftmodule %t/swap-Client.swiftmodule
// RUN: echo "import Client" | %target-swift-frontend -typecheck - -I %t/partials -I %t/normal -module-cache-path %t/cache/
//2> /dev/null
// RUN: mv %t/swap-Client.swiftmodule %t/normal/Client.swiftmodule

/// Swap A and B around! A is now empty and B defines the type.
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/A.swiftmodule -module-name A
// RUN: %target-swift-frontend %s -emit-module-path %t/partials/B.swiftmodule -module-name B -D LIB
Expand All @@ -25,7 +32,7 @@
// NORMALFAILURE-LABEL: *** DESERIALIZATION FAILURE ***
// NORMALFAILURE-LABEL: *** If any module named here was modified in the SDK, please delete the ***
// NORMALFAILURE-LABEL: *** new swiftmodule files from the SDK and keep only swiftinterfaces. ***
// NORMALFAILURE-NEXT: module 'Client' with full misc version {{.*}}'
// NORMALFAILURE-NEXT: module 'Client', builder version {{.*}}', built from source, resilient, loaded from
// NORMALFAILURE-NEXT: Could not deserialize type for 'foo()'
// NORMALFAILURE-NEXT: Caused by: top-level value not found
// NORMALFAILURE-NEXT: Cross-reference to module 'A'
Expand All @@ -37,14 +44,19 @@
// ALLOWFAILURE-LABEL: *** DESERIALIZATION FAILURE ***
// ALLOWFAILURE-LABEL: *** If any module named here was modified in the SDK, please delete the ***
// ALLOWFAILURE-LABEL: *** new swiftmodule files from the SDK and keep only swiftinterfaces. ***
// ALLOWFAILURE-NEXT: module 'Client' with full misc version {{.*}}' (built with -experimental-allow-module-with-compiler-errors)
// ALLOWFAILURE-NEXT: module 'Client', builder version {{.*}}', built from source, non-resilient, built with -experimental-allow-module-with-compiler-errors, loaded from
// ALLOWFAILURE-NEXT: Could not deserialize type for 'foo()'
// ALLOWFAILURE-NEXT: Caused by: top-level value not found
// ALLOWFAILURE-NEXT: Cross-reference to module 'A'
// ALLOWFAILURE-NEXT: ... SomeType
// ALLOWFAILURE-NEXT: Notes:
// ALLOWFAILURE-NEXT: * There is a matching 'SomeType' in module 'B'. If this is imported from clang, please make sure the header is part of a single clang module.

/// Test a swiftmodule rebuilt from the swiftinterface.
// RUN: not --crash %target-swift-frontend -emit-sil %t/cache/Client-*.swiftmodule -module-name Client -I %t/partials -disable-deserialization-recovery 2> %t/cache_stderr
// RUN: cat %t/cache_stderr | %FileCheck %s -check-prefixes=CACHEFAILURE
// CACHEFAILURE: module 'Client', builder version {{.*}}', built from swiftinterface, resilient

#if LIB
public struct SomeType {
public init() {}
Expand Down