mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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.
This commit is contained in:
@@ -549,6 +549,11 @@ ERROR(serialization_target_too_new_repl,none,
|
||||
"module file's minimum deployment target is %0 v%1.%2%select{|.%3}3: %4",
|
||||
(StringRef, unsigned, unsigned, unsigned, StringRef))
|
||||
|
||||
ERROR(serialization_fatal,Fatal,
|
||||
"fatal error encountered while reading from module '%0'; "
|
||||
"please file a bug report with your project and the crash log",
|
||||
(StringRef))
|
||||
|
||||
ERROR(reserved_member_name,none,
|
||||
"type member may not be named %0, since it would conflict with the"
|
||||
" 'foo.%1' expression", (DeclName, StringRef))
|
||||
|
||||
@@ -436,6 +436,10 @@ public:
|
||||
return getStatus();
|
||||
}
|
||||
|
||||
/// Emits one last diagnostic, logs the error, and then aborts for the stack
|
||||
/// trace.
|
||||
void fatal(llvm::Error error) LLVM_ATTRIBUTE_NORETURN;
|
||||
|
||||
ASTContext &getContext() const {
|
||||
assert(FileContext && "no associated context yet");
|
||||
return FileContext->getParentModule()->getASTContext();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "swift/Serialization/ModuleFile.h"
|
||||
#include "swift/Serialization/ModuleFormat.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/DiagnosticsSema.h"
|
||||
#include "swift/AST/ForeignErrorConvention.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/Initializer.h"
|
||||
@@ -95,7 +96,7 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
class PrettyXRefTrace : public llvm::PrettyStackTraceEntry {
|
||||
class XRefTracePath {
|
||||
class PathPiece {
|
||||
public:
|
||||
enum class Kind {
|
||||
@@ -196,12 +197,11 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
ModuleDecl &baseM;
|
||||
SmallVector<PathPiece, 8> path;
|
||||
|
||||
public:
|
||||
PrettyXRefTrace(ModuleDecl &M) : baseM(M) {}
|
||||
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
|
||||
|
||||
void addValue(Identifier name) {
|
||||
path.push_back({ PathPiece::Kind::Value, name });
|
||||
@@ -241,16 +241,27 @@ namespace {
|
||||
path.pop_back();
|
||||
}
|
||||
|
||||
void print(raw_ostream &os) const override {
|
||||
void print(raw_ostream &os, StringRef leading = "") const {
|
||||
os << "Cross-reference to module '" << baseM.getName() << "'\n";
|
||||
for (auto &piece : path) {
|
||||
os << "\t... ";
|
||||
os << leading << "... ";
|
||||
piece.print(os);
|
||||
os << "\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PrettyXRefTrace :
|
||||
public llvm::PrettyStackTraceEntry,
|
||||
public XRefTracePath {
|
||||
public:
|
||||
explicit PrettyXRefTrace(ModuleDecl &M) : XRefTracePath(M) {}
|
||||
|
||||
void print(raw_ostream &os) const override {
|
||||
XRefTracePath::print(os, "\t");
|
||||
}
|
||||
};
|
||||
|
||||
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
|
||||
const char *Action;
|
||||
const ModuleFile *MF;
|
||||
@@ -262,6 +273,30 @@ namespace {
|
||||
os << Action << " \'" << getNameOfModule(MF) << "'\n";
|
||||
}
|
||||
};
|
||||
|
||||
class XRefError : public llvm::ErrorInfo<XRefError> {
|
||||
friend ErrorInfo;
|
||||
static const char ID;
|
||||
|
||||
XRefTracePath path;
|
||||
const char *message;
|
||||
public:
|
||||
template <size_t N>
|
||||
XRefError(const char (&message)[N], XRefTracePath path)
|
||||
: path(path), message(message) {}
|
||||
|
||||
void log(raw_ostream &OS) const override {
|
||||
OS << message << "\n";
|
||||
path.print(OS);
|
||||
}
|
||||
|
||||
std::error_code convertToErrorCode() const override {
|
||||
// This is a deprecated part of llvm::Error, so we just return a very
|
||||
// generic value.
|
||||
return {EINVAL, std::generic_category()};
|
||||
}
|
||||
};
|
||||
const char XRefError::ID = '\0';
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
@@ -286,6 +321,17 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ModuleFile::fatal(llvm::Error error) {
|
||||
if (FileContext) {
|
||||
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Name);
|
||||
}
|
||||
|
||||
logAllUnhandledErrors(std::move(error), llvm::errs(),
|
||||
"\n*** DESERIALIZATION FAILURE (please include this "
|
||||
"section in any bug report) ***\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
|
||||
assert(FileContext && "cannot delay actions before associating with a file");
|
||||
ModuleDecl *associatedModule = getAssociatedModule();
|
||||
@@ -1421,9 +1467,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
||||
}
|
||||
|
||||
if (values.empty()) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"top-level value not found",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
return llvm::make_error<XRefError>("top-level value not found", pathTrace);
|
||||
}
|
||||
|
||||
// Filters for values discovered in the remaining path pieces.
|
||||
@@ -1542,18 +1586,16 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
||||
pathTrace.addType(filterTy);
|
||||
|
||||
if (values.size() != 1) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"multiple matching base values",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
return llvm::make_error<XRefError>("multiple matching base values",
|
||||
pathTrace);
|
||||
}
|
||||
|
||||
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
|
||||
values.clear();
|
||||
|
||||
if (!nominal) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"base is not a nominal type",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
return llvm::make_error<XRefError>("base is not a nominal type",
|
||||
pathTrace);
|
||||
}
|
||||
|
||||
auto members = nominal->lookupDirect(memberName);
|
||||
@@ -1642,9 +1684,8 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
||||
|
||||
case XREF_GENERIC_PARAM_PATH_PIECE: {
|
||||
if (values.size() != 1) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"multiple matching base values",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
return llvm::make_error<XRefError>("multiple matching base values",
|
||||
pathTrace);
|
||||
}
|
||||
|
||||
uint32_t paramIndex;
|
||||
@@ -1678,14 +1719,14 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
||||
paramList = fn->getGenericParams();
|
||||
|
||||
if (!paramList) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
return llvm::make_error<XRefError>(
|
||||
"cross-reference to generic param for non-generic type",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
pathTrace);
|
||||
}
|
||||
if (paramIndex >= paramList->size()) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
return llvm::make_error<XRefError>(
|
||||
"generic argument index out of bounds",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
pathTrace);
|
||||
}
|
||||
|
||||
values.clear();
|
||||
@@ -1709,9 +1750,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
||||
}
|
||||
|
||||
if (values.empty()) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"result not found",
|
||||
std::error_code(EINVAL, std::generic_category()));
|
||||
return llvm::make_error<XRefError>("result not found", pathTrace);
|
||||
}
|
||||
|
||||
// Reset the module filter.
|
||||
@@ -2156,8 +2195,7 @@ static uint64_t encodeLazyConformanceContextData(uint64_t numProtocols,
|
||||
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
Expected<Decl *> deserialized = getDeclChecked(DID, ForcedContext);
|
||||
if (!deserialized) {
|
||||
error();
|
||||
return nullptr;
|
||||
fatal(deserialized.takeError());
|
||||
}
|
||||
return deserialized.get();
|
||||
}
|
||||
@@ -3685,8 +3723,7 @@ Optional<swift::ResultConvention> getActualResultConvention(uint8_t raw) {
|
||||
Type ModuleFile::getType(TypeID TID) {
|
||||
Expected<Type> deserialized = getTypeChecked(TID);
|
||||
if (!deserialized) {
|
||||
error();
|
||||
return Type();
|
||||
fatal(deserialized.takeError());
|
||||
}
|
||||
return deserialized.get();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user