Skip to content

Commit e831dca

Browse files
committed
[Serialization] Save path traces from failed cross-references.
This is important information in a crash trace, so let's make sure to preserve it even as the stack unwinds.
1 parent 3dbc9de commit e831dca

File tree

3 files changed

+74
-28
lines changed

3 files changed

+74
-28
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,11 @@ ERROR(serialization_target_too_new_repl,none,
549549
"module file's minimum deployment target is %0 v%1.%2%select{|.%3}3: %4",
550550
(StringRef, unsigned, unsigned, unsigned, StringRef))
551551

552+
ERROR(serialization_fatal,Fatal,
553+
"fatal error encountered while reading from module '%0'; "
554+
"please file a bug report with your project and the crash log",
555+
(StringRef))
556+
552557
ERROR(reserved_member_name,none,
553558
"type member may not be named %0, since it would conflict with the"
554559
" 'foo.%1' expression", (DeclName, StringRef))

include/swift/Serialization/ModuleFile.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,10 @@ class ModuleFile : public LazyMemberLoader {
436436
return getStatus();
437437
}
438438

439+
/// Emits one last diagnostic, logs the error, and then aborts for the stack
440+
/// trace.
441+
void fatal(llvm::Error error) LLVM_ATTRIBUTE_NORETURN;
442+
439443
ASTContext &getContext() const {
440444
assert(FileContext && "no associated context yet");
441445
return FileContext->getParentModule()->getASTContext();

lib/Serialization/Deserialization.cpp

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "swift/Serialization/ModuleFile.h"
1414
#include "swift/Serialization/ModuleFormat.h"
1515
#include "swift/AST/ASTContext.h"
16+
#include "swift/AST/DiagnosticsSema.h"
1617
#include "swift/AST/ForeignErrorConvention.h"
1718
#include "swift/AST/GenericEnvironment.h"
1819
#include "swift/AST/Initializer.h"
@@ -95,7 +96,7 @@ namespace {
9596
}
9697
};
9798

98-
class PrettyXRefTrace : public llvm::PrettyStackTraceEntry {
99+
class XRefTracePath {
99100
class PathPiece {
100101
public:
101102
enum class Kind {
@@ -196,12 +197,11 @@ namespace {
196197
}
197198
};
198199

199-
private:
200200
ModuleDecl &baseM;
201201
SmallVector<PathPiece, 8> path;
202202

203203
public:
204-
PrettyXRefTrace(ModuleDecl &M) : baseM(M) {}
204+
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
205205

206206
void addValue(Identifier name) {
207207
path.push_back({ PathPiece::Kind::Value, name });
@@ -241,16 +241,27 @@ namespace {
241241
path.pop_back();
242242
}
243243

244-
void print(raw_ostream &os) const override {
244+
void print(raw_ostream &os, StringRef leading = "") const {
245245
os << "Cross-reference to module '" << baseM.getName() << "'\n";
246246
for (auto &piece : path) {
247-
os << "\t... ";
247+
os << leading << "... ";
248248
piece.print(os);
249249
os << "\n";
250250
}
251251
}
252252
};
253253

254+
class PrettyXRefTrace :
255+
public llvm::PrettyStackTraceEntry,
256+
public XRefTracePath {
257+
public:
258+
explicit PrettyXRefTrace(ModuleDecl &M) : XRefTracePath(M) {}
259+
260+
void print(raw_ostream &os) const override {
261+
XRefTracePath::print(os, "\t");
262+
}
263+
};
264+
254265
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
255266
const char *Action;
256267
const ModuleFile *MF;
@@ -262,6 +273,30 @@ namespace {
262273
os << Action << " \'" << getNameOfModule(MF) << "'\n";
263274
}
264275
};
276+
277+
class XRefError : public llvm::ErrorInfo<XRefError> {
278+
friend ErrorInfo;
279+
static const char ID;
280+
281+
XRefTracePath path;
282+
const char *message;
283+
public:
284+
template <size_t N>
285+
XRefError(const char (&message)[N], XRefTracePath path)
286+
: path(path), message(message) {}
287+
288+
void log(raw_ostream &OS) const override {
289+
OS << message << "\n";
290+
path.print(OS);
291+
}
292+
293+
std::error_code convertToErrorCode() const override {
294+
// This is a deprecated part of llvm::Error, so we just return a very
295+
// generic value.
296+
return {EINVAL, std::generic_category()};
297+
}
298+
};
299+
const char XRefError::ID = '\0';
265300
} // end anonymous namespace
266301

267302

@@ -286,6 +321,17 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
286321
#endif
287322
}
288323

324+
void ModuleFile::fatal(llvm::Error error) {
325+
if (FileContext) {
326+
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Name);
327+
}
328+
329+
logAllUnhandledErrors(std::move(error), llvm::errs(),
330+
"\n*** DESERIALIZATION FAILURE (please include this "
331+
"section in any bug report) ***\n");
332+
abort();
333+
}
334+
289335
ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
290336
assert(FileContext && "cannot delay actions before associating with a file");
291337
ModuleDecl *associatedModule = getAssociatedModule();
@@ -1421,9 +1467,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
14211467
}
14221468

