Skip to content

Commit 62d5f6f

Browse files
authored
Merge pull request #71739 from tshortli/module-serialization-remarks
Serialization: Skip invalid decls during module serialization
2 parents b79c4de + b46d179 commit 62d5f6f

File tree

9 files changed

+146
-16
lines changed

9 files changed

+146
-16
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,19 @@ 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+
REMARK(serialization_skipped_invalid_type,none,
815+
"serialization skipped for invalid type %0",
816+
(TypeRepr *))
817+
REMARK(serialization_skipped_invalid_type_unknown_name,none,
818+
"serialization skipped for invalid type",
819+
())
820+
ERROR(serialization_failed,none,
821+
"serialization of module %0 failed due to the errors above",
822+
(const ModuleDecl *))
823+
811824
ERROR(serialization_load_failed,Fatal,
812825
"failed to load module '%0'", (StringRef))
813826
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: 69 additions & 16 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"
@@ -3045,12 +3046,12 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
30453046
if (D->getResolvedMacro(const_cast<CustomAttr *>(theAttr)))
30463047
return;
30473048

3048-
auto typeID = S.addTypeRef(
3049-
D->getResolvedCustomAttrType(const_cast<CustomAttr *>(theAttr)));
3050-
if (!typeID && !S.allowCompilerErrors()) {
3051-
llvm::PrettyStackTraceString message("CustomAttr has no type");
3052-
abort();
3053-
}
3049+
auto attrType =
3050+
D->getResolvedCustomAttrType(const_cast<CustomAttr *>(theAttr));
3051+
if (S.skipTypeIfInvalid(attrType, theAttr->getTypeRepr()))
3052+
return;
3053+
3054+
auto typeID = S.addTypeRef(attrType);
30543055
CustomDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
30553056
theAttr->isImplicit(),
30563057
typeID, theAttr->isArgUnsafe());
@@ -3656,27 +3657,37 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
36563657
}
36573658
case PatternKind::Named: {
36583659
auto named = cast<NamedPattern>(pattern);
3660+
auto ty = getPatternType();
3661+
if (S.skipTypeIfInvalid(ty, named->getLoc()))
3662+
break;
36593663

36603664
unsigned abbrCode = S.DeclTypeAbbrCodes[NamedPatternLayout::Code];
36613665
NamedPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
36623666
S.addDeclRef(named->getDecl()),
3663-
S.addTypeRef(getPatternType()));
3667+
S.addTypeRef(ty));
36643668
break;
36653669
}
36663670
case PatternKind::Any: {
3671+
auto ty = getPatternType();
3672+
if (S.skipTypeIfInvalid(ty, pattern->getLoc()))
3673+
break;
3674+
36673675
unsigned abbrCode = S.DeclTypeAbbrCodes[AnyPatternLayout::Code];
36683676
auto anyPattern = cast<AnyPattern>(pattern);
36693677
AnyPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
3670-
S.addTypeRef(getPatternType()),
3678+
S.addTypeRef(ty),
36713679
anyPattern->isAsyncLet());
36723680
break;
36733681
}
36743682
case PatternKind::Typed: {
36753683
auto typed = cast<TypedPattern>(pattern);
3684+
auto ty = getPatternType();
3685+
if (S.skipTypeIfInvalid(ty, typed->getTypeRepr()))
3686+
break;
36763687

36773688
unsigned abbrCode = S.DeclTypeAbbrCodes[TypedPatternLayout::Code];
36783689
TypedPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
3679-
S.addTypeRef(getPatternType()));
3690+
S.addTypeRef(ty));
36803691
writePattern(typed->getSubPattern());
36813692
break;
36823693
}
@@ -4996,13 +5007,8 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
49965007
PrettyStackTraceDecl trace("serializing", D);
49975008
assert(DeclsToSerialize.hasRef(D));
49985009

4999-
if (D->isInvalid()) {
5000-
assert(allowCompilerErrors() &&
5001-
"cannot create a module with an invalid decl");
5002-
5003-
if (canSkipWhenInvalid(D))
5004-
return;
5005-
}
5010+
if (skipDeclIfInvalid(D))
5011+
return;
50065012

