diff --git a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp --- a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp +++ b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp @@ -17,18 +17,27 @@ void clang::dataflow::copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst, Environment &Env) { + auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType(); + auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType(); + + auto SrcDecl = SrcType->getAsCXXRecordDecl(); + auto DstDecl = DstType->getAsCXXRecordDecl(); + + bool compatibleTypes = + SrcType == DstType || + (SrcDecl && DstDecl && SrcDecl->isDerivedFrom(DstDecl)); + (void)compatibleTypes; + LLVM_DEBUG({ - if (Dst.getType().getCanonicalType().getUnqualifiedType() != - Src.getType().getCanonicalType().getUnqualifiedType()) { + if (!compatibleTypes) { llvm::dbgs() << "Source type " << Src.getType() << "\n"; llvm::dbgs() << "Destination type " << Dst.getType() << "\n"; } }); - assert(Dst.getType().getCanonicalType().getUnqualifiedType() == - Src.getType().getCanonicalType().getUnqualifiedType()); + assert(compatibleTypes); - for (auto [Field, SrcFieldLoc] : Src.children()) { - StorageLocation *DstFieldLoc = Dst.getChild(*Field); + for (auto [Field, DstFieldLoc] : Dst.children()) { + StorageLocation *SrcFieldLoc = Src.getChild(*Field); assert(Field->getType()->isReferenceType() || (SrcFieldLoc != nullptr && DstFieldLoc != nullptr)); diff --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp @@ -194,6 +194,40 @@ }); } +TEST(TransferTest, CopyRecordFromDerivedToBase) { + std::string Code = R"( + struct A { + int i; + }; + + struct B : public A { + }; + + void target(A a, B b) { + (void)a.i; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); + + const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); + auto &A = getLocForDecl(ASTCtx, Env, "a"); + auto &B = getLocForDecl(ASTCtx, Env, "b"); + + EXPECT_NE(Env.getValue(*A.getChild(*IDecl)), + Env.getValue(*B.getChild(*IDecl))); + + copyRecord(B, A, Env); + + EXPECT_EQ(Env.getValue(*A.getChild(*IDecl)), + Env.getValue(*B.getChild(*IDecl))); + }); +} + } // namespace } // namespace test } // namespace dataflow