Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3089,6 +3089,9 @@ def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup, DefaultIgnore; +def warn_impcast_float_result_precision : Warning< + "implicit conversion when assigning computation result loses floating-point precision: %0 to %1">, + InGroup, DefaultIgnore; def warn_impcast_double_promotion : Warning< "implicit conversion increases floating-point precision: %0 to %1">, InGroup, DefaultIgnore; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -8625,6 +8625,9 @@ } static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC, + bool *ICContext = nullptr); static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. @@ -9146,6 +9149,25 @@ return true; } +static bool ShouldWarnFloatPrecision(Sema &S, Expr *E, + const BuiltinType *SourceBT, + const BuiltinType *TargetBT, + SourceLocation CC) { + // Don't warn about float constants that are precisely + // representable in the target type. + Expr::EvalResult result; + if (E->EvaluateAsRValue(result, S.Context)) { + // Value might be a float, a float vector, or a float complex. + if (IsSameFloatAfterCast( + result.Val, S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + return false; + } + if (S.SourceMgr.isInSystemMacro(CC)) + return true; + return true; +} + /// Analyze the given simple or compound assignment for warning-worthy /// operations. static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { @@ -9188,6 +9210,29 @@ DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +/// Analyze the given compound assignment for the possible losing of +/// floating-point precision. +static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { + assert(E->isAssignmentOp() && (E->getOpcode() != BO_Assign) && + "Must be compound assignment operation"); + AnalyzeAssignment(S, E); + + QualType T = E->getLHS()->getType(); + const BuiltinType *SourceBT = dyn_cast( + S.Context.getCanonicalType(E->getRHS()->getType()).getTypePtr()); + const BuiltinType *TargetBT = + dyn_cast(S.Context.getCanonicalType(T).getTypePtr()); + + // If both source and target are floating points + if (SourceBT && SourceBT->isFloatingPoint() && TargetBT && + TargetBT->isFloatingPoint()) + // Builtin FP kinds are ordered by increasing FP rank. + if (SourceBT->getKind() > TargetBT->getKind()) + if (ShouldWarnFloatPrecision(S, E, SourceBT, TargetBT, E->getOperatorLoc())) + // warn about dropping FP rank. + DiagnoseImpCast(S, E->getRHS(), T, E->getOperatorLoc(), + diag::warn_impcast_float_result_precision); +} /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, @@ -9501,9 +9546,8 @@ return true; } -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) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -9555,7 +9599,7 @@ return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } - + // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) @@ -9594,21 +9638,8 @@ // Builtin FP kinds are ordered by increasing FP rank. if (SourceBT->getKind() > TargetBT->getKind()) { - // Don't warn about float constants that are precisely - // representable in the target type. - Expr::EvalResult result; - if (E->EvaluateAsRValue(result, S.Context)) { - // Value might be a float, a float vector, or a float complex. - if (IsSameFloatAfterCast(result.Val, - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) - return; - } - - if (S.SourceMgr.isInSystemMacro(CC)) - return; - - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); + if (ShouldWarnFloatPrecision(S, E, SourceBT, TargetBT, CC)) + DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } // ... or possibly if we're increasing rank, too else if (TargetBT->getKind() > SourceBT->getKind()) { @@ -9832,7 +9863,7 @@ if (E->isTypeDependent() || E->isValueDependent()) return; - + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa(E)) { @@ -9876,6 +9907,9 @@ // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); + // And with compound assignments. + if (BO->isAssignmentOp()) + return AnalyzeCompoundAssignment(S, BO); } // These break the otherwise-useful invariant below. Fortunately, Index: test/Sema/constant-conversion.c =================================================================== --- test/Sema/constant-conversion.c +++ test/Sema/constant-conversion.c @@ -73,7 +73,7 @@ f.twoBits1 = ~1; // no-warning f.twoBits2 = ~2; // expected-warning {{implicit truncation from 'int' to bit-field changes value from -3 to 1}} f.twoBits1 &= ~1; // no-warning - f.twoBits2 &= ~2; // no-warning + f.twoBits2 &= ~2; // expected-warning {{implicit truncation from 'int' to bit-field changes value from -3 to 1}} } void test8() { Index: test/Sema/conversion.c =================================================================== --- test/Sema/conversion.c +++ test/Sema/conversion.c @@ -436,10 +436,15 @@ } void double2float_test2(double a, float *b) { - *b += a; + *b += a; // expected-warning {{implicit conversion when assigning computation result loses floating-point precision: 'double' to 'float'}} } float sinf (float x); double double2float_test3(double a) { return sinf(a); // expected-warning {{implicit conversion loses floating-point precision: 'double' to 'float'}} } + +float double2float_test4 (double a, float b) { + b -= a; // expected-warning {{implicit conversion when assigning computation result loses floating-point precision: 'double' to 'float'}} + return b; +}