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 @@ -169,17 +169,17 @@ /// Models a symbolic pointer. Specifically, any value of type `T*`. class PointerValue final : public Value { public: - explicit PointerValue(StorageLocation &PointeeLoc) + explicit PointerValue(StorageLocation *PointeeLoc) : Value(Kind::Pointer), PointeeLoc(PointeeLoc) {} static bool classof(const Value *Val) { return Val->getKind() == Kind::Pointer; } - StorageLocation &getPointeeLoc() const { return PointeeLoc; } + StorageLocation *getPointeeLoc() const { return PointeeLoc; } private: - StorageLocation &PointeeLoc; + StorageLocation *PointeeLoc; }; /// Models a value of `struct` or `class` type. diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -97,7 +97,7 @@ auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr); if (Res.second) { auto &PointeeLoc = createStorageLocation(CanonicalPointeeType); - Res.first->second = &arena().create(PointeeLoc); + Res.first->second = &arena().create(&PointeeLoc); } return *Res.first->second; } 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 @@ -161,6 +161,14 @@ return CurrentEnv.makeTopBoolValue(); } + if (auto *PrevPtr = dyn_cast(&Prev)) { + auto &CurPtr = cast(Current); + + if (PrevPtr->getPointeeLoc() != CurPtr.getPointeeLoc()) + // TODO: Preserve properties + return CurrentEnv.create(nullptr); + } + // FIXME: Add other built-in model widening. // Custom-model widening. @@ -757,7 +765,7 @@ StorageLocation &PointeeLoc = createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); - return &arena().create(PointeeLoc); + return &arena().create(&PointeeLoc); } if (Type->isRecordType()) { @@ -899,7 +907,7 @@ return nullptr; if (ImplicitObject->getType()->isPointerType()) { if (auto *Val = cast_or_null(Env.getValue(*ImplicitObject))) - return &cast(Val->getPointeeLoc()); + return cast_or_null(Val->getPointeeLoc()); return nullptr; } return cast_or_null( @@ -913,7 +921,7 @@ return nullptr; if (ME.isArrow()) { if (auto *Val = cast_or_null(Env.getValue(*Base))) - return &cast(Val->getPointeeLoc()); + return cast_or_null(Val->getPointeeLoc()); return nullptr; } return cast_or_null(Env.getStorageLocation(*Base)); diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -100,8 +100,8 @@ case Value::Kind::FormulaBool: break; case Value::Kind::Pointer: - JOS.attributeObject( - "pointee", [&] { dump(cast(V).getPointeeLoc()); }); + if (StorageLocation *PointeeLoc = cast(V).getPointeeLoc()) + JOS.attributeObject("pointee", [&] { dump(*PointeeLoc); }); break; case Value::Kind::Record: for (const auto &Child : cast(V).getLoc().children()) diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -315,40 +315,43 @@ // `Value` representing the optional (here, `OptionalVal`). if (auto *ValueProp = OptionalVal.getProperty("value")) { auto *ValuePtr = clang::cast(ValueProp); - auto &ValueLoc = ValuePtr->getPointeeLoc(); - if (Env.getValue(ValueLoc) != nullptr) - return &ValueLoc; - - // The property was previously set, but the value has been lost. This can - // happen in various situations, for example: - // - Because of an environment merge (where the two environments mapped the - // property to different values, which resulted in them both being - // discarded). - // - When two blocks in the CFG, with neither a dominator of the other, - // visit the same optional value. (FIXME: This is something we can and - // should fix -- see also the lengthy FIXME below.) - // - Or even when a block is revisited during testing to collect - // per-statement state. - // FIXME: This situation means that the optional contents are not shared - // between branches and the like. Practically, this lack of sharing - // reduces the precision of the model when the contents are relevant to - // the check, like another optional or a boolean that influences control - // flow. - if (ValueLoc.getType()->isRecordType()) { - refreshRecordValue(cast(ValueLoc), Env); - return &ValueLoc; - } else { - auto *ValueVal = Env.createValue(ValueLoc.getType()); - if (ValueVal == nullptr) - return nullptr; - Env.setValue(ValueLoc, *ValueVal); - return &ValueLoc; + auto *ValueLoc = ValuePtr->getPointeeLoc(); + if (ValueLoc != nullptr) { + if (Env.getValue(*ValueLoc) != nullptr) + return ValueLoc; + + // The property was previously set, but the value has been lost. This can + // happen in various situations, for example: + // - Because of an environment merge (where the two environments mapped + // the + // property to different values, which resulted in them both being + // discarded). + // - When two blocks in the CFG, with neither a dominator of the other, + // visit the same optional value. (FIXME: This is something we can and + // should fix -- see also the lengthy FIXME below.) + // - Or even when a block is revisited during testing to collect + // per-statement state. + // FIXME: This situation means that the optional contents are not shared + // between branches and the like. Practically, this lack of sharing + // reduces the precision of the model when the contents are relevant to + // the check, like another optional or a boolean that influences control + // flow. + if (ValueLoc->getType()->isRecordType()) { + refreshStructValue(cast(*ValueLoc), Env); + return ValueLoc; + } else { + auto *ValueVal = Env.createValue(ValueLoc->getType()); + if (ValueVal == nullptr) + return nullptr; + Env.setValue(*ValueLoc, *ValueVal); + return ValueLoc; + } } } auto Ty = Q.getNonReferenceType(); auto &ValueLoc = Env.createObject(Ty); - auto &ValuePtr = Env.create(ValueLoc); + auto &ValuePtr = Env.create(&ValueLoc); // FIXME: // The change we make to the `value` property below may become visible to // other blocks that aren't successors of the current block and therefore @@ -429,7 +432,8 @@ Value *getValueBehindPossiblePointer(const Expr &E, const Environment &Env) { Value *Val = Env.getValue(E); if (auto *PointerVal = dyn_cast_or_null(Val)) - return Env.getValue(PointerVal->getPointeeLoc()); + if (PointerVal->getPointeeLoc() != nullptr) + return Env.getValue(*PointerVal->getPointeeLoc()); return Val; } @@ -450,7 +454,7 @@ getValueBehindPossiblePointer(*ObjectExpr, State.Env)) { if (auto *Loc = maybeInitializeOptionalValueMember( UnwrapExpr->getType()->getPointeeType(), *OptionalVal, State.Env)) { - State.Env.setValue(*UnwrapExpr, State.Env.create(*Loc)); + State.Env.setValue(*UnwrapExpr, State.Env.create(Loc)); } } } diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -315,7 +315,7 @@ if (PointeeLoc == nullptr) break; - Env.setValue(*S, Env.create(*PointeeLoc)); + Env.setValue(*S, Env.create(PointeeLoc)); break; } case CK_BuiltinFnToFnPtr: @@ -340,7 +340,8 @@ if (SubExprVal == nullptr) break; - Env.setStorageLocation(*S, SubExprVal->getPointeeLoc()); + if (SubExprVal->getPointeeLoc() != nullptr) + Env.setStorageLocation(*S, *SubExprVal->getPointeeLoc()); break; } case UO_AddrOf: { @@ -349,7 +350,7 @@ break; if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr)) - Env.setValue(*S, Env.create(*PointeeLoc)); + Env.setValue(*S, Env.create(PointeeLoc)); break; } case UO_LNot: { @@ -372,7 +373,7 @@ // `this` expression's pointee. return; - Env.setValue(*S, Env.create(*ThisPointeeLoc)); + Env.setValue(*S, Env.create(ThisPointeeLoc)); } void VisitCXXNewExpr(const CXXNewExpr *S) { diff --git a/clang/lib/Analysis/FlowSensitive/Value.cpp b/clang/lib/Analysis/FlowSensitive/Value.cpp --- a/clang/lib/Analysis/FlowSensitive/Value.cpp +++ b/clang/lib/Analysis/FlowSensitive/Value.cpp @@ -21,7 +21,7 @@ const Value &Val2) { if (auto *IndVal1 = dyn_cast(&Val1)) { auto *IndVal2 = cast(&Val2); - return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); + return IndVal1->getPointeeLoc() == IndVal2->getPointeeLoc(); } return false; } @@ -36,7 +36,7 @@ switch (Val.getKind()) { case Value::Kind::Pointer: { const auto *PV = dyn_cast(&Val); - return OS << "Pointer(" << &PV->getPointeeLoc() << ")"; + return OS << "Pointer(" << PV->getPointeeLoc() << ")"; } // FIXME: support remaining cases. default: 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 @@ -165,7 +165,7 @@ ASSERT_THAT(FooValue, NotNull()); EXPECT_TRUE(isa(FooValue->getPointeeLoc())); - auto *FooPointeeValue = Env.getValue(FooValue->getPointeeLoc()); + auto *FooPointeeValue = Env.getValue(*FooValue->getPointeeLoc()); ASSERT_THAT(FooPointeeValue, NotNull()); EXPECT_TRUE(isa(FooPointeeValue)); }); @@ -496,7 +496,7 @@ const auto &FooPtrVal = *cast(getFieldValue(&BarLoc, *FooPtrDecl, Env)); const auto &FooPtrPointeeLoc = - cast(FooPtrVal.getPointeeLoc()); + *cast(FooPtrVal.getPointeeLoc()); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull()); EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull()); @@ -504,8 +504,9 @@ const auto &BazPtrVal = *cast(getFieldValue(&BarLoc, *BazPtrDecl, Env)); - const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); - EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); + const StorageLocation *BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); + ASSERT_THAT(BazPtrPointeeLoc, NotNull()); + EXPECT_THAT(Env.getValue(*BazPtrPointeeLoc), NotNull()); }); } @@ -534,8 +535,8 @@ ASSERT_TRUE(isa_and_nonnull(FooLoc)); const PointerValue *FooVal = cast(Env.getValue(*FooLoc)); - const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); - EXPECT_TRUE(isa(&FooPointeeLoc)); + const auto &FooPointeeLoc = + *cast(FooVal->getPointeeLoc()); const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); EXPECT_TRUE(isa_and_nonnull(FooPointeeVal)); @@ -637,28 +638,32 @@ const auto &FooLoc = *cast(Env.getStorageLocation(*FooDecl)); const auto &FooVal = *cast(Env.getValue(FooLoc)); + ASSERT_THAT(FooVal.getPointeeLoc(), NotNull()); const auto &FooPointeeVal = - *cast(Env.getValue(FooVal.getPointeeLoc())); + *cast(Env.getValue(*FooVal.getPointeeLoc())); const auto &BarVal = *cast(getFieldValue(&FooPointeeVal, *BarDecl, Env)); + ASSERT_THAT(BarVal.getPointeeLoc(), NotNull()); const auto &BarPointeeVal = - *cast(Env.getValue(BarVal.getPointeeLoc())); + *cast(Env.getValue(*BarVal.getPointeeLoc())); EXPECT_THAT(getFieldValue(&BarPointeeVal, *FooRefDecl, Env), NotNull()); const auto &FooPtrVal = *cast( getFieldValue(&BarPointeeVal, *FooPtrDecl, Env)); + ASSERT_THAT(FooPtrVal.getPointeeLoc(), NotNull()); const auto &FooPtrPointeeLoc = - cast(FooPtrVal.getPointeeLoc()); + cast(*FooPtrVal.getPointeeLoc()); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); EXPECT_THAT(getFieldValue(&BarPointeeVal, *BazRefDecl, Env), NotNull()); const auto &BazPtrVal = *cast( getFieldValue(&BarPointeeVal, *BazPtrDecl, Env)); - const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); - EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); + const StorageLocation *BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); + ASSERT_THAT(BazPtrPointeeLoc, NotNull()); + EXPECT_THAT(Env.getValue(*BazPtrPointeeLoc), NotNull()); }); } @@ -915,7 +920,8 @@ ASSERT_THAT(BarDecl, NotNull()); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); + ASSERT_THAT(BarVal->getPointeeLoc(), NotNull()); + EXPECT_EQ(Env.getValue(*BarVal->getPointeeLoc()), FooVal); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); @@ -1099,10 +1105,10 @@ ASSERT_TRUE(isa_and_nonnull(FooLoc)); const PointerValue *FooVal = cast(Env.getValue(*FooLoc)); - const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); - EXPECT_TRUE(isa(&FooPointeeLoc)); + const StorageLocation *FooPointeeLoc = FooVal->getPointeeLoc(); + EXPECT_TRUE(isa(FooPointeeLoc)); - const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); + const Value *FooPointeeVal = Env.getValue(*FooPointeeLoc); EXPECT_TRUE(isa_and_nonnull(FooPointeeVal)); }); } @@ -2521,21 +2527,21 @@ EXPECT_NE(FooXVal, BazVal); EXPECT_NE(BarVal, BazVal); - const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); + const StorageLocation *FooPointeeLoc = FooXVal->getPointeeLoc(); EXPECT_TRUE(isa(FooPointeeLoc)); - EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); + EXPECT_THAT(Env.getValue(*FooPointeeLoc), IsNull()); - const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); + const StorageLocation *BarPointeeLoc = BarVal->getPointeeLoc(); EXPECT_TRUE(isa(BarPointeeLoc)); - EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); + EXPECT_THAT(Env.getValue(*BarPointeeLoc), IsNull()); - const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); + const StorageLocation *BazPointeeLoc = BazVal->getPointeeLoc(); EXPECT_TRUE(isa(BazPointeeLoc)); - EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); + EXPECT_THAT(Env.getValue(*BazPointeeLoc), IsNull()); - const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); + const StorageLocation *NullPointeeLoc = NullVal->getPointeeLoc(); EXPECT_TRUE(isa(NullPointeeLoc)); - EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); + EXPECT_THAT(Env.getValue(*NullPointeeLoc), IsNull()); }); } @@ -2631,7 +2637,7 @@ const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + EXPECT_EQ(BarVal->getPointeeLoc(), FooLoc); }); } @@ -2657,7 +2663,7 @@ const auto *FooVal = cast(Env.getValue(*FooDecl)); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); + EXPECT_EQ(BarVal->getPointeeLoc(), FooVal->getPointeeLoc()); }); } @@ -2747,8 +2753,9 @@ const auto *FooVal = cast(EnvAfterLoop.getValue(*FooDecl)); + ASSERT_THAT(FooVal->getPointeeLoc(), NotNull()); const auto *FooPointeeVal = - cast(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); + cast(EnvAfterLoop.getValue(*FooVal->getPointeeLoc())); const auto *BarVal = cast(EnvInLoop.getValue(*BarDecl)); EXPECT_EQ(BarVal, FooPointeeVal); @@ -3814,8 +3821,7 @@ auto *LVal = dyn_cast(InnerEnv.getValue(*LDecl)); ASSERT_THAT(LVal, NotNull()); - EXPECT_EQ(&LVal->getPointeeLoc(), - InnerEnv.getStorageLocation(*ValDecl)); + EXPECT_EQ(LVal->getPointeeLoc(), InnerEnv.getStorageLocation(*ValDecl)); // Outer. LVal = dyn_cast(OuterEnv.getValue(*LDecl)); @@ -3823,8 +3829,7 @@ // 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)); + EXPECT_NE(LVal->getPointeeLoc(), OuterEnv.getStorageLocation(*ValDecl)); }); } @@ -3843,10 +3848,7 @@ } } )cc"; - // FIXME: Implement pointer value widening to make analysis converge. - ASSERT_THAT_ERROR( - checkDataflowWithNoopAnalysis(Code), - llvm::FailedWithMessage("maximum number of iterations reached")); + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { @@ -3869,9 +3871,7 @@ } )cc"; // FIXME: Implement pointer value widening to make analysis converge. - ASSERT_THAT_ERROR( - checkDataflowWithNoopAnalysis(Code), - llvm::FailedWithMessage("maximum number of iterations reached")); + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { @@ -5470,7 +5470,8 @@ auto &P = getValueForDecl(ASTCtx, Env, "p"); - EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); + ASSERT_THAT(P.getPointeeLoc(), NotNull()); + EXPECT_THAT(Env.getValue(*P.getPointeeLoc()), NotNull()); }); } @@ -5504,7 +5505,7 @@ auto &P = getValueForDecl(ASTCtx, Env, "p"); - auto &OuterLoc = cast(P.getPointeeLoc()); + auto &OuterLoc = *cast(P.getPointeeLoc()); auto &OuterFieldLoc = *cast(OuterLoc.getChild(*OuterField)); auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); @@ -5545,13 +5546,13 @@ getValueForDecl(ASTCtx, Env, "non_member_p1"); auto &NonMemberP2 = getValueForDecl(ASTCtx, Env, "non_member_p2"); - EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); + EXPECT_EQ(NonMemberP1.getPointeeLoc(), NonMemberP2.getPointeeLoc()); auto &MemberP1 = getValueForDecl(ASTCtx, Env, "member_p1"); auto &MemberP2 = getValueForDecl(ASTCtx, Env, "member_p2"); - EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); + EXPECT_EQ(MemberP1.getPointeeLoc(), MemberP2.getPointeeLoc()); }); } diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -768,7 +768,7 @@ const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + EXPECT_EQ(BarVal->getPointeeLoc(), FooLoc); }); } diff --git a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp @@ -31,8 +31,8 @@ TEST(ValueTest, AliasedPointersEquivalent) { auto L = ScalarStorageLocation(QualType()); - PointerValue V1(L); - PointerValue V2(L); + PointerValue V1(&L); + PointerValue V2(&L); EXPECT_TRUE(areEquivalentValues(V1, V2)); EXPECT_TRUE(areEquivalentValues(V2, V1)); } @@ -60,7 +60,7 @@ TEST(ValueTest, DifferentKindsNotEquivalent) { Arena A; auto L = ScalarStorageLocation(QualType()); - PointerValue V1(L); + PointerValue V1(&L); TopBoolValue V2(A.makeAtomRef(Atom(0))); EXPECT_FALSE(areEquivalentValues(V1, V2)); EXPECT_FALSE(areEquivalentValues(V2, V1)); @@ -68,9 +68,9 @@ TEST(ValueTest, NotAliasedPointersNotEquivalent) { auto L1 = ScalarStorageLocation(QualType()); - PointerValue V1(L1); + PointerValue V1(&L1); auto L2 = ScalarStorageLocation(QualType()); - PointerValue V2(L2); + PointerValue V2(&L2); EXPECT_FALSE(areEquivalentValues(V1, V2)); EXPECT_FALSE(areEquivalentValues(V2, V1)); }