Skip to content

Commit 72da8f4

Browse files
committed
Serialization: Skip invalid decls during module serialization.
When `-enable-lazy-typecheck` is specified, serialization may be expected to run on an AST containing invalid declarations since type checking may happen on-demand, during serialization, in this mode. If the declarations that are invalid are not skipped, then the compiler is likely to crash when attempting to serialize them. Now, invalid declarations are skipped and an error is emitted at the end of serialization to note that serialization failed. Additionally, a new `-Rmodule-serialization` flag can be specified to request more detailed information about module serialization failures. This would be useful in a situation where lazy typechecking does not produce any diagnostic for some reason, but module serialization fails and more information is therefore required to debug. Resolves rdar://123260476
1 parent d4c54af commit 72da8f4

File tree

9 files changed

+71
-7
lines changed

9 files changed

+71
-7
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,13 @@ WARNING(sema_import_current_module_with_file,none,
808808
ERROR(sema_opening_import,Fatal,
809809
"opening import file for module %0: %1", (Identifier, StringRef))
810810

811+
REMARK(serialization_skipped_invalid_decl,none,
812+
"serialization skipped invalid %kind0",
813+
(const Decl *))
814+
ERROR(serialization_failed,none,
815+
"serialization of module %0 failed due to the errors above",
816+
(const ModuleDecl *))
817+
811818
ERROR(serialization_load_failed,Fatal,
812819
"failed to load module '%0'", (StringRef))
813820
ERROR(module_interface_build_failed,Fatal,

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ namespace swift {
243243
/// Emit remarks about contextual inconsistencies in loaded modules.
244244
bool EnableModuleRecoveryRemarks = false;
245245

246+
/// Emit remarks for unexpected conditions when serializing a module.
247+
bool EnableModuleSerializationRemarks = false;
248+
246249
/// Emit remarks about the source of each element exposed by the module API.
247250
bool EnableModuleApiImportRemarks = false;
248251

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,10 @@ def remark_skip_explicit_interface_build : Flag<["-"], "Rskip-explicit-interface
417417
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
418418
HelpText<"Emit a remark if an explicit module interface invocation has an early exit because the expected output is up-to-date">;
419419

420+
def remark_module_serialization : Flag<["-"], "Rmodule-serialization">,
421+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
422+
HelpText<"Emit remarks about module serialization">;
423+
420424
def emit_tbd : Flag<["-"], "emit-tbd">,
421425
HelpText<"Emit a TBD file">,
422426
Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput]>;

include/swift/Serialization/SerializationOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ namespace swift {
159159
bool IsOSSA = false;
160160
bool SkipNonExportableDecls = false;
161161
bool ExplicitModuleBuild = false;
162+
bool EnableSerializationRemarks = false;
162163
};
163164

164165
} // end namespace swift

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10881088

10891089
Opts.EnableModuleLoadingRemarks = Args.hasArg(OPT_remark_loading_module);
10901090
Opts.EnableModuleRecoveryRemarks = Args.hasArg(OPT_remark_module_recovery);
1091+
Opts.EnableModuleSerializationRemarks =
1092+
Args.hasArg(OPT_remark_module_serialization);
10911093
Opts.EnableModuleApiImportRemarks = Args.hasArg(OPT_remark_module_api_import);
10921094
Opts.EnableMacroLoadingRemarks = Args.hasArg(OPT_remark_macro_loading);
10931095
Opts.EnableIndexingSystemModuleRemarks = Args.hasArg(OPT_remark_indexing_system_module);

lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ SerializationOptions CompilerInvocation::computeSerializationOptions(
253253

254254
serializationOpts.ExplicitModuleBuild = FrontendOpts.DisableImplicitModules;
255255

256+
serializationOpts.EnableSerializationRemarks =
257+
getLangOptions().EnableModuleSerializationRemarks;
258+
256259
return serializationOpts;
257260
}
258261

lib/Serialization/Serialization.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/ASTVisitor.h"
1919
#include "swift/AST/AutoDiff.h"
2020
#include "swift/AST/DiagnosticsCommon.h"
21+
#include "swift/AST/DiagnosticsSema.h"
2122
#include "swift/AST/Expr.h"
2223
#include "swift/AST/FileSystem.h"
2324
#include "swift/AST/ForeignAsyncConvention.h"
@@ -4998,13 +4999,8 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
49984999
PrettyStackTraceDecl trace("serializing", D);
49995000
assert(DeclsToSerialize.hasRef(D));
50005001

5001-
if (D->isInvalid()) {
5002-
assert(allowCompilerErrors() &&
5003-
"cannot create a module with an invalid decl");
5004-
5005-
if (canSkipWhenInvalid(D))
5006-
return;
5007-
}
5002+
if (skipDeclIfInvalid(D))
5003+
return;
50085004

50095005
BitOffset initialOffset = Out.GetCurrentBitNo();
50105006
SWIFT_DEFER {
@@ -6782,6 +6778,11 @@ void Serializer::writeToStream(
67826778
S.writeInputBlock();
67836779
S.writeSIL(SILMod, options.SerializeAllSIL);
67846780
S.writeAST(DC);
6781+
6782+
if (S.hadError)
6783+
S.getASTContext().Diags.diagnose(SourceLoc(), diag::serialization_failed,
6784+
S.M);
6785+
67856786
if (!options.DisableCrossModuleIncrementalInfo && DepGraph) {
67866787
fine_grained_dependencies::writeFineGrainedDependencyGraph(
67876788
S.Out, *DepGraph, fine_grained_dependencies::Purpose::ForSwiftModule);
@@ -6795,6 +6796,22 @@ bool Serializer::allowCompilerErrors() const {
67956796
return getASTContext().LangOpts.AllowModuleWithCompilerErrors;
67966797
}
67976798

6799+
bool Serializer::skipDeclIfInvalid(const Decl *decl) {
6800+
if (!decl->isInvalid())
6801+
return false;
6802+
6803+
if (allowCompilerErrors())
6804+
return canSkipWhenInvalid(decl);
6805+
6806+
if (Options.EnableSerializationRemarks) {
6807+
getASTContext().Diags.diagnose(
6808+
decl->getLoc(), diag::serialization_skipped_invalid_decl, decl);
6809+
}
6810+
6811+
hadError = true;
6812+
return true;
6813+
}
6814+
67986815
void serialization::writeToStream(
67996816
raw_ostream &os, ModuleOrSourceFile DC, const SILModule *M,
68006817
const SerializationOptions &options,

lib/Serialization/Serialization.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ class Serializer : public SerializerBase {
112112

113113
SmallVector<DeclID, 16> exportedPrespecializationDecls;
114114

115+
/// Will be set to true if any serialization step failed, for example due to
116+
/// an error in the AST.
117+
bool hadError = false;
118+
115119
/// Helper for serializing entities in the AST block object graph.
116120
///
117121
/// Keeps track of assigning IDs to newly-seen entities, and collecting
@@ -570,6 +574,11 @@ class Serializer : public SerializerBase {
570574
void writePrimaryAssociatedTypes(ArrayRef<AssociatedTypeDecl *> assocTypes);
571575

572576
bool allowCompilerErrors() const;
577+
578+
private:
579+
/// If the declaration is invalid, records that an error occurred and returns
580+
/// true if the decl should be skipped.
581+
bool skipDeclIfInvalid(const Decl *decl);
573582
};
574583

575584
} // end namespace serialization
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Verify the -emit-module job fails with a broken AST.
2+
// RUN: not %target-swift-frontend -emit-module %s -emit-module-path /dev/null -module-name lazy_typecheck -swift-version 5 -enable-library-evolution -parse-as-library -experimental-lazy-typecheck -experimental-skip-all-function-bodies -experimental-skip-non-exportable-decls 2>&1 | %FileCheck %s
3+
4+
// CHECK: <unknown>:0: error: serialization of module 'lazy_typecheck' failed due to the errors above
5+
6+
// Verify typechecking errors are emitted.
7+
// RUN: %target-swift-frontend -emit-module %s -emit-module-path /dev/null -module-name lazy_typecheck -swift-version 5 -enable-library-evolution -parse-as-library -experimental-lazy-typecheck -experimental-skip-all-function-bodies -experimental-skip-non-exportable-decls -verify -verify-ignore-unknown
8+
9+
// Verify output with -Rmodule-serialization.
10+
// RUN: %target-swift-frontend -emit-module %s -emit-module-path /dev/null -module-name lazy_typecheck -swift-version 5 -enable-library-evolution -parse-as-library -experimental-lazy-typecheck -experimental-skip-all-function-bodies -experimental-skip-non-exportable-decls -verify -verify-ignore-unknown -Rmodule-serialization -verify-additional-prefix serialization-
11+
12+
public func returnsInvalidType() -> InvalidType { fatalError() }
13+
// expected-error@-1 {{cannot find type 'InvalidType' in scope}}
14+
// expected-serialization-remark@-2 {{serialization skipped invalid global function 'returnsInvalidType()'}}
15+
16+
public func takesInvalidType(_ x: InvalidType) {}
17+
// expected-error@-1 {{cannot find type 'InvalidType' in scope}}
18+
// expected-serialization-remark@-2 {{serialization skipped invalid global function 'takesInvalidType'}}

0 commit comments

Comments
 (0)