Unverified Commit 6b573f46 authored by martinboehme's avatar martinboehme Committed by GitHub
Browse files

[clang][dataflow] Fix assert-fail when calling assignment operator with...

[clang][dataflow] Fix assert-fail when calling assignment operator with by-value parameter. (#71384)

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.
parent e09184ff
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -514,8 +514,14 @@ public:
          !Method->isMoveAssignmentOperator())
        return;

      auto *LocSrc =
      RecordStorageLocation *LocSrc = nullptr;
      if (Arg1->isPRValue()) {
        if (auto *Val = cast_or_null<RecordValue>(Env.getValue(*Arg1)))
          LocSrc = &Val->getLoc();
      } else {
        LocSrc =
            cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg1));
      }
      auto *LocDst =
          cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg0));

+37 −0
Original line number Diff line number Diff line
@@ -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<DataflowAnalysisState<NoopLattice>> &Results,
         ASTContext &ASTCtx) {
        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
        const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");

        const auto &FooLoc =
            getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
        const auto &BarLoc =
            getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");

        const auto *FooBazVal =
            cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
        const auto *BarBazVal =
            cast<IntegerValue>(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.