50075013
BitOffset initialOffset = Out.GetCurrentBitNo();
50085014
SWIFT_DEFER {
@@ -6780,6 +6786,11 @@ void Serializer::writeToStream(
67806786
S.writeInputBlock();
67816787
S.writeSIL(SILMod, options.SerializeAllSIL);
67826788
S.writeAST(DC);
6789+
6790+
if (S.hadError)
6791+
S.getASTContext().Diags.diagnose(SourceLoc(), diag::serialization_failed,
6792+
S.M);
6793+
67836794
if (!options.DisableCrossModuleIncrementalInfo && DepGraph) {
67846795
fine_grained_dependencies::writeFineGrainedDependencyGraph(
67856796
S.Out, *DepGraph, fine_grained_dependencies::Purpose::ForSwiftModule);
@@ -6793,6 +6804,48 @@ bool Serializer::allowCompilerErrors() const {
67936804
return getASTContext().LangOpts.AllowModuleWithCompilerErrors;
67946805
}
67956806

6807+
bool Serializer::skipDeclIfInvalid(const Decl *decl) {
6808+
if (!decl->isInvalid())
6809+
return false;
6810+
6811+
if (allowCompilerErrors())
6812+
return canSkipWhenInvalid(decl);
6813+
6814+
if (Options.EnableSerializationRemarks) {
6815+
getASTContext().Diags.diagnose(
6816+
decl->getLoc(), diag::serialization_skipped_invalid_decl, decl);
6817+
}
6818+
6819+
hadError = true;
6820+
return true;
6821+
}
6822+
6823+
bool Serializer::skipTypeIfInvalid(Type ty, TypeRepr *tyRepr) {
6824+
if ((ty && !ty->hasError()) || allowCompilerErrors())
6825+
return false;
6826+
6827+
if (Options.EnableSerializationRemarks) {
6828+
getASTContext().Diags.diagnose(
6829+
tyRepr->getLoc(), diag::serialization_skipped_invalid_type, tyRepr);
6830+
}
6831+
6832+
hadError = true;
6833+
return true;
6834+
}
6835+
6836+
bool Serializer::skipTypeIfInvalid(Type ty, SourceLoc loc) {
6837+
if ((ty && !ty->hasError()) || allowCompilerErrors())
6838+
return false;
6839+
6840+
if (Options.EnableSerializationRemarks) {
6841+
getASTContext().Diags.diagnose(
6842+
loc, diag::serialization_skipped_invalid_type_unknown_name);
6843+
}
6844+
6845+
hadError = true;
6846+
return true;
6847+
}
6848+
67966849
void serialization::writeToStream(
67976850
raw_ostream &os, ModuleOrSourceFile DC, const SILModule *M,
67986851
const SerializationOptions &options,

lib/Serialization/Serialization.h

Lines changed: 17 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,19 @@ 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);
582+
583+
/// If the type is invalid, records that an error occurred and returns
584+
/// true if the type should be skipped.
585+
bool skipTypeIfInvalid(Type ty, TypeRepr *tyRepr);
586+
587+
/// If the type is invalid, records that an error occurred and returns
588+
/// true if the type should be skipped.
589+
bool skipTypeIfInvalid(Type ty, SourceLoc loc);
573590
};
574591

575592
} // end namespace serialization
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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'}}
19+
20+
@InvalidCustomAttr public struct HasInvalidCustomAttr {}
21+
// FIXME: An error should be emitted for the invalid attribute
22+
// expected-serialization-remark@-2 {{serialization skipped for invalid type 'InvalidCustomAttr'}}
23+
24+
public var varWithExplicitInvalidType: InvalidType
25+
// expected-error@-1 {{cannot find type 'InvalidType' in scope}}
26+
// expected-serialization-remark@-2 {{serialization skipped invalid var 'varWithExplicitInvalidType'}}
27+
// expected-serialization-remark@-3 {{serialization skipped for invalid type 'InvalidType'}}
28+
29+
public var varWithImplicitInvalidType = (1 as InvalidType)
30+
// expected-error@-1 {{cannot find type 'InvalidType' in scope}}
31+
// expected-serialization-remark@-2 {{serialization skipped invalid var 'varWithImplicitInvalidType'}}
32+
// expected-serialization-remark@-3 {{serialization skipped for invalid type}}
33+
34+
public var _: InvalidType

0 commit comments

Comments
 (0)