[clang] Revert "[clang][dataflow] Model conditional operator correctly." (PR #89577)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 22 00:36:00 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (martinboehme)
<details>
<summary>Changes</summary>
Reverts llvm/llvm-project#<!-- -->89213
This is causing buildbot failures.
---
Full diff: https://github.com/llvm/llvm-project/pull/89577.diff
7 Files Affected:
- (modified) clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h (-15)
- (modified) clang/include/clang/Analysis/FlowSensitive/Transfer.h (+1-2)
- (modified) clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (+22-24)
- (modified) clang/lib/Analysis/FlowSensitive/Transfer.cpp (+15-42)
- (modified) clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp (+2-2)
- (modified) clang/unittests/Analysis/FlowSensitive/TestingSupport.h (+2-2)
- (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+4-62)
``````````diff
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index cdf89c7def2c91..d50dba35f8264c 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -244,21 +244,6 @@ class Environment {
Environment::ValueModel &Model,
ExprJoinBehavior ExprBehavior);
- /// Returns a value that approximates both `Val1` and `Val2`, or null if no
- /// such value can be produced.
- ///
- /// `Env1` and `Env2` can be used to query child values and path condition
- /// implications of `Val1` and `Val2` respectively. The joined value will be
- /// produced in `JoinedEnv`.
- ///
- /// Requirements:
- ///
- /// `Val1` and `Val2` must model values of type `Type`.
- static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1,
- Value *Val2, const Environment &Env2,
- Environment &JoinedEnv,
- Environment::ValueModel &Model);
-
/// Widens the environment point-wise, using `PrevEnv` as needed to inform the
/// approximation.
///
diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
index 940025e02100f9..ed148250d8eb29 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
@@ -53,8 +53,7 @@ class StmtToEnvMap {
/// Requirements:
///
/// `S` must not be `ParenExpr` or `ExprWithCleanups`.
-void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
- Environment::ValueModel &Model);
+void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env);
} // namespace dataflow
} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 3cb656adcbdc0c..05395e07a7a68c 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -237,8 +237,13 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
continue;
assert(It->second != nullptr);
- if (Value *JoinedVal = Environment::joinValues(
- Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
+ if (areEquivalentValues(*Val, *It->second)) {
+ Result.insert({Loc, Val});
+ continue;
+ }
+
+ if (Value *JoinedVal = joinDistinctValues(
+ Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) {
Result.insert({Loc, JoinedVal});
}
}
@@ -770,16 +775,27 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
- if (EnvA.CallStack.empty()) {
+ if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) {
+ // `ReturnVal` might not always get set -- for example if we have a return
+ // statement of the form `return some_other_func()` and we decide not to
+ // analyze `some_other_func()`.
+ // In this case, we can't say anything about the joined return value -- we
+ // don't simply want to propagate the return value that we do have, because
+ // it might not be the correct one.
+ // This occurs for example in the test `ContextSensitiveMutualRecursion`.
JoinedEnv.ReturnVal = nullptr;
+ } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) {
+ JoinedEnv.ReturnVal = EnvA.ReturnVal;
} else {
+ assert(!EnvA.CallStack.empty());
// FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
- JoinedEnv.ReturnVal =
- joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
- EnvB, JoinedEnv, Model);
+ if (Value *JoinedVal =
+ joinDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
+ *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
+ JoinedEnv.ReturnVal = JoinedVal;
}
if (EnvA.ReturnLoc == EnvB.ReturnLoc)
@@ -805,24 +821,6 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
return JoinedEnv;
}
-Value *Environment::joinValues(QualType Ty, Value *Val1,
- const Environment &Env1, Value *Val2,
- const Environment &Env2, Environment &JoinedEnv,
- Environment::ValueModel &Model) {
- if (Val1 == nullptr || Val2 == nullptr)
- // We can't say anything about the joined value -- even if one of the values
- // is non-null, we don't want to simply propagate it, because it would be
- // too specific: Because the other value is null, that means we have no
- // information at all about the value (i.e. the value is unconstrained).
- return nullptr;
-
- if (areEquivalentValues(*Val1, *Val2))
- // Arbitrarily return one of the two values.
- return Val1;
-
- return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
-}
-
StorageLocation &Environment::createStorageLocation(QualType Type) {
return DACtx->createStorageLocation(Type);
}
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index f56fd64296cc45..2771c8b2e37ebb 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -124,9 +124,8 @@ namespace {
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
- TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
- Environment::ValueModel &Model)
- : StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}
+ TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
+ : StmtToEnv(StmtToEnv), Env(Env) {}
void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
@@ -642,41 +641,17 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}
void VisitConditionalOperator(const ConditionalOperator *S) {
- const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
- const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());
-
- if (TrueEnv == nullptr || FalseEnv == nullptr) {
- // We should always have an environment as we should visit the true /
- // false branches before the conditional operator.
- assert(false);
- return;
- }
-
- if (S->isGLValue()) {
- StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());
- StorageLocation *FalseLoc =
- FalseEnv->getStorageLocation(*S->getFalseExpr());
- if (TrueLoc == FalseLoc && TrueLoc != nullptr)
- Env.setStorageLocation(*S, *TrueLoc);
- } else if (!S->getType()->isRecordType()) {
- // The conditional operator can evaluate to either of the values of the
- // two branches. To model this, join these two values together to yield
- // the result of the conditional operator.
- // Note: Most joins happen in `computeBlockInputState()`, but this case is
- // different:
- // - `computeBlockInputState()` (which in turn calls `Environment::join()`
- // joins values associated with the _same_ expression or storage
- // location, then associates the joined value with that expression or
- // storage location. This join has nothing to do with transfer --
- // instead, it joins together the results of performing transfer on two
- // different blocks.
- // - Here, we join values associated with _different_ expressions (the
- // true and false branch), then associate the joined value with a third
- // expression (the conditional operator itself). This join is what it
- // means to perform transfer on the conditional operator.
- if (Value *Val = Environment::joinValues(
- S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
- FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))
+ // FIXME: Revisit this once flow conditions are added to the framework. For
+ // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
+ // condition.
+ // When we do this, we will need to retrieve the values of the operands from
+ // the environments for the basic blocks they are computed in, in a similar
+ // way to how this is done for short-circuited logical operators in
+ // `getLogicOperatorSubExprValue()`.
+ if (S->isGLValue())
+ Env.setStorageLocation(*S, Env.createObject(S->getType()));
+ else if (!S->getType()->isRecordType()) {
+ if (Value *Val = Env.createValue(S->getType()))
Env.setValue(*S, *Val);
}
}
@@ -835,14 +810,12 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
const StmtToEnvMap &StmtToEnv;
Environment &Env;
- Environment::ValueModel &Model;
};
} // namespace
-void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
- Environment::ValueModel &Model) {
- TransferVisitor(StmtToEnv, Env, Model).Visit(&S);
+void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
+ TransferVisitor(StmtToEnv, Env).Visit(&S);
}
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 12eff4dd4b781d..71d5c1a6c4f4a3 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -316,7 +316,7 @@ builtinTransferStatement(unsigned CurBlockID, const CFGStmt &Elt,
const Stmt *S = Elt.getStmt();
assert(S != nullptr);
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, CurBlockID, InputState), *S,
- InputState.Env, AC.Analysis);
+ InputState.Env);
}
/// Built-in transfer function for `CFGInitializer`.
@@ -452,7 +452,7 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC,
// terminator condition, but not as a `CFGElement`. The condition of an if
// statement is one such example.
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, Block.getBlockID(), State),
- *TerminatorCond, State.Env, AC.Analysis);
+ *TerminatorCond, State.Env);
// If the transfer function didn't produce a value, create an atom so that
// we have *some* value for the condition expression. This ensures that
diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index 3b0e05ed72220e..e3c7ff685f5724 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -456,7 +456,7 @@ const IndirectFieldDecl *findIndirectFieldDecl(ASTContext &ASTCtx,
/// Requirements:
///
/// `Name` must be unique in `ASTCtx`.
-template <class LocT = StorageLocation>
+template <class LocT>
LocT &getLocForDecl(ASTContext &ASTCtx, const Environment &Env,
llvm::StringRef Name) {
const ValueDecl *VD = findValueDecl(ASTCtx, Name);
@@ -470,7 +470,7 @@ LocT &getLocForDecl(ASTContext &ASTCtx, const Environment &Env,
/// Requirements:
///
/// `Name` must be unique in `ASTCtx`.
-template <class ValueT = Value>
+template <class ValueT>
ValueT &getValueForDecl(ASTContext &ASTCtx, const Environment &Env,
llvm::StringRef Name) {
const ValueDecl *VD = findValueDecl(ASTCtx, Name);
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 3a62bc0c02080f..bb16138126c8f9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5275,67 +5275,6 @@ TEST(TransferTest, BinaryOperatorComma) {
});
}
-TEST(TransferTest, ConditionalOperatorValue) {
- std::string Code = R"(
- void target(bool Cond, bool B1, bool B2) {
- bool JoinSame = Cond ? B1 : B1;
- bool JoinDifferent = Cond ? B1 : B2;
- // [[p]]
- }
- )";
- runDataflow(
- Code,
- [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
- ASTContext &ASTCtx) {
- Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
-
- auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1");
- auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2");
- auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, "JoinSame");
- auto &JoinDifferent =
- getValueForDecl<BoolValue>(ASTCtx, Env, "JoinDifferent");
-
- EXPECT_EQ(&JoinSame, &B1);
-
- const Formula &JoinDifferentEqB1 =
- Env.arena().makeEquals(JoinDifferent.formula(), B1.formula());
- EXPECT_TRUE(Env.allows(JoinDifferentEqB1));
- EXPECT_FALSE(Env.proves(JoinDifferentEqB1));
-
- const Formula &JoinDifferentEqB2 =
- Env.arena().makeEquals(JoinDifferent.formula(), B2.formula());
- EXPECT_TRUE(Env.allows(JoinDifferentEqB2));
- EXPECT_FALSE(Env.proves(JoinDifferentEqB1));
- });
-}
-
-TEST(TransferTest, ConditionalOperatorLocation) {
- std::string Code = R"(
- void target(bool Cond, int I1, int I2) {
- int &JoinSame = Cond ? I1 : I1;
- int &JoinDifferent = Cond ? I1 : I2;
- // [[p]]
- }
- )";
- runDataflow(
- Code,
- [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
- ASTContext &ASTCtx) {
- Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
-
- StorageLocation &I1 = getLocForDecl(ASTCtx, Env, "I1");
- StorageLocation &I2 = getLocForDecl(ASTCtx, Env, "I2");
- StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, "JoinSame");
- StorageLocation &JoinDifferent =
- getLocForDecl(ASTCtx, Env, "JoinDifferent");
-
- EXPECT_EQ(&JoinSame, &I1);
-
- EXPECT_NE(&JoinDifferent, &I1);
- EXPECT_NE(&JoinDifferent, &I2);
- });
-}
-
TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
std::string Code = R"(
void target(bool Foo) {
@@ -5583,7 +5522,10 @@ TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
auto *Loc = Env.getReturnStorageLocation();
EXPECT_THAT(Loc, NotNull());
- EXPECT_EQ(Loc, SLoc);
+ // TODO: We would really like to make this stronger assertion, but that
+ // doesn't work because we don't propagate values correctly through
+ // the conditional operator yet.
+ // EXPECT_EQ(Loc, SLoc);
},
{BuiltinOptions{ContextSensitiveOptions{}}});
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/89577
More information about the cfe-commits
mailing list