Skip to content

Commit 642980c

Browse files
committed
[Serialization] Add flag to force unsafe recovery from some xref failures
Intro a deserialization mode controlled by the flag `-experimental-force-workaround-broken-modules` to attempt unsafe recovery from deserialization failures caused by project issues. The one issue handled at this time is when a type moves from one module to another. With this new mode the compiler may be able to pick a matching type in a different module. This is risky to use, but may help in a pinch for a client to fix and issue in a library over which they have no control.
1 parent 144d7eb commit 642980c

File tree

6 files changed

+53
-10
lines changed

6 files changed

+53
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,10 @@ NOTE(modularization_issue_side_effect_type_error,none,
893893
"could not deserialize type for %0",
894894
(DeclName))
895895

896+
NOTE(modularization_issue_worked_around,none,
897+
"attempting forced recovery using top-level declaration from %0",
898+
(Identifier))
899+
896900
ERROR(reserved_member_name,none,
897901
"type member must not be named %0, since it would conflict with the"
898902
" 'foo.%1' expression", (DeclName, StringRef))

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,11 @@ namespace swift {
390390
bool EnableDeserializationSafety =
391391
::getenv("SWIFT_ENABLE_DESERIALIZATION_SAFETY");
392392

393+
/// Attempt to recover for imported modules with broken modularization
394+
/// in an unsafe way. Currently applies only to xrefs where the target
395+
/// decl moved to a different module that is already loaded.
396+
bool ForceWorkaroundBrokenModules = false;
397+
393398
/// Whether to enable the new operator decl and precedencegroup lookup
394399
/// behavior. This is a staging flag, and will be removed in the future.
395400
bool EnableNewOperatorLookup = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,10 @@ def disable_deserialization_safety :
588588
Flag<["-"], "disable-deserialization-safety">,
589589
HelpText<"Don't avoid reading potentially unsafe decls in swiftmodules">;
590590

591+
def force_workaround_broken_modules :
592+
Flag<["-"], "experimental-force-workaround-broken-modules">,
593+
HelpText<"Attempt unsafe recovery for imported modules with broken modularization">;
594+
591595
def enable_experimental_string_processing :
592596
Flag<["-"], "enable-experimental-string-processing">,
593597
HelpText<"Enable experimental string processing">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
564564
Opts.EnableDeserializationSafety
565565
= A->getOption().matches(OPT_enable_deserialization_safety);
566566
}
567+
Opts.ForceWorkaroundBrokenModules
568+
|= Args.hasArg(OPT_force_workaround_broken_modules);
567569

568570
// Whether '/.../' regex literals are enabled. This implies experimental
569571
// string processing.

lib/Serialization/Deserialization.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,8 +1803,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18031803
}
18041804

18051805
auto getXRefDeclNameForError = [&]() -> DeclName {
1806+
BCOffsetRAII restoreOffset(DeclTypeCursor);
18061807
DeclName result = pathTrace.getLastName();
1807-
while (--pathLen) {
1808+
uint32_t namePathLen = pathLen;
1809+
while (--namePathLen) {
18081810
llvm::BitstreamEntry entry =
18091811
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
18101812
if (entry.Kind != llvm::BitstreamEntry::Record)
@@ -1869,8 +1871,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18691871
// up to the caller to recover if possible.
18701872

18711873
// Look for types and value decls in other modules. This extra information
1872-
// is mostly for compiler engineers to understand a likely solution at a
1873-
// quick glance.
1874+
// will be used for diagnostics by the caller logic.
18741875
SmallVector<char, 64> strScratch;
18751876

18761877
auto errorKind = ModularizationError::Kind::DeclNotFound;
@@ -1945,13 +1946,32 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
19451946
auto declName = getXRefDeclNameForError();
19461947
auto expectedIn = baseModule->getName();
19471948
auto referencedFrom = getName();
1948-
return llvm::make_error<ModularizationError>(declName,
1949-
isType,
1950-
errorKind,
1951-
expectedIn,
1952-
referencedFrom,
1953-
foundIn,
1954-
pathTrace);
1949+
auto error = llvm::make_error<ModularizationError>(declName,
1950+
isType,
1951+
errorKind,
1952+
expectedIn,
1953+
referencedFrom,
1954+
foundIn,
1955+
pathTrace);
1956+
1957+
// If we want to workaround broken modularization, we can keep going if
1958+
// we found a matching top-level decl in a different module. This is
1959+
// obviously dangerous as it could just be some other decl that happens to
1960+
// match.
1961+
if (getContext().LangOpts.ForceWorkaroundBrokenModules &&
1962+
errorKind == ModularizationError::Kind::DeclMoved &&
1963+
!values.empty()) {
1964+
// Print the error as a remark and notify of the recovery attempt.
1965+
llvm::handleAllErrors(std::move(error),
1966+
[&](const ModularizationError &modularError) {
1967+
modularError.diagnose(this, DiagnosticBehavior::Remark);
1968+
});
1969+
getContext().Diags.diagnose(getSourceLoc(),
1970+
diag::modularization_issue_worked_around,
1971+
foundIn);
1972+
} else {
1973+
return error;
1974+
}
19551975
}
19561976

19571977
// Filters for values discovered in the remaining path pieces.

test/Serialization/modularization-error.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
// RUN: | %FileCheck --check-prefixes CHECK,CHECK-MOVED %s
1515
// CHECK-MOVED: LibWithXRef.swiftmodule:1:1: error: reference to type 'MyType' broken by a context change; 'MyType' was expected to be in 'A', but now a candidate is found only in 'B'
1616

17+
/// Force working around the broken modularization to get a result and no errors.
18+
// RUN: %target-swift-frontend -emit-sil %t/LibWithXRef.swiftmodule -module-name LibWithXRef -I %t \
19+
// RUN: -experimental-force-workaround-broken-modules 2>&1 \
20+
// RUN: | %FileCheck --check-prefixes CHECK-WORKAROUND %s
21+
// CHECK-WORKAROUND: remark: reference to type 'MyType' broken by a context change; 'MyType' was expected to be in 'A', but now a candidate is found only in 'B'
22+
// CHECK-WORKAROUND: note: attempting forced recovery using top-level declaration from 'B'
23+
// CHECK-WORKAROUND: func foo() -> some Proto
24+
1725
/// Change MyType into a function.
1826
// RUN: %target-swift-frontend %t/LibTypeChanged.swift -emit-module-path %t/A.swiftmodule -module-name A
1927
// RUN: %target-swift-frontend %t/Empty.swift -emit-module-path %t/B.swiftmodule -module-name B

0 commit comments

Comments
 (0)