Implement LWG-3720 Restrict the valid types of arg-id for width and precision in std-format-spec (#3511)

Co-authored-by: A. Jiang <de34@live.cn>
This commit is contained in:
Igor Zhukov 2023-03-04 06:40:42 +07:00 коммит произвёл GitHub
Родитель 4e5425cee4
Коммит efd50e8961
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 16 добавлений и 4 удалений

Просмотреть файл

@ -1410,13 +1410,17 @@ _NODISCARD constexpr basic_format_arg<_Context> _Get_arg(const _Context& _Ctx, c
return _Arg;
}
template <class _Ty>
inline constexpr bool _Is_signed_or_unsigned_large_integer_t =
_Is_any_of_v<remove_cv_t<_Ty>, int, unsigned int, long, unsigned long, long long, unsigned long long>;
// Checks that the type and value of an argument associated with a dynamic
// width specifier are valid.
class _Width_checker {
public:
template <class _Ty>
_NODISCARD constexpr unsigned long long operator()(const _Ty _Value) const {
if constexpr (is_integral_v<_Ty>) {
if constexpr (_Is_signed_or_unsigned_large_integer_t<_Ty>) {
if constexpr (is_signed_v<_Ty>) {
if (_Value < 0) {
_Throw_format_error("Negative width.");
@ -1435,7 +1439,7 @@ class _Precision_checker {
public:
template <class _Ty>
_NODISCARD constexpr unsigned long long operator()(const _Ty _Value) const {
if constexpr (is_integral_v<_Ty>) {
if constexpr (_Is_signed_or_unsigned_large_integer_t<_Ty>) {
if constexpr (is_signed_v<_Ty>) {
if (_Value < 0) {
_Throw_format_error("Negative precision.");

Просмотреть файл

@ -1356,10 +1356,13 @@ void libfmt_formatter_test_runtime_width() {
throw_helper(STR("{0:{1}}"), 0, (int_max + 1u));
throw_helper(STR("{0:{1}}"), 0, -1l);
throw_helper(STR("{0:{1}}"), 0, (int_max + 1ul));
assert(format(STR("{0:{1}}"), 0, '0')
== STR(" 0")); // behavior differs from libfmt, but conforms
throw_helper(STR("{0:{1}}"), 0, 0.0);
// LWG-3720: Restrict the valid types of arg-id for width and precision in std-format-spec
throw_helper(STR("{:*^{}}"), 'a', true);
throw_helper(STR("{:*^{}}"), 'a', '0');
assert(format(STR("{:*^{}}"), 'a', static_cast<signed char>(2)) == STR("a*"));
assert(format(STR("{0:{1}}"), 42, 0) == STR("42")); // LWG-3721: zero dynamic width is OK
assert(format(STR("{0:{1}}"), -42, 4) == STR(" -42"));
@ -1407,6 +1410,11 @@ void libfmt_formatter_test_runtime_precision() {
throw_helper(STR("{0:.{1}}"), reinterpret_cast<void*>(0xcafe), 2);
throw_helper(STR("{0:.{1}f}"), reinterpret_cast<void*>(0xcafe), 2);
assert(format(STR("{0:.{1}}"), STR("str"), 2) == STR("st"));
// LWG-3720: Restrict the valid types of arg-id for width and precision in std-format-spec
throw_helper(STR("{:.{}f}"), 3.14f, true);
throw_helper(STR("{:.{}f}"), 3.14f, '0');
assert(format(STR("{:.{}f}"), 3.14f, static_cast<signed char>(2)) == STR("3.14"));
}
template <class charT>