[clang] ef1e1b3 - [clang][dataflow] Add support for (built-in) (in)equality operators
Yitzhak Mandelbaum via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 1 10:23:22 PDT 2022
Author: Yitzhak Mandelbaum
Date: 2022-04-01T17:13:21Z
New Revision: ef1e1b3106a544389cf393647cda57b5b0642ef3
URL: https://github.com/llvm/llvm-project/commit/ef1e1b3106a544389cf393647cda57b5b0642ef3
DIFF: https://github.com/llvm/llvm-project/commit/ef1e1b3106a544389cf393647cda57b5b0642ef3.diff
LOG: [clang][dataflow] Add support for (built-in) (in)equality operators
Adds logical interpretation of built-in equality operators, `==` and `!=`.s
Differential Revision: https://reviews.llvm.org/D122830
Added:
Modified:
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index a3ff345ce5e84..1f5de9d67c135 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
@@ -37,6 +38,26 @@ static const Expr *skipExprWithCleanups(const Expr *E) {
return E;
}
+static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
+ Environment &Env) {
+ // Equality of booleans involves implicit integral casts. Ignore these casts
+ // for now and focus on the values associated with the wrapped expressions.
+ // FIXME: Consider changing this once the framework offers better support for
+ // integral casts.
+ const Expr *LHSNorm = LHS.IgnoreCasts();
+ const Expr *RHSNorm = RHS.IgnoreCasts();
+ assert(LHSNorm != nullptr);
+ assert(RHSNorm != nullptr);
+
+ if (auto *LHSValue = dyn_cast_or_null<BoolValue>(
+ Env.getValue(*LHSNorm, SkipPast::Reference)))
+ if (auto *RHSValue = dyn_cast_or_null<BoolValue>(
+ Env.getValue(*RHSNorm, SkipPast::Reference)))
+ return Env.makeIff(*LHSValue, *RHSValue);
+
+ return Env.makeAtomicBoolValue();
+}
+
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
@@ -83,8 +104,16 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
break;
}
+ case BO_NE:
+ case BO_EQ: {
+ auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
+ : Env.makeNot(LHSEqRHSValue));
+ break;
+ }
default:
- // FIXME: Add support for BO_EQ, BO_NE.
break;
}
}
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index d9b38f0d67170..0e474c84a1b5f 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2578,4 +2578,74 @@ TEST_F(TransferTest, AssignMemberBeforeCopy) {
});
}
+TEST_F(TransferTest, BooleanEquality) {
+ std::string Code = R"(
+ void target(bool Bar) {
+ bool Foo = true;
+ if (Bar == Foo) {
+ (void)0;
+ /*[[p-then]]*/
+ } else {
+ (void)0;
+ /*[[p-else]]*/
+ }
+ }
+ )";
+ runDataflow(
+ Code, [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
+ const Environment &EnvElse = Results[0].second.Env;
+ const Environment &EnvThen = Results[1].second.Env;
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ auto &BarValThen =
+ *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
+ EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen));
+
+ auto &BarValElse =
+ *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
+ EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse));
+ });
+}
+
+TEST_F(TransferTest, BooleanInequality) {
+ std::string Code = R"(
+ void target(bool Bar) {
+ bool Foo = true;
+ if (Bar != Foo) {
+ (void)0;
+ /*[[p-then]]*/
+ } else {
+ (void)0;
+ /*[[p-else]]*/
+ }
+ }
+ )";
+ runDataflow(
+ Code, [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
+ const Environment &EnvElse = Results[0].second.Env;
+ const Environment &EnvThen = Results[1].second.Env;
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ auto &BarValThen =
+ *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
+ EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen));
+
+ auto &BarValElse =
+ *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
+ EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse));
+ });
+}
+
} // namespace
More information about the cfe-commits
mailing list