https://github.com/YutongZhuu updated https://github.com/llvm/llvm-project/pull/133653
>From ca795c3f27e37ad8a8f165a3b10e9415cbfd66a5 Mon Sep 17 00:00:00 2001 From: Yutong Zhu <y25...@uwaterloo.ca> Date: Sat, 12 Apr 2025 15:32:46 -0400 Subject: [PATCH 1/2] Improved the -Wtautological-overlap-compare diagnostics to warn about overlapping and non-overlapping ranges involving character literals and floating-point literals. --- clang/docs/ReleaseNotes.rst | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Analysis/CFG.cpp | 179 +++++++++++------- clang/lib/Sema/AnalysisBasedWarnings.cpp | 5 +- clang/test/Sema/warn-overlap.c | 119 ++++++++++-- 5 files changed, 211 insertions(+), 97 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 11f62bc881b03..de5c877cf996b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -352,6 +352,9 @@ Improvements to Clang's diagnostics - Now correctly diagnose a tentative definition of an array with static storage duration in pedantic mode in C. (#GH50661) +- Improved the ``-Wtautological-overlap-compare`` diagnostics to warn about overlapping and non-overlapping ranges involving character literals and floating-point literals. + The warning message for non-overlapping cases has also been improved (#GH13473). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 180ca39bc07e9..c8b5c94676d18 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10356,7 +10356,7 @@ def warn_tautological_negation_or_compare: Warning< "'||' of a value and its negation always evaluates to true">, InGroup<TautologicalNegationCompare>, DefaultIgnore; def warn_tautological_overlap_comparison : Warning< - "overlapping comparisons always evaluate to %select{false|true}0">, + "%select{non-|}0overlapping comparisons always evaluate to %select{false|true}0">, InGroup<TautologicalOverlapCompare>, DefaultIgnore; def warn_depr_array_comparison : Warning< "comparison between two arrays is deprecated; " diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 9af1e915482da..ec7c1fbfc423a 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -70,19 +70,18 @@ static SourceLocation GetEndLoc(Decl *D) { return D->getLocation(); } -/// Returns true on constant values based around a single IntegerLiteral. -/// Allow for use of parentheses, integer casts, and negative signs. -/// FIXME: it would be good to unify this function with -/// getIntegerLiteralSubexpressionValue at some point given the similarity -/// between the functions. +/// Returns true on constant values based around a single IntegerLiteral, +/// CharacterLiteral, or FloatingLiteral. Allow for use of parentheses, integer +/// casts, and negative signs. -static bool IsIntegerLiteralConstantExpr(const Expr *E) { +static bool IsLiteralConstantExpr(const Expr *E) { // Allow parentheses E = E->IgnoreParens(); // Allow conversions to different integer kind. if (const auto *CE = dyn_cast<CastExpr>(E)) { - if (CE->getCastKind() != CK_IntegralCast) + if (CE->getCastKind() != CK_IntegralCast && + CE->getCastKind() != CK_IntegralToFloating) return false; E = CE->getSubExpr(); } @@ -93,16 +92,16 @@ static bool IsIntegerLiteralConstantExpr(const Expr *E) { return false; E = UO->getSubExpr(); } - - return isa<IntegerLiteral>(E); + return isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) || + isa<FloatingLiteral>(E); } /// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral -/// constant expression or EnumConstantDecl from the given Expr. If it fails, -/// returns nullptr. -static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { +/// FloatingLiteral, CharacterLiteral or EnumConstantDecl from the given Expr. +/// If it fails, returns nullptr. +static const Expr *tryTransformToLiteralConstant(const Expr *E) { E = E->IgnoreParens(); - if (IsIntegerLiteralConstantExpr(E)) + if (IsLiteralConstantExpr(E)) return E; if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) return isa<EnumConstantDecl>(DR->getDecl()) ? DR : nullptr; @@ -119,7 +118,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) { BinaryOperatorKind Op = B->getOpcode(); const Expr *MaybeDecl = B->getLHS(); - const Expr *Constant = tryTransformToIntOrEnumConstant(B->getRHS()); + const Expr *Constant = tryTransformToLiteralConstant(B->getRHS()); // Expr looked like `0 == Foo` instead of `Foo == 0` if (Constant == nullptr) { // Flip the operator @@ -133,7 +132,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) { Op = BO_GE; MaybeDecl = B->getRHS(); - Constant = tryTransformToIntOrEnumConstant(B->getLHS()); + Constant = tryTransformToLiteralConstant(B->getLHS()); } return std::make_tuple(MaybeDecl, Op, Constant); @@ -1082,10 +1081,10 @@ class CFGBuilder { return std::nullopt; } + template <typename APFloatOrInt> TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation, - const llvm::APSInt &Value1, - const llvm::APSInt &Value2) { - assert(Value1.isSigned() == Value2.isSigned()); + const APFloatOrInt &Value1, + const APFloatOrInt &Value2) { switch (Relation) { default: return TryResult(); @@ -1170,82 +1169,116 @@ class CFGBuilder { if (!areExprTypesCompatible(NumExpr1, NumExpr2)) return {}; + // Check that the two expressions are of the same type. Expr::EvalResult L1Result, L2Result; - if (!NumExpr1->EvaluateAsInt(L1Result, *Context) || - !NumExpr2->EvaluateAsInt(L2Result, *Context)) - return {}; - - llvm::APSInt L1 = L1Result.Val.getInt(); - llvm::APSInt L2 = L2Result.Val.getInt(); - - // Can't compare signed with unsigned or with different bit width. - if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth()) + if (!NumExpr1->EvaluateAsRValue(L1Result, *Context) || + !NumExpr2->EvaluateAsRValue(L2Result, *Context)) return {}; - // Values that will be used to determine if result of logical - // operator is always true/false - const llvm::APSInt Values[] = { - // Value less than both Value1 and Value2 - llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()), - // L1 - L1, - // Value between Value1 and Value2 - ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), - L1.isUnsigned()), - // L2 - L2, - // Value greater than both Value1 and Value2 - llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()), - }; - - // Check whether expression is always true/false by evaluating the following + // Check whether expression is always true/false by evaluating the + // following // * variable x is less than the smallest literal. // * variable x is equal to the smallest literal. // * Variable x is between smallest and largest literal. // * Variable x is equal to the largest literal. // * Variable x is greater than largest literal. - bool AlwaysTrue = true, AlwaysFalse = true; - // Track value of both subexpressions. If either side is always - // true/false, another warning should have already been emitted. - bool LHSAlwaysTrue = true, LHSAlwaysFalse = true; - bool RHSAlwaysTrue = true, RHSAlwaysFalse = true; - for (const llvm::APSInt &Value : Values) { - TryResult Res1, Res2; - Res1 = analyzeLogicOperatorCondition(BO1, Value, L1); - Res2 = analyzeLogicOperatorCondition(BO2, Value, L2); - - if (!Res1.isKnown() || !Res2.isKnown()) - return {}; + auto analyzeConditions = [&](const auto &Values, + const BinaryOperatorKind *BO1, + const BinaryOperatorKind *BO2) -> TryResult { + bool AlwaysTrue = true, AlwaysFalse = true; + // Track value of both subexpressions. If either side is always + // true/false, another warning should have already been emitted. + bool LHSAlwaysTrue = true, LHSAlwaysFalse = true; + bool RHSAlwaysTrue = true, RHSAlwaysFalse = true; + + for (const auto &Value : Values) { + TryResult Res1 = + analyzeLogicOperatorCondition(*BO1, Value, Values[1] /* L1 */); + TryResult Res2 = + analyzeLogicOperatorCondition(*BO2, Value, Values[3] /* L2 */); + + if (!Res1.isKnown() || !Res2.isKnown()) + return {}; + + const bool isAnd = B->getOpcode() == BO_LAnd; + const bool combine = isAnd ? (Res1.isTrue() && Res2.isTrue()) + : (Res1.isTrue() || Res2.isTrue()); + + AlwaysTrue &= combine; + AlwaysFalse &= !combine; + + LHSAlwaysTrue &= Res1.isTrue(); + LHSAlwaysFalse &= Res1.isFalse(); + RHSAlwaysTrue &= Res2.isTrue(); + RHSAlwaysFalse &= Res2.isFalse(); + } - if (B->getOpcode() == BO_LAnd) { - AlwaysTrue &= (Res1.isTrue() && Res2.isTrue()); - AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue()); - } else { - AlwaysTrue &= (Res1.isTrue() || Res2.isTrue()); - AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue()); + if (AlwaysTrue || AlwaysFalse) { + if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue && + !RHSAlwaysFalse && BuildOpts.Observer) { + BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); + } + return TryResult(AlwaysTrue); } + return {}; + }; - LHSAlwaysTrue &= Res1.isTrue(); - LHSAlwaysFalse &= Res1.isFalse(); - RHSAlwaysTrue &= Res2.isTrue(); - RHSAlwaysFalse &= Res2.isFalse(); + // Handle integer comparison + if (L1Result.Val.getKind() == APValue::Int && + L2Result.Val.getKind() == APValue::Int) { + llvm::APSInt L1 = L1Result.Val.getInt(); + llvm::APSInt L2 = L2Result.Val.getInt(); + + // Can't compare signed with unsigned or with different bit width. + if (L1.isSigned() != L2.isSigned() || + L1.getBitWidth() != L2.getBitWidth()) + return {}; + + // Values that will be used to determine if result of logical + // operator is always true/false + const llvm::APSInt Values[] = { + // Value less than both Value1 and Value2 + llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()), + // L1 + L1, + // Value between Value1 and Value2 + ((L1 < L2) ? L1 : L2) + + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()), + // L2 + L2, + // Value greater than both Value1 and Value2 + llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()), + }; + + return analyzeConditions(Values, &BO1, &BO2); } - if (AlwaysTrue || AlwaysFalse) { - if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue && - !RHSAlwaysFalse && BuildOpts.Observer) - BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); - return TryResult(AlwaysTrue); + // Handle float comparison + if (L1Result.Val.getKind() == APValue::Float && + L2Result.Val.getKind() == APValue::Float) { + llvm::APFloat L1 = L1Result.Val.getFloat(); + llvm::APFloat L2 = L2Result.Val.getFloat(); + llvm::APFloat MidValue = L1; + MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven); + MidValue.divide(llvm::APFloat(2.0), llvm::APFloat::rmNearestTiesToEven); + + const llvm::APFloat Values[] = { + llvm::APFloat::getSmallest(L1.getSemantics(), true), L1, MidValue, L2, + llvm::APFloat::getLargest(L2.getSemantics(), false), + }; + + return analyzeConditions(Values, &BO1, &BO2); } + return {}; } /// A bitwise-or with a non-zero constant always evaluates to true. TryResult checkIncorrectBitwiseOrOperator(const BinaryOperator *B) { const Expr *LHSConstant = - tryTransformToIntOrEnumConstant(B->getLHS()->IgnoreParenImpCasts()); + tryTransformToLiteralConstant(B->getLHS()->IgnoreParenImpCasts()); const Expr *RHSConstant = - tryTransformToIntOrEnumConstant(B->getRHS()->IgnoreParenImpCasts()); + tryTransformToLiteralConstant(B->getRHS()->IgnoreParenImpCasts()); if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant)) return {}; diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 38aa3f0edf718..9173758cb143e 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -166,13 +166,14 @@ class LogicalErrorHandler : public CFGCallback { S.Diag(B->getExprLoc(), DiagID) << DiagRange; } - void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override { + void compareAlwaysTrue(const BinaryOperator *B, + bool isAlwaysTrueOrFalse) override { if (HasMacroID(B)) return; SourceRange DiagRange = B->getSourceRange(); S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison) - << DiagRange << isAlwaysTrue; + << DiagRange << isAlwaysTrueOrFalse; } void compareBitwiseEquality(const BinaryOperator *B, diff --git a/clang/test/Sema/warn-overlap.c b/clang/test/Sema/warn-overlap.c index 2db07ebcd17b8..6b9ff65006cc4 100644 --- a/clang/test/Sema/warn-overlap.c +++ b/clang/test/Sema/warn-overlap.c @@ -37,37 +37,37 @@ void f(int x) { if (x >= 0 || x <= 0) { } // expected-warning {{overlapping comparisons always evaluate to true}} // > && < - if (x > 2 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x > 2 && x < 2) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x > 2 && x < 3) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x > 0 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x > 2 && x < 1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x > 2 && x < 2) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x > 2 && x < 3) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x > 0 && x < 1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} - if (x > 2 && x <= 1) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x > 2 && x <= 2) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x > 2 && x <= 1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x > 2 && x <= 2) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} if (x > 2 && x <= 3) { } - if (x >= 2 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x >= 2 && x < 2) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x >= 2 && x < 1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x >= 2 && x < 2) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} if (x >= 2 && x < 3) { } - if (x >= 0 && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x >= 0 && x < 0) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} - if (x >= 2 && x <= 1) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x >= 2 && x <= 1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} if (x >= 2 && x <= 2) { } if (x >= 2 && x <= 3) { } // !=, ==, .. if (x != 2 || x != 3) { } // expected-warning {{overlapping comparisons always evaluate to true}} if (x != 2 || x < 3) { } // expected-warning {{overlapping comparisons always evaluate to true}} - if (x == 2 && x == 3) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x == 2 && x > 3) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (x == 3 && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}} - if (3 == x && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x == 2 && x == 3) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x == 2 && x > 3) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (x == 3 && x < 0) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} + if (3 == x && x < 0) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} if (x == mydefine && x > 3) { } if (x == (mydefine + 1) && x > 3) { } if (x != CHOICE_0 || x != CHOICE_1) { } // expected-warning {{overlapping comparisons always evaluate to true}} - if (x == CHOICE_0 && x == CHOICE_1) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (x == CHOICE_0 && x == CHOICE_1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} // Don't warn if comparing x to different types if (x == CHOICE_0 && x == 1) { } @@ -80,7 +80,7 @@ void f(int x) { void enums(enum Choices c) { if (c != CHOICE_0 || c != CHOICE_1) { } // expected-warning {{overlapping comparisons always evaluate to true}} - if (c == CHOICE_0 && c == CHOICE_1) { } // expected-warning {{overlapping comparisons always evaluate to false}} + if (c == CHOICE_0 && c == CHOICE_1) { } // expected-warning {{non-overlapping comparisons always evaluate to false}} // Don't warn if comparing x to different types if (c == CHOICE_0 && c == 1) { } @@ -117,12 +117,12 @@ void assignment(int x) { int a = x > 4 || x < 10; // expected-warning@-1{{overlapping comparisons always evaluate to true}} int b = x < 2 && x > 5; - // expected-warning@-1{{overlapping comparisons always evaluate to false}} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} int c = x != 1 || x != 3; // expected-warning@-1{{overlapping comparisons always evaluate to true}} int d = x == 1 && x == 2; - // expected-warning@-1{{overlapping comparisons always evaluate to false}} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} int e = x < 1 || x != 0; // expected-warning@-1{{overlapping comparisons always evaluate to true}} @@ -132,12 +132,12 @@ int returns(int x) { return x > 4 || x < 10; // expected-warning@-1{{overlapping comparisons always evaluate to true}} return x < 2 && x > 5; - // expected-warning@-1{{overlapping comparisons always evaluate to false}} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} return x != 1 || x != 3; // expected-warning@-1{{overlapping comparisons always evaluate to true}} return x == 1 && x == 2; - // expected-warning@-1{{overlapping comparisons always evaluate to false}} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} return x < 1 || x != 0; // expected-warning@-1{{overlapping comparisons always evaluate to true}} @@ -169,7 +169,84 @@ int struct_test(struct A a) { return a.x > 5 && a.y < 1; // no warning, different variables return a.x > 5 && a.x < 1; - // expected-warning@-1{{overlapping comparisons always evaluate to false}} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} return a.y == 1 || a.y != 1; // expected-warning@-1{{overlapping comparisons always evaluate to true}} } + +void char_tests(char c) { + if (c > 'a' || c < 'z') {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} + if (c > 'z' && c < 'a') {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (c == 'a' && c == 'z') {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (c != 'a' || c != 'z') {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} + +void float_tests(float f) { + if (f > 1.0 || f < 2.0) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} + if (f > 2.0 && f < 1.0) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (f == 1.0 && f == 2.0) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (f != 1.0 || f != 2.0) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} + +void double_tests(double d) { + if (d > 3.5 || d < 4.5) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} + if (d > 4.5 && d < 3.5) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (d == 3.5 && d == 4.5) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (d != 3.5 || d != 4.5) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} + +void mixed_float_double_tests(float f, double d) { + if (f > 1.0 || d < 2.0) {} + // no warning, different types + if (f > 2.0 && d < 1.0) {} + // no warning, different types + if (f == 1.0 && d == 2.0) {} + // no warning, different types + if (f != 1.0 || d != 2.0) {} + // no warning, different types +} + +void float_edge_cases(float f) { + if (f > 0.0 || f < 0.0) {} + // no-warning + if (f > 0.0 && f < 0.0) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}}} + if (f == 0.0 && f == -0.0) {} + // no-warning + if (f != 0.0 || f != -0.0) {} + // no warning +} + +void double_edge_cases(double d) { + if (d > 0.0 || d < 0.0) {} + // no-warning + if (d > 0.0 && d < 0.0) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (d == 0.0 && d == -0.0) {} + // no warning + if (d != 0.0 || d != -0.0) {} + // no warning +} + +void float_int_literal_tests(float f) { + if (f > 1 || f < 2) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} + if (f > 2 && f < 1) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (f == 1 && f == 2) {} + // expected-warning@-1{{non-overlapping comparisons always evaluate to false}} + if (f != 1 || f != 2) {} + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} >From 21ff235f988dec97e4dedcee29b9c52fc1181b9a Mon Sep 17 00:00:00 2001 From: Yutong Zhu <y25...@uwaterloo.ca> Date: Sat, 12 Apr 2025 17:12:13 -0400 Subject: [PATCH 2/2] Fix github test case failure --- clang/lib/Analysis/CFG.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index ec7c1fbfc423a..0a7cbdb70c4f6 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -36,6 +36,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" @@ -1260,7 +1261,7 @@ class CFGBuilder { llvm::APFloat L2 = L2Result.Val.getFloat(); llvm::APFloat MidValue = L1; MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven); - MidValue.divide(llvm::APFloat(2.0), llvm::APFloat::rmNearestTiesToEven); + MidValue.divide(llvm::APFloat(L1.getSemantics(), llvm::APInt(64, 2)), llvm::APFloat::rmNearestTiesToEven); const llvm::APFloat Values[] = { llvm::APFloat::getSmallest(L1.getSemantics(), true), L1, MidValue, L2, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits