Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -51,6 +51,7 @@ def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; def LiteralConversion : DiagGroup<"literal-conversion">; +def PrecisionConversion : DiagGroup<"precision-conversion">; def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; @@ -714,6 +715,7 @@ ImplicitIntConversion, ImplicitFloatConversion, LiteralConversion, + PrecisionConversion, NonLiteralNullConversion, // (1-1)->pointer (etc) NullConversion, // NULL->non-pointer ObjCLiteralConversion, Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3223,6 +3223,10 @@ "implicit conversion turns floating-point number into integer: %0 to %1">, InGroup, DefaultIgnore; +def warn_impcast_precision_float_to_integer : Warning< + "implicit conversion from %0 to %1 changes value from %2 to %3">, + InGroup; + def warn_impcast_float_to_integer : Warning< "implicit conversion from %0 to %1 changes value from %2 to %3">, InGroup, DefaultIgnore; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -105,6 +105,19 @@ 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 &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) { @@ -10414,15 +10427,8 @@ 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) @@ -10855,6 +10861,32 @@ 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); Index: test/Sema/ext_vector_casts.c =================================================================== --- test/Sema/ext_vector_casts.c +++ test/Sema/ext_vector_casts.c @@ -118,7 +118,7 @@ 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; Index: test/Sema/impcast-integer-float.c =================================================================== --- test/Sema/impcast-integer-float.c +++ test/Sema/impcast-integer-float.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 %s -verify -Wconversion -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}} +}