[clang] d002495 - [clang][dataflow] Support integral casts
Yitzhak Mandelbaum via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 5 06:55:52 PDT 2022
Author: Yitzhak Mandelbaum
Date: 2022-04-05T13:55:32Z
New Revision: d002495b949c1d0d2db22605f134d722a39637fa
URL: https://github.com/llvm/llvm-project/commit/d002495b949c1d0d2db22605f134d722a39637fa
DIFF: https://github.com/llvm/llvm-project/commit/d002495b949c1d0d2db22605f134d722a39637fa.diff
LOG: [clang][dataflow] Support integral casts
Adds support for implicit casts `CK_IntegralCast` and `CK_IntegralToBoolean`.
Differential Revision: https://reviews.llvm.org/D123037
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 271167b90030d..a1a6025312db9 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -199,6 +199,22 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
assert(SubExpr != nullptr);
switch (S->getCastKind()) {
+ case CK_IntegralToBoolean: {
+ // This cast creates a new, boolean value from the integral value. We
+ // model that with a fresh value in the environment, unless it's already a
+ // boolean.
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ if (auto *SubExprVal = dyn_cast_or_null<BoolValue>(
+ Env.getValue(*SubExpr, SkipPast::Reference)))
+ Env.setValue(Loc, *SubExprVal);
+ else
+ // FIXME: If integer modeling is added, then update this code to create
+ // the boolean based on the integer model.
+ Env.setValue(Loc, Env.makeAtomicBoolValue());
+ break;
+ }
+
case CK_LValueToRValue: {
auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
if (SubExprVal == nullptr)
@@ -209,6 +225,13 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(ExprLoc, *SubExprVal);
break;
}
+
+ case CK_IntegralCast:
+ // FIXME: This cast creates a new integral value from the
+ // subexpression. But, because we don't model integers, we don't
+ // distinguish between this new value and the underlying one. If integer
+ // modeling is added, then update this code to create a fresh location and
+ // value.
case CK_UncheckedDerivedToBase:
case CK_ConstructorConversion:
case CK_UserDefinedConversion:
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 2fa5be182eea5..32beab89a18be 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1900,10 +1900,97 @@ TEST_F(TransferTest, StaticCast) {
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
ASSERT_THAT(BarDecl, NotNull());
- const auto *FooVal =
- cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
- const auto *BarVal =
- cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
+ const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
+ const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
+ EXPECT_TRUE(isa<IntegerValue>(FooVal));
+ EXPECT_TRUE(isa<IntegerValue>(BarVal));
+ EXPECT_EQ(FooVal, BarVal);
+ });
+}
+
+TEST_F(TransferTest, IntegralCast) {
+ std::string Code = R"(
+ void target(int Foo) {
+ long Bar = Foo;
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
+ const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
+ EXPECT_TRUE(isa<IntegerValue>(FooVal));
+ EXPECT_TRUE(isa<IntegerValue>(BarVal));
+ EXPECT_EQ(FooVal, BarVal);
+ });
+}
+
+TEST_F(TransferTest, IntegraltoBooleanCast) {
+ std::string Code = R"(
+ void target(int Foo) {
+ bool Bar = Foo;
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
+ const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
+ EXPECT_TRUE(isa<IntegerValue>(FooVal));
+ EXPECT_TRUE(isa<BoolValue>(BarVal));
+ });
+}
+
+TEST_F(TransferTest, IntegralToBooleanCastFromBool) {
+ std::string Code = R"(
+ void target(bool Foo) {
+ int Zab = Foo;
+ bool Bar = Zab;
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
+ const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
+ EXPECT_TRUE(isa<BoolValue>(FooVal));
+ EXPECT_TRUE(isa<BoolValue>(BarVal));
EXPECT_EQ(FooVal, BarVal);
});
}
@@ -2394,6 +2481,35 @@ TEST_F(TransferTest, BuiltinExpect) {
});
}
+// `__builtin_expect` takes and returns a `long` argument, so other types
+// involve casts. This verifies that we identify the input and output in that
+// case.
+TEST_F(TransferTest, BuiltinExpectBoolArg) {
+ std::string Code = R"(
+ void target(bool Foo) {
+ bool Bar = __builtin_expect(Foo, true);
+ /*[[p]]*/
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const auto &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None),
+ Env.getValue(*BarDecl, SkipPast::None));
+ });
+}
+
TEST_F(TransferTest, BuiltinUnreachable) {
std::string Code = R"(
void target(bool Foo) {
More information about the cfe-commits
mailing list