mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:24:42 +01:00
Avoid printing enums as characters (#4676)
Given code like the following:
```
auto kind = ConversionTarget::Kind{0};
CARBON_CHECK(!loc_id.is_valid(), "hello {0} world", kind);
```
Currently we would print 'hello <the next line>', as the check string
would be treated as terminating at the '{0}', so it does not print the
rest of the string or a newline. This is because ConversionTarget::Kind
is an enum with underlying type `int8_t` which is a char, and
llvm::formatv does not look if the type is an enum and treat is
specially. So it prints it as a char rather than a number, which in this
case is a nul terminator.
With this change, the '{0}' value will be converted to a larger integer
before being passed through to llvm::formatv so that char-sized enums
will print as a number, and the result is that we will print 'hello 0
world\n' as the developer intended.
This commit is contained in:
+26
-3
@@ -43,6 +43,28 @@ CheckCondition(bool condition)
|
||||
const char* condition_str,
|
||||
llvm::StringRef extra_message) -> void;
|
||||
|
||||
// Allow converting format values; the default behaviour is to just pass them
|
||||
// through.
|
||||
template <typename T>
|
||||
auto ConvertFormatValue(T&& t) -> T&& {
|
||||
return std::forward<T>(t);
|
||||
}
|
||||
|
||||
// Convert enums to larger integers so that byte-sized enums are not confused
|
||||
// with being chars and printed as invalid (or nul-terminating) characters.
|
||||
// Scoped enums are explicitly converted to integers so they can be printed
|
||||
// without the user writing a cast.
|
||||
template <typename T>
|
||||
requires(std::is_enum_v<std::remove_reference_t<T>>)
|
||||
auto ConvertFormatValue(T&& t) {
|
||||
if constexpr (std::is_signed_v<
|
||||
std::underlying_type_t<std::remove_reference_t<T>>>) {
|
||||
return static_cast<int64_t>(t);
|
||||
} else {
|
||||
return static_cast<uint64_t>(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a check failure, including rendering any user-provided message using
|
||||
// a format string.
|
||||
//
|
||||
@@ -64,9 +86,10 @@ template <TemplateString Kind, TemplateString File, int Line,
|
||||
// at all, just the condition.
|
||||
CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(), "");
|
||||
} else {
|
||||
CheckFailImpl(
|
||||
Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(),
|
||||
llvm::formatv(FormatStr.c_str(), std::forward<Ts>(values)...).str());
|
||||
CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(),
|
||||
llvm::formatv(FormatStr.c_str(),
|
||||
ConvertFormatValue(std::forward<Ts>(values))...)
|
||||
.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user