diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -166,15 +166,15 @@ } }; -/// Base class for values that refer to storage locations. -class IndirectionValue : public Value { +/// Models a dereferenced pointer. For example, a reference in C++ or an lvalue +/// in C. +class ReferenceValue final : public Value { public: - /// Constructs a value that refers to `PointeeLoc`. - explicit IndirectionValue(Kind ValueKind, StorageLocation &PointeeLoc) - : Value(ValueKind), PointeeLoc(PointeeLoc) {} + explicit ReferenceValue(StorageLocation &PointeeLoc) + : Value(Kind::Reference), PointeeLoc(PointeeLoc) {} static bool classof(const Value *Val) { - return Val->getKind() == Kind::Reference || Val->getKind() == Kind::Pointer; + return Val->getKind() == Kind::Reference; } StorageLocation &getPointeeLoc() const { return PointeeLoc; } @@ -183,27 +183,20 @@ StorageLocation &PointeeLoc; }; -/// Models a dereferenced pointer. For example, a reference in C++ or an lvalue -/// in C. -class ReferenceValue final : public IndirectionValue { -public: - explicit ReferenceValue(StorageLocation &PointeeLoc) - : IndirectionValue(Kind::Reference, PointeeLoc) {} - - static bool classof(const Value *Val) { - return Val->getKind() == Kind::Reference; - } -}; - /// Models a symbolic pointer. Specifically, any value of type `T*`. -class PointerValue final : public IndirectionValue { +class PointerValue final : public Value { public: explicit PointerValue(StorageLocation &PointeeLoc) - : IndirectionValue(Kind::Pointer, PointeeLoc) {} + : Value(Kind::Pointer), PointeeLoc(PointeeLoc) {} static bool classof(const Value *Val) { return Val->getKind() == Kind::Pointer; } + + StorageLocation &getPointeeLoc() const { return PointeeLoc; } + +private: + StorageLocation &PointeeLoc; }; /// Models a value of `struct` or `class` type, with a flat map of fields to diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -50,22 +50,25 @@ return Result; } +static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) { + if (auto *IndVal1 = dyn_cast(Val1)) { + auto *IndVal2 = cast(Val2); + return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); + } + if (auto *IndVal1 = dyn_cast(Val1)) { + auto *IndVal2 = cast(Val2); + return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); + } + return false; +} + /// Returns true if and only if `Val1` is equivalent to `Val2`. static bool equivalentValues(QualType Type, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment::ValueModel &Model) { - if (Val1 == Val2) - return true; - - if (auto *IndVal1 = dyn_cast(Val1)) { - auto *IndVal2 = cast(Val2); - assert(IndVal1->getKind() == IndVal2->getKind()); - if (&IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc()) - return true; - } - - return Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2); + return Val1 == Val2 || areEquivalentIndirectionValues(Val1, Val2) || + Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2); } /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, @@ -89,12 +92,8 @@ } // FIXME: add unit tests that cover this statement. - if (auto *IndVal1 = dyn_cast(Val1)) { - auto *IndVal2 = cast(Val2); - assert(IndVal1->getKind() == IndVal2->getKind()); - if (&IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc()) { - return Val1; - } + if (areEquivalentIndirectionValues(Val1, Val2)) { + return Val1; } // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -122,24 +122,24 @@ // [[p]] } )"; - runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + 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 *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); - const StorageLocation *FooLoc = - Env.getStorageLocation(*FooDecl, SkipPast::None); - ASSERT_TRUE(isa_and_nonnull(FooLoc)); + const StorageLocation *FooLoc = + Env.getStorageLocation(*FooDecl, SkipPast::None); + ASSERT_TRUE(isa_and_nonnull(FooLoc)); - const Value *FooVal = Env.getValue(*FooLoc); - EXPECT_TRUE(isa_and_nonnull(FooVal)); - }); + const Value *FooVal = Env.getValue(*FooLoc); + EXPECT_TRUE(isa_and_nonnull(FooVal)); + }); } TEST_F(TransferTest, StructVarDecl) { @@ -293,29 +293,29 @@ // [[p]] } )"; - runDataflow( - Code, [](llvm::ArrayRef< - std::pair>> - Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results, ElementsAre(Pair("p", _))); - const Environment &Env = Results[0].second.Env; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + 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 *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); - const StorageLocation *FooLoc = - Env.getStorageLocation(*FooDecl, SkipPast::None); - ASSERT_TRUE(isa_and_nonnull(FooLoc)); + const StorageLocation *FooLoc = + Env.getStorageLocation(*FooDecl, SkipPast::None); + ASSERT_TRUE(isa_and_nonnull(FooLoc)); - const ReferenceValue *FooVal = - cast(Env.getValue(*FooLoc)); - const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); - EXPECT_TRUE(isa(&FooPointeeLoc)); + const ReferenceValue *FooVal = + cast(Env.getValue(*FooLoc)); + const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); + EXPECT_TRUE(isa(&FooPointeeLoc)); - const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); - EXPECT_TRUE(isa_and_nonnull(FooPointeeVal)); - }); + const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); + EXPECT_TRUE(isa_and_nonnull(FooPointeeVal)); + }); } TEST_F(TransferTest, SelfReferentialReferenceVarDecl) { @@ -3327,23 +3327,23 @@ ASSERT_THAT(LDecl, NotNull()); // Inner. - auto *LVal = dyn_cast( - InnerEnv.getValue(*LDecl, SkipPast::None)); + auto *LVal = + dyn_cast(InnerEnv.getValue(*LDecl, SkipPast::None)); ASSERT_THAT(LVal, NotNull()); EXPECT_EQ(&LVal->getPointeeLoc(), InnerEnv.getStorageLocation(*ValDecl, SkipPast::Reference)); // Outer. - LVal = dyn_cast( - OuterEnv.getValue(*LDecl, SkipPast::None)); + LVal = + dyn_cast(OuterEnv.getValue(*LDecl, SkipPast::None)); ASSERT_THAT(LVal, NotNull()); // The loop body may not have been executed, so we should not conclude // that `l` points to `val`. EXPECT_NE(&LVal->getPointeeLoc(), OuterEnv.getStorageLocation(*ValDecl, SkipPast::Reference)); -}); + }); } TEST_F(TransferTest, DoesNotCrashOnUnionThisExpr) {