Skip to content

Commit 23bfc27

Browse files
authored
[clang][dataflow] Use ignoreCFGOmittedNodes() in setValue(). (#78245)
This is to be consistent with `getValue()`, which also uses `ignoreCFGOmittedNodes()`. Before this fix, it was not possible to retrieve a `Value` from a "CFG omitted" node that had previously been set using `setValue()`; see the accompanying test, which fails without the fix. I discovered this issue while running internal integration tests on #78127.
1 parent 19cab7e commit 23bfc27

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -803,13 +803,15 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
803803
}
804804

805805
void Environment::setValue(const Expr &E, Value &Val) {
806+
const Expr &CanonE = ignoreCFGOmittedNodes(E);
807+
806808
if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
807-
assert(isOriginalRecordConstructor(E) ||
808-
&RecordVal->getLoc() == &getResultObjectLocation(E));
809+
assert(isOriginalRecordConstructor(CanonE) ||
810+
&RecordVal->getLoc() == &getResultObjectLocation(CanonE));
809811
}
810812

811-
assert(E.isPRValue());
812-
ExprToVal[&E] = &Val;
813+
assert(CanonE.isPRValue());
814+
ExprToVal[&CanonE] = &Val;
813815
}
814816

815817
Value *Environment::getValue(const StorageLocation &Loc) const {

clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,52 @@ TEST_F(EnvironmentTest, FlowCondition) {
5858
EXPECT_FALSE(Env.allows(NotX));
5959
}
6060

61+
TEST_F(EnvironmentTest, SetAndGetValueOnCfgOmittedNodes) {
62+
// Check that we can set a value on an expression that is omitted from the CFG
63+
// (see `ignoreCFGOmittedNodes()`), then retrieve that same value from the
64+
// expression. This is a regression test; `setValue()` and `getValue()`
65+
// previously did not use `ignoreCFGOmittedNodes()` consistently.
66+
67+
using namespace ast_matchers;
68+
69+
std::string Code = R"cc(
70+
struct S {
71+
int f();
72+
};
73+
void target() {
74+
// Method call on a temporary produces an `ExprWithCleanups`.
75+
S().f();
76+
(1);
77+
}
78+
)cc";
79+
80+
auto Unit =
81+
tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});
82+
auto &Context = Unit->getASTContext();
83+
84+
ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
85+
86+
const ExprWithCleanups *WithCleanups = selectFirst<ExprWithCleanups>(
87+
"cleanups",
88+
match(exprWithCleanups(hasType(isInteger())).bind("cleanups"), Context));
89+
ASSERT_NE(WithCleanups, nullptr);
90+
91+
const ParenExpr *Paren = selectFirst<ParenExpr>(
92+
"paren", match(parenExpr(hasType(isInteger())).bind("paren"), Context));
93+
ASSERT_NE(Paren, nullptr);
94+
95+
Environment Env(DAContext);
96+
IntegerValue *Val1 =
97+
cast<IntegerValue>(Env.createValue(Unit->getASTContext().IntTy));
98+
Env.setValue(*WithCleanups, *Val1);
99+
EXPECT_EQ(Env.getValue(*WithCleanups), Val1);
100+
101+
IntegerValue *Val2 =
102+
cast<IntegerValue>(Env.createValue(Unit->getASTContext().IntTy));
103+
Env.setValue(*Paren, *Val2);
104+
EXPECT_EQ(Env.getValue(*Paren), Val2);
105+
}
106+
61107
TEST_F(EnvironmentTest, CreateValueRecursiveType) {
62108
using namespace ast_matchers;
63109

0 commit comments

Comments
 (0)