error.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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 EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
  5. #define EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
  6. #include <optional>
  7. #include "common/check.h"
  8. #include "common/error.h"
  9. #include "executable_semantics/ast/source_location.h"
  10. #include "llvm/Support/Signals.h"
  11. #include "llvm/Support/raw_ostream.h"
  12. namespace Carbon {
  13. // A helper class for accumulating error message and converting to
  14. // `Carbon::Error`/`Carbon::ErrorOr<T>`.
  15. class ErrorBuilder {
  16. public:
  17. explicit ErrorBuilder(std::optional<SourceLocation> loc = std::nullopt)
  18. : out_(message_) {
  19. if (loc.has_value()) {
  20. out_ << *loc << ": ";
  21. }
  22. }
  23. // Accumulates string message.
  24. template <typename T>
  25. [[nodiscard]] auto operator<<(const T& message) -> ErrorBuilder& {
  26. out_ << message;
  27. return *this;
  28. }
  29. // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
  30. operator Error() { return Error(message_); }
  31. template <typename V>
  32. // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
  33. operator ErrorOr<V>() {
  34. return Error(message_);
  35. }
  36. std::string message_;
  37. llvm::raw_string_ostream out_;
  38. };
  39. // Builds a Carbon::Error instance with the specified message. This should be
  40. // used for non-recoverable errors with user input.
  41. //
  42. // For example:
  43. // return FATAL_PROGRAM_ERROR(line_num) << "Line is bad!";
  44. // return FATAL_PROGRAM_ERROR_NO_LINE() << "Application is bad!";
  45. //
  46. // Where possible, try to identify the error as a compilation or
  47. // runtime error. Use CHECK/FATAL for internal errors. The generic program
  48. // error option is provided as a fallback for cases that don't fit those
  49. // classifications.
  50. //
  51. // TODO: replace below macro invocations with direct `return ErrorBuilder() <<
  52. // xx` calls.
  53. #define FATAL_PROGRAM_ERROR_NO_LINE() \
  54. Carbon::ErrorBuilder() << "PROGRAM ERROR: "
  55. #define FATAL_PROGRAM_ERROR(line) \
  56. FATAL_PROGRAM_ERROR_NO_LINE() << (line) << ": "
  57. #define FATAL_COMPILATION_ERROR_NO_LINE() \
  58. Carbon::ErrorBuilder() << "COMPILATION ERROR: "
  59. #define FATAL_COMPILATION_ERROR(line) \
  60. FATAL_COMPILATION_ERROR_NO_LINE() << (line) << ": "
  61. #define FATAL_RUNTIME_ERROR_NO_LINE() \
  62. Carbon::ErrorBuilder() << "RUNTIME ERROR: "
  63. #define FATAL_RUNTIME_ERROR(line) \
  64. FATAL_RUNTIME_ERROR_NO_LINE() << (line) << ": "
  65. // Macro hackery to get a unique variable name.
  66. #define MAKE_UNIQUE_NAME_IMPL(a, b, c) a##b##c
  67. #define MAKE_UNIQUE_NAME(a, b, c) MAKE_UNIQUE_NAME_IMPL(a, b, c)
  68. #define RETURN_IF_ERROR_IMPL(unique_name, expr) \
  69. if (auto unique_name = (expr); /* NOLINT(bugprone-macro-parentheses) */ \
  70. !(unique_name).ok()) { \
  71. return std::move(unique_name).error(); \
  72. }
  73. #define RETURN_IF_ERROR(expr) \
  74. RETURN_IF_ERROR_IMPL( \
  75. MAKE_UNIQUE_NAME(_llvm_error_line, __LINE__, __COUNTER__), expr)
  76. #define ASSIGN_OR_RETURN_IMPL(unique_name, var, expr) \
  77. auto unique_name = (expr); /* NOLINT(bugprone-macro-parentheses) */ \
  78. if (!(unique_name).ok()) { \
  79. return std::move(unique_name).error(); \
  80. } \
  81. var = std::move(*(unique_name)); /* NOLINT(bugprone-macro-parentheses) */
  82. #define ASSIGN_OR_RETURN(var, expr) \
  83. ASSIGN_OR_RETURN_IMPL( \
  84. MAKE_UNIQUE_NAME(_llvm_expected_line, __LINE__, __COUNTER__), var, expr)
  85. } // namespace Carbon
  86. #endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_H_