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 @@ -395,8 +395,15 @@ std::function PostVisitCFG) { - PostOrderCFGView POV(&CFCtx.getCFG()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); + std::optional WTO = getIntervalWTO(CFCtx.getCFG()); + if (!WTO) + return llvm::createStringError(std::errc::invalid_argument, + "input CFG not reducible"); + WTOCompare Cmp(*WTO); + WTODataflowWorklist Worklist(CFCtx.getCFG(), Cmp); + // FIXME: provide fallback? + // PostOrderCFGView POV(&CFCtx.getCFG()); + // ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); std::vector> BlockStates( CFCtx.getCFG().size(), std::nullopt); diff --git a/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp b/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp @@ -123,17 +123,17 @@ transfer() recordState(Elements=2, Branches=0, Joins=0) -enterBlock(3) -transferBranch(0) +enterBlock(2) +transferBranch(1) recordState(Elements=2, Branches=1, Joins=0) -enterElement(q) +enterElement(p) transfer() recordState(Elements=3, Branches=1, Joins=0) -enterBlock(2) -transferBranch(1) +enterBlock(3) +transferBranch(0) recordState(Elements=2, Branches=1, Joins=0) -enterElement(p) +enterElement(q) transfer() recordState(Elements=3, Branches=1, Joins=0) diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2673,6 +2673,49 @@ }); } +TEST(TransferTest, SequencedWhilesNoTimeout) { + std::string Code = R"( + void target() { + bool b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + b = true; + while (b) { + b = false; + } + (void)0; + /*[[p]]*/ + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + EXPECT_EQ(Results.size(), 1u); + }); +} + TEST(TransferTest, AggregateInitialization) { std::string BracesCode = R"( struct A {