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 @@ -171,19 +171,45 @@ } void VisitUnaryOperator(const UnaryOperator *S) { - if (S->getOpcode() == UO_Deref) { - assert(S->getSubExpr() != nullptr); + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); + assert(SubExpr != nullptr); + + switch (S->getOpcode()) { + case UO_Deref: { const auto *SubExprVal = cast_or_null( - Env.getValue(*S->getSubExpr(), SkipPast::Reference)); + Env.getValue(*SubExpr, SkipPast::Reference)); if (SubExprVal == nullptr) - return; + break; auto &Loc = Env.createStorageLocation(*S); Env.setStorageLocation(*S, Loc); Env.setValue(Loc, Env.takeOwnership(std::make_unique( SubExprVal->getPointeeLoc()))); + break; + } + case UO_AddrOf: { + // Do not form a pointer to a reference. If `SubExpr` is assigned a + // `ReferenceValue` then form a value that points to the location of its + // pointee. + StorageLocation *PointeeLoc = + Env.getStorageLocation(*SubExpr, SkipPast::Reference); + if (PointeeLoc == nullptr) + break; + + auto &PointerLoc = Env.createStorageLocation(*S); + auto &PointerVal = + Env.takeOwnership(std::make_unique(*PointeeLoc)); + Env.setStorageLocation(*S, PointerLoc); + Env.setValue(PointerLoc, PointerVal); + break; + } + default: + // FIXME: Add support for UO_LNot. + break; } - // FIXME: Add support for UO_AddrOf, UO_LNot. } void VisitCXXThisExpr(const CXXThisExpr *S) { 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 @@ -1699,4 +1699,63 @@ }); } +TEST_F(TransferTest, AddrOfValue) { + std::string Code = R"( + void target() { + int Foo; + int *Bar = &Foo; + // [[p]] + } + )"; + 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 *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooLoc = cast( + Env.getStorageLocation(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + }); +} + +TEST_F(TransferTest, AddrOfReference) { + std::string Code = R"( + void target(int *Foo) { + int *Bar = &(*Foo); + // [[p]] + } + )"; + 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 *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooVal = + cast(Env.getValue(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); + }); +} + } // namespace