Index: clang/lib/Analysis/FlowSensitive/RecordOps.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/RecordOps.cpp +++ clang/lib/Analysis/FlowSensitive/RecordOps.cpp @@ -17,29 +17,37 @@ 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)); + 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()) { - assert(SrcFieldLoc != nullptr); + for (auto [Field, DstFieldLoc] : Dst.children()) { + assert(DstFieldLoc != nullptr); - StorageLocation &DstFieldLoc = Dst.getChild(*Field); + StorageLocation &SrcFieldLoc = Src.getChild(*Field); if (Field->getType()->isRecordType()) { - copyRecord(cast(*SrcFieldLoc), - cast(DstFieldLoc), Env); + copyRecord(cast(SrcFieldLoc), + cast(*DstFieldLoc), Env); } else { - if (Value *Val = Env.getValue(*SrcFieldLoc)) - Env.setValue(DstFieldLoc, *Val); + if (Value *Val = Env.getValue(SrcFieldLoc)) + Env.setValue(*DstFieldLoc, *Val); else - Env.clearValue(DstFieldLoc); + Env.clearValue(*DstFieldLoc); } } Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2290,6 +2290,28 @@ ASTContext &ASTCtx) {}); } +TEST(TransferTest, CopyConstructorWithUncheckedDerivedToBaseImplicitCast) { + std::string Code = R"( + class A { + public: + A(const A&) = default; + int a; + }; + + class target : public A { + public: + target(const target& b) = default; + target* copy() { + return new target(*this); + } + }; + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) {}); +} + TEST(TransferTest, MoveConstructor) { std::string Code = R"( namespace std {