diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 96fe6df88dbb9..05f8101b0068a 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -803,13 +803,15 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) { } void Environment::setValue(const Expr &E, Value &Val) { + const Expr &CanonE = ignoreCFGOmittedNodes(E); + if (auto *RecordVal = dyn_cast(&Val)) { - assert(isOriginalRecordConstructor(E) || - &RecordVal->getLoc() == &getResultObjectLocation(E)); + assert(isOriginalRecordConstructor(CanonE) || + &RecordVal->getLoc() == &getResultObjectLocation(CanonE)); } - assert(E.isPRValue()); - ExprToVal[&E] = &Val; + assert(CanonE.isPRValue()); + ExprToVal[&CanonE] = &Val; } Value *Environment::getValue(const StorageLocation &Loc) const { diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 003434a58b107..8799d03dfd3c5 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -58,6 +58,52 @@ TEST_F(EnvironmentTest, FlowCondition) { EXPECT_FALSE(Env.allows(NotX)); } +TEST_F(EnvironmentTest, SetAndGetValueOnCfgOmittedNodes) { + // Check that we can set a value on an expression that is omitted from the CFG + // (see `ignoreCFGOmittedNodes()`), then retrieve that same value from the + // expression. This is a regression test; `setValue()` and `getValue()` + // previously did not use `ignoreCFGOmittedNodes()` consistently. + + using namespace ast_matchers; + + std::string Code = R"cc( + struct S { + int f(); + }; + void target() { + // Method call on a temporary produces an `ExprWithCleanups`. + S().f(); + (1); + } + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + const ExprWithCleanups *WithCleanups = selectFirst( + "cleanups", + match(exprWithCleanups(hasType(isInteger())).bind("cleanups"), Context)); + ASSERT_NE(WithCleanups, nullptr); + + const ParenExpr *Paren = selectFirst( + "paren", match(parenExpr(hasType(isInteger())).bind("paren"), Context)); + ASSERT_NE(Paren, nullptr); + + Environment Env(DAContext); + IntegerValue *Val1 = + cast(Env.createValue(Unit->getASTContext().IntTy)); + Env.setValue(*WithCleanups, *Val1); + EXPECT_EQ(Env.getValue(*WithCleanups), Val1); + + IntegerValue *Val2 = + cast(Env.createValue(Unit->getASTContext().IntTy)); + Env.setValue(*Paren, *Val2); + EXPECT_EQ(Env.getValue(*Paren), Val2); +} + TEST_F(EnvironmentTest, CreateValueRecursiveType) { using namespace ast_matchers;