From d46aec9f00a53d2105631ea44e69d59c5f52c3f5 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 1/9] [Basic] Handle multiline strings in `abortWithPrettyStackTraceMessage` Improve the formatting by indenting to match the rest of the pretty stack trace. --- include/swift/Basic/PrettyStackTrace.h | 6 ++++-- lib/Basic/PrettyStackTrace.cpp | 27 +++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/swift/Basic/PrettyStackTrace.h b/include/swift/Basic/PrettyStackTrace.h index 90bc97a5fd71e..425c33d88ecf6 100644 --- a/include/swift/Basic/PrettyStackTrace.h +++ b/include/swift/Basic/PrettyStackTrace.h @@ -51,13 +51,15 @@ class PrettyStackTraceSwiftVersion : public llvm::PrettyStackTraceEntry { }; /// Aborts the program, printing a given message to a PrettyStackTrace frame -/// before exiting. +/// before exiting. This should be preferred over manually logging to stderr and +/// aborting since that won't be picked up by the crash reporter. [[noreturn]] void abortWithPrettyStackTraceMessage( llvm::function_ref message); /// Aborts the program, printing a given message to a PrettyStackTrace frame -/// before exiting. +/// before exiting. This should be preferred over manually logging to stderr and +/// aborting since that won't be picked up by the crash reporter. [[noreturn]] void abortWithPrettyStackTraceMessage(llvm::StringRef message); diff --git a/lib/Basic/PrettyStackTrace.cpp b/lib/Basic/PrettyStackTrace.cpp index afcbd1a5196df..dcaf821ffa596 100644 --- a/lib/Basic/PrettyStackTrace.cpp +++ b/lib/Basic/PrettyStackTrace.cpp @@ -40,17 +40,38 @@ void PrettyStackTraceSwiftVersion::print(llvm::raw_ostream &out) const { out << version::getSwiftFullVersion() << '\n'; } +namespace { +/// Similar to PrettyStackTraceString, but formats multi-line strings for +/// the stack trace. +class PrettyStackTraceMultilineString : public llvm::PrettyStackTraceEntry { + StringRef Str; + +public: + PrettyStackTraceMultilineString(StringRef str) : Str(str) {} + void print(raw_ostream &OS) const override { + // For each line, add a leading character and indentation to better match + // the formatting of the stack trace. + for (auto c : Str.rtrim('\n')) { + OS << c; + if (c == '\n') + OS << "| \t"; + } + OS << '\n'; + } +}; +} // end anonymous namespace + void swift::abortWithPrettyStackTraceMessage( llvm::function_ref message) { llvm::SmallString<0> errorStr; llvm::raw_svector_ostream out(errorStr); message(out); - llvm::PrettyStackTraceString trace(errorStr.c_str()); + + PrettyStackTraceMultilineString trace(errorStr); abort(); } void swift::abortWithPrettyStackTraceMessage(StringRef message) { - auto messageStr = message.str(); - llvm::PrettyStackTraceString trace(messageStr.c_str()); + PrettyStackTraceMultilineString trace(message); abort(); } From 92641253f7c68ccb1a1d055c1325f19d249356a1 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 2/9] [Basic] NFC: Remove `ASSERT_help` from header It's not clear this is a useful utility to expose since it will only print the message once. --- include/swift/Basic/Assertions.h | 7 ------- lib/Basic/Assertions.cpp | 36 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h index d8155add80baf..4ee7b56c9d797 100644 --- a/include/swift/Basic/Assertions.h +++ b/include/swift/Basic/Assertions.h @@ -190,11 +190,4 @@ extern int CONDITIONAL_ASSERT_Global_enable_flag; #define SWIFT_ASSERT_ONLY_DECL DEBUG_ASSERT_DECL #define SWIFT_ASSERT_ONLY DEBUG_ASSERT_EXPR -// ================================ Utility and Helper Functions ================================ - -// Utility function to print out help information for -// various command-line options that affect the assertion -// behavior. -void ASSERT_help(); - #endif // SWIFT_BASIC_ASSERTIONS_H diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp index e195ec0745668..f2ce73f1cf632 100644 --- a/lib/Basic/Assertions.cpp +++ b/lib/Basic/Assertions.cpp @@ -34,6 +34,24 @@ int CONDITIONAL_ASSERT_Global_enable_flag = 1; // Default to `on` in debug builds #endif +static void ASSERT_help() { + static int ASSERT_help_shown = 0; + if (ASSERT_help_shown) { + return; + } + ASSERT_help_shown = 1; + + if (!AssertHelp) { + llvm::errs() << "(to display assertion configuration options: -Xllvm -assert-help)\n"; + return; + } + + llvm::errs() << "\n"; + llvm::errs() << "Control assertion behavior with one or more of the following options:\n\n"; + llvm::errs() << " -Xllvm -assert-continue\n"; + llvm::errs() << " Continue after any failed assertion\n\n"; +} + void ASSERT_failure(const char *expr, const char *filename, int line, const char *func) { // Find the last component of `filename` // Needed on Windows MSVC, which lacks __FILE_NAME__ @@ -62,24 +80,6 @@ void ASSERT_failure(const char *expr, const char *filename, int line, const char abort(); } -void ASSERT_help() { - static int ASSERT_help_shown = 0; - if (ASSERT_help_shown) { - return; - } - ASSERT_help_shown = 1; - - if (!AssertHelp) { - llvm::errs() << "(to display assertion configuration options: -Xllvm -assert-help)\n"; - return; - } - - llvm::errs() << "\n"; - llvm::errs() << "Control assertion behavior with one or more of the following options:\n\n"; - llvm::errs() << " -Xllvm -assert-continue\n"; - llvm::errs() << " Continue after any failed assertion\n\n"; -} - // This has to be callable in the same way as the macro version, // so we can't put it inside a namespace. #undef CONDITIONAL_ASSERT_enabled From ffb474e0b904a2f5b0457040df29724d3e66682c Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 3/9] [Basic] NFC: Factor out `_FILENAME_FOR_ASSERT` macro --- include/swift/Basic/Assertions.h | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h index 4ee7b56c9d797..1a18712f6437b 100644 --- a/include/swift/Basic/Assertions.h +++ b/include/swift/Basic/Assertions.h @@ -24,6 +24,13 @@ #define ASSERT_UNLIKELY(expression) ((expression)) #endif +// Visual Studio doesn't have __FILE_NAME__ +#ifdef __FILE_NAME__ +#define _FILENAME_FOR_ASSERT __FILE_NAME__ +#else +#define _FILENAME_FOR_ASSERT __FILE__ +#endif + // ================================ Mandatory Asserts ================================ // `ASSERT(expr)`: @@ -41,27 +48,13 @@ // that are more expensive than you think. You can switch those to // `CONDITIONAL_ASSERT` or `DEBUG_ASSERT` as needed. -// Visual Studio doesn't have __FILE_NAME__ -#ifdef __FILE_NAME__ - -#define ASSERT(expr) \ - do { \ - if (ASSERT_UNLIKELY(!(expr))) { \ - ASSERT_failure(#expr, __FILE_NAME__, __LINE__, __func__); \ - } \ - } while (0) - -#else - -#define ASSERT(expr) \ - do { \ - if (ASSERT_UNLIKELY(!(expr))) { \ - ASSERT_failure(#expr, __FILE__, __LINE__, __func__); \ - } \ +#define ASSERT(expr) \ + do { \ + if (ASSERT_UNLIKELY(!(expr))) { \ + ASSERT_failure(#expr, _FILENAME_FOR_ASSERT, __LINE__, __func__); \ + } \ } while (0) -#endif - // Function that reports the actual failure when it occurs. void ASSERT_failure(const char *expr, const char *file, int line, const char *func); From d672f750e742cea258b8b7b26815208ea1ca5b9d Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 4/9] [Basic] Rename `abortWithPrettyStackTraceMessage` to `ABORT` Turn it into a wrapping macro that includes the file location, and move into `Assertions.h`. --- include/swift/Basic/Assertions.h | 31 +++++++++++++ include/swift/Basic/PrettyStackTrace.h | 13 ------ lib/AST/ASTScopePrinting.cpp | 2 +- lib/Basic/Assertions.cpp | 52 ++++++++++++++++++++++ lib/Basic/Mangler.cpp | 6 +-- lib/Basic/PrettyStackTrace.cpp | 36 --------------- lib/Serialization/ModuleFileSharedCore.cpp | 2 +- lib/Serialization/Serialization.cpp | 4 +- 8 files changed, 90 insertions(+), 56 deletions(-) diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h index 1a18712f6437b..37b83d4fb8cd4 100644 --- a/include/swift/Basic/Assertions.h +++ b/include/swift/Basic/Assertions.h @@ -17,6 +17,8 @@ #ifndef SWIFT_BASIC_ASSERTIONS_H #define SWIFT_BASIC_ASSERTIONS_H +#include "swift/Basic/LLVM.h" + // Only for use in this header #if __has_builtin(__builtin_expect) #define ASSERT_UNLIKELY(expression) (__builtin_expect(!!(expression), 0)) @@ -183,4 +185,33 @@ extern int CONDITIONAL_ASSERT_Global_enable_flag; #define SWIFT_ASSERT_ONLY_DECL DEBUG_ASSERT_DECL #define SWIFT_ASSERT_ONLY DEBUG_ASSERT_EXPR +// ================================ Abort ====================================== + +/// Implementation for \c ABORT, not to be used directly. +[[noreturn]] +void _ABORT(const char *file, int line, const char *func, + llvm::function_ref message); + +/// Implementation for \c ABORT, not to be used directly. +[[noreturn]] +void _ABORT(const char *file, int line, const char *func, + llvm::StringRef message); + +// Aborts the program, printing a given message to a PrettyStackTrace frame +// before exiting. This should be preferred over manually logging to stderr and +// `abort()`'ing since that won't be picked up by the crash reporter. +// +// There are two different forms of ABORT: +// +// ``` +// ABORT("abort with string"); +// +// ABORT([&](auto &out) { +// out << "abort with arbitrary stream"; +// node.dump(out); +// }); +// ``` +// +#define ABORT(arg) _ABORT(_FILENAME_FOR_ASSERT, __LINE__, __func__, (arg)) + #endif // SWIFT_BASIC_ASSERTIONS_H diff --git a/include/swift/Basic/PrettyStackTrace.h b/include/swift/Basic/PrettyStackTrace.h index 425c33d88ecf6..a105d6a23b0ff 100644 --- a/include/swift/Basic/PrettyStackTrace.h +++ b/include/swift/Basic/PrettyStackTrace.h @@ -50,19 +50,6 @@ class PrettyStackTraceSwiftVersion : public llvm::PrettyStackTraceEntry { void print(llvm::raw_ostream &OS) const override; }; -/// Aborts the program, printing a given message to a PrettyStackTrace frame -/// before exiting. This should be preferred over manually logging to stderr and -/// aborting since that won't be picked up by the crash reporter. -[[noreturn]] -void abortWithPrettyStackTraceMessage( - llvm::function_ref message); - -/// Aborts the program, printing a given message to a PrettyStackTrace frame -/// before exiting. This should be preferred over manually logging to stderr and -/// aborting since that won't be picked up by the crash reporter. -[[noreturn]] -void abortWithPrettyStackTraceMessage(llvm::StringRef message); - } // end namespace swift #endif // SWIFT_BASIC_PRETTYSTACKTRACE_H diff --git a/lib/AST/ASTScopePrinting.cpp b/lib/AST/ASTScopePrinting.cpp index cedd542a2d59e..2ff3cb5a38fcc 100644 --- a/lib/AST/ASTScopePrinting.cpp +++ b/lib/AST/ASTScopePrinting.cpp @@ -72,7 +72,7 @@ void ASTScopeImpl::dumpOneScopeMapLocation( void ASTScopeImpl::abortWithVerificationError( llvm::function_ref messageFn) const { - abortWithPrettyStackTraceMessage([&](auto &out) { + ABORT([&](auto &out) { out << "ASTScopeImpl verification error in source file '" << getSourceFile()->getFilename() << "':\n"; messageFn(out); diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp index f2ce73f1cf632..672ee882bdfe5 100644 --- a/lib/Basic/Assertions.cpp +++ b/lib/Basic/Assertions.cpp @@ -14,7 +14,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "swift/Basic/Assertions.h" #include @@ -52,6 +54,9 @@ static void ASSERT_help() { llvm::errs() << " Continue after any failed assertion\n\n"; } +[[noreturn]] +static inline void _abortWithMessage(llvm::StringRef message); + void ASSERT_failure(const char *expr, const char *filename, int line, const char *func) { // Find the last component of `filename` // Needed on Windows MSVC, which lacks __FILE_NAME__ @@ -86,3 +91,50 @@ void ASSERT_failure(const char *expr, const char *filename, int line, const char int CONDITIONAL_ASSERT_enabled() { return (CONDITIONAL_ASSERT_Global_enable_flag != 0); } + +// MARK: ABORT + +namespace { +/// Similar to PrettyStackTraceString, but formats multi-line strings for +/// the stack trace. +class PrettyStackTraceMultilineString : public llvm::PrettyStackTraceEntry { + llvm::StringRef Str; + +public: + PrettyStackTraceMultilineString(llvm::StringRef str) : Str(str) {} + void print(llvm::raw_ostream &OS) const override { + // For each line, add a leading character and indentation to better match + // the formatting of the stack trace. + for (auto c : Str.rtrim('\n')) { + OS << c; + if (c == '\n') + OS << "| \t"; + } + OS << '\n'; + } +}; +} // end anonymous namespace + +static void _abortWithMessage(llvm::StringRef message) { + // Use a pretty stack trace to ensure the message gets picked up the + // crash reporter. + PrettyStackTraceMultilineString trace(message); + + abort(); +} + +void _ABORT(const char *file, int line, const char *func, + llvm::function_ref message) { + llvm::SmallString<0> errorStr; + llvm::raw_svector_ostream out(errorStr); + out << "Abort: " << "function " << func << " at " + << file << ":" << line << "\n"; + message(out); + + _abortWithMessage(errorStr); +} + +void _ABORT(const char *file, int line, const char *func, + llvm::StringRef message) { + _ABORT(file, line, func, [&](auto &out) { out << message; }); +} diff --git a/lib/Basic/Mangler.cpp b/lib/Basic/Mangler.cpp index 8d6f410b58400..f8f6f5c2a18e0 100644 --- a/lib/Basic/Mangler.cpp +++ b/lib/Basic/Mangler.cpp @@ -202,13 +202,13 @@ void Mangler::verify(StringRef nameStr, ManglingFlavor Flavor) { Demangler Dem; NodePointer Root = Dem.demangleSymbol(nameStr); if (!Root || treeContains(Root, Node::Kind::Suffix)) { - abortWithPrettyStackTraceMessage([&](auto &out) { + ABORT([&](auto &out) { out << "Can't demangle: " << nameStr; }); } auto mangling = mangleNode(Root, Flavor); if (!mangling.isSuccess()) { - abortWithPrettyStackTraceMessage([&](auto &out) { + ABORT([&](auto &out) { out << "Can't remangle: " << nameStr; }); } @@ -216,7 +216,7 @@ void Mangler::verify(StringRef nameStr, ManglingFlavor Flavor) { if (Remangled == nameStr) return; - abortWithPrettyStackTraceMessage([&](auto &out) { + ABORT([&](auto &out) { out << "Remangling failed:\n"; out << "original = " << nameStr << "\n"; out << "remangled = " << Remangled; diff --git a/lib/Basic/PrettyStackTrace.cpp b/lib/Basic/PrettyStackTrace.cpp index dcaf821ffa596..78d4e8d277405 100644 --- a/lib/Basic/PrettyStackTrace.cpp +++ b/lib/Basic/PrettyStackTrace.cpp @@ -39,39 +39,3 @@ void PrettyStackTraceFileContents::print(llvm::raw_ostream &out) const { void PrettyStackTraceSwiftVersion::print(llvm::raw_ostream &out) const { out << version::getSwiftFullVersion() << '\n'; } - -namespace { -/// Similar to PrettyStackTraceString, but formats multi-line strings for -/// the stack trace. -class PrettyStackTraceMultilineString : public llvm::PrettyStackTraceEntry { - StringRef Str; - -public: - PrettyStackTraceMultilineString(StringRef str) : Str(str) {} - void print(raw_ostream &OS) const override { - // For each line, add a leading character and indentation to better match - // the formatting of the stack trace. - for (auto c : Str.rtrim('\n')) { - OS << c; - if (c == '\n') - OS << "| \t"; - } - OS << '\n'; - } -}; -} // end anonymous namespace - -void swift::abortWithPrettyStackTraceMessage( - llvm::function_ref message) { - llvm::SmallString<0> errorStr; - llvm::raw_svector_ostream out(errorStr); - message(out); - - PrettyStackTraceMultilineString trace(errorStr); - abort(); -} - -void swift::abortWithPrettyStackTraceMessage(StringRef message) { - PrettyStackTraceMultilineString trace(message); - abort(); -} diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index 4d014d1990bde..87a979377f1ed 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -695,7 +695,7 @@ std::string ModuleFileSharedCore::Dependency::getPrettyPrintedPath() const { } void ModuleFileSharedCore::fatal(llvm::Error error) const { - abortWithPrettyStackTraceMessage([&](auto &out) { + ABORT([&](auto &out) { out << "*** DESERIALIZATION FAILURE ***\n"; out << "*** If any module named here was modified in the SDK, please delete the ***\n"; out << "*** new swiftmodule files from the SDK and keep only swiftinterfaces. ***\n"; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index e27c7033c0d52..8d7782e519305 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5337,7 +5337,7 @@ void Serializer::writeASTBlockEntity(const Decl *D) { SWIFT_DEFER { // This is important enough to leave on in Release builds. if (initialOffset == Out.GetCurrentBitNo()) { - abortWithPrettyStackTraceMessage("failed to serialize anything"); + ABORT("failed to serialize anything"); } }; @@ -6164,7 +6164,7 @@ void Serializer::writeASTBlockEntity(Type ty) { SWIFT_DEFER { // This is important enough to leave on in Release builds. if (initialOffset == Out.GetCurrentBitNo()) { - abortWithPrettyStackTraceMessage("failed to serialize anything"); + ABORT("failed to serialize anything"); } }; From a6e94ab0bd774b5c116bff50534bbca314e65ee0 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 5/9] [Basic] Fallback to dumping to stderr when backtracing is disabled Make sure we still output the error message when pretty backtracing is disabled. --- lib/Basic/Assertions.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp index 672ee882bdfe5..a4f9a335db696 100644 --- a/lib/Basic/Assertions.cpp +++ b/lib/Basic/Assertions.cpp @@ -120,6 +120,10 @@ static void _abortWithMessage(llvm::StringRef message) { // crash reporter. PrettyStackTraceMultilineString trace(message); + // If pretty backtracing is disabled, fall back to dumping to stderr. + if (!llvm::SavePrettyStackState()) + llvm::errs() << message << '\n'; + abort(); } From be8604959e64d7838cae9b8e28f2133c88e0bba8 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 6/9] [Basic] Switch `ASSERT` and friends to `_abortWithMessage` Ensure the message gets printed to the pretty stack trace, allowing it to be picked up by CrashReporter. --- lib/Basic/Assertions.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp index a4f9a335db696..8c84d0c7e323d 100644 --- a/lib/Basic/Assertions.cpp +++ b/lib/Basic/Assertions.cpp @@ -36,7 +36,7 @@ int CONDITIONAL_ASSERT_Global_enable_flag = 1; // Default to `on` in debug builds #endif -static void ASSERT_help() { +static void ASSERT_help(llvm::raw_ostream &out) { static int ASSERT_help_shown = 0; if (ASSERT_help_shown) { return; @@ -44,14 +44,14 @@ static void ASSERT_help() { ASSERT_help_shown = 1; if (!AssertHelp) { - llvm::errs() << "(to display assertion configuration options: -Xllvm -assert-help)\n"; + out << "(to display assertion configuration options: -Xllvm -assert-help)\n"; return; } - llvm::errs() << "\n"; - llvm::errs() << "Control assertion behavior with one or more of the following options:\n\n"; - llvm::errs() << " -Xllvm -assert-continue\n"; - llvm::errs() << " Continue after any failed assertion\n\n"; + out << "\n"; + out << "Control assertion behavior with one or more of the following options:\n\n"; + out << " -Xllvm -assert-continue\n"; + out << " Continue after any failed assertion\n\n"; } [[noreturn]] @@ -68,21 +68,24 @@ void ASSERT_failure(const char *expr, const char *filename, int line, const char } } - llvm::errs() - << "Assertion failed: " - << "(" << expr << "), " - << "function " << func << " at " - << filename << ":" - << line << ".\n"; + llvm::SmallString<0> message; + llvm::raw_svector_ostream out(message); - ASSERT_help(); + out << "Assertion failed: " + << "(" << expr << "), " + << "function " << func << " at " + << filename << ":" + << line << ".\n"; + + ASSERT_help(out); if (AssertContinue) { + llvm::errs() << message; llvm::errs() << "Continuing after failed assertion (-Xllvm -assert-continue)\n"; return; } - abort(); + _abortWithMessage(message); } // This has to be callable in the same way as the macro version, From bdd74e717e775f1953fdec41b877f493ebf2bc2f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 7/9] [AST] Remove redundant logging in `validateGenericSignature` We already setup a PrettyStackTrace to include the generic signature on a crash. --- lib/AST/GenericSignature.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index d629055e23c94..d3416dae9940b 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -1162,10 +1162,6 @@ static Requirement stripBoundDependentMemberTypes(Requirement req) { void swift::validateGenericSignature(ASTContext &context, GenericSignature sig) { - llvm::errs() << "Validating generic signature: "; - sig->print(llvm::errs()); - llvm::errs() << "\n"; - // Try building a new signature having the same requirements. SmallVector genericParams; for (auto *genericParam : sig.getGenericParams()) From b8fc71c684808ae18c29e05cc2a05dabfc12cc7f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 8/9] [AST] Fix an accidental use of `llvm::errs` --- lib/AST/RequirementMachine/TypeDifference.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/AST/RequirementMachine/TypeDifference.cpp b/lib/AST/RequirementMachine/TypeDifference.cpp index a575882659dca..214e79d563b95 100644 --- a/lib/AST/RequirementMachine/TypeDifference.cpp +++ b/lib/AST/RequirementMachine/TypeDifference.cpp @@ -63,9 +63,9 @@ MutableTerm TypeDifference::getReplacementSubstitution(unsigned index) const { } void TypeDifference::dump(llvm::raw_ostream &out) const { - llvm::errs() << "Base term: " << BaseTerm << "\n"; - llvm::errs() << "LHS: " << LHS << "\n"; - llvm::errs() << "RHS: " << RHS << "\n"; + out << "Base term: " << BaseTerm << "\n"; + out << "LHS: " << LHS << "\n"; + out << "RHS: " << RHS << "\n"; for (const auto &pair : SameTypes) { out << "- " << getOriginalSubstitution(pair.first) << " (#"; From edca7c85ad53e8e786db04ee6997e539e09b6dcd Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 19 May 2025 20:55:01 +0100 Subject: [PATCH 9/9] Adopt `ABORT` throughout the compiler Convert a bunch of places where we're dumping to stderr and calling `abort` over to using `ABORT` such that the message gets printed to the pretty stack trace. This ensures it gets picked up by CrashReporter. --- include/swift/SIL/SILCloner.h | 11 +- lib/AST/ASTContext.cpp | 7 +- lib/AST/ASTMangler.cpp | 20 +- lib/AST/AvailabilityScope.cpp | 19 +- lib/AST/Bridging/MiscBridging.cpp | 11 +- lib/AST/Expr.cpp | 7 +- lib/AST/GenericSignature.cpp | 187 ++++++++-------- .../LocalArchetypeRequirementCollector.cpp | 7 +- lib/AST/ParameterPack.cpp | 9 +- lib/AST/Requirement.cpp | 9 +- .../ConcreteTypeWitness.cpp | 13 +- lib/AST/RequirementMachine/Diagnostics.cpp | 5 +- .../GenericSignatureQueries.cpp | 97 +++++---- .../RequirementMachine/HomotopyReduction.cpp | 74 ++++--- lib/AST/RequirementMachine/InterfaceType.cpp | 78 +++---- .../MinimalConformances.cpp | 103 ++++----- lib/AST/RequirementMachine/PropertyMap.cpp | 16 +- .../PropertyUnification.cpp | 4 +- .../RequirementMachine/RequirementMachine.cpp | 21 +- .../RequirementMachineRequests.cpp | 19 +- lib/AST/RequirementMachine/RewriteContext.cpp | 32 ++- lib/AST/RequirementMachine/RewriteLoop.cpp | 206 ++++++++++-------- lib/AST/RequirementMachine/RewriteSystem.cpp | 49 +++-- .../SimplifySubstitutions.cpp | 9 +- lib/AST/RequirementMachine/Symbol.cpp | 14 +- lib/AST/RequirementMachine/TypeDifference.cpp | 75 ++++--- lib/AST/SubstitutionMap.cpp | 44 ++-- lib/ClangImporter/ImportDecl.cpp | 10 +- lib/IRGen/IRGenDebugInfo.cpp | 44 ++-- lib/SIL/IR/SILModule.cpp | 17 +- lib/SIL/Utils/Dominance.cpp | 22 +- .../Utils/GenericSpecializationMangler.cpp | 5 +- lib/SIL/Utils/SILBridging.cpp | 16 +- lib/SIL/Verifier/MemoryLifetimeVerifier.cpp | 7 +- lib/SILOptimizer/PassManager/Passes.cpp | 13 +- lib/SILOptimizer/SILCombiner/SILCombine.cpp | 45 ++-- lib/Sema/AssociatedTypeInference.cpp | 40 ++-- lib/Sema/CSApply.cpp | 9 +- lib/Sema/ConstraintGraph.cpp | 28 ++- lib/Sema/OpenedExistentials.cpp | 7 +- lib/Serialization/ModuleFile.cpp | 14 +- lib/Serialization/ModuleFileCoreTableInfo.h | 6 +- 42 files changed, 758 insertions(+), 671 deletions(-) diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 3be450dd60cc4..3691e0ca73ec0 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -557,11 +557,12 @@ class SILCloner : protected SILInstructionVisitor { } if (substConf.isInvalid()) { - llvm::errs() << "Invalid substituted conformance in SIL cloner:\n"; - Functor.dump(llvm::errs()); - llvm::errs() << "\noriginal conformance:\n"; - conformance.dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Invalid substituted conformance in SIL cloner:\n"; + Functor.dump(out); + out << "\noriginal conformance:\n"; + conformance.dump(out); + }); } if (asImpl().shouldSubstOpaqueArchetypes()) { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 3a1fc4f977f02..91fcb097f4847 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5819,9 +5819,10 @@ ProtocolConformanceRef ProtocolConformanceRef::forAbstract( break; default: - llvm::errs() << "Abstract conformance with bad subject type:\n"; - conformingType->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Abstract conformance with bad subject type:\n"; + conformingType->dump(out); + }); } // Figure out which arena this should go in. diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index f8286d86f6403..eab548632bcc4 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1446,8 +1446,7 @@ void ASTMangler::appendType(Type type, GenericSignature sig, case TypeKind::BuiltinUnsafeValueBuffer: return appendOperator("BB"); case TypeKind::BuiltinUnboundGeneric: - llvm::errs() << "Don't know how to mangle a BuiltinUnboundGenericType\n"; - abort(); + ABORT("Don't know how to mangle a BuiltinUnboundGenericType"); case TypeKind::Locatable: { auto loc = cast(tybase); return appendType(loc->getSinglyDesugaredType(), sig, forDecl); @@ -1756,9 +1755,10 @@ void ASTMangler::appendType(Type type, GenericSignature sig, case TypeKind::PackArchetype: case TypeKind::ElementArchetype: case TypeKind::ExistentialArchetype: - llvm::errs() << "Cannot mangle free-standing archetype: "; - tybase->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot mangle free-standing archetype: "; + tybase->dump(out); + }); case TypeKind::OpaqueTypeArchetype: { auto opaqueType = cast(tybase); @@ -4468,8 +4468,7 @@ static unsigned conformanceRequirementIndex( ++result; } - llvm::errs() <<"Conformance access path step is missing from requirements"; - abort(); + ABORT("Conformance access path step is missing from requirements"); } void ASTMangler::appendDependentProtocolConformance( @@ -4573,9 +4572,10 @@ void ASTMangler::appendAnyProtocolConformance( } else if (conformance.isPack()) { appendPackProtocolConformance(conformance.getPack(), genericSig); } else { - llvm::errs() << "Bad conformance in mangler: "; - conformance.dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Bad conformance in mangler: "; + conformance.dump(out); + }); } } diff --git a/lib/AST/AvailabilityScope.cpp b/lib/AST/AvailabilityScope.cpp index e24ba24da5e0f..36e2b003541a6 100644 --- a/lib/AST/AvailabilityScope.cpp +++ b/lib/AST/AvailabilityScope.cpp @@ -519,15 +519,16 @@ static void verificationError( ASTContext &ctx, llvm::StringRef msg, std::initializer_list> labelsAndNodes) { - llvm::errs() << msg << "\n"; - for (auto pair : labelsAndNodes) { - auto label = std::get<0>(pair); - auto scope = std::get<1>(pair); - llvm::errs() << label << ":\n"; - scope->print(llvm::errs(), ctx.SourceMgr); - llvm::errs() << "\n"; - } - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + for (auto pair : labelsAndNodes) { + auto label = std::get<0>(pair); + auto scope = std::get<1>(pair); + out << label << ":\n"; + scope->print(out, ctx.SourceMgr); + out << "\n"; + } + }); } void AvailabilityScope::verify(const AvailabilityScope *parent, diff --git a/lib/AST/Bridging/MiscBridging.cpp b/lib/AST/Bridging/MiscBridging.cpp index 54fe953ff8979..3e9eff7c4015b 100644 --- a/lib/AST/Bridging/MiscBridging.cpp +++ b/lib/AST/Bridging/MiscBridging.cpp @@ -64,8 +64,9 @@ static SwiftMetatype declMetatypes[(unsigned)DeclKind::Last_Decl + 1]; SwiftMetatype Decl::getDeclMetatype(DeclKind kind) { SwiftMetatype metatype = declMetatypes[(unsigned)kind]; if (declMetatypesInitialized && !metatype) { - llvm::errs() << "Decl " << getKindName(kind) << " not registered\n"; - abort(); + ABORT([&](auto &out) { + out << "Decl " << getKindName(kind) << " not registered"; + }); } return metatype; } @@ -83,9 +84,9 @@ void registerBridgedDecl(BridgedStringRef bridgedClassName, .Default(std::nullopt); if (!declKind) { - llvm::errs() << "Unknown Decl class " << bridgedClassName.unbridged() - << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Unknown Decl class " << bridgedClassName.unbridged(); + }); } declMetatypes[(unsigned)declKind.value()] = metatype; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 140872ecbf9b6..be42874021291 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1994,9 +1994,10 @@ unsigned AbstractClosureExpr::getDiscriminator() const { } if (getRawDiscriminator() == InvalidDiscriminator) { - llvm::errs() << "Closure does not have an assigned discriminator:\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Closure does not have an assigned discriminator:\n"; + this->dump(out); + }); } return getRawDiscriminator(); diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index d3416dae9940b..502fc0914eb3c 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -886,15 +886,18 @@ void GenericSignature::verify() const { } void GenericSignature::verify(ArrayRef reqts) const { - auto dumpAndAbort = [&]() { - llvm::errs() << "All requirements:\n"; - for (auto reqt : reqts) { - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - } - getPointer()->getRequirementMachine()->dump(llvm::errs()); - abort(); - }; + auto dumpAndAbort = + [&](llvm::function_ref message) { + ABORT([&](auto &out) { + message(out); + out << "\nAll requirements:\n"; + for (auto reqt : reqts) { + reqt.dump(out); + out << "\n"; + } + getPointer()->getRequirementMachine()->dump(out); + }); + }; auto canSig = getCanonicalSignature(); @@ -913,17 +916,17 @@ void GenericSignature::verify(ArrayRef reqts) const { // Left-hand side must be a canonical type parameter. if (reqt.getKind() != RequirementKind::SameType) { if (!reqt.getFirstType()->isTypeParameter()) { - llvm::errs() << "Left-hand side must be a type parameter: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Left-hand side must be a type parameter: "; + reqt.dump(out); + }); } if (!canSig->isReducedType(reqt.getFirstType())) { - llvm::errs() << "Left-hand side is not reduced: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Left-hand side is not reduced: "; + reqt.dump(out); + }); } } @@ -931,40 +934,40 @@ void GenericSignature::verify(ArrayRef reqts) const { switch (reqt.getKind()) { case RequirementKind::SameShape: if (!reqt.getFirstType()->is()) { - llvm::errs() << "Left hand side is not a generic parameter: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Left hand side is not a generic parameter: "; + reqt.dump(out); + }); } if (!reqt.getFirstType()->isRootParameterPack()) { - llvm::errs() << "Left hand side is not a parameter pack: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Left hand side is not a parameter pack: "; + reqt.dump(out); + }); } if (!reqt.getSecondType()->is()) { - llvm::errs() << "Right hand side is not a generic parameter: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Right hand side is not a generic parameter: "; + reqt.dump(out); + }); } if (!reqt.getSecondType()->isRootParameterPack()) { - llvm::errs() << "Right hand side is not a parameter pack: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Right hand side is not a parameter pack: "; + reqt.dump(out); + }); } break; case RequirementKind::Superclass: if (!canSig->isReducedType(reqt.getSecondType())) { - llvm::errs() << "Right-hand side is not reduced: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Right-hand side is not reduced: "; + reqt.dump(out); + }); } break; @@ -987,53 +990,53 @@ void GenericSignature::verify(ArrayRef reqts) const { auto &component = sameTypeComponents[canType]; if (!hasReducedOrConcreteParent(firstType)) { - llvm::errs() << "Left hand side does not have a reduced parent: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Left hand side does not have a reduced parent: "; + reqt.dump(out); + }); } if (reqt.getSecondType()->isTypeParameter()) { if (!hasReducedOrConcreteParent(secondType)) { - llvm::errs() << "Right hand side does not have a reduced parent: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Right hand side does not have a reduced parent: "; + reqt.dump(out); + }); } if (compareDependentTypes(firstType, secondType) >= 0) { - llvm::errs() << "Out-of-order type parameters: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Out-of-order type parameters: "; + reqt.dump(out); + }); } if (component.empty()) { component.push_back(firstType); } else if (!component.back()->isEqual(firstType)) { - llvm::errs() << "Same-type requirement within an equiv. class " - << "is out-of-order: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Same-type requirement within an equiv. class " + << "is out-of-order: "; + reqt.dump(out); + }); } component.push_back(secondType); } else { if (!canSig->isReducedType(secondType)) { - llvm::errs() << "Right hand side is not reduced: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Right hand side is not reduced: "; + reqt.dump(out); + }); } if (component.empty()) { component.push_back(secondType); } else if (!component.back()->isEqual(secondType)) { - llvm::errs() << "Inconsistent concrete requirement in equiv. class: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Inconsistent concrete requirement in equiv. class: "; + reqt.dump(out); + }); } } break; @@ -1054,10 +1057,10 @@ void GenericSignature::verify(ArrayRef reqts) const { int compareLHS = compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType()); if (compareLHS > 0) { - llvm::errs() << "Out-of-order left-hand side: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Out-of-order left-hand side: "; + reqt.dump(out); + }); } // If we have a concrete same-type requirement, we shouldn't have any @@ -1065,19 +1068,19 @@ void GenericSignature::verify(ArrayRef reqts) const { if (reqt.getKind() == RequirementKind::SameType && !reqt.getSecondType()->isTypeParameter()) { if (compareLHS >= 0) { - llvm::errs() << "Concrete subject type should not have " - << "any other requirements: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Concrete subject type should not have " + << "any other requirements: "; + reqt.dump(out); + }); } } if (prevReqt.compare(reqt) >= 0) { - llvm::errs() << "Out-of-order requirement: "; - reqt.dump(llvm::errs()); - llvm::errs() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Out-of-order requirement: "; + reqt.dump(out); + }); } } @@ -1092,19 +1095,21 @@ void GenericSignature::verify(ArrayRef reqts) const { ProtocolType::canonicalizeProtocols(canonicalProtos); if (protos.size() != canonicalProtos.size()) { - llvm::errs() << "Redundant conformance requirements in signature " - << *this << ":\n"; - llvm::errs() << "Ours:\n"; - for (auto *proto : protos) - llvm::errs() << "- " << proto->getName() << "\n"; - llvm::errs() << "Theirs:\n"; - for (auto *proto : canonicalProtos) - llvm::errs() << "- " << proto->getName() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Redundant conformance requirements in signature " << *this + << ":\n"; + out << "Ours:\n"; + for (auto *proto : protos) + out << "- " << proto->getName() << "\n"; + out << "Theirs:\n"; + for (auto *proto : canonicalProtos) + out << "- " << proto->getName(); + }); } if (!std::equal(protos.begin(), protos.end(), canonicalProtos.begin())) { - llvm::errs() << "Out-of-order conformance requirements\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Out-of-order conformance requirements"; + }); } } @@ -1112,11 +1117,11 @@ void GenericSignature::verify(ArrayRef reqts) const { for (const auto &pair : sameTypeComponents) { if (pair.second.front()->isTypeParameter() && !canSig->isReducedType(pair.second.front())) { - llvm::errs() << "Abstract same-type requirement involving concrete types\n"; - llvm::errs() << "Reduced type: " << pair.first << "\n"; - llvm::errs() << "Left hand side of first requirement: " - << pair.second.front() << "\n"; - dumpAndAbort(); + dumpAndAbort([&](auto &out) { + out << "Abstract same-type requirement involving concrete types\n"; + out << "Reduced type: " << pair.first << "\n"; + out << "Left hand side of first requirement: " << pair.second.front(); + }); } } } diff --git a/lib/AST/LocalArchetypeRequirementCollector.cpp b/lib/AST/LocalArchetypeRequirementCollector.cpp index 642bca5a72342..b3fb9be240aff 100644 --- a/lib/AST/LocalArchetypeRequirementCollector.cpp +++ b/lib/AST/LocalArchetypeRequirementCollector.cpp @@ -183,9 +183,10 @@ Type MapLocalArchetypesOutOfContext::getInterfaceType( ++depth; } - llvm::errs() << "Fell off the end:\n"; - interfaceTy->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Fell off the end:\n"; + interfaceTy->dump(out); + }); } Type MapLocalArchetypesOutOfContext::operator()(SubstitutableType *type) const { diff --git a/lib/AST/ParameterPack.cpp b/lib/AST/ParameterPack.cpp index cd1f00f9e1e93..cf09518406db3 100644 --- a/lib/AST/ParameterPack.cpp +++ b/lib/AST/ParameterPack.cpp @@ -380,10 +380,11 @@ unsigned ParameterList::getOrigParamIndex(SubstitutionMap subMap, remappedIndex -= substCount; } - llvm::errs() << "Invalid substituted argument index: " << substIndex << "\n"; - subMap.dump(llvm::errs()); - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Invalid substituted argument index: " << substIndex << "\n"; + subMap.dump(out); + dump(out); + }); } /// Foo => Pack{T..., Int, String} diff --git a/lib/AST/Requirement.cpp b/lib/AST/Requirement.cpp index 6397486287236..46b38a4340b75 100644 --- a/lib/AST/Requirement.cpp +++ b/lib/AST/Requirement.cpp @@ -255,10 +255,11 @@ int Requirement::compare(const Requirement &other) const { // We should only have multiple conformance requirements. if (getKind() != RequirementKind::Conformance) { - llvm::errs() << "Unordered generic requirements\n"; - llvm::errs() << "LHS: "; dump(llvm::errs()); llvm::errs() << "\n"; - llvm::errs() << "RHS: "; other.dump(llvm::errs()); llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Unordered generic requirements\n"; + out << "LHS: "; dump(out); out << "\n"; + out << "RHS: "; other.dump(out); + }); } int compareProtos = diff --git a/lib/AST/RequirementMachine/ConcreteTypeWitness.cpp b/lib/AST/RequirementMachine/ConcreteTypeWitness.cpp index 7c31a63512294..532dc741f9b23 100644 --- a/lib/AST/RequirementMachine/ConcreteTypeWitness.cpp +++ b/lib/AST/RequirementMachine/ConcreteTypeWitness.cpp @@ -249,12 +249,13 @@ void PropertyMap::concretizeTypeWitnessInConformance( } else if (conformance.isAbstract()) { auto archetype = concreteType->getAs(); if (archetype == nullptr) { - llvm::errs() << "Should only have an abstract conformance with an " - << "opaque archetype type\n"; - llvm::errs() << "Symbol: " << concreteConformanceSymbol << "\n"; - llvm::errs() << "Term: " << key << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Should only have an abstract conformance with an opaque " + << "archetype type\n"; + out << "Symbol: " << concreteConformanceSymbol << "\n"; + out << "Term: " << key << "\n"; + dump(out); + }); } typeWitness = archetype->getNestedType(assocType)->getCanonicalType(); diff --git a/lib/AST/RequirementMachine/Diagnostics.cpp b/lib/AST/RequirementMachine/Diagnostics.cpp index 47f47e21ff137..cd990c1068f18 100644 --- a/lib/AST/RequirementMachine/Diagnostics.cpp +++ b/lib/AST/RequirementMachine/Diagnostics.cpp @@ -308,8 +308,9 @@ getRequirementForDiagnostics(Type subject, Symbol property, property.getLayoutConstraint()); default: - llvm::errs() << "Bad property symbol: " << property << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Bad property symbol: " << property; + }); } } diff --git a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp index 14815edf4ed45..3d8648ee72397 100644 --- a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp +++ b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp @@ -274,8 +274,9 @@ RequirementMachine::getLongestValidPrefix(const MutableTerm &term) const { case Symbol::Kind::ConcreteConformance: case Symbol::Kind::Shape: case Symbol::Kind::PackElement: - llvm::errs() <<"Invalid symbol in a type term: " << term << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Invalid symbol in a type term: " << term; + }); } // This symbol is valid, add it to the longest prefix. @@ -436,25 +437,25 @@ Type RequirementMachine::getReducedTypeParameter( // If U is not concrete, we have an invalid member type of a dependent // type, which is not valid in this generic signature. Give up. if (prefix.empty() || prefixType->isTypeParameter()) { - llvm::errs() << "\n"; - llvm::errs() << "getReducedTypeParameter() was called\n"; - llvm::errs() << " with " << Sig << ",\n"; - llvm::errs() << " and " << t << ".\n\n"; - if (prefix.empty()) { - llvm::errs() << "This type parameter contains the generic parameter " - << Type(t->getRootGenericParam()) << ".\n\n"; - llvm::errs() << "This generic parameter is not part of the given " - << "generic signature.\n\n"; - } else { - llvm::errs() << "This type parameter's reduced term is " << term << ".\n\n"; - llvm::errs() << "This is not a valid term, because " << prefix << " does not " - << "have a member type named " << term[prefix.size()] << ".\n\n"; - } - llvm::errs() << "This usually indicates the caller passed the wrong type or " - << "generic signature to getReducedType().\n\n"; + ABORT([&](auto &out) { + out << "getReducedTypeParameter() was called\n"; + out << " with " << Sig << ",\n"; + out << " and " << t << ".\n\n"; + if (prefix.empty()) { + out << "This type parameter contains the generic parameter " + << Type(t->getRootGenericParam()) << ".\n\n"; + out << "This generic parameter is not part of the given " + << "generic signature.\n\n"; + } else { + out << "This type parameter's reduced term is " << term << ".\n\n"; + out << "This is not a valid term, because " << prefix << " does not " + << "have a member type named " << term[prefix.size()] << ".\n\n"; + } + out << "This usually indicates the caller passed the wrong type or " + << "generic signature to getReducedType().\n\n"; - dump(llvm::errs()); - abort(); + dump(out); + }); } // Compute the type of the unresolved suffix term V. @@ -603,13 +604,14 @@ RequirementMachine::getConformancePath(Type type, } if (CurrentConformancePaths.empty()) { - llvm::errs() << "Failed to find conformance path for "; - llvm::errs() << type << " (" << term << ")" << " : "; - llvm::errs() << protocol->getName() << ":\n"; - type.dump(llvm::errs()); - llvm::errs() << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Failed to find conformance path for "; + out << type << " (" << term << ")" << " : "; + out << protocol->getName() << ":\n"; + type.dump(out); + out << "\n"; + dump(out); + }); } // The buffer consists of all conformance paths of length N. @@ -751,10 +753,11 @@ RequirementMachine::getReducedShapeTerm(Type type) const { if (term.size() != 2 || term[0].getKind() != Symbol::Kind::GenericParam || term[1].getKind() != Symbol::Kind::Shape) { - llvm::errs() << "Invalid reduced shape\n"; - llvm::errs() << "Type: " << type << "\n"; - llvm::errs() << "Term: " << term << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Invalid reduced shape\n"; + out << "Type: " << type << "\n"; + out << "Term: " << term; + }); } MutableTerm reducedTerm(term.begin(), term.end() - 1); @@ -791,9 +794,10 @@ void RequirementMachine::verify(const MutableTerm &term) const { return genericParam->isEqual(otherType); }); if (found == genericParams.end()) { - llvm::errs() << "Bad generic parameter in " << term << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Bad generic parameter in " << term << "\n"; + dump(out); + }); } } @@ -820,8 +824,9 @@ void RequirementMachine::verify(const MutableTerm &term) const { case Symbol::Kind::ConcreteType: case Symbol::Kind::ConcreteConformance: case Symbol::Kind::Shape: - llvm::errs() << "Bad initial symbol in " << term << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Bad initial symbol in " << term; + }); break; } } @@ -847,8 +852,9 @@ void RequirementMachine::verify(const MutableTerm &term) const { case Symbol::Kind::ConcreteType: case Symbol::Kind::ConcreteConformance: case Symbol::Kind::PackElement: - llvm::errs() << "Bad interior symbol " << symbol << " in " << term << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Bad interior symbol " << symbol << " in " << term; + }); break; } } @@ -858,12 +864,13 @@ void RequirementMachine::verify(const MutableTerm &term) const { // We should end up with the same term. if (simplified != term) { - llvm::errs() << "Term verification failed\n"; - llvm::errs() << "Initial term: " << term << "\n"; - llvm::errs() << "Erased term: " << erased << "\n"; - llvm::errs() << "Simplified term: " << simplified << "\n"; - llvm::errs() << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Term verification failed\n"; + out << "Initial term: " << term << "\n"; + out << "Erased term: " << erased << "\n"; + out << "Simplified term: " << simplified << "\n"; + out << "\n"; + dump(out); + }); } } diff --git a/lib/AST/RequirementMachine/HomotopyReduction.cpp b/lib/AST/RequirementMachine/HomotopyReduction.cpp index 3efadceb16953..30bd13d795efd 100644 --- a/lib/AST/RequirementMachine/HomotopyReduction.cpp +++ b/lib/AST/RequirementMachine/HomotopyReduction.cpp @@ -730,11 +730,11 @@ void RewriteSystem::verifyRedundantConformances( "Redundant conformance is not a conformance rule?"); if (!rule.isRedundant()) { - llvm::errs() << "Homotopy reduction did not eliminate redundant " - << "conformance?\n"; - llvm::errs() << "(#" << ruleID << ") " << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Homotopy reduction did not eliminate redundant conformance?\n"; + out << "(#" << ruleID << ") " << rule << "\n\n"; + dump(out); + }); } } } @@ -752,10 +752,11 @@ void RewriteSystem::verifyMinimizedRules( // Ignore the rewrite rule if it is not part of our minimization domain. if (!isInMinimizationDomain(rule.getLHS().getRootProtocol())) { if (rule.isRedundant()) { - llvm::errs() << "Redundant rule outside minimization domain: " - << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Redundant rule outside minimization domain: " << rule + << "\n\n"; + dump(out); + }); } continue; @@ -765,9 +766,10 @@ void RewriteSystem::verifyMinimizedRules( // be redundant. if (rule.isPermanent()) { if (rule.isRedundant()) { - llvm::errs() << "Permanent rule is redundant: " << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Permanent rule is redundant: " << rule << "\n\n"; + dump(out); + }); } continue; @@ -783,18 +785,20 @@ void RewriteSystem::verifyMinimizedRules( if (rule.isLHSSimplified() && !rule.isRedundant() && !rule.isProtocolConformanceRule()) { - llvm::errs() << "Simplified rule is not redundant: " << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Simplified rule is not redundant: " << rule << "\n\n"; + dump(out); + }); } // RHS-simplified and substitution-simplified rules should be redundant. if ((rule.isRHSSimplified() || rule.isSubstitutionSimplified()) && !rule.isRedundant()) { - llvm::errs() << "Simplified rule is not redundant: " << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Simplified rule is not redundant: " << rule << "\n\n"; + dump(out); + }); } if (rule.isRedundant() && @@ -803,17 +807,19 @@ void RewriteSystem::verifyMinimizedRules( !rule.isSubstitutionSimplified() && !rule.containsNameSymbols() && !redundantConformances.count(ruleID)) { - llvm::errs() << "Minimal conformance is redundant: " << rule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Minimal conformance is redundant: " << rule << "\n\n"; + dump(out); + }); } } if (RedundantRules.size() != redundantRuleCount) { - llvm::errs() << "Expected " << RedundantRules.size() << " redundant rules " - << "but counted " << redundantRuleCount << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Expected " << RedundantRules.size() << " redundant rules " + << "but counted " << redundantRuleCount << "\n"; + dump(out); + }); } // Replacement paths for redundant rules can only reference other redundant @@ -823,10 +829,11 @@ void RewriteSystem::verifyMinimizedRules( for (const auto &pair : llvm::reverse(RedundantRules)) { const auto &rule = getRule(pair.first); if (!rule.isRedundant()) { - llvm::errs() << "Recorded replacement path for non-redundant rule " - << rule << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Recorded replacement path for non-redundant rule " << rule + << "\n"; + dump(out); + }); } for (const auto &step : pair.second) { @@ -835,10 +842,11 @@ void RewriteSystem::verifyMinimizedRules( const auto &otherRule = getRule(otherRuleID); if (otherRule.isRedundant() && !laterRedundantRules.count(otherRuleID)) { - llvm::errs() << "Redundant requirement path contains a redundant " - "rule " << otherRule << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Redundant requirement path contains a redundant rule " + << otherRule << "\n"; + dump(out); + }); } } } diff --git a/lib/AST/RequirementMachine/InterfaceType.cpp b/lib/AST/RequirementMachine/InterfaceType.cpp index 48f96f84adafe..56216ef16653c 100644 --- a/lib/AST/RequirementMachine/InterfaceType.cpp +++ b/lib/AST/RequirementMachine/InterfaceType.cpp @@ -250,15 +250,14 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, unsigned index = GenericParamKey(genericParam).findIndexIn(genericParams); if (index == genericParams.size()) { - llvm::errs() << "Cannot build interface type for term " - << MutableTerm(begin, end) << "\n"; - llvm::errs() << "Invalid generic parameter: " - << Type(genericParam) << "\n"; - llvm::errs() << "Valid generic parameters: "; - for (auto *otherParam : genericParams) - llvm::errs() << " " << otherParam->getCanonicalType(); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Cannot build interface type for term " + << MutableTerm(begin, end) << "\n"; + out << "Invalid generic parameter: " << Type(genericParam) << "\n"; + out << "Valid generic parameters: "; + for (auto *otherParam : genericParams) + out << " " << otherParam->getCanonicalType(); + }); } result = genericParams[index]; @@ -300,8 +299,9 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, case Symbol::Kind::ConcreteType: case Symbol::Kind::ConcreteConformance: case Symbol::Kind::Shape: - llvm::errs() << "Invalid root symbol: " << MutableTerm(begin, end) << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Invalid root symbol: " << MutableTerm(begin, end); + }); } } @@ -348,12 +348,12 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, auto *props = map.lookUpProperties(prefix.rbegin(), prefix.rend()); if (props == nullptr) { - llvm::errs() << "Cannot build interface type for term " - << MutableTerm(begin, end) << "\n"; - llvm::errs() << "Prefix does not conform to any protocols: " - << prefix << "\n\n"; - map.dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot build interface type for term " + << MutableTerm(begin, end) << "\n"; + out << "Prefix does not conform to any protocols: " << prefix << "\n\n"; + map.dump(out); + }); } // Assert that the associated type's protocol appears among the set @@ -367,16 +367,16 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, auto *assocType = props->getAssociatedType(symbol.getName()); if (assocType == nullptr) { - llvm::errs() << "Cannot build interface type for term " - << MutableTerm(begin, end) << "\n"; - llvm::errs() << "Prefix term does not have a nested type named " - << symbol.getName() << ": " - << prefix << "\n"; - llvm::errs() << "Property map entry: "; - props->dump(llvm::errs()); - llvm::errs() << "\n\n"; - map.dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot build interface type for term " + << MutableTerm(begin, end) << "\n"; + out << "Prefix term does not have a nested type named " + << symbol.getName() << ": " << prefix << "\n"; + out << "Property map entry: "; + props->dump(out); + out << "\n\n"; + map.dump(out); + }); } result = DependentMemberType::get(result, assocType); @@ -487,18 +487,18 @@ Type PropertyMap::getTypeFromSubstitutionSchema( bool isShapePosition = (pos == TypePosition::Shape); bool isShapeTerm = (substitution.back() == Symbol::forShape(Context)); if (isShapePosition != isShapeTerm) { - llvm::errs() << "Shape vs. type mixup\n\n"; - schema.dump(llvm::errs()); - llvm::errs() << "Substitutions:\n"; - for (auto otherSubst : substitutions) { - llvm::errs() << "- "; - otherSubst.dump(llvm::errs()); - llvm::errs() << "\n"; - } - llvm::errs() << "\n"; - dump(llvm::errs()); - - abort(); + ABORT([&](auto &out) { + out << "Shape vs. type mixup\n\n"; + schema.dump(out); + out << "Substitutions:\n"; + for (auto otherSubst : substitutions) { + out << "- "; + otherSubst.dump(out); + out << "\n"; + } + out << "\n"; + dump(out); + }); } // Undo the thing where the count type of a PackExpansionType diff --git a/lib/AST/RequirementMachine/MinimalConformances.cpp b/lib/AST/RequirementMachine/MinimalConformances.cpp index 3bce42b4d49b3..15e69d882d2a8 100644 --- a/lib/AST/RequirementMachine/MinimalConformances.cpp +++ b/lib/AST/RequirementMachine/MinimalConformances.cpp @@ -179,9 +179,10 @@ RewriteSystem::decomposeTermIntoConformanceRuleLeftHandSides( RewritePath steps; bool simplified = simplify(term, &steps); if (!simplified) { - llvm::errs() << "Term does not conform to protocol: " << term << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Term does not conform to protocol: " << term << "\n"; + dump(out); + }); } ASSERT(steps.size() == 1 && @@ -291,8 +292,9 @@ static const ProtocolDecl *getParentConformanceForTerm(Term lhs) { break; } - llvm::errs() << "Bad symbol in " << lhs << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Bad symbol in " << lhs; + }); } /// Collect conformance rules and parent paths, and record an initial @@ -615,19 +617,20 @@ void RewriteSystem::computeCandidateConformancePaths( RewritePath rewritePath; bool result = simplify(yp, &rewritePath); if (!result) { - llvm::errs() << "Does not conform to protocol: " << yp << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Does not conform to protocol: " << yp << "\n"; + dump(out); + }); } if (rewritePath.size() != 1) { - llvm::errs() << "Funny rewrite path: "; + ABORT([&](auto &out) { + out << "Funny rewrite path: "; - yp = y; - yp.add(rhs.getLHS().back()); - rewritePath.dump(llvm::errs(), yp, *this); - llvm::errs() << "\n"; - abort(); + yp = y; + yp.add(rhs.getLHS().back()); + rewritePath.dump(out, yp, *this); + }); } if (rewritePath.begin()->StartOffset == 0) { @@ -800,15 +803,15 @@ void MinimalConformances::verifyMinimalConformanceEquations() const { auto *otherProto = otherRule.getLHS().back().getProtocol(); if (proto != otherProto) { - llvm::errs() << "Invalid equation: "; - dumpMinimalConformanceEquation(llvm::errs(), - pair.first, pair.second); - llvm::errs() << "\n"; - llvm::errs() << "Mismatched conformance:\n"; - llvm::errs() << "Base rule: " << rule << "\n"; - llvm::errs() << "Final rule: " << otherRule << "\n\n"; - dumpMinimalConformanceEquations(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Invalid equation: "; + dumpMinimalConformanceEquation(out, pair.first, pair.second); + out << "\n"; + out << "Mismatched conformance:\n"; + out << "Base rule: " << rule << "\n"; + out << "Final rule: " << otherRule << "\n\n"; + dumpMinimalConformanceEquations(out); + }); } MutableTerm otherTerm; @@ -819,13 +822,13 @@ void MinimalConformances::verifyMinimalConformanceEquations() const { bool isLastElement = (i == path.size() - 1); if ((isLastElement && !rule.isAnyConformanceRule()) || (!isLastElement && !rule.isProtocolConformanceRule())) { - llvm::errs() << "Equation term is not a conformance rule: "; - dumpMinimalConformanceEquation(llvm::errs(), - pair.first, pair.second); - llvm::errs() << "\n"; - llvm::errs() << "Term: " << rule << "\n"; - dumpMinimalConformanceEquations(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Equation term is not a conformance rule: "; + dumpMinimalConformanceEquation(out, pair.first, pair.second); + out << "\n"; + out << "Term: " << rule << "\n"; + dumpMinimalConformanceEquations(out); + }); } otherTerm.append(rule.getRHS()); @@ -834,15 +837,15 @@ void MinimalConformances::verifyMinimalConformanceEquations() const { (void) System.simplify(otherTerm); if (baseTerm != otherTerm) { - llvm::errs() << "Invalid equation: "; - dumpMinimalConformanceEquation(llvm::errs(), - pair.first, pair.second); - llvm::errs() << "\n"; - llvm::errs() << "Invalid conformance path:\n"; - llvm::errs() << "Expected: " << baseTerm << "\n"; - llvm::errs() << "Got: " << otherTerm << "\n\n"; - dumpMinimalConformanceEquations(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Invalid equation: "; + dumpMinimalConformanceEquation(out, pair.first, pair.second); + out << "\n"; + out << "Invalid conformance path:\n"; + out << "Expected: " << baseTerm << "\n"; + out << "Got: " << otherTerm << "\n\n"; + dumpMinimalConformanceEquations(out); + }); } } } @@ -941,22 +944,24 @@ void MinimalConformances::verifyMinimalConformances() const { llvm::SmallDenseSet visited; if (!isConformanceRuleRecoverable(visited, ruleID)) { - llvm::errs() << "Redundant conformance is not recoverable:\n"; - llvm::errs() << rule << "\n\n"; - dumpMinimalConformanceEquations(llvm::errs()); - dumpMinimalConformances(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Redundant conformance is not recoverable:\n"; + out << rule << "\n\n"; + dumpMinimalConformanceEquations(out); + dumpMinimalConformances(out); + }); } continue; } if (rule.containsNameSymbols()) { - llvm::errs() << "Minimal conformance contains unresolved symbols: "; - llvm::errs() << rule << "\n\n"; - dumpMinimalConformanceEquations(llvm::errs()); - dumpMinimalConformances(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Minimal conformance contains unresolved symbols: "; + out << rule << "\n\n"; + dumpMinimalConformanceEquations(out); + dumpMinimalConformances(out); + }); } } } diff --git a/lib/AST/RequirementMachine/PropertyMap.cpp b/lib/AST/RequirementMachine/PropertyMap.cpp index 9f25f4269fdf8..cf4ee4005edc8 100644 --- a/lib/AST/RequirementMachine/PropertyMap.cpp +++ b/lib/AST/RequirementMachine/PropertyMap.cpp @@ -364,14 +364,14 @@ PropertyMap::getOrCreateProperties(Term key) { Entries.push_back(props); auto oldProps = Trie.insert(key.rbegin(), key.rend(), props); if (oldProps) { - llvm::errs() << "Duplicate property map entry for " << key << "\n"; - llvm::errs() << "Old:\n"; - (*oldProps)->dump(llvm::errs()); - llvm::errs() << "\n"; - llvm::errs() << "New:\n"; - props->dump(llvm::errs()); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Duplicate property map entry for " << key << "\n"; + out << "Old:\n"; + (*oldProps)->dump(out); + out << "\n"; + out << "New:\n"; + props->dump(out); + }); } return props; diff --git a/lib/AST/RequirementMachine/PropertyUnification.cpp b/lib/AST/RequirementMachine/PropertyUnification.cpp index 58d78095c4228..0a15d160a0949 100644 --- a/lib/AST/RequirementMachine/PropertyUnification.cpp +++ b/lib/AST/RequirementMachine/PropertyUnification.cpp @@ -221,9 +221,7 @@ void PropertyMap::addLayoutProperty( props->LayoutRule = ruleID; } else { - llvm::errs() << "Arbitrary intersection of layout requirements is " - << "supported yet\n"; - abort(); + ABORT("Arbitrary intersection of layout requirements isn't supported yet"); } } diff --git a/lib/AST/RequirementMachine/RequirementMachine.cpp b/lib/AST/RequirementMachine/RequirementMachine.cpp index 1fa52060f0c4f..b1432766ff43a 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.cpp +++ b/lib/AST/RequirementMachine/RequirementMachine.cpp @@ -231,19 +231,22 @@ void RequirementMachine::checkCompletionResult(CompletionResult result) const { break; case CompletionResult::MaxRuleCount: - llvm::errs() << "Rewrite system exceeded maximum rule count\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Rewrite system exceeded maximum rule count\n"; + dump(out); + }); case CompletionResult::MaxRuleLength: - llvm::errs() << "Rewrite system exceeded rule length limit\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Rewrite system exceeded rule length limit\n"; + dump(out); + }); case CompletionResult::MaxConcreteNesting: - llvm::errs() << "Rewrite system exceeded concrete type nesting depth limit\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Rewrite system exceeded concrete type nesting depth limit\n"; + dump(out); + }); } } diff --git a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp index f05d6ca577a35..dd0afbea65619 100644 --- a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp +++ b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp @@ -163,15 +163,16 @@ static void splitConcreteEquivalenceClasses( ctx.LangOpts.RequirementMachineMaxSplitConcreteEquivClassAttempts; if (attempt >= maxAttempts) { - llvm::errs() << "Splitting concrete equivalence classes did not " - << "reach fixed point after " << attempt << " attempts.\n"; - llvm::errs() << "Last attempt produced these requirements:\n"; - for (auto req : requirements) { - req.dump(llvm::errs()); - llvm::errs() << "\n"; - } - machine->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Splitting concrete equivalence classes did not " + << "reach fixed point after " << attempt << " attempts.\n"; + out << "Last attempt produced these requirements:\n"; + for (auto req : requirements) { + req.dump(out); + out << "\n"; + } + machine->dump(out); + }); } splitRequirements.clear(); diff --git a/lib/AST/RequirementMachine/RewriteContext.cpp b/lib/AST/RequirementMachine/RewriteContext.cpp index c739df898d356..d9d1564b18164 100644 --- a/lib/AST/RequirementMachine/RewriteContext.cpp +++ b/lib/AST/RequirementMachine/RewriteContext.cpp @@ -267,9 +267,9 @@ RequirementMachine *RewriteContext::getRequirementMachine( auto &machine = Machines[sig]; if (machine) { if (!machine->isComplete()) { - llvm::errs() << "Re-entrant construction of requirement " - << "machine for " << sig << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Re-entrant construction of requirement machine for " << sig; + }); } return machine; @@ -433,10 +433,8 @@ RewriteContext::getProtocolComponentImpl(const ProtocolDecl *proto) { auto found = Protos.find(proto); if (found == Protos.end()) { - if (ProtectProtocolComponentRec) { - llvm::errs() << "Too much recursion is bad\n"; - abort(); - } + if (ProtectProtocolComponentRec) + ABORT("Too much recursion is bad"); ProtectProtocolComponentRec = true; @@ -469,11 +467,11 @@ RewriteContext::startComputingRequirementSignatures( auto &component = getProtocolComponentImpl(proto); if (component.ComputingRequirementSignatures) { - llvm::errs() << "Re-entrant minimization of requirement signatures for: "; - for (auto *proto : component.Protos) - llvm::errs() << " " << proto->getName(); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Re-entrant minimization of requirement signatures for: "; + for (auto *proto : component.Protos) + out << " " << proto->getName(); + }); } component.ComputingRequirementSignatures = true; @@ -508,11 +506,11 @@ RequirementMachine *RewriteContext::getRequirementMachine( if (component.Machine) { if (!component.Machine->isComplete()) { - llvm::errs() << "Re-entrant construction of requirement machine for: "; - for (auto *proto : component.Protos) - llvm::errs() << " " << proto->getName(); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Re-entrant construction of requirement machine for: "; + for (auto *proto : component.Protos) + out << " " << proto->getName(); + }); } return component.Machine; diff --git a/lib/AST/RequirementMachine/RewriteLoop.cpp b/lib/AST/RequirementMachine/RewriteLoop.cpp index 9c373e3729820..ef5a661d3e18b 100644 --- a/lib/AST/RequirementMachine/RewriteLoop.cpp +++ b/lib/AST/RequirementMachine/RewriteLoop.cpp @@ -430,16 +430,17 @@ void RewriteLoop::verify(const RewriteSystem &system) const { } if (evaluator.getCurrentTerm() != Basepoint) { - llvm::errs() << "Not a loop: "; - dump(llvm::errs(), system); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Not a loop: "; + dump(out, system); + }); } if (evaluator.isInContext()) { - llvm::errs() << "Leftover terms on evaluator stack\n"; - evaluator.dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Leftover terms on evaluator stack\n"; + evaluator.dump(out); + }); } } @@ -555,17 +556,19 @@ void RewritePathEvaluator::dump(llvm::raw_ostream &out) const { void RewritePathEvaluator::checkPrimary() const { if (Primary.empty()) { - llvm::errs() << "Empty primary stack\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Empty primary stack\n"; + dump(out); + }); } } void RewritePathEvaluator::checkSecondary() const { if (Secondary.empty()) { - llvm::errs() << "Empty secondary stack\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Empty secondary stack\n"; + dump(out); + }); } } @@ -587,12 +590,13 @@ RewritePathEvaluator::applyRewriteRule(const RewriteStep &step, auto rhs = (step.Inverse ? rule.getLHS() : rule.getRHS()); auto bug = [&](StringRef msg) { - llvm::errs() << msg << "\n"; - llvm::errs() << "- Term: " << term << "\n"; - llvm::errs() << "- StartOffset: " << step.StartOffset << "\n"; - llvm::errs() << "- EndOffset: " << step.EndOffset << "\n"; - llvm::errs() << "- Expected subterm: " << lhs << "\n"; - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + out << "- Term: " << term << "\n"; + out << "- StartOffset: " << step.StartOffset << "\n"; + out << "- EndOffset: " << step.EndOffset << "\n"; + out << "- Expected subterm: " << lhs; + }); }; if (term.size() != step.StartOffset + lhs.size() + step.EndOffset) { @@ -632,11 +636,12 @@ RewritePathEvaluator::applyPrefixSubstitutions(const RewriteStep &step, // We're either adding or removing the prefix to each concrete substitution. Symbol &last = *(term.end() - step.EndOffset - 1); if (!last.hasSubstitutions()) { - llvm::errs() << "Invalid rewrite path\n"; - llvm::errs() << "- Term: " << term << "\n"; - llvm::errs() << "- Start offset: " << step.StartOffset << "\n"; - llvm::errs() << "- End offset: " << step.EndOffset << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Invalid rewrite path\n"; + out << "- Term: " << term << "\n"; + out << "- Start offset: " << step.StartOffset << "\n"; + out << "- End offset: " << step.EndOffset; + }); } last = last.transformConcreteSubstitutions( @@ -645,13 +650,14 @@ RewritePathEvaluator::applyPrefixSubstitutions(const RewriteStep &step, if (!std::equal(t.begin(), t.begin() + step.Arg, prefix.begin())) { - llvm::errs() << "Invalid rewrite path\n"; - llvm::errs() << "- Term: " << term << "\n"; - llvm::errs() << "- Substitution: " << t << "\n"; - llvm::errs() << "- Start offset: " << step.StartOffset << "\n"; - llvm::errs() << "- End offset: " << step.EndOffset << "\n"; - llvm::errs() << "- Expected subterm: " << prefix << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Invalid rewrite path\n"; + out << "- Term: " << term << "\n"; + out << "- Substitution: " << t << "\n"; + out << "- Start offset: " << step.StartOffset << "\n"; + out << "- End offset: " << step.EndOffset << "\n"; + out << "- Expected subterm: " << prefix; + }); } MutableTerm mutTerm(t.begin() + step.Arg, t.end()); @@ -698,17 +704,19 @@ void RewritePathEvaluator::applyDecompose(const RewriteStep &step, const auto &term = getCurrentTerm(); auto symbol = *(term.end() - step.EndOffset - 1); if (!symbol.hasSubstitutions()) { - llvm::errs() << "Expected term with superclass or concrete type symbol" - << " on primary stack\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Expected term with superclass or concrete type symbol" + << " on primary stack\n"; + dump(out); + }); } // The symbol must have the expected number of substitutions. if (symbol.getSubstitutions().size() != numSubstitutions) { - llvm::errs() << "Expected " << numSubstitutions << " substitutions\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Expected " << numSubstitutions << " substitutions\n"; + dump(out); + }); } // Push each substitution on the primary stack. @@ -720,9 +728,10 @@ void RewritePathEvaluator::applyDecompose(const RewriteStep &step, // a term that takes the form U.[concrete: C].V or U.[superclass: C].V, // where |V| == EndOffset. if (Primary.size() < numSubstitutions + 1) { - llvm::errs() << "Not enough terms on primary stack\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Not enough terms on primary stack\n"; + dump(out); + }); } // The term immediately underneath the substitutions is the one we're @@ -733,18 +742,20 @@ void RewritePathEvaluator::applyDecompose(const RewriteStep &step, // The symbol at the end of this term must have the expected number of // substitutions. if (symbol.getSubstitutions().size() != numSubstitutions) { - llvm::errs() << "Expected " << numSubstitutions << " substitutions\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Expected " << numSubstitutions << " substitutions\n"; + dump(out); + }); } for (unsigned i = 0; i < numSubstitutions; ++i) { const auto &substitution = *(Primary.end() - numSubstitutions + i); if (MutableTerm(symbol.getSubstitutions()[i]) != substitution) { - llvm::errs() << "Expected " << symbol.getSubstitutions()[i] << "\n"; - llvm::errs() << "Got " << substitution << "\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Expected " << symbol.getSubstitutions()[i] << "\n"; + out << "Got " << substitution << "\n"; + dump(out); + }); } } @@ -765,12 +776,13 @@ RewritePathEvaluator::applyRelation(const RewriteStep &step, auto rhs = (step.Inverse ? relation.first : relation.second); auto bug = [&](StringRef msg) { - llvm::errs() << msg << "\n"; - llvm::errs() << "- Term: " << term << "\n"; - llvm::errs() << "- StartOffset: " << step.StartOffset << "\n"; - llvm::errs() << "- EndOffset: " << step.EndOffset << "\n"; - llvm::errs() << "- Expected subterm: " << lhs << "\n"; - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + out << "- Term: " << term << "\n"; + out << "- StartOffset: " << step.StartOffset << "\n"; + out << "- EndOffset: " << step.EndOffset << "\n"; + out << "- Expected subterm: " << lhs << "\n"; + }); }; if (term.size() != step.StartOffset + lhs.size() + step.EndOffset) { @@ -799,15 +811,16 @@ void RewritePathEvaluator::applyDecomposeConcrete(const RewriteStep &step, const auto &difference = system.getTypeDifference(step.Arg); auto bug = [&](StringRef msg) { - llvm::errs() << msg << "\n"; - llvm::errs() << "- StartOffset: " << step.StartOffset << "\n"; - llvm::errs() << "- EndOffset: " << step.EndOffset << "\n"; - llvm::errs() << "- DifferenceID: " << step.Arg << "\n"; - llvm::errs() << "\nType difference:\n"; - difference.dump(llvm::errs()); - llvm::errs() << "\nEvaluator state:\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + out << "- StartOffset: " << step.StartOffset << "\n"; + out << "- EndOffset: " << step.EndOffset << "\n"; + out << "- DifferenceID: " << step.Arg << "\n"; + out << "\nType difference:\n"; + difference.dump(out); + out << "\nEvaluator state:\n"; + dump(out); + }); }; auto substitutions = difference.LHS.getSubstitutions(); @@ -837,9 +850,12 @@ void RewritePathEvaluator::applyDecomposeConcrete(const RewriteStep &step, const auto &otherSubstitution = *(Primary.end() - numSubstitutions + n); auto expectedSubstitution = difference.getReplacementSubstitution(n); if (otherSubstitution != expectedSubstitution) { - llvm::errs() << "Got: " << otherSubstitution << "\n"; - llvm::errs() << "Expected: " << expectedSubstitution << "\n"; - bug("Unexpected substitution term on the stack"); + SmallString<0> message; + llvm::raw_svector_ostream out(message); + out << "Unexpected substitution term on the stack\n"; + out << "Got: " << otherSubstitution << "\n"; + out << "Expected: " << expectedSubstitution << "\n"; + bug(message); } } @@ -872,20 +888,21 @@ RewritePathEvaluator::applyLeftConcreteProjection(const RewriteStep &step, leftBaseTerm.add(difference.LHS); auto bug = [&](StringRef msg) { - llvm::errs() << msg << "\n"; - llvm::errs() << "- StartOffset: " << step.StartOffset << "\n"; - llvm::errs() << "- EndOffset: " << step.EndOffset << "\n"; - llvm::errs() << "- SubstitutionIndex: " << index << "\n"; - llvm::errs() << "- LeftProjection: " << leftProjection << "\n"; - llvm::errs() << "- LeftBaseTerm: " << leftBaseTerm << "\n"; - llvm::errs() << "- DifferenceID: " << step.getTypeDifferenceID() << "\n"; - llvm::errs() << "\nType difference:\n"; - difference.dump(llvm::errs()); - llvm::errs() << ":\n"; - difference.dump(llvm::errs()); - llvm::errs() << "\nEvaluator state:\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + out << "- StartOffset: " << step.StartOffset << "\n"; + out << "- EndOffset: " << step.EndOffset << "\n"; + out << "- SubstitutionIndex: " << index << "\n"; + out << "- LeftProjection: " << leftProjection << "\n"; + out << "- LeftBaseTerm: " << leftBaseTerm << "\n"; + out << "- DifferenceID: " << step.getTypeDifferenceID() << "\n"; + out << "\nType difference:\n"; + difference.dump(out); + out << ":\n"; + difference.dump(out); + out << "\nEvaluator state:\n"; + dump(out); + }); }; if (!step.Inverse) { @@ -933,20 +950,21 @@ RewritePathEvaluator::applyRightConcreteProjection(const RewriteStep &step, rightBaseTerm.add(difference.RHS); auto bug = [&](StringRef msg) { - llvm::errs() << msg << "\n"; - llvm::errs() << "- StartOffset: " << step.StartOffset << "\n"; - llvm::errs() << "- EndOffset: " << step.EndOffset << "\n"; - llvm::errs() << "- SubstitutionIndex: " << index << "\n"; - llvm::errs() << "- LeftProjection: " << leftProjection << "\n"; - llvm::errs() << "- RightProjection: " << rightProjection << "\n"; - llvm::errs() << "- LeftBaseTerm: " << leftBaseTerm << "\n"; - llvm::errs() << "- RightBaseTerm: " << rightBaseTerm << "\n"; - llvm::errs() << "- DifferenceID: " << step.getTypeDifferenceID() << "\n"; - llvm::errs() << "\nType difference:\n"; - difference.dump(llvm::errs()); - llvm::errs() << "\nEvaluator state:\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << msg << "\n"; + out << "- StartOffset: " << step.StartOffset << "\n"; + out << "- EndOffset: " << step.EndOffset << "\n"; + out << "- SubstitutionIndex: " << index << "\n"; + out << "- LeftProjection: " << leftProjection << "\n"; + out << "- RightProjection: " << rightProjection << "\n"; + out << "- LeftBaseTerm: " << leftBaseTerm << "\n"; + out << "- RightBaseTerm: " << rightBaseTerm << "\n"; + out << "- DifferenceID: " << step.getTypeDifferenceID() << "\n"; + out << "\nType difference:\n"; + difference.dump(out); + out << "\nEvaluator state:\n"; + dump(out); + }); }; if (!step.Inverse) { diff --git a/lib/AST/RequirementMachine/RewriteSystem.cpp b/lib/AST/RequirementMachine/RewriteSystem.cpp index 6be27b082a240..2cf620b660e82 100644 --- a/lib/AST/RequirementMachine/RewriteSystem.cpp +++ b/lib/AST/RequirementMachine/RewriteSystem.cpp @@ -261,17 +261,18 @@ bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs, auto oldRuleID = Trie.insert(lhs.begin(), lhs.end(), newRuleID); if (oldRuleID) { - llvm::errs() << "Duplicate rewrite rule!\n"; - const auto &oldRule = getRule(*oldRuleID); - llvm::errs() << "Old rule #" << *oldRuleID << ": "; - oldRule.dump(llvm::errs()); - llvm::errs() << "\nTrying to replay what happened when I simplified this term:\n"; - Debug |= DebugFlags::Simplify; - MutableTerm term = lhs; - simplify(lhs); - - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Duplicate rewrite rule!\n"; + const auto &oldRule = getRule(*oldRuleID); + out << "Old rule #" << *oldRuleID << ": "; + oldRule.dump(out); + out << "\nTrying to replay what happened when I simplified this term:\n"; + Debug |= DebugFlags::Simplify; + MutableTerm term = lhs; + simplify(lhs); + + dump(out); + }); } // Tell the caller that we added a new rule. @@ -339,12 +340,13 @@ void RewriteSystem::addRules( newRule.getLHS().end(), newRuleID); if (oldRuleID) { - llvm::errs() << "Imported rules have duplicate left hand sides!\n"; - llvm::errs() << "New rule #" << newRuleID << ": " << newRule << "\n"; - const auto &oldRule = getRule(*oldRuleID); - llvm::errs() << "Old rule #" << *oldRuleID << ": " << oldRule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Imported rules have duplicate left hand sides!\n"; + out << "New rule #" << newRuleID << ": " << newRule << "\n"; + const auto &oldRule = getRule(*oldRuleID); + out << "Old rule #" << *oldRuleID << ": " << oldRule << "\n\n"; + dump(out); + }); } } @@ -505,12 +507,13 @@ void RewriteSystem::recordRewriteLoop(MutableTerm basepoint, } void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const { -#define ASSERT_RULE(expr) \ - if (!(expr)) { \ - llvm::errs() << "&&& Malformed rewrite rule: " << rule << "\n"; \ - llvm::errs() << "&&& " << #expr << "\n\n"; \ - dump(llvm::errs()); \ - abort(); \ +#define ASSERT_RULE(expr) \ + if (!(expr)) { \ + ABORT([&](auto &out) { \ + out << "&&& Malformed rewrite rule: " << rule << "\n"; \ + out << "&&& " << #expr << "\n\n"; \ + dump(out); \ + }); \ } for (const auto &rule : getLocalRules()) { diff --git a/lib/AST/RequirementMachine/SimplifySubstitutions.cpp b/lib/AST/RequirementMachine/SimplifySubstitutions.cpp index 68aeba1277228..b03af4006c80f 100644 --- a/lib/AST/RequirementMachine/SimplifySubstitutions.cpp +++ b/lib/AST/RequirementMachine/SimplifySubstitutions.cpp @@ -262,10 +262,11 @@ void RewriteSystem::processTypeDifference(const TypeDifference &difference, if (lhsRule.getRHS() == difference.BaseTerm && !lhsRule.isSubstitutionSimplified()) { if (lhsRule.isFrozen()) { - llvm::errs() << "Frozen rule should already be subst-simplified: " - << lhsRule << "\n\n"; - dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Frozen rule should already be subst-simplified: " << lhsRule + << "\n\n"; + dump(out); + }); } lhsRule.markSubstitutionSimplified(); } diff --git a/lib/AST/RequirementMachine/Symbol.cpp b/lib/AST/RequirementMachine/Symbol.cpp index 47582fcae66c2..0db2590f04d5a 100644 --- a/lib/AST/RequirementMachine/Symbol.cpp +++ b/lib/AST/RequirementMachine/Symbol.cpp @@ -613,10 +613,11 @@ std::optional Symbol::compare(Symbol other, RewriteContext &ctx) const { } if (result == 0) { - llvm::errs() << "Two distinct symbols should not compare equal\n"; - llvm::errs() << "LHS: " << *this << "\n"; - llvm::errs() << "RHS: " << other << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Two distinct symbols should not compare equal\n"; + out << "LHS: " << *this << "\n"; + out << "RHS: " << other; + }); } return result; @@ -646,8 +647,9 @@ Symbol Symbol::withConcreteSubstitutions( break; } - llvm::errs() << "Bad symbol kind: " << *this << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Bad symbol kind: " << *this; + }); } /// For a superclass or concrete type symbol diff --git a/lib/AST/RequirementMachine/TypeDifference.cpp b/lib/AST/RequirementMachine/TypeDifference.cpp index 214e79d563b95..e1b18ef8344c2 100644 --- a/lib/AST/RequirementMachine/TypeDifference.cpp +++ b/lib/AST/RequirementMachine/TypeDifference.cpp @@ -79,11 +79,12 @@ void TypeDifference::dump(llvm::raw_ostream &out) const { } void TypeDifference::verify(RewriteContext &ctx) const { -#define VERIFY(expr, str) \ - if (!(expr)) { \ - llvm::errs() << "TypeDifference::verify(): " << str << "\n"; \ - dump(llvm::errs()); \ - abort(); \ +#define VERIFY(expr, str) \ + if (!(expr)) { \ + ABORT([&](auto &out) { \ + out << "TypeDifference::verify(): " << str << "\n"; \ + dump(out); \ + }); \ } VERIFY(LHS.getKind() == RHS.getKind(), "Kind mismatch"); @@ -214,12 +215,13 @@ namespace { } void verify() const { -#define VERIFY(expr, str) \ - if (!(expr)) { \ - llvm::errs() << "ConcreteTypeMatcher::verify(): " << str << "\n"; \ - dump(llvm::errs()); \ - abort(); \ - } +#define VERIFY(expr, str) \ + if (!(expr)) { \ + ABORT([&](auto &out) { \ + out << "ConcreteTypeMatcher::verify(): " << str << "\n"; \ + dump(out); \ + }); \ + } llvm::DenseSet lhsVisited; llvm::DenseSet rhsVisited; @@ -460,16 +462,17 @@ bool RewriteSystem::computeTypeDifference( if (!isConflict) { // The meet operation should be commutative. if (lhsMeetRhs.RHS != rhsMeetLhs.RHS) { - llvm::errs() << "Meet operation was not commutative:\n\n"; + ABORT([&](auto &out) { + out << "Meet operation was not commutative:\n\n"; - llvm::errs() << "LHS: " << lhs << "\n"; - llvm::errs() << "RHS: " << rhs << "\n"; - matcher.dump(llvm::errs()); + out << "LHS: " << lhs << "\n"; + out << "RHS: " << rhs << "\n"; + matcher.dump(out); - llvm::errs() << "\n"; - llvm::errs() << "LHS ∧ RHS: " << lhsMeetRhs.RHS << "\n"; - llvm::errs() << "RHS ∧ LHS: " << rhsMeetLhs.RHS << "\n"; - abort(); + out << "\n"; + out << "LHS ∧ RHS: " << lhsMeetRhs.RHS << "\n"; + out << "RHS ∧ LHS: " << rhsMeetLhs.RHS; + }); } // The meet operation should be idempotent. @@ -483,16 +486,17 @@ bool RewriteSystem::computeTypeDifference( lhsMeetLhsMeetRhs.verify(Context); if (lhsMeetRhs.RHS != lhsMeetLhsMeetRhs.RHS) { - llvm::errs() << "Meet operation was not idempotent:\n\n"; + ABORT([&](auto &out) { + out << "Meet operation was not idempotent:\n\n"; - llvm::errs() << "LHS: " << lhs << "\n"; - llvm::errs() << "RHS: " << rhs << "\n"; - matcher.dump(llvm::errs()); + out << "LHS: " << lhs << "\n"; + out << "RHS: " << rhs << "\n"; + matcher.dump(out); - llvm::errs() << "\n"; - llvm::errs() << "LHS ∧ RHS: " << lhsMeetRhs.RHS << "\n"; - llvm::errs() << "LHS ∧ (LHS ∧ RHS): " << lhsMeetLhsMeetRhs.RHS << "\n"; - abort(); + out << "\n"; + out << "LHS ∧ RHS: " << lhsMeetRhs.RHS << "\n"; + out << "LHS ∧ (LHS ∧ RHS): " << lhsMeetLhsMeetRhs.RHS; + }); } } @@ -506,16 +510,17 @@ bool RewriteSystem::computeTypeDifference( rhsMeetRhsMeetRhs.verify(Context); if (lhsMeetRhs.RHS != rhsMeetRhsMeetRhs.RHS) { - llvm::errs() << "Meet operation was not idempotent:\n\n"; + ABORT([&](auto &out) { + out << "Meet operation was not idempotent:\n\n"; - llvm::errs() << "LHS: " << lhs << "\n"; - llvm::errs() << "RHS: " << rhs << "\n"; - matcher.dump(llvm::errs()); + out << "LHS: " << lhs << "\n"; + out << "RHS: " << rhs << "\n"; + matcher.dump(out); - llvm::errs() << "\n"; - llvm::errs() << "RHS ∧ LHS: " << rhsMeetLhs.RHS << "\n"; - llvm::errs() << "RHS ∧ (RHS ∧ LHS): " << rhsMeetRhsMeetRhs.RHS << "\n"; - abort(); + out << "\n"; + out << "RHS ∧ LHS: " << rhsMeetLhs.RHS << "\n"; + out << "RHS ∧ (RHS ∧ LHS): " << rhsMeetRhsMeetRhs.RHS; + }); } } } diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 7affba9899246..3d89b5a9b90a4 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -505,10 +505,10 @@ void SubstitutionMap::verify(bool allowInvalid) const { if (conformance.isInvalid()) { if (!allowInvalid) { - llvm::errs() << "Unexpected invalid conformance in substitution map:\n"; - dump(llvm::dbgs()); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Unexpected invalid conformance in substitution map:\n"; + dump(out); + }); } continue; @@ -522,10 +522,10 @@ void SubstitutionMap::verify(bool allowInvalid) const { !substType->is() && !substType->is() && !substType->is()) { - llvm::errs() << "Unexpected abstract conformance in substitution map:\n"; - dump(llvm::errs()); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Unexpected abstract conformance in substitution map:\n"; + dump(out); + }); } continue; @@ -550,12 +550,12 @@ void SubstitutionMap::verify(bool allowInvalid) const { if (substType->getSuperclass()) continue; - llvm::errs() << "Expected to find a self conformance:\n"; - substType->dump(llvm::errs()); - llvm::errs() << "Substitution map:\n"; - dump(llvm::errs()); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Expected to find a self conformance:\n"; + substType->dump(out); + out << "Substitution map:\n"; + dump(out); + }); } continue; @@ -565,14 +565,14 @@ void SubstitutionMap::verify(bool allowInvalid) const { continue; if (!concrete->getType()->isEqual(substType)) { - llvm::errs() << "Conformance with wrong conforming type:\n"; - concrete->getType()->dump(llvm::errs()); - llvm::errs() << "Should be:\n"; - substType->dump(llvm::errs()); - llvm::errs() << "Substitution map:\n"; - dump(llvm::errs()); - llvm::errs() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "Conformance with wrong conforming type:\n"; + concrete->getType()->dump(out); + out << "Should be:\n"; + substType->dump(out); + out << "Substitution map:\n"; + dump(out); + }); } } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 365f96fad1667..9a4960ee413ed 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -9799,11 +9799,11 @@ static void finishTypeWitnesses( } if (!satisfied) { - llvm::errs() << ("Cannot look up associated type for " - "imported conformance:\n"); - conformance->getType().dump(llvm::errs()); - assocType->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot look up associated type for imported conformance:\n"; + conformance->getType().dump(out); + assocType->dump(out); + }); } } } diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 7dbfeca194219..721ee2b3f6d94 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1066,34 +1066,34 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { auto &Ctx = Ty->getASTContext(); Type Reconstructed = Demangle::getTypeForMangling(Ctx, SugaredName, Sig); if (!Reconstructed) { - llvm::errs() << "Failed to reconstruct type for " << SugaredName - << "\n"; - llvm::errs() << "Original type:\n"; - Ty->dump(llvm::errs()); - if (Sig) - llvm::errs() << "Generic signature: " << Sig << "\n"; - llvm::errs() << SWIFT_CRASH_BUG_REPORT_MESSAGE << "\n" - << "Pass '-Xfrontend -disable-round-trip-debug-types' to disable " - "this assertion.\n"; - abort(); + ABORT([&](auto &out) { + out << "Failed to reconstruct type for " << SugaredName << "\n"; + out << "Original type:\n"; + Ty->dump(out); + if (Sig) + out << "Generic signature: " << Sig << "\n"; + out << SWIFT_CRASH_BUG_REPORT_MESSAGE << "\n" + << "Pass '-Xfrontend -disable-round-trip-debug-types' to disable " + "this assertion."; + }); } else if (!Reconstructed->isEqual(Ty) && // FIXME: Some existential types are reconstructed without // an explicit ExistentialType wrapping the constraint. !equalWithoutExistentialTypes(Reconstructed, Ty) && !EqualUpToClangTypes().check(Reconstructed, Ty)) { // [FIXME: Include-Clang-type-in-mangling] Remove second check - llvm::errs() << "Incorrect reconstructed type for " << SugaredName - << "\n"; - llvm::errs() << "Original type:\n"; - Ty->dump(llvm::errs()); - llvm::errs() << "Reconstructed type:\n"; - Reconstructed->dump(llvm::errs()); - if (Sig) - llvm::errs() << "Generic signature: " << Sig << "\n"; - llvm::errs() << SWIFT_CRASH_BUG_REPORT_MESSAGE << "\n" - << "Pass '-Xfrontend -disable-round-trip-debug-types' to disable " - "this assertion.\n"; - abort(); + ABORT([&](auto &out) { + out << "Incorrect reconstructed type for " << SugaredName << "\n"; + out << "Original type:\n"; + Ty->dump(out); + out << "Reconstructed type:\n"; + Reconstructed->dump(out); + if (Sig) + out << "Generic signature: " << Sig << "\n"; + out << SWIFT_CRASH_BUG_REPORT_MESSAGE << "\n" + << "Pass '-Xfrontend -disable-round-trip-debug-types' to disable " + "this assertion."; + }); } } diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index 6b15487e17355..efdc86ad94346 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -839,14 +839,15 @@ void SILModule::notifyAddedInstruction(SILInstruction *inst) { SILValue &val = RootLocalArchetypeDefs[{genericEnv, inst->getFunction()}]; if (val) { if (!isa(val)) { - // Print a useful error message (and not just abort with an assert). - llvm::errs() << "re-definition of local environment in function " - << inst->getFunction()->getName() << ":\n"; - inst->print(llvm::errs()); - llvm::errs() << "previously defined in function " - << val->getFunction()->getName() << ":\n"; - val->print(llvm::errs()); - abort(); + ABORT([&](auto &out) { + // Print a useful error message (and not just abort with an assert). + out << "re-definition of local environment in function " + << inst->getFunction()->getName() << ":\n"; + inst->print(out); + out << "previously defined in function " + << val->getFunction()->getName() << ":\n"; + val->print(out); + }); } // The local environment was unresolved so far. Replace the placeholder // by inst. diff --git a/lib/SIL/Utils/Dominance.cpp b/lib/SIL/Utils/Dominance.cpp index 6984d33dc8972..bd4b6b66b6c08 100644 --- a/lib/SIL/Utils/Dominance.cpp +++ b/lib/SIL/Utils/Dominance.cpp @@ -90,11 +90,12 @@ void DominanceInfo::verify() const { // And compare. if (errorOccurredOnComparison(OtherDT)) { - llvm::errs() << "DominatorTree is not up to date!\nComputed:\n"; - print(llvm::errs()); - llvm::errs() << "\nActual:\n"; - OtherDT.print(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "DominatorTree is not up to date!\nComputed:\n"; + print(out); + out << "\nActual:\n"; + OtherDT.print(out); + }); } } @@ -147,11 +148,12 @@ void PostDominanceInfo::verify() const { // And compare. if (errorOccurredOnComparison(OtherDT)) { - llvm::errs() << "PostDominatorTree is not up to date!\nComputed:\n"; - print(llvm::errs()); - llvm::errs() << "\nActual:\n"; - OtherDT.print(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "PostDominatorTree is not up to date!\nComputed:\n"; + print(out); + out << "\nActual:\n"; + OtherDT.print(out); + }); } } diff --git a/lib/SIL/Utils/GenericSpecializationMangler.cpp b/lib/SIL/Utils/GenericSpecializationMangler.cpp index d4cc51ae2f64e..27cf65e1b8cc5 100644 --- a/lib/SIL/Utils/GenericSpecializationMangler.cpp +++ b/lib/SIL/Utils/GenericSpecializationMangler.cpp @@ -42,8 +42,9 @@ class AttributeDemangler : public Demangle::Demangler { NodePointer Parent) { DemangleInitRAII state(*this, MangledSpecialization, nullptr); if (!parseAndPushNodes()) { - llvm::errs() << "Can't demangle: " << MangledSpecialization << '\n'; - abort(); + ABORT([&](auto &out) { + out << "Can't demangle: " << MangledSpecialization; + }); } for (Node *Nd : NodeStack) { addChild(Parent, Nd); diff --git a/lib/SIL/Utils/SILBridging.cpp b/lib/SIL/Utils/SILBridging.cpp index e29b64c86aff1..994d9bc8f4ffb 100644 --- a/lib/SIL/Utils/SILBridging.cpp +++ b/lib/SIL/Utils/SILBridging.cpp @@ -50,8 +50,10 @@ bool swiftModulesInitialized() { SwiftMetatype SILNode::getSILNodeMetatype(SILNodeKind kind) { SwiftMetatype metatype = nodeMetatypes[(unsigned)kind]; if (nodeMetatypesInitialized && !metatype) { - llvm::errs() << "Instruction " << getSILInstructionName((SILInstructionKind)kind) << " not registered\n"; - abort(); + ABORT([&](auto &out) { + out << "Instruction " << getSILInstructionName((SILInstructionKind)kind) + << " not registered"; + }); } return metatype; } @@ -103,16 +105,18 @@ void registerBridgedClass(BridgedStringRef bridgedClassName, SwiftMetatype metat prefixedName = std::string("SIL") + std::string(className); iter = valueNamesToKind.find(prefixedName); if (iter == valueNamesToKind.end()) { - llvm::errs() << "Unknown bridged node class " << className << '\n'; - abort(); + ABORT([&](auto &out) { + out << "Unknown bridged node class " << className; + }); } className = prefixedName; } SILNodeKind kind = iter->second; SwiftMetatype existingTy = nodeMetatypes[(unsigned)kind]; if (existingTy) { - llvm::errs() << "Double registration of class " << className << '\n'; - abort(); + ABORT([&](auto &out) { + out << "Double registration of class " << className; + }); } nodeMetatypes[(unsigned)kind] = metatype; } diff --git a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp index d83fc493224d9..aa79c1be31d76 100644 --- a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp +++ b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp @@ -259,9 +259,10 @@ void MemoryLifetimeVerifier::reportError(const Twine &complaint, if (DontAbortOnMemoryLifetimeErrors) return; - llvm::errs() << "in function:\n"; - function->print(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "in function:\n"; + function->print(out); + }); } void MemoryLifetimeVerifier::require(const Bits &wrongBits, diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp index d5b6c1c387ba8..deaeb69423543 100644 --- a/lib/SILOptimizer/PassManager/Passes.cpp +++ b/lib/SILOptimizer/PassManager/Passes.cpp @@ -239,8 +239,9 @@ static void runBridgedModulePass(BridgedModulePassRunFn &runFunction, runFunction = bridgedModulePassRunFunctions[passName]; if (!runFunction) { if (passesRegistered) { - llvm::errs() << "Swift pass " << passName << " is not registered\n"; - abort(); + ABORT([&](auto &out) { + out << "Swift pass " << passName << " is not registered"; + }); } return; } @@ -259,15 +260,15 @@ static void runBridgedFunctionPass(BridgedFunctionPassRunFn &runFunction, runFunction = bridgedFunctionPassRunFunctions[passName]; if (!runFunction) { if (passesRegistered) { - llvm::errs() << "Swift pass " << passName << " is not registered\n"; - abort(); + ABORT([&](auto &out) { + out << "Swift pass " << passName << " is not registered"; + }); } return; } } if (!f->isBridged()) { - llvm::errs() << "SILFunction metatype is not registered\n"; - abort(); + ABORT("SILFunction metatype is not registered"); } runFunction({{f}, {passManager->getSwiftPassInvocation()}}); } diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index f79c6d0eedf1b..2efaeed6eb5c5 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -613,28 +613,29 @@ void SILCombine_registerInstructionPass(BridgedStringRef instClassName, passesRegistered = true; } -#define _RUN_SWIFT_SIMPLIFICATON(INST) \ - static BridgedInstructionPassRunFn runFunction = nullptr; \ - static bool passDisabled = false; \ - if (!runFunction) { \ - runFunction = swiftInstPasses[#INST]; \ - if (!runFunction) { \ - if (passesRegistered) { \ - llvm::errs() << "Swift pass " << #INST << " is not registered\n"; \ - abort(); \ - } else { \ - return nullptr; \ - } \ - } \ - StringRef instName = getSILInstructionName(SILInstructionKind::INST); \ - passDisabled = SILPassManager::isInstructionPassDisabled(instName); \ - } \ - if (passDisabled && \ - SILPassManager::disablePassesForFunction(inst->getFunction())) { \ - return nullptr; \ - } \ - runSwiftInstructionPass(inst, runFunction); \ - return nullptr; \ +#define _RUN_SWIFT_SIMPLIFICATON(INST) \ + static BridgedInstructionPassRunFn runFunction = nullptr; \ + static bool passDisabled = false; \ + if (!runFunction) { \ + runFunction = swiftInstPasses[#INST]; \ + if (!runFunction) { \ + if (passesRegistered) { \ + ABORT([&](auto &out) { \ + out << "Swift pass " << #INST << " is not registered"; \ + }); \ + } else { \ + return nullptr; \ + } \ + } \ + StringRef instName = getSILInstructionName(SILInstructionKind::INST); \ + passDisabled = SILPassManager::isInstructionPassDisabled(instName); \ + } \ + if (passDisabled && \ + SILPassManager::disablePassesForFunction(inst->getFunction())) { \ + return nullptr; \ + } \ + runSwiftInstructionPass(inst, runFunction); \ + return nullptr; #define INSTRUCTION_SIMPLIFICATION(INST) \ SILInstruction *SILCombiner::visit##INST(INST *inst) { \ diff --git a/lib/Sema/AssociatedTypeInference.cpp b/lib/Sema/AssociatedTypeInference.cpp index 3fa6ea780f17a..74dd27865f33a 100644 --- a/lib/Sema/AssociatedTypeInference.cpp +++ b/lib/Sema/AssociatedTypeInference.cpp @@ -449,10 +449,11 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup( // Conformances constructed by the ClangImporter should have explicit type // witnesses already. if (isa(dc->getModuleScopeContext())) { - llvm::errs() << "Cannot look up associated type for imported conformance:\n"; - conformance->getType().dump(llvm::errs()); - assocType->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot look up associated type for imported conformance:\n"; + conformance->getType().dump(out); + assocType->dump(out); + }); } NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | @@ -1608,11 +1609,12 @@ AssociatedTypeInference::getPotentialTypeWitnessesFromRequirement( // Conformances constructed by the ClangImporter should have explicit type // witnesses already. if (isa(conformance->getDeclContext()->getModuleScopeContext())) { - llvm::errs() << "Cannot infer associated types for imported conformance:\n"; - conformance->getType().dump(llvm::errs()); - for (auto assocTypeDecl : allUnresolved) - assocTypeDecl->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Cannot infer associated types for imported conformance:\n"; + conformance->getType().dump(out); + for (auto assocTypeDecl : allUnresolved) + assocTypeDecl->dump(out); + }); } TypeReprCycleCheckWalker cycleCheck(dc->getASTContext(), allUnresolved); @@ -2720,19 +2722,19 @@ bool AssociatedTypeInference::simplifyCurrentTypeWitnesses() { LLVM_DEBUG(llvm::dbgs() << "Simplifying type witnesses -- iteration " << iterations << "\n"); if (++iterations > 100) { - llvm::errs() << "Too many iterations in simplifyCurrentTypeWitnesses()\n"; - - for (auto assocType : proto->getAssociatedTypeMembers()) { - if (conformance->hasTypeWitness(assocType)) - continue; + ABORT([&](auto &out) { + out << "Too many iterations in simplifyCurrentTypeWitnesses()\n"; - auto known = typeWitnesses.begin(assocType); - assert(known != typeWitnesses.end()); + for (auto assocType : proto->getAssociatedTypeMembers()) { + if (conformance->hasTypeWitness(assocType)) + continue; - llvm::errs() << assocType->getName() << ": " << known->first << "\n"; - } + auto known = typeWitnesses.begin(assocType); + assert(known != typeWitnesses.end()); - abort(); + out << assocType->getName() << ": " << known->first << "\n"; + } + }); } auto selfTy = proto->getSelfInterfaceType()->getCanonicalType(); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 09e66754859ce..d0d04ff1a406a 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -8055,10 +8055,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (fromType->hasUnresolvedType() || toType->hasUnresolvedType()) return cs.cacheType(new (ctx) UnresolvedTypeConversionExpr(expr, toType)); - llvm::errs() << "Unhandled coercion:\n"; - fromType->dump(llvm::errs()); - toType->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Unhandled coercion:\n"; + fromType->dump(out); + toType->dump(out); + }); } static bool isSelfRefInInitializer(Expr *baseExpr, diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp index d24f8a3f49b58..402c8f191f599 100644 --- a/lib/Sema/ConstraintGraph.cpp +++ b/lib/Sema/ConstraintGraph.cpp @@ -254,36 +254,40 @@ void ConstraintGraphNode::truncateEquivalenceClass(unsigned prevSize) { void ConstraintGraphNode::addReferencedVar(TypeVariableType *typeVar) { bool inserted = References.insert(typeVar); if (!inserted) { - llvm::errs() << "$T" << TypeVar->getImpl().getID() << " already " - << "references $T" << typeVar->getImpl().getID() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "$T" << TypeVar->getImpl().getID() << " already " + << "references $T" << typeVar->getImpl().getID(); + }); } } void ConstraintGraphNode::addReferencedBy(TypeVariableType *typeVar) { bool inserted = ReferencedBy.insert(typeVar); if (!inserted) { - llvm::errs() << "$T" << TypeVar->getImpl().getID() << " already " - << "referenced by $T" << typeVar->getImpl().getID() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "$T" << TypeVar->getImpl().getID() << " already " + << "referenced by $T" << typeVar->getImpl().getID(); + }); } } void ConstraintGraphNode::removeReference(TypeVariableType *typeVar) { auto removed = References.remove(typeVar); if (!removed) { - llvm::errs() << "$T" << TypeVar->getImpl().getID() << " does not " - << "reference $T" << typeVar->getImpl().getID() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "$T" << TypeVar->getImpl().getID() << " does not " + << "reference $T" << typeVar->getImpl().getID(); + }); } } void ConstraintGraphNode::removeReferencedBy(TypeVariableType *typeVar) { auto removed = ReferencedBy.remove(typeVar); if (!removed) { - llvm::errs() << "$T" << TypeVar->getImpl().getID() << " not " - << "referenced by $T" << typeVar->getImpl().getID() << "\n"; - abort(); + ABORT([&](auto &out) { + out << "$T" << TypeVar->getImpl().getID() << " not " + << "referenced by $T" << typeVar->getImpl().getID(); + }); } } diff --git a/lib/Sema/OpenedExistentials.cpp b/lib/Sema/OpenedExistentials.cpp index 00d978bc6b88e..95c84653d2a63 100644 --- a/lib/Sema/OpenedExistentials.cpp +++ b/lib/Sema/OpenedExistentials.cpp @@ -291,9 +291,10 @@ findGenericParameterReferencesRec(CanGenericSignature genericSig, // Everything else should be a type parameter. if (!type->isTypeParameter()) { - llvm::errs() << "Unhandled type:\n"; - type->dump(llvm::errs()); - abort(); + ABORT([&](auto &out) { + out << "Unhandled type:\n"; + type->dump(out); + }); } if (!type->getRootGenericParam()->isEqual(origParam)) { diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index c66b8f7f048f7..2f175f020e318 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -1175,16 +1175,18 @@ void ModuleFile::collectBasicSourceFileInfo( auto fingerprintIncludingTypeMembers = Fingerprint::fromString(fpStrIncludingTypeMembers); if (!fingerprintIncludingTypeMembers) { - llvm::errs() << "Unconvertible fingerprint including type members'" - << fpStrIncludingTypeMembers << "'\n"; - abort(); + ABORT([&](auto &out) { + out << "Unconvertible fingerprint including type members '" + << fpStrIncludingTypeMembers << "'"; + }); } auto fingerprintExcludingTypeMembers = Fingerprint::fromString(fpStrExcludingTypeMembers); if (!fingerprintExcludingTypeMembers) { - llvm::errs() << "Unconvertible fingerprint excluding type members'" - << fpStrExcludingTypeMembers << "'\n"; - abort(); + ABORT([&](auto &out) { + out << "Unconvertible fingerprint excluding type members '" + << fpStrExcludingTypeMembers << "'"; + }); } callback(BasicSourceFileInfo(filePath, fingerprintIncludingTypeMembers.value(), diff --git a/lib/Serialization/ModuleFileCoreTableInfo.h b/lib/Serialization/ModuleFileCoreTableInfo.h index 2dc30c7e7d8cd..9a4d7fc9fab68 100644 --- a/lib/Serialization/ModuleFileCoreTableInfo.h +++ b/lib/Serialization/ModuleFileCoreTableInfo.h @@ -579,8 +579,10 @@ class ModuleFileSharedCore::DeclFingerprintsTableInfo { Fingerprint::DIGEST_LENGTH}; if (auto fp = Fingerprint::fromString(str)) return fp.value(); - llvm::errs() << "Unconvertable fingerprint '" << str << "'\n"; - abort(); + + ABORT([&](auto &out) { + out << "Unconvertable fingerprint '" << str << "'"; + }); } };