Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3229,6 +3229,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) { @@ -10473,15 +10486,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) @@ -10914,6 +10920,29 @@ return; } + if (Source->isIntegerType() && TargetBT && TargetBT->isFloatingType()) { + llvm::APSInt IntValue; + if (E->EvaluateAsInt(IntValue, S.Context, Expr::SE_AllowSideEffects)) { + 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)); + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); Index: test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp +++ test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp @@ -133,8 +133,10 @@ // Constants. Agg f7 = {12345678}; // OK (exactly fits in a float) Agg f8 = {EnumVal}; // OK + // expected-warning@+1 {{implicit conversion from 'int' to 'float' changes value from 123456789 to 1.2345679E+8}} Agg f9 = {123456789}; // expected-error {{ cannot be narrowed }} expected-note {{silence}} - + + // expected-warning@+1 {{implicit conversion from 'int' to 'float' changes value from 123456789 to 1.2345679E+8}} Agg ce1 = { Convert(123456789) }; // expected-error {{constant expression evaluates to 123456789 which cannot be narrowed to type 'float'}} expected-note {{silence}} Agg ce2 = { ConvertVar() }; // expected-error {{non-constant-expression cannot be narrowed from type 'long long' to 'double'}} expected-note {{silence}} } Index: test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp +++ test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp @@ -121,8 +121,10 @@ // Constants. Agg f4 = {12345678}; // OK (exactly fits in a float) + // expected-warning@+1 {{implicit conversion from 'int' to 'float' changes value from 123456789 to 1.2345679E+8}} Agg f5 = {123456789}; // expected-warning {{ cannot be narrowed }} expected-note {{silence}} + // expected-warning@+1 {{implicit conversion from 'int' to 'float' changes value from 123456789 to 1.2345679E+8}} Agg ce1 = { Convert(123456789) }; // expected-warning {{constant expression evaluates to 123456789 which cannot be narrowed to type 'float'}} expected-note {{silence}} Agg ce2 = { ConvertVar() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'long long' to 'double'}} expected-note {{silence}} } 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,20 @@ +// RUN: %clang_cc1 %s -verify -Wfloat-precision -triple x86_64-linux -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; + + float d = (__uint128_t)-1; // expected-warning {{implicit conversion from '__uint128_t' (aka 'unsigned __int128') to 'float' changes value from 340282366920938463463374607431768211455 to +Inf}} +}