check_internal.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. // Evaluates a condition in a CHECK. This diagnoses if the condition evaluates
  10. // to the constant `true` or `false`.
  11. [[clang::always_inline]] constexpr bool
  12. // Trailing GNU function attributes are incompatible with trailing return types.
  13. // Filed as https://github.com/llvm/llvm-project/issues/118697
  14. // NOLINTNEXTLINE(modernize-use-trailing-return-type)
  15. CheckCondition(bool condition)
  16. __attribute__((diagnose_if(condition,
  17. "CHECK condition is always true; replace with "
  18. "static_assert if this is intended",
  19. "error")))
  20. __attribute__((diagnose_if(!condition,
  21. "CHECK condition is always false; replace with "
  22. "CARBON_FATAL if this is intended",
  23. "error"))) {
  24. return condition;
  25. }
  26. // Implements the check failure message printing.
  27. //
  28. // This is out-of-line and will arrange to stop the program, print any debugging
  29. // information and this string.
  30. //
  31. // This API uses `const char*` C string arguments rather than `llvm::StringRef`
  32. // because we know that these are available as C strings and passing them that
  33. // way lets the code size of calling it be smaller: it only needs to materialize
  34. // a single pointer argument for each. The runtime cost of re-computing the size
  35. // should be minimal. The extra message however might not be compile-time
  36. // guaranteed to be a C string so we use a normal `StringRef` there.
  37. [[noreturn]] auto CheckFailImpl(const char* kind, const char* file, int line,
  38. const char* condition_str,
  39. llvm::StringRef extra_message) -> void;
  40. // Allow converting format values; the default behaviour is to just pass them
  41. // through.
  42. template <typename T>
  43. auto ConvertFormatValue(T&& t) -> T&& {
  44. return std::forward<T>(t);
  45. }
  46. // Convert enums to larger integers so that byte-sized enums are not confused
  47. // with being chars and printed as invalid (or nul-terminating) characters.
  48. // Scoped enums are explicitly converted to integers so they can be printed
  49. // without the user writing a cast.
  50. template <typename T>
  51. requires(std::is_enum_v<std::remove_reference_t<T>>)
  52. auto ConvertFormatValue(T&& t) {
  53. if constexpr (std::is_signed_v<
  54. std::underlying_type_t<std::remove_reference_t<T>>>) {
  55. return static_cast<int64_t>(t);
  56. } else {
  57. return static_cast<uint64_t>(t);
  58. }
  59. }
  60. // Prints a check failure, including rendering any user-provided message using
  61. // a format string.
  62. //
  63. // Most of the parameters are passed as compile-time template strings to avoid
  64. // runtime cost of parameter setup in optimized builds. Each of these are passed
  65. // along to the underlying implementation to include in the final printed
  66. // message.
  67. //
  68. // Any user-provided format string and values are directly passed to
  69. // `llvm::formatv` which handles all of the formatting of output.
  70. template <TemplateString Kind, TemplateString File, int Line,
  71. TemplateString ConditionStr, TemplateString FormatStr, typename... Ts>
  72. [[noreturn, gnu::cold, clang::noinline]] auto CheckFail(Ts&&... values)
  73. -> void {
  74. if constexpr (llvm::StringRef(FormatStr).empty()) {
  75. // Skip the format string rendering if empty. Note that we don't skip it
  76. // even if there are no values as we want to have consistent handling of
  77. // `{}`s in the format string. This case is about when there is no message
  78. // at all, just the condition.
  79. CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(), "");
  80. } else {
  81. CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(),
  82. llvm::formatv(FormatStr.c_str(),
  83. ConvertFormatValue(std::forward<Ts>(values))...)
  84. .str());
  85. }
  86. }
  87. } // namespace Carbon::Internal
  88. // Evaluates the condition of a CHECK as a boolean value.
  89. //
  90. // This performs a contextual conversion to bool, diagnoses if the condition is
  91. // always true or always false, and returns its value.
  92. #define CARBON_INTERNAL_CHECK_CONDITION(cond) \
  93. (Carbon::Internal::CheckCondition(true && (cond)))
  94. // Implements check messages without any formatted values.
  95. //
  96. // Passes each of the provided components of the message to the template
  97. // parameters of the check failure printing function above, including an empty
  98. // string for the format string. Because there are multiple template arguments,
  99. // the entire call is wrapped in parentheses.
  100. #define CARBON_INTERNAL_CHECK_IMPL(kind, file, line, condition_str) \
  101. (Carbon::Internal::CheckFail<kind, file, line, condition_str, "">())
  102. // Implements check messages with a format string and potentially formatted
  103. // values.
  104. //
  105. // Each of the main components is passed as a template arguments, and then any
  106. // formatted values are passed as arguments. Because there are multiple template
  107. // arguments, the entire call is wrapped in parentheses.
  108. #define CARBON_INTERNAL_CHECK_IMPL_FORMAT(kind, file, line, condition_str, \
  109. format_str, ...) \
  110. (Carbon::Internal::CheckFail<kind, file, line, condition_str, format_str>( \
  111. __VA_ARGS__))
  112. // Implements the failure of a check.
  113. //
  114. // Collects all the metadata about the failure to be printed, such as source
  115. // location and stringified condition, and passes those, any format string and
  116. // formatted arguments to the correct implementation macro above.
  117. #define CARBON_INTERNAL_CHECK(condition, ...) \
  118. CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
  119. "CHECK", __FILE__, __LINE__, #condition __VA_OPT__(, ) __VA_ARGS__)
  120. // Implements the fatal macro.
  121. //
  122. // Similar to the check failure macro, but tags the message as a fatal one and
  123. // leaves the stringified condition empty.
  124. #define CARBON_INTERNAL_FATAL(...) \
  125. CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
  126. "FATAL", __FILE__, __LINE__, "" __VA_OPT__(, ) __VA_ARGS__)
  127. #ifdef NDEBUG
  128. // For `DCHECK` in optimized builds we have a dead check that we want to
  129. // potentially "use" arguments, but otherwise have the minimal overhead. We
  130. // avoid forming interesting format strings here so that we don't have to
  131. // repeatedly instantiate the `Check` function above. This format string would
  132. // be an error if actually used.
  133. #define CARBON_INTERNAL_DEAD_DCHECK(condition, ...) \
  134. CARBON_INTERNAL_DEAD_DCHECK_IMPL##__VA_OPT__(_FORMAT)(__VA_ARGS__)
  135. #define CARBON_INTERNAL_DEAD_DCHECK_IMPL() \
  136. Carbon::Internal::CheckFail<"", "", 0, "", "">()
  137. #define CARBON_INTERNAL_DEAD_DCHECK_IMPL_FORMAT(format_str, ...) \
  138. Carbon::Internal::CheckFail<"", "", 0, "", "">(__VA_ARGS__)
  139. #endif
  140. #endif // CARBON_COMMON_CHECK_INTERNAL_H_