}
};
-/// 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; }
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
return Result;
}
+static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) {
+ if (auto *IndVal1 = dyn_cast<ReferenceValue>(Val1)) {
+ auto *IndVal2 = cast<ReferenceValue>(Val2);
+ return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
+ }
+ if (auto *IndVal1 = dyn_cast<PointerValue>(Val1)) {
+ auto *IndVal2 = cast<PointerValue>(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<IndirectionValue>(Val1)) {
- auto *IndVal2 = cast<IndirectionValue>(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`,
}
// FIXME: add unit tests that cover this statement.
- if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) {
- auto *IndVal2 = cast<IndirectionValue>(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`
// [[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;
+ 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 *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
- const StorageLocation *FooLoc =
- Env.getStorageLocation(*FooDecl, SkipPast::None);
- ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+ const StorageLocation *FooLoc =
+ Env.getStorageLocation(*FooDecl, SkipPast::None);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
- const Value *FooVal = Env.getValue(*FooLoc);
- EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
- });
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+ });
}
TEST_F(TransferTest, StructVarDecl) {
// [[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;
+ 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 *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
- const StorageLocation *FooLoc =
- Env.getStorageLocation(*FooDecl, SkipPast::None);
- ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+ const StorageLocation *FooLoc =
+ Env.getStorageLocation(*FooDecl, SkipPast::None);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
- const ReferenceValue *FooVal =
- cast<ReferenceValue>(Env.getValue(*FooLoc));
- const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
- EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
+ const ReferenceValue *FooVal =
+ cast<ReferenceValue>(Env.getValue(*FooLoc));
+ const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
+ EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
- const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
- EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
- });
+ const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
+ EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
+ });
}
TEST_F(TransferTest, SelfReferentialReferenceVarDecl) {
ASSERT_THAT(LDecl, NotNull());
// Inner.
- auto *LVal = dyn_cast<IndirectionValue>(
- InnerEnv.getValue(*LDecl, SkipPast::None));
+ auto *LVal =
+ dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl, SkipPast::None));
ASSERT_THAT(LVal, NotNull());
EXPECT_EQ(&LVal->getPointeeLoc(),
InnerEnv.getStorageLocation(*ValDecl, SkipPast::Reference));
// Outer.
- LVal = dyn_cast<IndirectionValue>(
- OuterEnv.getValue(*LDecl, SkipPast::None));
+ LVal =
+ dyn_cast<PointerValue>(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) {