[clang] [clang][dataflow] Fix assignment of unknown values. (PR #178943)
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 30 11:11:33 PST 2026
https://github.com/haoNoQ created https://github.com/llvm/llvm-project/pull/178943
Just because the right-hand side of the assignment doesn't have a known value, doesn't mean the left-hand side gets to keep its old value.
>From b07a3bf6a86d453813a3f139140375b65f7e74a6 Mon Sep 17 00:00:00 2001
From: Artem Dergachev <artem.dergachev at gmail.com>
Date: Fri, 30 Jan 2026 13:41:07 -0500
Subject: [PATCH] [clang][dataflow] Fix assignment of unknown values.
Just because the right-hand side of the assignment doesn't have a known value,
doesn't mean the left-hand side gets to keep its old value.
---
clang/lib/Analysis/FlowSensitive/Transfer.cpp | 2 +-
.../Analysis/FlowSensitive/TransferTest.cpp | 76 +++++++++++++++++++
2 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 9d1b00293f394..51cc1f9bc26ab 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -170,7 +170,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
auto *RHSVal = Env.getValue(*RHS);
if (RHSVal == nullptr)
- break;
+ RHSVal = Env.createValue(LHS->getType());
// Assign a value to the storage location of the left-hand side.
Env.setValue(*LHSLoc, *RHSVal);
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index a6308d115aa70..5ff0983543369 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -935,6 +935,82 @@ TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) {
});
}
+TEST(TransferTest, BinaryOperatorAssignUnknown) {
+ std::string Code = R"(
+ int unknown();
+
+ void target() {
+ int Foo = unknown();
+ int FooAtA = Foo;
+
+ Foo = unknown();
+ int FooAtB = Foo;
+
+ Foo += unknown();
+ int FooAtC = Foo;
+
+ // [[p]]
+
+ if (FooAtA != FooAtB) {
+ (void)0;
+ // [[q]]
+ }
+
+ if (FooAtB != FooAtC) {
+ (void)0;
+ // [[r]]
+ }
+ }
+ )";
+ using ast_matchers::binaryOperator;
+ using ast_matchers::match;
+ using ast_matchers::selectFirst;
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p", "q", "r"));
+
+ // Check that the second unknown value is different.
+ const Environment &EnvP = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooAtADecl = findValueDecl(ASTCtx, "FooAtA");
+ ASSERT_THAT(FooAtADecl, NotNull());
+ const Value *FooAtAVal = EnvP.getValue(*FooAtADecl);
+ ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooAtAVal));
+
+ const ValueDecl *FooAtBDecl = findValueDecl(ASTCtx, "FooAtB");
+ ASSERT_THAT(FooAtBDecl, NotNull());
+ const Value *FooAtBVal = EnvP.getValue(*FooAtBDecl);
+ ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooAtBVal));
+
+ const ValueDecl *FooAtCDecl = findValueDecl(ASTCtx, "FooAtC");
+ ASSERT_THAT(FooAtCDecl, NotNull());
+ const Value *FooAtCVal = EnvP.getValue(*FooAtCDecl);
+ ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooAtCVal));
+
+ EXPECT_NE(FooAtAVal, FooAtBVal);
+ // FIXME: Should be NE too.
+ EXPECT_EQ(FooAtBVal, FooAtCVal);
+
+ // Check that the storage location is correctly propagated.
+ auto MatchResult = match(binaryOperator().bind("bo"), ASTCtx);
+ const auto *BO = selectFirst<BinaryOperator>("bo", MatchResult);
+ EXPECT_NE(BO, nullptr);
+ const StorageLocation *BOLoc = EnvP.getStorageLocation(*BO);
+ EXPECT_NE(BOLoc, nullptr);
+
+ // Check that the branches are reachable
+ // with a non-false flow condition.
+ const Environment &EnvQ = getEnvironmentAtAnnotation(Results, "q");
+ const Environment &EnvR = getEnvironmentAtAnnotation(Results, "r");
+
+ EXPECT_FALSE(EnvQ.proves(EnvQ.arena().makeLiteral(false)));
+ // FIXME: Should be FALSE too.
+ EXPECT_TRUE(EnvR.proves(EnvR.arena().makeLiteral(false)));
+ });
+}
+
TEST(TransferTest, VarDeclInitAssign) {
std::string Code = R"(
void target() {
More information about the cfe-commits
mailing list