14231469
if (values.empty()) {
1424-
return llvm::make_error<llvm::StringError>(
1425-
"top-level value not found",
1426-
std::error_code(EINVAL, std::generic_category()));
1470+
return llvm::make_error<XRefError>("top-level value not found", pathTrace);
14271471
}
14281472

14291473
// Filters for values discovered in the remaining path pieces.
@@ -1542,18 +1586,16 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
15421586
pathTrace.addType(filterTy);
15431587

15441588
if (values.size() != 1) {
1545-
return llvm::make_error<llvm::StringError>(
1546-
"multiple matching base values",
1547-
std::error_code(EINVAL, std::generic_category()));
1589+
return llvm::make_error<XRefError>("multiple matching base values",
1590+
pathTrace);
15481591
}
15491592

15501593
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
15511594
values.clear();
15521595

15531596
if (!nominal) {
1554-
return llvm::make_error<llvm::StringError>(
1555-
"base is not a nominal type",
1556-
std::error_code(EINVAL, std::generic_category()));
1597+
return llvm::make_error<XRefError>("base is not a nominal type",
1598+
pathTrace);
15571599
}
15581600

15591601
auto members = nominal->lookupDirect(memberName);
@@ -1642,9 +1684,8 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
16421684

16431685
case XREF_GENERIC_PARAM_PATH_PIECE: {
16441686
if (values.size() != 1) {
1645-
return llvm::make_error<llvm::StringError>(
1646-
"multiple matching base values",
1647-
std::error_code(EINVAL, std::generic_category()));
1687+
return llvm::make_error<XRefError>("multiple matching base values",
1688+
pathTrace);
16481689
}
16491690

16501691
uint32_t paramIndex;
@@ -1678,14 +1719,14 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
16781719
paramList = fn->getGenericParams();
16791720

16801721
if (!paramList) {
1681-
return llvm::make_error<llvm::StringError>(
1722+
return llvm::make_error<XRefError>(
16821723
"cross-reference to generic param for non-generic type",
1683-
std::error_code(EINVAL, std::generic_category()));
1724+
pathTrace);
16841725
}
16851726
if (paramIndex >= paramList->size()) {
1686-
return llvm::make_error<llvm::StringError>(
1727+
return llvm::make_error<XRefError>(
16871728
"generic argument index out of bounds",
1688-
std::error_code(EINVAL, std::generic_category()));
1729+
pathTrace);
16891730
}
16901731

16911732
values.clear();
@@ -1709,9 +1750,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
17091750
}
17101751

17111752
if (values.empty()) {
1712-
return llvm::make_error<llvm::StringError>(
1713-
"result not found",
1714-
std::error_code(EINVAL, std::generic_category()));
1753+
return llvm::make_error<XRefError>("result not found", pathTrace);
17151754
}
17161755

17171756
// Reset the module filter.
@@ -2156,8 +2195,7 @@ static uint64_t encodeLazyConformanceContextData(uint64_t numProtocols,
21562195
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
21572196
Expected<Decl *> deserialized = getDeclChecked(DID, ForcedContext);
21582197
if (!deserialized) {
2159-
error();
2160-
return nullptr;
2198+
fatal(deserialized.takeError());
21612199
}
21622200
return deserialized.get();
21632201
}
@@ -3685,8 +3723,7 @@ Optional<swift::ResultConvention> getActualResultConvention(uint8_t raw) {
36853723
Type ModuleFile::getType(TypeID TID) {
36863724
Expected<Type> deserialized = getTypeChecked(TID);
36873725
if (!deserialized) {
3688-
error();
3689-
return Type();
3726+
fatal(deserialized.takeError());
36903727
}
36913728
return deserialized.get();
36923729
}

0 commit comments

Comments
 (0)