check_internal.h 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_CHECK_INTERNAL_H_
  5. #define CARBON_COMMON_CHECK_INTERNAL_H_
  6. #include <cstdlib>
  7. #include "llvm/Support/ErrorHandling.h"
  8. #include "llvm/Support/Signals.h"
  9. #include "llvm/Support/raw_ostream.h"
  10. namespace Carbon::Internal {
  11. // Wraps a stream and exiting for fatal errors. Should only be used by check.h
  12. // macros.
  13. class ExitingStream {
  14. public:
  15. // A tag type that renders as ": " in an ExitingStream, but only if it is
  16. // followed by additional output. Otherwise, it renders as "". Primarily used
  17. // when building macros around these streams.
  18. struct AddSeparator {};
  19. // Internal type used in macros to dispatch to the `operator|` overload.
  20. struct Helper {};
  21. ExitingStream() {
  22. // Start all messages with a stack trace. Printing this first ensures the
  23. // error message is the last thing written which makes it easier to find. It
  24. // also helps ensure we report the most useful stack trace and location
  25. // information.
  26. llvm::errs() << "Stack trace:\n";
  27. llvm::sys::PrintStackTrace(llvm::errs());
  28. }
  29. [[noreturn]] ~ExitingStream() {
  30. llvm_unreachable(
  31. "Exiting streams should only be constructed by check.h macros that "
  32. "ensure the special operator| exits the program prior to their "
  33. "destruction!");
  34. }
  35. // If the bool cast occurs, it's because the condition is false. This supports
  36. // && short-circuiting the creation of ExitingStream.
  37. explicit operator bool() const { return true; }
  38. // Forward output to llvm::errs.
  39. template <typename T>
  40. auto operator<<(const T& message) -> ExitingStream& {
  41. if (separator_) {
  42. llvm::errs() << ": ";
  43. separator_ = false;
  44. }
  45. llvm::errs() << message;
  46. return *this;
  47. }
  48. auto operator<<(AddSeparator /*add_separator*/) -> ExitingStream& {
  49. separator_ = true;
  50. return *this;
  51. }
  52. // Low-precedence binary operator overload used in check.h macros to flush the
  53. // output and exit the program. We do this in a binary operator rather than
  54. // the destructor to ensure good debug info and backtraces for errors.
  55. [[noreturn]] friend auto operator|(Helper /*helper*/,
  56. ExitingStream& /*rhs*/) {
  57. // Finish with a newline.
  58. llvm::errs() << "\n";
  59. // We assume LLVM's exit handling is installed, which will stack trace on
  60. // `std::abort()`. We print a more user friendly stack trace on
  61. // construction, but it is still useful to exit the program with
  62. // `std::abort()` for integration with debuggers and other tools. We also
  63. // want to do any pending cleanups. So we replicate the signal handling here
  64. // and unregister LLVM's handlers right before we abort.
  65. llvm::sys::RunInterruptHandlers();
  66. llvm::sys::unregisterHandlers();
  67. std::abort();
  68. }
  69. private:
  70. // Whether a separator should be printed if << is used again.
  71. bool separator_ = false;
  72. };
  73. } // namespace Carbon::Internal
  74. #endif // CARBON_COMMON_CHECK_INTERNAL_H_