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",
|
"module file's minimum deployment target is %0 v%1.%2%select{|.%3}3: %4",
|
||||||
(StringRef, unsigned, unsigned, unsigned, StringRef))
|
(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,
|
ERROR(reserved_member_name,none,
|
||||||
"type member may not be named %0, since it would conflict with the"
|
"type member may not be named %0, since it would conflict with the"
|
||||||
" 'foo.%1' expression", (DeclName, StringRef))
|
" 'foo.%1' expression", (DeclName, StringRef))
|
||||||
|
|||||||
@@ -436,6 +436,10 @@ public:
|
|||||||
return getStatus();
|
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 {
|
ASTContext &getContext() const {
|
||||||
assert(FileContext && "no associated context yet");
|
assert(FileContext && "no associated context yet");
|
||||||
return FileContext->getParentModule()->getASTContext();
|
return FileContext->getParentModule()->getASTContext();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "swift/Serialization/ModuleFile.h"
|
#include "swift/Serialization/ModuleFile.h"
|
||||||
#include "swift/Serialization/ModuleFormat.h"
|
#include "swift/Serialization/ModuleFormat.h"
|
||||||
#include "swift/AST/ASTContext.h"
|
#include "swift/AST/ASTContext.h"
|
||||||
|
#include "swift/AST/DiagnosticsSema.h"
|
||||||
#include "swift/AST/ForeignErrorConvention.h"
|
#include "swift/AST/ForeignErrorConvention.h"
|
||||||
#include "swift/AST/GenericEnvironment.h"
|
#include "swift/AST/GenericEnvironment.h"
|
||||||
#include "swift/AST/Initializer.h"
|
#include "swift/AST/Initializer.h"
|
||||||
@@ -95,7 +96,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrettyXRefTrace : public llvm::PrettyStackTraceEntry {
|
class XRefTracePath {
|
||||||
class PathPiece {
|
class PathPiece {
|
||||||
public:
|
public:
|
||||||
enum class Kind {
|
enum class Kind {
|
||||||
@@ -196,12 +197,11 @@ namespace {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
ModuleDecl &baseM;
|
ModuleDecl &baseM;
|
||||||
SmallVector<PathPiece, 8> path;
|
SmallVector<PathPiece, 8> path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrettyXRefTrace(ModuleDecl &M) : baseM(M) {}
|
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
|
||||||
|
|
||||||
void addValue(Identifier name) {
|
void addValue(Identifier name) {
|
||||||
path.push_back({ PathPiece::Kind::Value, name });
|
path.push_back({ PathPiece::Kind::Value, name });
|
||||||
@@ -241,16 +241,27 @@ namespace {
|
|||||||
path.pop_back();
|
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";
|
os << "Cross-reference to module '" << baseM.getName() << "'\n";
|
||||||
for (auto &piece : path) {
|
for (auto &piece : path) {
|
||||||
os << "\t... ";
|
os << leading << "... ";
|
||||||
piece.print(os);
|
piece.print(os);
|
||||||
os << "\n";
|
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 {
|
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
|
||||||
const char *Action;
|
const char *Action;
|
||||||
const ModuleFile *MF;
|
const ModuleFile *MF;
|
||||||
@@ -262,6 +273,30 @@ namespace {
|
|||||||
os << Action << " \'" << getNameOfModule(MF) << "'\n";
|
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
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
@@ -286,6 +321,17 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
|
|||||||
#endif
|
#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() {
|
ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
|
||||||
assert(FileContext && "cannot delay actions before associating with a file");
|
assert(FileContext && "cannot delay actions before associating with a file");
|
||||||
ModuleDecl *associatedModule = getAssociatedModule();
|
ModuleDecl *associatedModule = getAssociatedModule();
|
||||||
@@ -1421,9 +1467,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (values.empty()) {
|
if (values.empty()) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>("top-level value not found", pathTrace);
|
||||||
"top-level value not found",
|
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters for values discovered in the remaining path pieces.
|
// Filters for values discovered in the remaining path pieces.
|
||||||
@@ -1542,18 +1586,16 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|||||||
pathTrace.addType(filterTy);
|
pathTrace.addType(filterTy);
|
||||||
|
|
||||||
if (values.size() != 1) {
|
if (values.size() != 1) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>("multiple matching base values",
|
||||||
"multiple matching base values",
|
pathTrace);
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
|
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
|
||||||
values.clear();
|
values.clear();
|
||||||
|
|
||||||
if (!nominal) {
|
if (!nominal) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>("base is not a nominal type",
|
||||||
"base is not a nominal type",
|
pathTrace);
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto members = nominal->lookupDirect(memberName);
|
auto members = nominal->lookupDirect(memberName);
|
||||||
@@ -1642,9 +1684,8 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|||||||
|
|
||||||
case XREF_GENERIC_PARAM_PATH_PIECE: {
|
case XREF_GENERIC_PARAM_PATH_PIECE: {
|
||||||
if (values.size() != 1) {
|
if (values.size() != 1) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>("multiple matching base values",
|
||||||
"multiple matching base values",
|
pathTrace);
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t paramIndex;
|
uint32_t paramIndex;
|
||||||
@@ -1678,14 +1719,14 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|||||||
paramList = fn->getGenericParams();
|
paramList = fn->getGenericParams();
|
||||||
|
|
||||||
if (!paramList) {
|
if (!paramList) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>(
|
||||||
"cross-reference to generic param for non-generic type",
|
"cross-reference to generic param for non-generic type",
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
pathTrace);
|
||||||
}
|
}
|
||||||
if (paramIndex >= paramList->size()) {
|
if (paramIndex >= paramList->size()) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>(
|
||||||
"generic argument index out of bounds",
|
"generic argument index out of bounds",
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
pathTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.clear();
|
values.clear();
|
||||||
@@ -1709,9 +1750,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (values.empty()) {
|
if (values.empty()) {
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<XRefError>("result not found", pathTrace);
|
||||||
"result not found",
|
|
||||||
std::error_code(EINVAL, std::generic_category()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the module filter.
|
// Reset the module filter.
|
||||||
@@ -2156,8 +2195,7 @@ static uint64_t encodeLazyConformanceContextData(uint64_t numProtocols,
|
|||||||
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||||
Expected<Decl *> deserialized = getDeclChecked(DID, ForcedContext);
|
Expected<Decl *> deserialized = getDeclChecked(DID, ForcedContext);
|
||||||
if (!deserialized) {
|
if (!deserialized) {
|
||||||
error();
|
fatal(deserialized.takeError());
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
return deserialized.get();
|
return deserialized.get();
|
||||||
}
|
}
|
||||||
@@ -3685,8 +3723,7 @@ Optional<swift::ResultConvention> getActualResultConvention(uint8_t raw) {
|
|||||||
Type ModuleFile::getType(TypeID TID) {
|
Type ModuleFile::getType(TypeID TID) {
|
||||||
Expected<Type> deserialized = getTypeChecked(TID);
|
Expected<Type> deserialized = getTypeChecked(TID);
|
||||||
if (!deserialized) {
|
if (!deserialized) {
|
||||||
error();
|
fatal(deserialized.takeError());
|
||||||
return Type();
|
|
||||||
}
|
}
|
||||||
return deserialized.get();
|
return deserialized.get();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user