Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3241,6 +3241,13 @@ "the only well defined values for BOOL are YES and NO">, InGroup; +def warn_impcast_integer_float_precision : Warning< + "implicit conversion from %0 to %1 may loses integer precision">, + InGroup, DefaultIgnore; +def warn_impcast_integer_float_precision_constant : Warning< + "implicit conversion from %2 to %3 changes value from %0 to %1">, + InGroup, DefaultIgnore; + def warn_impcast_fixed_point_range : Warning< "implicit conversion from %0 cannot fit within the range of values for %1">, InGroup; Index: clang/lib/Driver/ToolChains/Arch/AArch64.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -88,7 +88,7 @@ unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind); if (!llvm::AArch64::getExtensionFeatures(Extension, Features)) return false; - } + } if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) return false; Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -11400,6 +11400,54 @@ } } + // If we are casting an integer type to a floating point type, we might + // lose accuracy if the floating point type has a narrower signicand + // than the floating point type. Issue warnings for that accuracy loss. + if (SourceBT && TargetBT && + SourceBT->isIntegerType() && TargetBT->isFloatingType()) { + // Determine the number of precision bits in the source integer type. + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); + unsigned int SourcePrecision = SourceRange.Width; + + // Determine the number of precision bits in the target floating point type + // Also create the APFloat object to represent the converted value. + unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + llvm::APFloat SourceToFloatValue( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + + // If we manage to find out the precisions for both types, perform + // acccuracy loss check and issue warning if necessary. + if (SourcePrecision > 0 && TargetPrecision > 0 && + SourcePrecision > TargetPrecision) { + // If the source integer is a constant, then we are sure that the + // implicit conversion will lose precision. Otherwise, the implicit + // conversion *may* lose precision. + llvm::APSInt SourceInt; + if (E->isIntegerConstantExpr(SourceInt, S.Context)) { + // Obtain string representations of source value and converted value. + std::string PrettySourceValue = SourceInt.toString(10); + SourceToFloatValue.convertFromAPInt(SourceInt, + SourceBT->isSignedInteger(), llvm::APFloat::rmTowardZero); + SmallString<32> PrettySourceConvertedValue; + SourceToFloatValue.toString(PrettySourceConvertedValue, + SourcePrecision); + + // Issue constant integer to float precision loss warning. + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_float_precision_constant) + << PrettySourceValue << PrettySourceConvertedValue + << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + } else { + // Issue integer variable to float precision may loss warning. + DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_integer_float_precision); + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); Index: clang/test/Sema/conversion.c =================================================================== --- clang/test/Sema/conversion.c +++ clang/test/Sema/conversion.c @@ -233,7 +233,7 @@ takes_int(v); takes_long(v); takes_longlong(v); - takes_float(v); + takes_float(v); // expected-warning {{implicit conversion from 'int' to 'float' may loses integer precision}} takes_double(v); takes_longdouble(v); } @@ -244,8 +244,8 @@ takes_int(v); // expected-warning {{implicit conversion loses integer precision}} takes_long(v); takes_longlong(v); - takes_float(v); - takes_double(v); + takes_float(v); // expected-warning {{implicit conversion from 'long' to 'float' may loses integer precision}} + takes_double(v); // expected-warning {{implicit conversion from 'long' to 'double' may loses integer precision}} takes_longdouble(v); } @@ -255,8 +255,8 @@ takes_int(v); // expected-warning {{implicit conversion loses integer precision}} takes_long(v); takes_longlong(v); - takes_float(v); - takes_double(v); + takes_float(v); // expected-warning {{implicit conversion from 'long long' to 'float' may loses integer precision}} + takes_double(v); // expected-warning {{implicit conversion from 'long long' to 'double' may loses integer precision}} takes_longdouble(v); } Index: clang/test/Sema/ext_vector_casts.c =================================================================== --- clang/test/Sema/ext_vector_casts.c +++ clang/test/Sema/ext_vector_casts.c @@ -115,12 +115,12 @@ vl = vl + t; // expected-warning {{implicit conversion loses integer precision}} vf = 1 + vf; - vf = l + vf; + vf = l + vf; // expected-warning {{implicit conversion from 'long' to 'float2' (vector of 2 'float' values) may loses integer precision}} 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}} vf = vf + 2.1; // expected-warning {{implicit conversion loses floating-point precision}} - vd = l + vd; - vd = vd + t; + vd = l + vd; // expected-warning {{implicit conversion from 'long' to 'double2' (vector of 2 'double' values) may loses integer precision}} + vd = vd + t; // expected-warning {{implicit conversion from '__uint128_t' (aka 'unsigned __int128') to 'double2' (vector of 2 'double' values) may loses integer precision}} } Index: clang/test/Sema/implicit-float-conversion.c =================================================================== --- /dev/null +++ clang/test/Sema/implicit-float-conversion.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -verify -Wno-conversion -Wimplicit-float-conversion + + +long testReturn(long a, float b) { + return a + b; // expected-warning {{implicit conversion from 'long' to 'float' may loses integer precision}} +} + + +void testAssignment() { + float f = 222222; + double b = 222222222222L; + + float ff = 222222222222L; // expected-warning {{implicit conversion from 'long' to 'float' changes value}} + + long l = 222222222222L; + float fff = l; // expected-warning {{implicit conversion from 'long' to 'float' may loses integer precision}} +} + + +void testExpression() { + float a = 0.0f; + float b = 222222222222L + a; // expected-warning {{implicit conversion from 'long' to 'float' changes value}} + float c = 22222222 + 22222223; // expected-warning {{implicit conversion from 'int' to 'float' changes value}} + + int i = 0; + float d = i + a; // expected-warning {{implicit conversion from 'int' to 'float' may loses integer precision}} + + double e = 0.0; + double f = i + e; +}