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) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits