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 @@ -58,6 +58,7 @@ case Stmt::WhileStmtClass: case Stmt::DoStmtClass: case Stmt::ForStmtClass: + case Stmt::CXXForRangeStmtClass: return true; default: return false; @@ -108,6 +109,9 @@ return {nullptr, false}; } + // Don't do anything special for CXXForRangeStmt, because the condition (being + // implicitly generated) isn't visible from the loop body. + 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,24 @@ }); } + +TEST_F(TopTest, ForRangeStmtConverges) { + std::string Code = R"( + void target(bool Foo) { + int Ints[10]; + bool B = false; + for (int I : Ints) + B = true; + (void)0; + // [[after_loop]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + const AnalysisOutputs &) { + EXPECT_THAT(Results.keys(), + UnorderedElementsAre("loop_body", "after_loop")); + }); +} } // namespace