Skip to content
Snippets Groups Projects
Commit d002495b authored by Yitzhak Mandelbaum's avatar Yitzhak Mandelbaum
Browse files

[clang][dataflow] Support integral casts

Adds support for implicit casts `CK_IntegralCast` and `CK_IntegralToBoolean`.

Differential Revision: https://reviews.llvm.org/D123037
parent 54c50336
No related branches found
No related tags found
No related merge requests found
......@@ -199,6 +199,22 @@ public:
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 @@ public:
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:
......
......@@ -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) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment