Skip to content

Commit 06a3226

Browse files
authored
Merge pull request swiftlang#36199 from bnbarham/add-error-flag
[Deserialization] Output a diagnostic for invalid decls or types
2 parents 8b34d8b + ce70727 commit 06a3226

File tree

8 files changed

+94
-37
lines changed

8 files changed

+94
-37
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ class alignas(1 << DeclAlignInBits) Decl {
678678
friend class DeclIterator;
679679
friend class IterableDeclContext;
680680
friend class MemberLookupTable;
681+
friend class DeclDeserializer;
681682

682683
private:
683684
llvm::PointerUnion<DeclContext *, ASTContext *> Context;
@@ -694,6 +695,10 @@ class alignas(1 << DeclAlignInBits) Decl {
694695
};
695696
mutable CachedExternalSourceLocs const *CachedSerializedLocs = nullptr;
696697
const CachedExternalSourceLocs *getSerializedLocs() const;
698+
699+
/// Directly set the invalid bit
700+
void setInvalidBit();
701+
697702
protected:
698703

699704
Decl(DeclKind kind, llvm::PointerUnion<DeclContext *, ASTContext *> context)

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,9 +776,18 @@ NOTE(serialization_compatibility_version_mismatch,none,
776776
"(this is supported but may expose additional compiler issues)",
777777
(StringRef, StringRef, StringRef))
778778

779+
ERROR(serialization_invalid_decl,Fatal,
780+
"deserialized invalid declaration %0 (%1) in module '%2'",
781+
(DeclName, DescriptiveDeclKind, StringRef))
779782
ERROR(serialization_allowing_invalid_decl,none,
780-
"allowing deserialization of invalid declaration %0 from module '%1'",
781-
(DeclName, StringRef))
783+
"allowing deserialization of invalid declaration %0 (%1) in module '%2'",
784+
(DeclName, DescriptiveDeclKind, StringRef))
785+
ERROR(serialization_error_type,Fatal,
786+
"deserialized error type '%0' in module '%1'",
787+
(StringRef, StringRef))
788+
ERROR(serialization_allowing_error_type,none,
789+
"allowing deserialization of error type '%0' in module '%1'",
790+
(StringRef, StringRef))
782791

783792
ERROR(reserved_member_name,none,
784793
"type member must not be named %0, since it would conflict with the"

lib/AST/Decl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ bool Decl::isInvalid() const {
453453
llvm_unreachable("Unknown decl kind");
454454
}
455455

456+
void Decl::setInvalidBit() { Bits.Decl.Invalid = true; }
457+
456458
void Decl::setInvalid() {
457459
switch (getKind()) {
458460
#define VALUE_DECL(ID, PARENT)

lib/Serialization/DeclTypeRecordNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ OTHER(CLANG_TYPE, 253)
196196

197197
OTHER(DERIVATIVE_FUNCTION_CONFIGURATION, 254)
198198

199+
OTHER(ERROR_FLAG, 255)
200+
199201
#undef RECORD
200202
#undef DECLTYPERECORDNODES_HAS_RECORD_VAL
201203
#undef RECORD_VAL

lib/Serialization/Deserialization.cpp

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,8 @@ class DeclDeserializer {
23692369
ASTContext &ctx;
23702370
Serialized<Decl *> &declOrOffset;
23712371

2372+
bool IsInvalid = false;
2373+
23722374
DeclAttribute *DAttrs = nullptr;
23732375
DeclAttribute **AttrsNext = &DAttrs;
23742376

@@ -2421,6 +2423,22 @@ class DeclDeserializer {
24212423
if (!decl)
24222424
return;
24232425

2426+
if (IsInvalid) {
2427+
decl->setInvalidBit();
2428+
2429+
DeclName name;
2430+
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
2431+
name = VD->getName();
2432+
}
2433+
2434+
auto diagId = ctx.LangOpts.AllowModuleWithCompilerErrors
2435+
? diag::serialization_allowing_invalid_decl
2436+
: diag::serialization_invalid_decl;
2437+
ctx.Diags.diagnose(SourceLoc(), diagId, name,
2438+
decl->getDescriptiveKind(),
2439+
MF.getAssociatedModule()->getNameStr());
2440+
}
2441+
24242442
if (DAttrs)
24252443
decl->getAttrs().setRawAttributeChain(DAttrs);
24262444

@@ -2436,10 +2454,9 @@ class DeclDeserializer {
24362454
}
24372455
}
24382456

2439-
/// Deserializes decl attribute and attribute-like records from
2440-
/// \c MF.DeclTypesCursor until a non-attribute record is found,
2441-
/// passing each one to AddAttribute.
2442-
llvm::Error deserializeDeclAttributes();
2457+
/// Deserializes records common to all decls from \c MF.DeclTypesCursor (ie.
2458+
/// the invalid flag, attributes, and discriminators)
2459+
llvm::Error deserializeDeclCommon();
24432460

24442461
Expected<Decl *> getDeclCheckedImpl(
24452462
llvm::function_ref<bool(DeclAttributes)> matchAttributes = nullptr);
@@ -4083,19 +4100,6 @@ ModuleFile::getDeclChecked(
40834100
matchAttributes);
40844101
if (!deserialized)
40854102
return deserialized;
4086-
4087-
auto *decl = declOrOffset.get();
4088-
if (isAllowModuleWithCompilerErrorsEnabled() && decl->isInvalid()) {
4089-
if (!isa<ParamDecl>(decl) && !decl->isImplicit()) {
4090-
// The parent function will be invalid if the parameter is invalid,
4091-
// implicits should have an invalid explicit as well
4092-
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
4093-
getContext().Diags.diagnose(
4094-
VD->getLoc(), diag::serialization_allowing_invalid_decl,
4095-
VD->getName(), VD->getModuleContext()->getNameStr());
4096-
}
4097-
}
4098-
}
40994103
} else if (matchAttributes) {
41004104
// Decl was cached but we may need to filter it
41014105
if (!matchAttributes(declOrOffset.get()->getAttrs()))
@@ -4115,7 +4119,7 @@ ModuleFile::getDeclChecked(
41154119
return declOrOffset;
41164120
}
41174121

4118-
llvm::Error DeclDeserializer::deserializeDeclAttributes() {
4122+
llvm::Error DeclDeserializer::deserializeDeclCommon() {
41194123
using namespace decls_block;
41204124

41214125
SmallVector<uint64_t, 64> scratch;
@@ -4132,7 +4136,10 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
41324136
unsigned recordID = MF.fatalIfUnexpected(
41334137
MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
41344138

4135-
if (isDeclAttrRecord(recordID)) {
4139+
if (recordID == ERROR_FLAG) {
4140+
assert(!IsInvalid && "Error flag written multiple times");
4141+
IsInvalid = true;
4142+
} else if (isDeclAttrRecord(recordID)) {
41364143
DeclAttribute *Attr = nullptr;
41374144
bool skipAttr = false;
41384145
switch (recordID) {
@@ -4459,7 +4466,7 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
44594466
// because it requires `DifferentiableAttr::setOriginalDeclaration` to
44604467
// be called first. `DifferentiableAttr::setOriginalDeclaration` cannot
44614468
// be called here because the original declaration is not accessible in
4462-
// this function (`DeclDeserializer::deserializeDeclAttributes`).
4469+
// this function (`DeclDeserializer::deserializeDeclCommon`).
44634470
diffAttrParamIndicesMap[diffAttr] = indices;
44644471
diffAttr->setDerivativeGenericSignature(derivativeGenSig);
44654472
Attr = diffAttr;
@@ -4616,9 +4623,9 @@ Expected<Decl *>
46164623
DeclDeserializer::getDeclCheckedImpl(
46174624
llvm::function_ref<bool(DeclAttributes)> matchAttributes) {
46184625

4619-
auto attrError = deserializeDeclAttributes();
4620-
if (attrError)
4621-
return std::move(attrError);
4626+
auto commonError = deserializeDeclCommon();
4627+
if (commonError)
4628+
return std::move(commonError);
46224629

46234630
if (matchAttributes) {
46244631
// Deserialize the full decl only if matchAttributes finds a match.
@@ -5764,19 +5771,28 @@ class TypeDeserializer {
57645771

57655772
Expected<Type> deserializeErrorType(ArrayRef<uint64_t> scratch,
57665773
StringRef blobData) {
5767-
if (!MF.isAllowModuleWithCompilerErrorsEnabled())
5768-
MF.fatal();
5769-
57705774
TypeID origID;
57715775
decls_block::ErrorTypeLayout::readRecord(scratch, origID);
57725776

5773-
auto origTy = MF.getTypeChecked(origID);
5774-
if (!origTy)
5775-
return origTy.takeError();
5777+
auto origTyOrError = MF.getTypeChecked(origID);
5778+
if (!origTyOrError)
5779+
return origTyOrError.takeError();
5780+
5781+
auto origTy = *origTyOrError;
5782+
auto diagId = ctx.LangOpts.AllowModuleWithCompilerErrors
5783+
? diag::serialization_allowing_error_type
5784+
: diag::serialization_error_type;
5785+
// Generally not a super useful diagnostic, so only output once if there
5786+
// hasn't been any other diagnostic yet to ensure nothing slips by and
5787+
// causes SILGen to crash.
5788+
if (!ctx.hadError()) {
5789+
ctx.Diags.diagnose(SourceLoc(), diagId, StringRef(origTy.getString()),
5790+
MF.getAssociatedModule()->getNameStr());
5791+
}
57765792

5777-
if (!origTy.get())
5793+
if (!origTy)
57785794
return ErrorType::get(ctx);
5779-
return ErrorType::get(origTy.get());
5795+
return ErrorType::get(origTy);
57805796
}
57815797
};
57825798
}

lib/Serialization/ModuleFormat.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 600; // custom attr (unsafe)
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 601; // diagnose invalid AST
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -926,6 +926,11 @@ namespace decls_block {
926926
BCArray<BCVBR<6>>
927927
>;
928928

929+
/// A flag to mark a decl as being invalid
930+
using ErrorFlagLayout = BCRecordLayout<
931+
ERROR_FLAG
932+
>;
933+
929934
/// A placeholder for invalid types
930935
using ErrorTypeLayout = BCRecordLayout<
931936
ERROR_TYPE,

lib/Serialization/Serialization.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3001,6 +3001,9 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
30013001
}
30023002

30033003
void visit(const Decl *D) {
3004+
if (D->isInvalid())
3005+
writeDeclErrorFlag();
3006+
30043007
// Emit attributes (if any).
30053008
for (auto Attr : D->getAttrs())
30063009
writeDeclAttribute(D, Attr);
@@ -3015,6 +3018,12 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
30153018
DeclVisitor<DeclSerializer>::visit(const_cast<Decl *>(D));
30163019
}
30173020

3021+
void writeDeclErrorFlag() {
3022+
using namespace decls_block;
3023+
unsigned abbrCode = S.DeclTypeAbbrCodes[ErrorFlagLayout::Code];
3024+
ErrorFlagLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode);
3025+
}
3026+
30183027
void noteUseOfExportedPrespecialization(const AbstractFunctionDecl *afd) {
30193028
for (auto *A : afd->getAttrs().getAttributes<SpecializeAttr>()) {
30203029
auto *SA = cast<SpecializeAttr>(A);
@@ -4675,6 +4684,8 @@ void Serializer::writeAllDeclsAndTypes() {
46754684
registerDeclTypeAbbr<UnboundGenericTypeLayout>();
46764685
registerDeclTypeAbbr<OptionalTypeLayout>();
46774686
registerDeclTypeAbbr<DynamicSelfTypeLayout>();
4687+
4688+
registerDeclTypeAbbr<ErrorFlagLayout>();
46784689
registerDeclTypeAbbr<ErrorTypeLayout>();
46794690

46804691
registerDeclTypeAbbr<ClangTypeLayout>();

test/Frontend/allow-errors.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ func test(s: ValidStructInvalidMember) {
6868
// there were no errors)
6969
func other() -> Int {}
7070
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:22: error: missing return in a function expected to return 'Int'
71+
func other2() -> Bool {}
72+
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:24: error: missing return in a function expected to return 'Bool'
7173
#endif
7274

7375
// All invalid uses should have no errors in the file itself, all referenced
@@ -82,7 +84,8 @@ func test() {
8284
invalidFunc()
8385
}
8486
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
85-
// CHECK-INVALID-TOP: error: allowing deserialization of invalid declaration 'invalidFunc()' from module 'errors'
87+
// CHECK-INVALID-TOP: error: allowing deserialization of error type '<null>' in module 'errors'
88+
// CHECK-INVALID-TOP: error: allowing deserialization of invalid declaration 'invalidFunc()' (global function) in module 'errors'
8689
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
8790
#endif
8891

@@ -94,7 +97,9 @@ func test(s: ValidStructInvalidMember) {
9497
print(s.memberMissingType)
9598
}
9699
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
97-
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration 'memberMissingType' from module 'errors'
100+
// CHECK-INVALID-MEMBER: error: allowing deserialization of error type '<null>' in module 'errors'
101+
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration '_' (getter) in module 'errors'
102+
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration 'memberMissingType' (property) in module 'errors'
98103
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
99104
#endif
100105

@@ -106,6 +111,8 @@ func test(s: ValidStructInvalidMember) {
106111
s.funcBadArg()
107112
}
108113
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
109-
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'funcBadArg' from module 'errors'
114+
// CHECK-INVALID-METHOD: error: allowing deserialization of error type '<null>' in module 'errors'
115+
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'arg' (parameter) in module 'errors'
116+
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'funcBadArg' (instance method) in module 'errors'
110117
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
111118
#endif

0 commit comments

Comments
 (0)