rtrieu updated this revision to Diff 234180.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D71503/new/
https://reviews.llvm.org/D71503
Files:
clang/include/clang/AST/Expr.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/ExprConstant.cpp
clang/lib/Sema/SemaStmt.cpp
clang/test/SemaCXX/warn-loop-analysis-first-condition.cpp
Index: clang/test/SemaCXX/warn-loop-analysis-first-condition.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/warn-loop-analysis-first-condition.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 %s -Wfor-loop-analysis -verify
+// RUN: %clang_cc1 %s -Wall -verify
+
+#define OneHundred 100
+
+void test() {
+ // Loop variable
+ for (int i = OneHundred; i < 50; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 100 on loop initialization, but comparing 100 to 50 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = OneHundred; i > 50; --i) {}
+
+ // Outside variable
+ int j;
+ for (j = OneHundred; j < 50; ++j) {}
+ // expected-warning@-1{{variable 'j' is set to value 100 on loop initialization, but comparing 100 to 50 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (j = OneHundred; j > 50; --j) {}
+
+ // int->float conversion
+ for (int i = OneHundred; i < 5e1; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 100 on loop initialization, but comparing 100 to 5.000000e+01 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = OneHundred; i > 5e1; --i) {}
+
+ // const values
+ const int kStart = 0;
+ const int kInterval = 10;
+ for (int i = kStart; i < kStart; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 0 on loop initialization, but comparing 0 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = kStart; i < kStart + kInterval; ++i) {}
+
+ // Reversed comparison operator
+ for (int i = 100; i <= 1; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 100 on loop initialization, but comparing 100 to 1 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = 100; i >= 1; --i) {}
+
+ // Range endpoints mistakes
+ const int kMin = 0;
+ const int kMax = 8;
+ for (int i = kMin; i < kMin; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 0 on loop initialization, but comparing 0 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = kMax; i < kMin; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 8 on loop initialization, but comparing 8 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = kMin; i < kMax; ++i) {}
+
+ for (int i = 16; i < 16; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 16 on loop initialization, but comparing 16 to 16 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = 8; i < 16; ++i) {}
+
+ for (int i = 1; i <= (1 >> 5); ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 1 on loop initialization, but comparing 1 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = 1; i <= (1 << 5); ++i) {}
+
+ // Complex comparion operand
+ const int TwoK = 1024 * 2;
+ for (int i = 2048; i < TwoK; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 2048 on loop initialization, but comparing 2048 to 2048 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int i = 1024; i < TwoK; ++i) {}
+
+ // Signedness mistake
+ for (unsigned i = -5; i < 5; ++i) {}
+ // expected-warning@-1{{variable 'i' is set to value 4294967291 on loop initialization, but comparing 4294967291 to 5 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (signed i = -5; i < 5; ++i) {}
+
+ for (int i = 0xffffffff; i > 10; i -= 10) {}
+ // expected-warning@-1{{variable 'i' is set to value -1 on loop initialization, but comparing -1 to 10 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (unsigned int i = 0xffffffff; i > 10; i -= 10) {}
+
+ // Floating point
+ for (double x = 0; x > 10; x += .5) {}
+ // expected-warning@-1{{variable 'x' is set to value 0.000000e+00 on loop initialization, but comparing 0.000000e+00 to 1.000000e+01 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (double x = 0; x < 10; x += .5) {}
+
+ // Typos
+ for (int x = 0; x < 0000; ++x) {};
+ // expected-warning@-1{{variable 'x' is set to value 0 on loop initialization, but comparing 0 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int x = 0; x < 10000; ++x) {};
+
+ for (char c = '0'; c <= 9; ++c) {}
+ // expected-warning@-1{{variable 'c' is set to value 48 on loop initialization, but comparing 48 to 9 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (char c = '0'; c <= '9'; ++c) {}
+
+ int array[10];
+ for (int x = 5; x < 1; ++x) { array[x] = x; }
+ // expected-warning@-1{{variable 'x' is set to value 5 on loop initialization, but comparing 5 to 1 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+ for (int x = 5; x < 10; ++x) { array[x] = x; }
+}
+
+void testConversions() {
+ // No conversion
+ for (int x = 0; x > 5; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0 on loop initialization, but comparing 0 to 5 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Int conversion
+ for (short x = 0; x > 5; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0 on loop initialization, but comparing 0 to 5 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Float conversion
+ for (float x = 0; x > 5.0; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0.000000e+00 on loop initialization, but comparing 0.000000e+00 to 5.000000e+00 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Float to Int conversion
+ for (double x = 0; static_cast<int>(x) > 5; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0.000000e+00 on loop initialization, but comparing 0.000000e+00 to 5 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Int to Float conversion
+ for (int x = 0; x > 5.0; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0 on loop initialization, but comparing 0 to 5.000000e+00 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Bool to Int conversion
+ for (bool x = false; x > 0; x = !x) {}
+ // expected-warning@-1{{variable 'x' is set to value false on loop initialization, but comparing false to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Bool to Float conversion
+ for (bool x = false; x > 0.0; x = !x) {}
+ // expected-warning@-1{{variable 'x' is set to value false on loop initialization, but comparing false to 0.000000e+00 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Float to Bool conversion
+ for (float x = 0; static_cast<bool>(x) > 0; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0.000000e+00 on loop initialization, but comparing 0.000000e+00 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+
+ // Int to Bool conversion
+ for (int x = 0; static_cast<bool>(x) > 0; ++x) {}
+ // expected-warning@-1{{variable 'x' is set to value 0 on loop initialization, but comparing 0 to 0 in the loop condition is false and the loop body will never run}}
+ // expected-note@-2{{place parentheses around the condition to silence this warning}}
+}
+
+#define size1(X) (sizeof(X) / sizeof(X[0]))
+#define size2(X) (sizeof(X) / sizeof(X[0])) / 1
+#define size3(X) sizeof(array_helper(X))
+
+using size_t = decltype(sizeof(int));
+template <typename T, size_t N>
+auto array_helper(const T (&X)[N]) -> char (&)[N];
+
+const int MIN = 10;
+const int MAX = 5;
+
+void no_warning () {
+ // Parentheses to silence warning.
+ for (int x = 0; (x > 10); ++x) {}
+
+ int array[] = {};
+ // Processing empty array.
+ for (int x = 0; x < size1(array); ++x) {
+ array[x] = x;
+ }
+ for (int x = 0; x < size2(array); ++x) {
+ array[x] = x;
+ }
+ for (int x = 0; x < sizeof(array); ++x) {
+ array[x] = x;
+ }
+ for (int x = 0; x < sizeof(array)/sizeof(*array); ++x) {
+ array[x] = x;
+ }
+
+ int array1[] = {5};
+ // Skip first array element.
+ for (int x = 1; x < size1(array1); ++x) {
+ array1[x] = array[x - 1];
+ }
+ for (int x = 1; x < size2(array1); ++x) {
+ array1[x] = array[x - 1];
+ }
+ for (int x = 1; x < size3(array1); ++x) {
+ array1[x] = array[x - 1];
+ }
+ for (int x = 1; x < sizeof(array1); ++x) {
+ array1[x] = array[x - 1];
+ }
+ for (int x = 1; x < sizeof(array1)/sizeof(*array); ++x) {
+ array1[x] = array[x - 1];
+ }
+
+ // Code flow never reaches the loop.
+ if (MIN < MAX) {
+ for (int x = MIN; x < MAX; ++x) {}
+ }
+}
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -1739,6 +1740,258 @@
<< LoopIncrement;
}
+ // Look for any array access of the form array[x] where 'x' is a given Decl
+ // and array is constant array with given size.
+ class ArrayFinder : public ConstEvaluatedExprVisitor<ArrayFinder> {
+ // Tracking boolean
+ bool FoundArray;
+ // Decl used as array index
+ const VarDecl *VD;
+ // Target size for array
+ llvm::APInt Size;
+
+ public:
+ typedef ConstEvaluatedExprVisitor<ArrayFinder> Inherited;
+ ArrayFinder(const ASTContext &Context) : Inherited(Context) { }
+
+ bool CheckForArrays(const Stmt *Body, llvm::APInt TargetArraySize,
+ const VarDecl *D) {
+ FoundArray = false;
+ Size = TargetArraySize;
+ VD = D;
+ Visit(Body);
+ return FoundArray;
+ }
+
+ void VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ if (CheckArrayType(E->getBase()) && CheckIndex(E->getIdx())) {
+ FoundArray = true;
+ }
+ Inherited::VisitArraySubscriptExpr(E);
+ }
+
+ private:
+ // Helper function for checking array access.
+ bool CheckArrayType(const Expr *E) {
+ QualType ArrayTy = E->IgnoreImpCasts()->getType();
+ if (!ArrayTy->isConstantArrayType())
+ return false;
+ const ConstantArrayType *CAT = Context.getAsConstantArrayType(ArrayTy);
+ if (!CAT)
+ return false;
+ if (!llvm::APInt::isSameValue(CAT->getSize(), Size))
+ return false;
+ return true;
+ }
+
+ // Helper function for checking array access.
+ bool CheckIndex(const Expr *E) {
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImpCasts());
+ return DRE && DRE->getDecl() == VD;
+ }
+
+ };
+
+ // Emit a warning when the condition of a for-loop is false on the first
+ // iteration, making the loop body never executed. Conditions in parenthesis
+ // will silence the warning. Loop variables used as array accesses are also
+ // skipped.
+ void CheckFirstIterationCondition(Sema &S, const Stmt *First,
+ const Expr *Second, const Stmt *Body) {
+ if (!First || !Second || Second->isTypeDependent() ||
+ Second->isValueDependent())
+ return;
+ if (S.inTemplateInstantiation())
+ return;
+ if (Second->getExprLoc().isMacroID())
+ return;
+
+ if (S.Diags.isIgnored(diag::warn_loop_never_run, Second->getBeginLoc()))
+ return;
+
+ // Only work on loop conditions that are comparisons.
+ const BinaryOperator *CompareBO = dyn_cast<BinaryOperator>(Second);
+ if (!CompareBO || !CompareBO->isComparisonOp())
+ return;
+
+ // Examine the loop initilization and extract the single Decl used and its
+ // initial value.
+ const VarDecl *D = nullptr;
+ APValue InitValue;
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
+ // A loop variable being declared.
+ if (!DS->isSingleDecl())
+ return;
+ D = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!D || !D->getInit())
+ return;
+ Expr::EvalResult Result;
+ if (!D->getInit()->EvaluateAsRValue(Result, S.Context))
+ return;
+ InitValue = Result.Val;
+ } else if (const Expr *E = dyn_cast<Expr>(First)) {
+ // A variable from outside the loop is being assigned a value.
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens());
+ if (!BO || BO->getOpcode() != BO_Assign)
+ return;
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BO->getLHS());
+ if (!DRE || !DRE->getDecl())
+ return;
+ D = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!D)
+ return;
+ Expr::EvalResult Result;
+ if (!BO->getRHS()->EvaluateAsRValue(Result, S.Context))
+ return;
+ InitValue = Result.Val;
+ } else {
+ // Skip any other cases in the initialization.
+ return;
+ }
+
+ auto isVariable = [](const Expr *E, const Decl *D) {
+ E = E->IgnoreParenCasts();
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return false;
+ return DRE->getDecl() == D;
+ };
+
+ // Check that the variable from the initilization is one of the
+ // comparison operands.
+ const bool LHSisVariable = isVariable(CompareBO->getLHS(), D);
+ const bool RHSisVariable = isVariable(CompareBO->getRHS(), D);
+ if (!LHSisVariable && !RHSisVariable)
+ return;
+ if (LHSisVariable && RHSisVariable)
+ return;
+
+ // Normalize to Variable Opc Constant.
+ const auto Opc =
+ LHSisVariable
+ ? CompareBO->getOpcode()
+ : BinaryOperator::reverseComparisonOp(CompareBO->getOpcode());
+
+ const Expr *Variable =
+ LHSisVariable ? CompareBO->getLHS() : CompareBO->getRHS();
+ const Expr *Constant =
+ LHSisVariable ? CompareBO->getRHS() : CompareBO->getLHS();
+
+ // Convert the initial value of the variable from the variable type to
+ // the type used in the comparision. For instance, signed/unsigned
+ // conversions or float/int conversions.
+ APValue ConvertedValue;
+ if (!Variable->SubstituteValueWithCasts(S.Context, InitValue, D,
+ ConvertedValue))
+ return;
+
+ // Evaluate the constant operand of the compare expression.
+ Expr::EvalResult Result;
+ if (!Constant->EvaluateAsRValue(Result, S.Context))
+ return;
+ APValue CompareValue = Result.Val;
+
+ // Perform the first iteration comparison.
+ if (CompareValue.isFloat()) {
+ auto FloatCompareResult =
+ ConvertedValue.getFloat().compare(CompareValue.getFloat());
+ if (FloatCompareResult == llvm::APFloat::cmpUnordered)
+ return;
+ switch (Opc) {
+ default:
+ llvm_unreachable("Unexpected operator kind");
+ case BO_LT:
+ if (FloatCompareResult == llvm::APFloat::cmpLessThan)
+ return;
+ break;
+ case BO_GT:
+ if (FloatCompareResult == llvm::APFloat::cmpGreaterThan)
+ return;
+ break;
+ case BO_LE:
+ if (FloatCompareResult == llvm::APFloat::cmpLessThan ||
+ FloatCompareResult == llvm::APFloat::cmpEqual)
+ return;
+ break;
+ case BO_GE:
+ if (FloatCompareResult == llvm::APFloat::cmpGreaterThan ||
+ FloatCompareResult == llvm::APFloat::cmpEqual)
+ return;
+ break;
+ case BO_EQ:
+ if (FloatCompareResult == llvm::APFloat::cmpEqual)
+ return;
+ break;
+ case BO_NE:
+ if (FloatCompareResult == llvm::APFloat::cmpLessThan ||
+ FloatCompareResult == llvm::APFloat::cmpGreaterThan)
+ return;
+ break;
+ }
+ } else if (CompareValue.isInt()) {
+ switch (Opc) {
+ default:
+ llvm_unreachable("Unexpected operator kind");
+ case BO_LT:
+ if (ConvertedValue.getInt() < CompareValue.getInt())
+ return;
+ break;
+ case BO_GT:
+ if (ConvertedValue.getInt() > CompareValue.getInt())
+ return;
+ break;
+ case BO_LE:
+ if (ConvertedValue.getInt() <= CompareValue.getInt())
+ return;
+ break;
+ case BO_GE:
+ if (ConvertedValue.getInt() >= CompareValue.getInt())
+ return;
+ break;
+ case BO_EQ:
+ if (ConvertedValue.getInt() == CompareValue.getInt())
+ return;
+ break;
+ case BO_NE:
+ if (ConvertedValue.getInt() != CompareValue.getInt())
+ return;
+ break;
+ }
+ } else {
+ // Constant is neither an int of a float.
+ return;
+ }
+
+ // Exclude loops where:
+ // The loop variable is used as an index for array access
+ // The comparison operator is less than
+ // The constant comparison operand is the same as the array size
+ if (Body && CompareValue.isInt() && Opc == BO_LT) {
+ llvm::APSInt UpperRange = CompareValue.getInt();
+ if (UpperRange.isNonNegative() && UpperRange.getMinSignedBits() <= 64) {
+ if (ArrayFinder(S.Context).CheckForArrays(Body, UpperRange, D)) {
+ return;
+ }
+ }
+ }
+
+ auto PartialDiag =
+ S.PDiag(diag::warn_loop_never_run)
+ << D << InitValue.getAsString(S.Context, D->getType())
+ << CompareValue.getAsString(S.Context, Constant->getType())
+ << Second->getSourceRange();
+ S.DiagRuntimeBehavior(Second->getExprLoc(), Second, PartialDiag);
+
+ SourceLocation Open = Second->getBeginLoc();
+ SourceLocation Close =
+ S.getLocForEndOfToken(Second->getSourceRange().getEnd());
+ auto PartialDiagNote = S.PDiag(diag::note_loop_condition_silence)
+ << Second->getSourceRange()
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
+ S.DiagRuntimeBehavior(Second->getExprLoc(), Second, PartialDiagNote);
+ }
+
} // end namespace
@@ -1791,6 +2044,7 @@
CheckForLoopConditionalStatement(*this, Second.get().second, third.get(),
Body);
CheckForRedundantIteration(*this, third.get(), Body);
+ CheckFirstIterationCondition(*this, First, Second.get().second, Body);
if (Second.get().second &&
!Diags.isIgnored(diag::warn_comma_operator,
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -2351,9 +2351,10 @@
Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
- & APFloat::opInvalidOp)
- return HandleOverflow(Info, E, Value, DestType);
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) &
+ APFloat::opInvalidOp)
+ if (E)
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -14489,3 +14490,89 @@
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
return tryEvaluateBuiltinObjectSize(this, Type, Info, Result);
}
+
+// Recursively apply casts from E to InitValue and return resulting value.
+static bool AdjustCastValue(EvalInfo &Info, const Expr *E,
+ const APValue InitValue, const VarDecl *D,
+ APValue &Result) {
+ const auto *Cast = dyn_cast<CastExpr>(E->IgnoreParens());
+ if (!Cast)
+ return false;
+ switch (Cast->getCastKind()) {
+ default:
+ return false;
+ case CK_LValueToRValue:
+ // Base case, just return InitValue.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Cast->getSubExpr())) {
+ if (DRE->getDecl() == D) {
+ Result = InitValue;
+ return true;
+ }
+ }
+ return false;
+ case CK_NoOp:
+ return AdjustCastValue(Info, Cast->getSubExpr(), InitValue, D, Result);
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ break;
+ }
+
+ // Casts need to be applied in reverse order they are encountered, so
+ // process the sub-expression first.
+ const auto* SubE = Cast->getSubExpr();
+ if (!AdjustCastValue(Info, SubE, InitValue, D, Result))
+ return false;
+
+ const QualType SourceType = SubE->getType();
+ const QualType DestType = E->getType();
+
+ switch (Cast->getCastKind()) {
+ default:
+ llvm_unreachable("Unhandled cast kind");
+ case CK_IntegralCast: {
+ APSInt Init = Result.getInt();
+ Result.setInt(
+ HandleIntToIntCast(Info, nullptr, DestType, SourceType, Init));
+ return true;
+ }
+ case CK_IntegralToFloating: {
+ APValue Init(APFloat(0.f));
+ Init.swap(Result);
+ return HandleIntToFloatCast(Info, nullptr, SourceType, Init.getInt(),
+ DestType, Result.getFloat());
+ }
+ case CK_FloatingToIntegral: {
+ APValue Init((APSInt()));
+ Init.swap(Result);
+ return HandleFloatToIntCast(Info, nullptr, SourceType, Init.getFloat(),
+ DestType, Result.getInt());
+ }
+ case CK_IntegralToBoolean:
+ case CK_FloatingToBoolean: {
+ bool BoolResult;
+ if (!HandleConversionToBool(Result, BoolResult))
+ return false;
+ APValue Bool(APSInt(1, true));
+ Bool.getInt() = BoolResult;
+ Result = Bool;
+
+ return true;
+ }
+ case CK_FloatingCast:
+ return HandleFloatToFloatCast(Info, nullptr, SourceType, DestType,
+ Result.getFloat());
+ }
+}
+
+bool Expr::SubstituteValueWithCasts(ASTContext &Context,
+ const APValue InitValue, const VarDecl *D,
+ APValue &Result) const {
+ EvalStatus Status;
+ EvalInfo Info(Context, Status, EvalInfo::EM_IgnoreSideEffects);
+ return AdjustCastValue(Info, this, InitValue, D, Result);
+}
+
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -27,6 +27,13 @@
"and in the loop body">,
InGroup<ForLoopAnalysis>, DefaultIgnore;
def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
+def warn_loop_never_run : Warning<
+ "variable %0 is set to value %1 on loop initialization, "
+ "but comparing %1 to %2 in the loop condition is false and "
+ "the loop body will never run">,
+ InGroup<ForLoopAnalysis>, DefaultIgnore;
+def note_loop_condition_silence : Note<
+ "place parentheses around the condition to silence this warning">;
def warn_duplicate_enum_values : Warning<
"element %0 has been implicitly assigned %1 which another element has "
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -906,6 +906,12 @@
return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
}
+ // When the current Expr is a series of of casts on D, attempt to evaluate
+ // the Expr as if InitValue was substituted in for D and output resulting
+ // value to Result.
+ bool SubstituteValueWithCasts(ASTContext &Context, const APValue InitValue,
+ const VarDecl *D, APValue &Result) const;
+
/// Checks that the two Expr's will refer to the same value as a comparison
/// operand. The caller must ensure that the values referenced by the Expr's
/// are not modified between E1 and E2 or the result my be invalid.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits