diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ASTDumper.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/CFG.h" @@ -58,6 +59,7 @@ case Stmt::WhileStmtClass: case Stmt::DoStmtClass: case Stmt::ForStmtClass: + case Stmt::CXXForRangeStmtClass: return true; default: return false; @@ -108,6 +110,12 @@ return {nullptr, false}; } + TerminatorVisitorRetTy VisitCXXForRangeStmt(const CXXForRangeStmt *) { + // Don't do anything special for CXXForRangeStmt, because the condition + // (being implicitly generated) isn't visible from the loop body. + return {nullptr, false}; + } + TerminatorVisitorRetTy VisitBinaryOperator(const BinaryOperator *S) { assert(S->getOpcode() == BO_LAnd || S->getOpcode() == BO_LOr); auto *LHS = S->getLHS(); diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -1612,4 +1612,21 @@ }); } + +TEST_F(TopTest, ForRangeStmtConverges) { + std::string Code = R"( + void target(bool Foo) { + int Ints[10]; + bool B = false; + for (int I : Ints) + B = true; + } + )"; + runDataflow(Code, + [](const llvm::StringMap> &, + const AnalysisOutputs &) { + // No additional expectations. We're only checking that the + // analysis converged. + }); +} } // namespace