This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
sgatev marked an inline comment as done.
Closed by commit rGe363c5963dc3: [clang][dataflow] Extend flow condition in the
body of a do/while loop (authored by sgatev).
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D128183/new/
https://reviews.llvm.org/D128183
Files:
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -3628,25 +3628,81 @@
void target(bool Foo) {
while (Foo) {
(void)0;
- // [[while_branch]]
+ // [[loop_body]]
}
+ (void)0;
+ // [[after_loop]]
}
)";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("while_branch", _)));
- const Environment &Env = Results[0].second.Env;
+ runDataflow(
+ Code, [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results,
+ ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
+ const Environment &LoopBodyEnv = Results[1].second.Env;
+ const Environment &AfterLoopEnv = Results[0].second.Env;
- const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
- ASSERT_THAT(FooDecl, NotNull());
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
- BoolValue &FooVal =
- *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
- EXPECT_TRUE(Env.flowConditionImplies(FooVal));
- });
+ BoolValue &LoopBodyFooVal =
+ *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
+
+ BoolValue &AfterLoopFooVal =
+ *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
+ AfterLoopEnv.makeNot(AfterLoopFooVal)));
+ });
+}
+
+TEST_F(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
+ std::string Code = R"(
+ void target(bool Foo) {
+ bool Bar = true;
+ do {
+ (void)0;
+ // [[loop_body]]
+ Bar = false;
+ } while (Foo);
+ (void)0;
+ // [[after_loop]]
+ }
+ )";
+ runDataflow(
+ Code, [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results,
+ ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
+ const Environment &LoopBodyEnv = Results[1].second.Env;
+ const Environment &AfterLoopEnv = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ BoolValue &LoopBodyFooVal =
+ *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
+ BoolValue &LoopBodyBarVal =
+ *cast<BoolValue>(LoopBodyEnv.getValue(*BarDecl, SkipPast::None));
+ EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(
+ LoopBodyEnv.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
+
+ BoolValue &AfterLoopFooVal =
+ *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
+ BoolValue &AfterLoopBarVal =
+ *cast<BoolValue>(AfterLoopEnv.getValue(*BarDecl, SkipPast::None));
+ EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
+ AfterLoopEnv.makeNot(AfterLoopFooVal)));
+ EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
+ AfterLoopEnv.makeNot(AfterLoopBarVal)));
+ });
}
TEST_F(TransferTest, ForStmtBranchExtendsFlowCondition) {
@@ -3654,25 +3710,34 @@
void target(bool Foo) {
for (; Foo;) {
(void)0;
- // [[for_branch]]
+ // [[loop_body]]
}
+ (void)0;
+ // [[after_loop]]
}
)";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("for_branch", _)));
- const Environment &Env = Results[0].second.Env;
+ runDataflow(
+ Code, [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results,
+ ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
+ const Environment &LoopBodyEnv = Results[1].second.Env;
+ const Environment &AfterLoopEnv = Results[0].second.Env;
- const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
- ASSERT_THAT(FooDecl, NotNull());
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
- BoolValue &FooVal =
- *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
- EXPECT_TRUE(Env.flowConditionImplies(FooVal));
- });
+ BoolValue &LoopBodyFooVal =
+ *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
+
+ BoolValue &AfterLoopFooVal =
+ *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
+ AfterLoopEnv.makeNot(AfterLoopFooVal)));
+ });
}
} // namespace
Index: clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -89,6 +89,12 @@
extendFlowCondition(*Cond);
}
+ void VisitDoStmt(const DoStmt *S) {
+ auto *Cond = S->getCond();
+ assert(Cond != nullptr);
+ extendFlowCondition(*Cond);
+ }
+
void VisitForStmt(const ForStmt *S) {
auto *Cond = S->getCond();
assert(Cond != nullptr);
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -87,8 +87,13 @@
// have mutually exclusive conditions.
if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) {
auto *Expr2 = cast<BoolValue>(Val2);
- return &Env1.makeOr(Env1.makeAnd(Env1.getFlowConditionToken(), *Expr1),
- Env1.makeAnd(Env2.getFlowConditionToken(), *Expr2));
+ auto &MergedVal = MergedEnv.makeAtomicBoolValue();
+ MergedEnv.addToFlowCondition(MergedEnv.makeOr(
+ MergedEnv.makeAnd(Env1.getFlowConditionToken(),
+ MergedEnv.makeIff(MergedVal, *Expr1)),
+ MergedEnv.makeAnd(Env2.getFlowConditionToken(),
+ MergedEnv.makeIff(MergedVal, *Expr2))));
+ return &MergedVal;
}
// FIXME: add unit tests that cover this statement.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits