check_internal.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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 "common/template_string.h"
  7. #include "llvm/Support/FormatVariadic.h"
  8. namespace Carbon::Internal {
  9. // Implements the check failure message printing.
  10. //
  11. // This is out-of-line and will arrange to stop the program, print any debugging
  12. // information and this string.
  13. //
  14. // This API uses `const char*` C string arguments rather than `llvm::StringRef`
  15. // because we know that these are available as C strings and passing them that
  16. // way lets the code size of calling it be smaller: it only needs to materialize
  17. // a single pointer argument for each. The runtime cost of re-computing the size
  18. // should be minimal. The extra message however might not be compile-time
  19. // guaranteed to be a C string so we use a normal `StringRef` there.
  20. [[noreturn]] auto CheckFailImpl(const char* kind, const char* file, int line,
  21. const char* condition_str,
  22. llvm::StringRef extra_message) -> void;
  23. // Prints a check failure, including rendering any user-provided message using
  24. // a format string.
  25. //
  26. // Most of the parameters are passed as compile-time template strings to avoid
  27. // runtime cost of parameter setup in optimized builds. Each of these are passed
  28. // along to the underlying implementation to include in the final printed
  29. // message.
  30. //
  31. // Any user-provided format string and values are directly passed to
  32. // `llvm::formatv` which handles all of the formatting of output.
  33. template <TemplateString Kind, TemplateString File, int Line,
  34. TemplateString ConditionStr, TemplateString FormatStr, typename... Ts>
  35. [[noreturn, gnu::cold, clang::noinline]] auto CheckFail(Ts&&... values)
  36. -> void {
  37. if constexpr (llvm::StringRef(FormatStr).empty()) {
  38. // Skip the format string rendering if empty. Note that we don't skip it
  39. // even if there are no values as we want to have consistent handling of
  40. // `{}`s in the format string. This case is about when there is no message
  41. // at all, just the condition.
  42. CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(), "");
  43. } else {
  44. CheckFailImpl(
  45. Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(),
  46. llvm::formatv(FormatStr.c_str(), std::forward<Ts>(values)...).str());
  47. }
  48. }
  49. } // namespace Carbon::Internal
  50. // Implements check messages without any formatted values.
  51. //
  52. // Passes each of the provided components of the message to the template
  53. // parameters of the check failure printing function above, including an empty
  54. // string for the format string. Because there are multiple template arguments,
  55. // the entire call is wrapped in parentheses.
  56. #define CARBON_INTERNAL_CHECK_IMPL(kind, file, line, condition_str) \
  57. (Carbon::Internal::CheckFail<kind, file, line, condition_str, "">())
  58. // Implements check messages with a format string and potentially formatted
  59. // values.
  60. //
  61. // Each of the main components is passed as a template arguments, and then any
  62. // formatted values are passed as arguments. Because there are multiple template
  63. // arguments, the entire call is wrapped in parentheses.
  64. #define CARBON_INTERNAL_CHECK_IMPL_FORMAT(kind, file, line, condition_str, \
  65. format_str, ...) \
  66. (Carbon::Internal::CheckFail<kind, file, line, condition_str, format_str>( \
  67. __VA_ARGS__))
  68. // Implements the failure of a check.
  69. //
  70. // Collects all the metadata about the failure to be printed, such as source
  71. // location and stringified condition, and passes those, any format string and
  72. // formatted arguments to the correct implementation macro above.
  73. #define CARBON_INTERNAL_CHECK(condition, ...) \
  74. CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
  75. "CHECK", __FILE__, __LINE__, #condition __VA_OPT__(, ) __VA_ARGS__)
  76. // Implements the fatal macro.
  77. //
  78. // Similar to the check failure macro, but tags the message as a fatal one and
  79. // leaves the stringified condition empty.
  80. #define CARBON_INTERNAL_FATAL(...) \
  81. CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
  82. "FATAL", __FILE__, __LINE__, "" __VA_OPT__(, ) __VA_ARGS__)
  83. #ifdef NDEBUG
  84. // For `DCHECK` in optimized builds we have a dead check that we want to
  85. // potentially "use" arguments, but otherwise have the minimal overhead. We
  86. // avoid forming interesting format strings here so that we don't have to
  87. // repeatedly instantiate the `Check` function above. This format string would
  88. // be an error if actually used.
  89. #define CARBON_INTERNAL_DEAD_DCHECK(condition, ...) \
  90. CARBON_INTERNAL_DEAD_DCHECK_IMPL##__VA_OPT__(_FORMAT)(__VA_ARGS__)
  91. #define CARBON_INTERNAL_DEAD_DCHECK_IMPL() \
  92. Carbon::Internal::CheckFail<"", "", 0, "", "">()
  93. #define CARBON_INTERNAL_DEAD_DCHECK_IMPL_FORMAT(format_str, ...) \
  94. Carbon::Internal::CheckFail<"", "", 0, "", "">(__VA_ARGS__)
  95. #endif
  96. #endif // CARBON_COMMON_CHECK_INTERNAL_H_