diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index bb26e9f8dc8db..8b2f8ecc5027e 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -514,8 +514,14 @@ class TransferVisitor : public ConstStmtVisitor { !Method->isMoveAssignmentOperator()) return; - auto *LocSrc = - cast_or_null(Env.getStorageLocation(*Arg1)); + RecordStorageLocation *LocSrc = nullptr; + if (Arg1->isPRValue()) { + if (auto *Val = cast_or_null(Env.getValue(*Arg1))) + LocSrc = &Val->getLoc(); + } else { + LocSrc = + cast_or_null(Env.getStorageLocation(*Arg1)); + } auto *LocDst = cast_or_null(Env.getStorageLocation(*Arg0)); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 0f9f13df81707..bd9b98178b5d4 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2213,6 +2213,43 @@ TEST(TransferTest, AssignmentOperator) { }); } +// It's legal for the assignment operator to take its source parameter by value. +// Check that we handle this correctly. (This is a repro -- we used to +// assert-fail on this.) +TEST(TransferTest, AssignmentOperator_ArgByValue) { + std::string Code = R"( + struct A { + int Baz; + A &operator=(A); + }; + + void target() { + A Foo = { 1 }; + A Bar = { 2 }; + Foo = Bar; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); + + const auto &FooLoc = + getLocForDecl(ASTCtx, Env, "Foo"); + const auto &BarLoc = + getLocForDecl(ASTCtx, Env, "Bar"); + + const auto *FooBazVal = + cast(getFieldValue(&FooLoc, *BazDecl, Env)); + const auto *BarBazVal = + cast(getFieldValue(&BarLoc, *BazDecl, Env)); + EXPECT_EQ(FooBazVal, BarBazVal); + }); +} + TEST(TransferTest, AssignmentOperatorFromBase) { // This is a crash repro. We don't model the copy this case, so no // expectations on the copied field of the base class are checked.