Don't perform narrowing conversion for integers in printf (#255)
This commit is contained in:
parent
22f61140d1
commit
8474a6232d
27
format.cc
27
format.cc
@ -278,8 +278,21 @@ class PrecisionHandler :
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Converts an integer argument to an integral type T for printf.
|
template <typename T, typename U>
|
||||||
|
struct is_same {
|
||||||
|
enum { value = 0 };
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
struct is_same<T, T> {
|
||||||
|
enum { value = 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
// An argument visitor that converts an integer argument to T for printf,
|
||||||
|
// if T is an integral type. If T is not integral, the argument is converted
|
||||||
|
// to corresponding signed or unsigned type depending on the type specifier:
|
||||||
|
// 'd' and 'i' - signed, other - unsigned)
|
||||||
|
template <typename T = void>
|
||||||
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
||||||
private:
|
private:
|
||||||
fmt::internal::Arg &arg_;
|
fmt::internal::Arg &arg_;
|
||||||
@ -300,15 +313,17 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
void visit_any_int(U value) {
|
void visit_any_int(U value) {
|
||||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||||
using fmt::internal::Arg;
|
using fmt::internal::Arg;
|
||||||
if (sizeof(T) <= sizeof(int)) {
|
typedef typename fmt::internal::Conditional<
|
||||||
|
is_same<T, void>::value, U, T>::type TargetType;
|
||||||
|
if (sizeof(TargetType) <= sizeof(int)) {
|
||||||
// Extra casts are used to silence warnings.
|
// Extra casts are used to silence warnings.
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
arg_.type = Arg::INT;
|
arg_.type = Arg::INT;
|
||||||
arg_.int_value = static_cast<int>(static_cast<T>(value));
|
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
|
||||||
} else {
|
} else {
|
||||||
arg_.type = Arg::UINT;
|
arg_.type = Arg::UINT;
|
||||||
arg_.uint_value = static_cast<unsigned>(
|
typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
|
||||||
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
|
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
@ -809,7 +824,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
--s;
|
--s;
|
||||||
ArgConverter<int>(arg, *s).visit(arg);
|
ArgConverter<void>(arg, *s).visit(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
|
@ -289,6 +289,7 @@ SPECIALIZE_MAKE_SIGNED(unsigned, int);
|
|||||||
SPECIALIZE_MAKE_SIGNED(unsigned long, long);
|
SPECIALIZE_MAKE_SIGNED(unsigned long, long);
|
||||||
SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong);
|
SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong);
|
||||||
|
|
||||||
|
// Test length format specifier ``length_spec``.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
void TestLength(const char *length_spec, U value) {
|
void TestLength(const char *length_spec, U value) {
|
||||||
fmt::LongLong signed_value = value;
|
fmt::LongLong signed_value = value;
|
||||||
@ -388,6 +389,13 @@ TEST(PrintfTest, Int) {
|
|||||||
EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
|
EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, LongLong) {
|
||||||
|
// fmt::printf allows passing long long arguments to %d without length
|
||||||
|
// specifiers.
|
||||||
|
fmt::LongLong max = std::numeric_limits<fmt::LongLong>::max();
|
||||||
|
EXPECT_PRINTF(fmt::format("{}", max), "%d", max);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, Float) {
|
TEST(PrintfTest, Float) {
|
||||||
EXPECT_PRINTF("392.650000", "%f", 392.65);
|
EXPECT_PRINTF("392.650000", "%f", 392.65);
|
||||||
EXPECT_PRINTF("392.650000", "%F", 392.65);
|
EXPECT_PRINTF("392.650000", "%F", 392.65);
|
||||||
|
Loading…
Reference in New Issue
Block a user