Author: rtrieu Date: Thu Apr 21 16:04:55 2016 New Revision: 267054 URL: http://llvm.org/viewvc/llvm-project?rev=267054&view=rev Log: Split interesting warnings off from -Wfloat-conversion
Restructure the implict floating point to integer conversions so that interesting sub-groups are under different flags. Breakdown of warnings: No warning: Exact conversions from floating point to integer: int x = 10.0; int x = 1e10; -Wliteral-conversion - Floating point literal to integer with rounding: int x = 5.5; int x = -3.4; -Wfloat-conversion - All conversions not covered by the above two: int x = GetFloat(); int x = 5.5 + 3.5; -Wfloat-zero-conversion - The expression converted has a non-zero floating point value that gets converted to a zero integer value, excluded the cases falling under -Wliteral-conversion. Subset of -Wfloat-conversion. int x = 1.0 / 2.0; -Wfloat-overflow-conversion - The floating point value is outside the range of the integer type, exluding cases from -Wliteral conversion. Subset of -Wfloat-conversion. char x = 500; char x = -1000; -Wfloat-bool-conversion - Any conversion of a floating point type to bool. Subset of -Wfloat-conversion. if (GetFloat()) {} bool x = 5.0; -Wfloat-bool-constant-conversion - Conversion of a compile time evaluatable floating point value to bool. Subset of -Wfloat-bool-conversion. bool x = 1.0; bool x = 4.0 / 20.0; Also add EvaluateAsFloat to Sema, which is similar to EvaluateAsInt, but for floating point values. Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp cfe/trunk/test/SemaCXX/warn-float-conversion.cpp cfe/trunk/test/SemaCXX/warn-literal-conversion.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Thu Apr 21 16:04:55 2016 @@ -594,6 +594,13 @@ public: bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + /// EvaluateAsFloat - Return true if this is a constant which we can fold and + /// convert to a floating point value, using any crazy technique that we + /// want to. + bool + EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded without side-effects, but discard the result. bool isEvaluatable(const ASTContext &Ctx, Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Apr 21 16:04:55 2016 @@ -46,7 +46,17 @@ def BoolConversion : DiagGroup<"bool-con UndefinedBoolConversion]>; def IntConversion : DiagGroup<"int-conversion">; def EnumConversion : DiagGroup<"enum-conversion">; -def FloatConversion : DiagGroup<"float-conversion">; + +def FloatOverflowConversion : DiagGroup<"float-overflow-conversion">; +def FloatZeroConversion : DiagGroup<"float-zero-conversion">; +def FloatBoolConstantConversion : DiagGroup<"float-bool-constant-conversion">; +def FloatBoolConversion : + DiagGroup<"float-bool-conversion", [FloatBoolConstantConversion]>; +def FloatConversion : + DiagGroup<"float-conversion", [FloatBoolConversion, + FloatOverflowConversion, + FloatZeroConversion]>; + def DoublePromotion : DiagGroup<"double-promotion">; def EnumTooLarge : DiagGroup<"enum-too-large">; def UnsupportedNan : DiagGroup<"unsupported-nan">; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Apr 21 16:04:55 2016 @@ -2742,9 +2742,6 @@ def warn_impcast_float_precision : Warni def warn_impcast_double_promotion : Warning< "implicit conversion increases floating-point precision: %0 to %1">, InGroup<DoublePromotion>, DefaultIgnore; -def warn_impcast_float_integer : Warning< - "implicit conversion turns floating-point number into integer: %0 to %1">, - InGroup<FloatConversion>, DefaultIgnore; def warn_impcast_integer_sign : Warning< "implicit conversion changes signedness: %0 to %1">, InGroup<SignConversion>, DefaultIgnore; @@ -2763,9 +2760,29 @@ def warn_impcast_integer_precision_const def warn_impcast_bitfield_precision_constant : Warning< "implicit truncation from %2 to bitfield changes value from %0 to %1">, InGroup<BitFieldConstantConversion>; + def warn_impcast_literal_float_to_integer : Warning< "implicit conversion from %0 to %1 changes value from %2 to %3">, InGroup<LiteralConversion>; +def warn_impcast_float_integer : Warning< + "implicit conversion turns floating-point number into integer: %0 to %1">, + InGroup<FloatConversion>, DefaultIgnore; + +def warn_impcast_float_bool : Warning< + "implicit conversion turns floating-point number into boolean: %0 to %1">, + InGroup<FloatBoolConversion>, DefaultIgnore; +def warn_impcast_float_to_bool : Warning< + "implicit conversion from %0 to %1 changes value from %2 to %3">, + InGroup<FloatBoolConstantConversion>; + +def warn_impcast_float_to_integer : Warning< + "implicit conversion of out of range value from %0 to %1 changes value " + "from %2 to %3">, + InGroup<FloatOverflowConversion>, DefaultIgnore; +def warn_impcast_float_to_integer_zero : Warning< + "implicit conversion from %0 to %1 changes non-zero value from %2 to %3">, + InGroup<FloatZeroConversion>, DefaultIgnore; + def warn_impcast_string_literal_to_bool : Warning< "implicit conversion turns string literal into bool: %0 to %1">, InGroup<StringConversion>, DefaultIgnore; Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Apr 21 16:04:55 2016 @@ -9027,6 +9027,20 @@ bool Expr::EvaluateAsInt(APSInt &Result, return true; } +bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects) const { + if (!getType()->isRealFloatingType()) + return false; + + EvalResult ExprResult; + if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() || + hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) + return false; + + Result = ExprResult.Val.getFloat(); + return true; +} + bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Apr 21 16:04:55 2016 @@ -7382,19 +7382,78 @@ void DiagnoseImpCast(Sema &S, Expr *E, Q DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } -/// Diagnose an implicit cast from a literal expression. Does not warn when the -/// cast wouldn't lose information. -void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, - SourceLocation CContext) { - // Try to convert the literal exactly to an integer. If we can, don't warn. + +/// Diagnose an implicit cast from a floating point value to an integer value. +void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, + + SourceLocation CContext) { + const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); + const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty(); + + Expr *InnerE = E->IgnoreParenImpCasts(); + // We also want to warn on, e.g., "int i = -1.234" + if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) + if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) + InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); + + const bool IsLiteral = + isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE); + + llvm::APFloat Value(0.0); + bool IsConstant = + E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); + if (!IsConstant) { + if (IsBool) { + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_bool, + PruneWarnings); + } else { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } + bool isExact = false; - const llvm::APFloat &Value = FL->getValue(); + llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, - llvm::APFloat::rmTowardZero, &isExact) - == llvm::APFloat::opOK && isExact) - return; + if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, + &isExact) == llvm::APFloat::opOK && + isExact && !IsBool) { + if (IsLiteral) return; + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, + PruneWarnings); + } + + unsigned DiagID = 0; + if (IsBool) { + // Warn on all floating point to bool conversions + DiagID = diag::warn_impcast_float_to_bool; + } else if (IsLiteral) { + // Warn on floating point literal to integer. + DiagID = diag::warn_impcast_literal_float_to_integer; + } else if (IntegerValue == 0) { + if (Value.isZero()) { // Skip -0.0 to 0 conversion. + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + // Warn on non-zero to zero conversion. + DiagID = diag::warn_impcast_float_to_integer_zero; + } else { + if (IntegerValue.isUnsigned()) { + if (!IntegerValue.isMaxValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } else { // IntegerValue.isSigned() + if (!IntegerValue.isMaxSignedValue() && + !IntegerValue.isMinSignedValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } + // Warn on evaluatable floating point expression to integer conversion. + 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 @@ -7407,14 +7466,22 @@ void DiagnoseFloatingLiteralImpCast(Sema Value.toString(PrettySourceValue, precision); SmallString<16> PrettyTargetValue; - if (T->isSpecificBuiltinType(BuiltinType::Bool)) + if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; else IntegerValue.toString(PrettyTargetValue); - S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) - << FL->getType() << T.getUnqualifiedType() << PrettySourceValue - << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext); + if (PruneWarnings) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(DiagID) + << E->getType() << T.getUnqualifiedType() + << PrettySourceValue << PrettyTargetValue + << E->getSourceRange() << SourceRange(CContext)); + } else { + S.Diag(E->getExprLoc(), DiagID) + << E->getType() << T.getUnqualifiedType() << PrettySourceValue + << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext); + } } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -7748,22 +7815,12 @@ void CheckImplicitConversion(Sema &S, Ex return; } - // If the target is integral, always warn. + // If the target is integral, always warn. if (TargetBT && TargetBT->isInteger()) { if (S.SourceMgr.isInSystemMacro(CC)) return; - - Expr *InnerE = E->IgnoreParenImpCasts(); - // We also want to warn on, e.g., "int i = -1.234" - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) - if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) - InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); - - if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { - DiagnoseFloatingLiteralImpCast(S, FL, T, CC); - } else { - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer); - } + + DiagnoseFloatingImpCast(S, E, T, CC); } // Detect the case where a call result is converted from floating-point to Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp (original) +++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp Thu Apr 21 16:04:55 2016 @@ -58,8 +58,8 @@ void float_to_int() { Agg<char> ce1 = { Convert<float>(1.0) }; // expected-error {{type 'float' cannot be narrowed to 'char'}} expected-note {{silence}} Agg<char> ce2 = { ConvertVar<double>() }; // expected-error {{type 'double' cannot be narrowed to 'char'}} expected-note {{silence}} - bool b{1.0}; // expected-error {{type 'double' cannot be narrowed to 'bool'}} expected-note {{silence}} - Agg<bool> ab = {0.0}; // expected-error {{type 'double' cannot be narrowed to 'bool'}} expected-note {{silence}} + bool b{1.0}; // expected-error {{type 'double' cannot be narrowed to 'bool'}} expected-note {{silence}} expected-warning {{changes value}} + Agg<bool> ab = {0.0}; // expected-error {{type 'double' cannot be narrowed to 'bool'}} expected-note {{silence}} expected-warning {{changes value}} } // * from long double to double or float, or from double to float, except where Modified: cfe/trunk/test/SemaCXX/warn-float-conversion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-float-conversion.cpp?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-float-conversion.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-float-conversion.cpp Thu Apr 21 16:04:55 2016 @@ -1,5 +1,12 @@ -// RUN: %clang_cc1 -verify -fsyntax-only %s -Wfloat-conversion +// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-pc-linux-gnu %s -Wno-literal-conversion -Wfloat-conversion -DFLOAT_CONVERSION -DZERO -DBOOL -DCONSTANT_BOOL -DOVERFLOW +// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-pc-linux-gnu %s -Wno-conversion -Wfloat-overflow-conversion -DOVERFLOW +// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-pc-linux-gnu %s -Wno-conversion -Wfloat-zero-conversion -DZERO +// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-pc-linux-gnu %s -Wno-conversion -Wfloat-bool-constant-conversion -DCONSTANT_BOOL +// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-pc-linux-gnu %s -Wno-conversion -Wfloat-bool-conversion -DCONSTANT_BOOL -DBOOL +float ReturnFloat(); + +#ifdef FLOAT_CONVERSION bool ReturnBool(float f) { return f; //expected-warning{{conversion}} } @@ -36,3 +43,80 @@ void Convert(float f, double d, long dou l = ld; //expected-warning{{conversion}} } +void Test() { + int a1 = 10.0/2.0; //expected-warning{{conversion}} + int a2 = 1.0/2.0; //expected-warning{{conversion}} + bool a3 = ReturnFloat(); //expected-warning{{conversion}} + int a4 = 1e30 + 1; //expected-warning{{conversion}} +} + +void TestConstantFloat() { + // Don't warn on exact floating literals. + int a1 = 5.0; + int a2 = 1e3; + + int a3 = 5.5; // caught by -Wliteral-conversion + int a4 = 500.44; // caught by -Wliteral-convserion + + int b1 = 5.0 / 1.0; //expected-warning{{conversion}} + int b2 = 5.0 / 2.0; //expected-warning{{conversion}} + + const float five = 5.0; + + int b3 = five / 1.0; //expected-warning{{conversion}} + int b4 = five / 2.0; //expected-warning{{conversion}} +} +#endif // FLOAT_CONVERSION + +#ifdef CONSTANT_BOOL +const float pi = 3.1415; + +void TestConstantBool() { + bool b1 = 0.99f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0.99 to true}} + bool b2 = 0.99; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 0.99 to true}} + bool b3 = 0.0f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0 to false}} + bool b4 = 0.0; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 0 to false}} + bool b5 = 1.0f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 1 to true}} + bool b6 = 1.0; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 1 to true}} + bool b7 = pi; // expected-warning {{implicit conversion from 'const float' to 'bool' changes value from 3.1415 to true}} + bool b8 = pi - pi; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0 to false}} +} +#endif // CONSTANT_BOOL + +#ifdef BOOL +const float E = 2.718; + +float GetFloat(); +double GetDouble(); + +void TestBool() { + bool b1 = GetFloat(); // expected-warning {{implicit conversion turns floating-point number into boolean: 'float' to 'bool'}} + bool b2 = GetDouble(); // expected-warning {{implicit conversion turns floating-point number into boolean: 'double' to 'bool'}} + bool b3 = 0.0 * GetDouble(); // expected-warning {{implicit conversion turns floating-point number into boolean: 'double' to 'bool'}} + bool b4 = GetFloat() + GetDouble(); // expected-warning {{implicit conversion turns floating-point number into boolean: 'double' to 'bool'}} + bool b5 = E + GetFloat(); // expected-warning {{implicit conversion turns floating-point number into boolean: 'float' to 'bool'}} +} + +#endif // BOOL + +#ifdef ZERO +void TestZero() { + const float half = .5; + int a1 = half; // expected-warning{{implicit conversion from 'const float' to 'int' changes non-zero value from 0.5 to 0}} + int a2 = 1.0 / 2.0; // expected-warning{{implicit conversion from 'double' to 'int' changes non-zero value from 0.5 to 0}} + int a3 = 5; +} +#endif // ZERO + +#ifdef OVERFLOW +void TestOverflow() { + char a = 500.0; // caught by -Wliteral-conversion + char b = -500.0; // caught by -Wliteral-conversion + + const float LargeNumber = 1024; + char c = LargeNumber; // expected-warning{{implicit conversion of out of range value from 'const float' to 'char' changes value from 1024 to 127}} + char d = 400.0 + 400.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'char' changes value from 800 to 127}} + + char e = 1.0 / 0.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'char' changes value from +Inf to 127}} +} +#endif // OVERFLOW Modified: cfe/trunk/test/SemaCXX/warn-literal-conversion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-literal-conversion.cpp?rev=267054&r1=267053&r2=267054&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-literal-conversion.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-literal-conversion.cpp Thu Apr 21 16:04:55 2016 @@ -25,7 +25,7 @@ void test0() { // Test passing a literal floating-point value to a function that takes an integer. foo(1.2F); // expected-warning {{implicit conversion from 'float' to 'int' changes value from 1.2 to 1}} - int y10 = -1.2F; // expected-warning {{implicit conversion from 'float' to 'int' changes value from 1.2 to 1}} + int y10 = -1.2F; // expected-warning {{implicit conversion from 'float' to 'int' changes value from -1.2 to -1}} // -Wliteral-conversion does NOT catch const values. // (-Wconversion DOES catch them.) @@ -38,14 +38,3 @@ void test0() { int y = (24*60*60) * 0.25; int pennies = 123.45 * 100; } - -// Similarly, test floating point conversion to bool. Only float values of zero -// are converted to false; everything else is converted to true. -void test1() { - bool b1 = 0.99f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0.99 to true}} - bool b2 = 0.99; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 0.99 to true}} - // These do not warn because they can be directly converted to integral - // values. - bool b3 = 0.0f; - bool b4 = 0.0; -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits