IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
+ bool IsListInit = false);
static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
}
-static void
-CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
- bool *ICContext = nullptr) {
+static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC,
+ bool *ICContext = nullptr,
+ bool IsListInit = false) {
if (E->isTypeDependent() || E->isValueDependent()) return;
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
}
}
+ // If we are casting an integer type to a floating point type without
+ // initialization-list syntax, we might lose accuracy if the floating
+ // point type has a narrower significand than the integer type.
+ if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
+ TargetBT->isFloatingType() && !IsListInit) {
+ // 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.
+ unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+
+ if (SourcePrecision > 0 && TargetPrecision > 0 &&
+ SourcePrecision > TargetPrecision) {
+
+ llvm::APSInt SourceInt;
+ if (E->isIntegerConstantExpr(SourceInt, S.Context)) {
+ // If the source integer is a constant, convert it to the target
+ // floating point type. Issue a warning if the value changes
+ // during the whole conversion.
+ llvm::APFloat TargetFloatValue(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+ llvm::APFloat::opStatus ConversionStatus =
+ TargetFloatValue.convertFromAPInt(
+ SourceInt, SourceBT->isSignedInteger(),
+ llvm::APFloat::rmNearestTiesToEven);
+
+ if (ConversionStatus != llvm::APFloat::opOK) {
+ std::string PrettySourceValue = SourceInt.toString(10);
+ SmallString<32> PrettyTargetValue;
+ TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
+
+ S.DiagRuntimeBehavior(
+ E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_float_precision_constant)
+ << PrettySourceValue << PrettyTargetValue << E->getType() << T
+ << E->getSourceRange() << clang::SourceRange(CC));
+ }
+ } else {
+ // Otherwise, the implicit conversion may lose precision.
+ DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_integer_float_precision);
+ }
+ }
+ }
+
DiagnoseNullConversion(S, E, T, CC);
S.DiscardMisalignedMemberAddress(Target, E);
/// AnalyzeImplicitConversions - Find and report any interesting
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
- SourceLocation CC) {
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
+ bool IsListInit/*= false*/) {
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
+ // Propagate whether we are in a C++ list initialization expression.
+ // If so, we do not issue warnings for implicit int-float conversion
+ // precision loss, because C++11 narrowing already handles it.
+ IsListInit =
+ IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
+
if (E->isTypeDependent() || E->isValueDependent())
return;
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
if (E->getType() != T)
- CheckImplicitConversion(S, E, T, CC);
+ CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit);
// Now continue drilling into this expression.
// FIXME: Use a more uniform representation for this.
for (auto *SE : POE->semantics())
if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
- AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
+ AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit);
}
// Skip past explicit casts.
E = CE->getSubExpr()->IgnoreParenImpCasts();
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
- return AnalyzeImplicitConversions(S, E, CC);
+ return AnalyzeImplicitConversions(S, E, CC, IsListInit);
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
// Ignore checking string literals that are in logical and operators.
// This is a common pattern for asserts.
continue;
- AnalyzeImplicitConversions(S, ChildExpr, CC);
+ AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit);
}
if (BO && BO->isLogicalOp()) {
--- /dev/null
+// RUN: %clang_cc1 %s -verify -Wno-conversion -Wimplicit-int-float-conversion
+
+long testReturn(long a, float b) {
+ return a + b; // expected-warning {{implicit conversion from 'long' to 'float' may lose precision}}
+}
+
+void testAssignment() {
+ float f = 222222;
+ double b = 222222222222L;
+
+#ifndef __ILP32__
+ float ff = 222222222222L; // expected-warning {{implicit conversion from 'long' to 'float' changes value from 222222222222 to 222222221312}}
+ float ffff = 222222222222UL; // expected-warning {{implicit conversion from 'unsigned long' to 'float' changes value from 222222222222 to 222222221312}}
+#else
+ float ff = 222222222222L; // expected-warning {{implicit conversion from 'long long' to 'float' changes value from 222222222222 to 222222221312}}
+ float ffff = 222222222222UL; // expected-warning {{implicit conversion from 'unsigned long long' to 'float' changes value from 222222222222 to 222222221312}}
+#endif
+
+ long l = 222222222222L;
+ float fff = l; // expected-warning {{implicit conversion from 'long' to 'float' may lose precision}}
+}
+
+void testExpression() {
+ float a = 0.0f;
+
+#ifndef __ILP32__
+ float b = 222222222222L + a; // expected-warning {{implicit conversion from 'long' to 'float' changes value from 222222222222 to 222222221312}}
+#else
+ float b = 222222222222L + a; // expected-warning {{implicit conversion from 'long long' to 'float' changes value from 222222222222 to 222222221312}}
+#endif
+
+ float g = 22222222 + 22222222;
+ float c = 22222222 + 22222223; // expected-warning {{implicit conversion from 'int' to 'float' changes value from 44444445 to 44444444}}
+
+ int i = 0;
+ float d = i + a; // expected-warning {{implicit conversion from 'int' to 'float' may lose precision}}
+
+ double e = 0.0;
+ double f = i + e;
+}
+
+void testCNarrowing() {
+ // Since this is a C file. C++11 narrowing is not in effect.
+ // In this case, we should issue warnings.
+#ifndef __ILP32__
+ float a = {222222222222L}; // expected-warning {{implicit conversion from 'long' to 'float' changes value from 222222222222 to 222222221312}}
+#else
+ float a = {222222222222L}; // expected-warning {{implicit conversion from 'long long' to 'float' changes value from 222222222222 to 222222221312}}
+#endif
+
+ long b = 222222222222L;
+ float c = {b}; // expected-warning {{implicit conversion from 'long' to 'float' may lose precision}}
+}