diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index b46c947c691b9..b510114a7a355 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -531,6 +531,13 @@ class TransferVisitor : public ConstStmtVisitor { auto *LocDst = cast_or_null(Env.getStorageLocation(*Arg0)); + // The assignment operators are different from the type of the destination + // in this model (i.e. in one of their base classes). This must be very rare + // and we just bail. + if (Method->getThisObjectType().getCanonicalType().getUnqualifiedType() != + LocDst->getType().getCanonicalType().getUnqualifiedType()) + return; + if (LocSrc != nullptr && LocDst != nullptr) { copyRecord(*LocSrc, *LocDst, Env); Env.setStorageLocation(*S, *LocDst); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 0abd171f1d0b7..e0e3b71503d21 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2124,6 +2124,30 @@ TEST(TransferTest, AssignmentOperator) { }); } +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. + std::string Code = R"( + struct Base { + int base; + }; + struct Derived : public Base { + using Base::operator=; + int derived; + }; + void target(Base B, Derived D) { + D.base = 1; + D.derived = 1; + D = B; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) {}); +} + TEST(TransferTest, AssignmentOperatorFromCallResult) { std::string Code = R"( struct A {};