error.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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. operator Error() { return Error(message_); }
  30. template <typename V>
  31. operator ErrorOr<V>() {
  32. return Error(message_);
  33. }
  34. std::string message_;
  35. llvm::raw_string_ostream out_;
  36. };
  37. // Builds a Carbon::Error instance with the specified message. This should be
  38. // used for non-recoverable errors with user input.
  39. //
  40. // For example:
  41. // return FATAL_PROGRAM_ERROR(line_num) << "Line is bad!";
  42. // return FATAL_PROGRAM_ERROR_NO_LINE() << "Application is bad!";
  43. //
  44. // Where possible, try to identify the error as a compilation or
  45. // runtime error. Use CHECK/FATAL for internal errors. The generic program
  46. // error option is provided as a fallback for cases that don't fit those
  47. // classifications.
  48. //
  49. // TODO: replace below macro invocations with direct `return ErrorBuilder() <<
  50. // xx` calls.
  51. #define FATAL_PROGRAM_ERROR_NO_LINE() \
  52. Carbon::ErrorBuilder() << "PROGRAM ERROR: "
  53. #define FATAL_PROGRAM_ERROR(line) \
  54. FATAL_PROGRAM_ERROR_NO_LINE() << (line) << ": "
  55. #define FATAL_COMPILATION_ERROR_NO_LINE() \
  56. Carbon::ErrorBuilder() << "COMPILATION ERROR: "
  57. #define FATAL_COMPILATION_ERROR(line) \
  58. FATAL_COMPILATION_ERROR_NO_LINE() << (line) << ": "
  59. #define FATAL_RUNTIME_ERROR_NO_LINE() \
  60. Carbon::ErrorBuilder() << "RUNTIME ERROR: "
  61. #define FATAL_RUNTIME_ERROR(line) \
  62. FATAL_RUNTIME_ERROR_NO_LINE() << (line) << ": "
  63. // Macro hackery to get a unique variable name.
  64. #define MAKE_UNIQUE_NAME_IMPL(a, b, c) a##b##c
  65. #define MAKE_UNIQUE_NAME(a, b, c) MAKE_UNIQUE_NAME_IMPL(a, b, c)
  66. #define RETURN_IF_ERROR_IMPL(unique_name, expr) \
  67. if (auto unique_name = (expr); !unique_name.ok()) { \
  68. return std::move(unique_name).error(); \
  69. }
  70. #define RETURN_IF_ERROR(expr) \
  71. RETURN_IF_ERROR_IMPL( \
  72. MAKE_UNIQUE_NAME(_llvm_error_line, __LINE__, __COUNTER__), expr)
  73. #define ASSIGN_OR_RETURN_IMPL(unique_name, var, expr) \
  74. auto unique_name = (expr); \
  75. if (!unique_name.ok()) { \
  76. return std::move(unique_name).error(); \
  77. } \
  78. var = std::move(*unique_name);
  79. #define ASSIGN_OR_RETURN(var, expr) \
  80. ASSIGN_OR_RETURN_IMPL( \
  81. MAKE_UNIQUE_NAME(_llvm_expected_line, __LINE__, __COUNTER__), var, expr)
  82. } // namespace Carbon
  83. #endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_H_