From 113a40e6c9117356428d5cd791f0c014389e27f5 Mon Sep 17 00:00:00 2001 From: Martin Braenne Date: Mon, 6 Nov 2023 12:13:05 +0000 Subject: [PATCH] [clang][dataflow] Fix assert-fail when calling assignment operator with by-value parameter. The code assumed that the source parameter of an assignment operator is always passed by reference, but it is legal for it to be passed by value. This patch includes a test that assert-fails without the fix. --- clang/lib/Analysis/FlowSensitive/Transfer.cpp | 10 ++++- .../Analysis/FlowSensitive/TransferTest.cpp | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) 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.