forked from OSchip/llvm-project
[Diagnostics] Check integer to floating point number implicit conversions
Summary: GCC already catches these situations so we should handle it too. GCC warns in C++ mode only (does anybody know why?). I think it is useful in C mode too. Reviewers: rsmith, erichkeane, aaron.ballman, efriedma, xbolva00 Reviewed By: xbolva00 Subscribers: efriedma, craig.topper, scanon, cfe-commits Differential Revision: https://reviews.llvm.org/D52835 llvm-svn: 346865
This commit is contained in:
parent
2257cbb858
commit
a208bbd576
|
@ -3229,6 +3229,10 @@ def warn_impcast_float_integer : Warning<
|
|||
"implicit conversion turns floating-point number into integer: %0 to %1">,
|
||||
InGroup<FloatConversion>, DefaultIgnore;
|
||||
|
||||
def warn_impcast_precision_float_to_integer : Warning<
|
||||
"implicit conversion from %0 to %1 changes value from %2 to %3">,
|
||||
InGroup<DiagGroup<"float-precision">>;
|
||||
|
||||
def warn_impcast_float_to_integer : Warning<
|
||||
"implicit conversion from %0 to %1 changes value from %2 to %3">,
|
||||
InGroup<FloatOverflowConversion>, DefaultIgnore;
|
||||
|
|
|
@ -105,6 +105,19 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
|
|||
Context.getTargetInfo());
|
||||
}
|
||||
|
||||
// FIXME: Force the precision of the source value down so we don't print
|
||||
// digits which are usually useless (we don't really care here if we
|
||||
// truncate a digit by accident in edge cases). Ideally, APFloat::toString
|
||||
// would automatically print the shortest representation, but it's a bit
|
||||
// tricky to implement.
|
||||
static void PrettyPrintFloat(const llvm::APFloat &floatValue,
|
||||
const llvm::fltSemantics &floatSem,
|
||||
SmallVectorImpl<char> &prettyFloatValue) {
|
||||
unsigned precision = llvm::APFloat::semanticsPrecision(floatSem);
|
||||
precision = llvm::divideCeil(precision * 59, 196);
|
||||
floatValue.toString(prettyFloatValue, precision);
|
||||
}
|
||||
|
||||
/// Checks that a call expression's argument count is the desired number.
|
||||
/// This is useful when doing custom type-checking. Returns true on error.
|
||||
static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
|
||||
|
@ -10473,15 +10486,8 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
|
|||
DiagID = diag::warn_impcast_float_to_integer;
|
||||
}
|
||||
|
||||
// FIXME: Force the precision of the source value down so we don't print
|
||||
// digits which are usually useless (we don't really care here if we
|
||||
// truncate a digit by accident in edge cases). Ideally, APFloat::toString
|
||||
// would automatically print the shortest representation, but it's a bit
|
||||
// tricky to implement.
|
||||
SmallString<16> PrettySourceValue;
|
||||
unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
|
||||
precision = (precision * 59 + 195) / 196;
|
||||
Value.toString(PrettySourceValue, precision);
|
||||
PrettyPrintFloat(Value, Value.getSemantics(), PrettySourceValue);
|
||||
|
||||
SmallString<16> PrettyTargetValue;
|
||||
if (IsBool)
|
||||
|
@ -10914,6 +10920,32 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
|
|||
return;
|
||||
}
|
||||
|
||||
if (Source->isIntegerType() && TargetBT && TargetBT->isFloatingType()) {
|
||||
llvm::APSInt IntValue;
|
||||
if (E->EvaluateAsInt(IntValue, S.Context, Expr::SE_AllowSideEffects)) {
|
||||
if (S.SourceMgr.isInSystemMacro(CC))
|
||||
return;
|
||||
const llvm::fltSemantics &FloatSemantics =
|
||||
S.Context.getFloatTypeSemantics(QualType(TargetBT, 0));
|
||||
llvm::APFloat FloatValue(FloatSemantics);
|
||||
if (FloatValue.convertFromAPInt(IntValue, Source->isSignedIntegerType(),
|
||||
llvm::APFloat::rmNearestTiesToEven) !=
|
||||
llvm::APFloat::opOK) {
|
||||
SmallString<16> PrettyTargetValue;
|
||||
SmallString<16> PrettySourceValue;
|
||||
PrettyPrintFloat(FloatValue, FloatSemantics, PrettyTargetValue);
|
||||
IntValue.toString(PrettySourceValue);
|
||||
|
||||
S.DiagRuntimeBehavior(
|
||||
E->getExprLoc(), E,
|
||||
S.PDiag(diag::warn_impcast_precision_float_to_integer)
|
||||
<< E->getType() << T << PrettySourceValue << PrettyTargetValue
|
||||
<< E->getSourceRange() << clang::SourceRange(CC));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DiagnoseNullConversion(S, E, T, CC);
|
||||
|
||||
S.DiscardMisalignedMemberAddress(Target, E);
|
||||
|
|
|
@ -118,7 +118,7 @@ static void splats(int i, long l, __uint128_t t, float f, double d) {
|
|||
vf = l + vf;
|
||||
vf = 2.0 + vf;
|
||||
vf = d + vf; // expected-warning {{implicit conversion loses floating-point precision}}
|
||||
vf = vf + 0xffffffff;
|
||||
vf = vf + 0xffffffff; // expected-warning {{implicit conversion from 'unsigned int' to 'float2' (vector of 2 'float' values) changes value from 4294967295 to 4.2949673E+9}}
|
||||
vf = vf + 2.1; // expected-warning {{implicit conversion loses floating-point precision}}
|
||||
|
||||
vd = l + vd;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// RUN: %clang_cc1 %s -verify -Wfloat-precision -fsyntax-only
|
||||
|
||||
#define shift_plus_one(x) ((1ULL << x) + 1)
|
||||
|
||||
void test(void) {
|
||||
float a1 = (1ULL << 31) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483649 to 2.1474836E+9}}
|
||||
float a2 = 1ULL << 31;
|
||||
float a3 = shift_plus_one(31); // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483649 to 2.1474836E+9}}
|
||||
float a4 = (1ULL << 31) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483647 to 2.1474836E+9}}
|
||||
|
||||
double b1 = (1ULL << 63) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775809 to 9.223372036854775E+18}}
|
||||
double b2 = 1ULL << 63;
|
||||
double b3 = shift_plus_one(63); // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775809 to 9.223372036854775E+18}}
|
||||
double b4 = (1ULL << 63) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775807 to 9.223372036854775E+18}}
|
||||
|
||||
long double c1 = ((__int128)1 << 127) + 1; // expected-warning {{implicit conversion from '__int128' to 'long double' changes value from -170141183460469231731687303715884105727 to -1.7014118346046923173E+38}}
|
||||
long double c2 = (__int128)1 << 127;
|
||||
|
||||
_Float16 d1 = (1ULL << 15) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32769 to 3.277E+4}}
|
||||
_Float16 d2 = 1ULL << 15;
|
||||
_Float16 d3 = shift_plus_one(15); // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32769 to 3.277E+4}}
|
||||
_Float16 d4 = (1ULL << 15) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32767 to 3.277E+4}}
|
||||
|
||||
float e = (__uint128_t)-1; // expected-warning {{implicit conversion from '__uint128_t' (aka 'unsigned __int128') to 'float' changes value from 340282366920938463463374607431768211455 to +Inf}}
|
||||
}
|
||||
// RUN: %clang_cc1 %s -verify -Wfloat-precision -fsyntax-only
|
||||
|
||||
#define shift_plus_one(x) ((1ULL << x) + 1)
|
||||
|
||||
void test(void) {
|
||||
float a1 = (1ULL << 31) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483649 to 2.1474836E+9}}
|
||||
float a2 = 1ULL << 31;
|
||||
float a3 = shift_plus_one(31); // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483649 to 2.1474836E+9}}
|
||||
float a4 = (1ULL << 31) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 2147483647 to 2.1474836E+9}}
|
||||
|
||||
double b1 = (1ULL << 63) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775809 to 9.223372036854775E+18}}
|
||||
double b2 = 1ULL << 63;
|
||||
double b3 = shift_plus_one(63); // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775809 to 9.223372036854775E+18}}
|
||||
double b4 = (1ULL << 63) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to 'double' changes value from 9223372036854775807 to 9.223372036854775E+18}}
|
||||
|
||||
long double c1 = ((__int128)1 << 127) + 1; // expected-warning {{implicit conversion from '__int128' to 'long double' changes value from -170141183460469231731687303715884105727 to -1.7014118346046923173E+38}}
|
||||
long double c2 = (__int128)1 << 127;
|
||||
|
||||
_Float16 d1 = (1ULL << 15) + 1; // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32769 to 3.277E+4}}
|
||||
_Float16 d2 = 1ULL << 15;
|
||||
_Float16 d3 = shift_plus_one(15); // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32769 to 3.277E+4}}
|
||||
_Float16 d4 = (1ULL << 15) - 1; // expected-warning {{implicit conversion from 'unsigned long long' to '_Float16' changes value from 32767 to 3.277E+4}}
|
||||
|
||||
float e = (__uint128_t)-1; // expected-warning {{implicit conversion from '__uint128_t' (aka 'unsigned __int128') to 'float' changes value from 340282366920938463463374607431768211455 to +Inf}}
|
||||
}
|
Loading…
Reference in New Issue