diff --git a/clang/include/clang/Analysis/FlowSensitive/Arena.h b/clang/include/clang/Analysis/FlowSensitive/Arena.h index d8a123c52eb83..83b4ddeec0256 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Arena.h +++ b/clang/include/clang/Analysis/FlowSensitive/Arena.h @@ -84,6 +84,12 @@ class Arena { /// will be a value that represents the true boolean literal. BoolValue &makeEquals(BoolValue &LHS, BoolValue &RHS); + /// Returns a symbolic integer value that models an integer literal equal to + /// `Value`. These literals are the same every time. + /// Integer literals are not typed; the type is determined by the `Expr` that + /// an integer literal is associated with. + IntegerValue &makeIntLiteral(llvm::APInt Value); + /// Returns a symbolic boolean value that models a boolean literal equal to /// `Value`. These literals are the same every time. AtomicBoolValue &makeLiteral(bool Value) const { @@ -103,8 +109,9 @@ class Arena { std::vector> Locs; std::vector> Vals; - // Indices that are used to avoid recreating the same composite boolean - // values. + // Indices that are used to avoid recreating the same integer literals and + // composite boolean values. + llvm::DenseMap IntegerLiterals; llvm::DenseMap, ConjunctionValue *> ConjunctionVals; llvm::DenseMap, DisjunctionValue *> diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index a31f5ec116425..059cb841e89c7 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -448,6 +448,12 @@ class Environment { return DACtx->arena().create(std::forward(args)...); } + /// Returns a symbolic integer value that models an integer literal equal to + /// `Value` + IntegerValue &getIntLiteralValue(llvm::APInt Value) const { + return DACtx->arena().makeIntLiteral(Value); + } + /// Returns a symbolic boolean value that models a boolean literal equal to /// `Value` AtomicBoolValue &getBoolLiteralValue(bool Value) const { diff --git a/clang/lib/Analysis/FlowSensitive/Arena.cpp b/clang/lib/Analysis/FlowSensitive/Arena.cpp index a0182af85a228..cff6c45e18542 100644 --- a/clang/lib/Analysis/FlowSensitive/Arena.cpp +++ b/clang/lib/Analysis/FlowSensitive/Arena.cpp @@ -68,4 +68,12 @@ BoolValue &Arena::makeEquals(BoolValue &LHS, BoolValue &RHS) { return *Res.first->second; } +IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) { + auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr); + + if (Inserted) + It->second = &create(); + return *It->second; +} + } // namespace clang::dataflow diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index e0cb872cfa372..e7f596ace6aaa 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -48,9 +48,15 @@ const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env) { - if (auto *LHSValue = dyn_cast_or_null(Env.getValueStrict(LHS))) - if (auto *RHSValue = dyn_cast_or_null(Env.getValueStrict(RHS))) - return Env.makeIff(*LHSValue, *RHSValue); + Value *LHSValue = Env.getValueStrict(LHS); + Value *RHSValue = Env.getValueStrict(RHS); + + if (LHSValue == RHSValue) + return Env.getBoolLiteralValue(true); + + if (auto *LHSBool = dyn_cast_or_null(LHSValue)) + if (auto *RHSBool = dyn_cast_or_null(RHSValue)) + return Env.makeIff(*LHSBool, *RHSBool); return Env.makeAtomicBoolValue(); } @@ -776,6 +782,10 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValueStrict(*S, Env.getBoolLiteralValue(S->getValue())); } + void VisitIntegerLiteral(const IntegerLiteral *S) { + Env.setValueStrict(*S, Env.getIntLiteralValue(S->getValue())); + } + void VisitParenExpr(const ParenExpr *S) { // The CFG does not contain `ParenExpr` as top-level statements in basic // blocks, however manual traversal to sub-expressions may encounter them. diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 7077f7344a858..5f52d74afe388 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -811,6 +811,31 @@ TEST(TransferTest, BinaryOperatorAssign) { }); } +TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) { + std::string Code = R"( + void target() { + int Foo = 1; + // [[before]] + Foo = 2; + // [[after]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Before = + getEnvironmentAtAnnotation(Results, "before"); + const Environment &After = getEnvironmentAtAnnotation(Results, "after"); + + const auto &ValBefore = + getValueForDecl(ASTCtx, Before, "Foo"); + const auto &ValAfter = + getValueForDecl(ASTCtx, After, "Foo"); + EXPECT_NE(&ValBefore, &ValAfter); + }); +} + TEST(TransferTest, VarDeclInitAssign) { std::string Code = R"( void target() { @@ -3441,6 +3466,24 @@ TEST(TransferTest, BooleanInequality) { }); } +TEST(TransferTest, IntegerLiteralEquality) { + std::string Code = R"( + void target() { + bool equal = (42 == 42); + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + auto &Equal = getValueForDecl(ASTCtx, Env, "equal"); + EXPECT_TRUE(Env.flowConditionImplies(Equal)); + }); +} + TEST(TransferTest, CorrelatedBranches) { std::string Code = R"( void target(bool B, bool C) {