check.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 COMMON_CHECK_H_
  5. #define COMMON_CHECK_H_
  6. #include "llvm/Support/ErrorHandling.h"
  7. #include "llvm/Support/Signals.h"
  8. #include "llvm/Support/raw_ostream.h"
  9. namespace Carbon {
  10. namespace Internal {
  11. // Wraps a stream and exiting for fatal errors. Should only be used by the
  12. // macros below.
  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 below.
  20. struct Helper {};
  21. [[noreturn]] ~ExitingStream() {
  22. llvm_unreachable(
  23. "Exiting streams should only be constructed with the below macros that "
  24. "ensure the special operator| exits the program prior to their "
  25. "destruction!");
  26. }
  27. // Indicates that the program is exiting due to a bug in the program, rather
  28. // than, e.g., invalid input.
  29. ExitingStream& TreatAsBug() {
  30. treat_as_bug_ = true;
  31. return *this;
  32. }
  33. // If the bool cast occurs, it's because the condition is false. This supports
  34. // && short-circuiting the creation of ExitingStream.
  35. explicit operator bool() const { return true; }
  36. // Forward output to llvm::errs.
  37. template <typename T>
  38. ExitingStream& operator<<(const T& message) {
  39. if (separator_) {
  40. llvm::errs() << ": ";
  41. separator_ = false;
  42. }
  43. llvm::errs() << message;
  44. return *this;
  45. }
  46. ExitingStream& operator<<(AddSeparator /*unused*/) {
  47. separator_ = true;
  48. return *this;
  49. }
  50. // Low-precedence binary operator overload used in macros below to flush the
  51. // output and exit the program. We do this in a binary operator rather than
  52. // the destructor to ensure good debug info and backtraces for errors.
  53. [[noreturn]] friend auto operator|(Helper /*unused*/, ExitingStream& rhs) {
  54. // Finish with a newline.
  55. llvm::errs() << "\n";
  56. if (rhs.treat_as_bug_) {
  57. std::abort();
  58. } else {
  59. std::exit(-1);
  60. }
  61. }
  62. private:
  63. // Whether a separator should be printed if << is used again.
  64. bool separator_ = false;
  65. // Whether the program is exiting due to a bug.
  66. bool treat_as_bug_ = false;
  67. };
  68. } // namespace Internal
  69. // Raw exiting stream. This should be used when building other forms of exiting
  70. // macros like those below. It evaluates to a temporary `ExitingStream` object
  71. // that can be manipulated, streamed into, and then will exit the program.
  72. #define RAW_EXITING_STREAM() \
  73. Carbon::Internal::ExitingStream::Helper() | Carbon::Internal::ExitingStream()
  74. // Checks the given condition, and if it's false, prints a stack, streams the
  75. // error message, then exits. This should be used for unexpected errors, such as
  76. // a bug in the application.
  77. //
  78. // For example:
  79. // CHECK(is_valid) << "Data is not valid!";
  80. #define CHECK(condition) \
  81. (condition) ? (void)0 \
  82. : RAW_EXITING_STREAM().TreatAsBug() \
  83. << "CHECK failure at " << __FILE__ << ":" << __LINE__ \
  84. << ": " #condition \
  85. << Carbon::Internal::ExitingStream::AddSeparator()
  86. // This is similar to CHECK, but is unconditional. Writing FATAL() is clearer
  87. // than CHECK(false) because it avoids confusion about control flow.
  88. //
  89. // For example:
  90. // FATAL() << "Unreachable!";
  91. #define FATAL() \
  92. RAW_EXITING_STREAM().TreatAsBug() \
  93. << "FATAL failure at " << __FILE__ << ":" << __LINE__ << ": "
  94. } // namespace Carbon
  95. #endif // COMMON_CHECK_H_