diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 9c16479191948..e1ffe6c4a8eef 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -10671,6 +10671,70 @@ void ASTReader::finishPendingActions() { // Inform any classes that had members added that they now have more members. for (auto [RD, MD] : PendingAddedClassMembers) { + // The module we just imported added MD to RD so we should do the same, but + // only RD doesn't already contain the same member. This can happen when two + // modules independent add and serialize the same implicit member. + + // Fast path: we can check for the presence of implicit special members + // (default/copy/move constructors + copy/move assignments + destructors) + // with RD's needsImplicit*() methods (which are constant time). + if (const auto *Ctor = dyn_cast(MD)) { + if (!Ctor->isInheritingConstructor()) { + if (Ctor->isDefaultConstructor()) { + if (RD->needsImplicitDefaultConstructor()) + RD->addHiddenDecl(MD); + continue; + } + if (Ctor->isCopyConstructor()) { + if (RD->needsImplicitCopyConstructor()) + RD->addHiddenDecl(MD); + continue; + } + if (Ctor->isMoveConstructor()) { + if (RD->needsImplicitMoveConstructor()) + RD->addHiddenDecl(MD); + continue; + } + } + } else if (const auto *Mthd = dyn_cast(MD)) { + if (isa(Mthd)) { + if (RD->needsImplicitDestructor()) + RD->addHiddenDecl(MD); + continue; + } + if (Mthd->isCopyAssignmentOperator()) { + if (RD->needsImplicitCopyAssignment()) + RD->addHiddenDecl(MD); + continue; + } + if (Mthd->isMoveAssignmentOperator()) { + if (RD->needsImplicitMoveAssignment()) + RD->addHiddenDecl(MD); + continue; + } + } + + if (auto *FD = dyn_cast(MD)) { + // Slow path: this is some other implicit added member (e.g., inherited + // constructor). We need iterate through all of RD's members and compare + // their ODR hash against MD's. + auto needToAddMD = true; + for (auto *RDD : RD->noload_decls()) { + if (auto *RDFD = dyn_cast(RDD)) { + if (FD->getODRHash() == RDFD->getODRHash()) { + needToAddMD = false; + break; + } + } + } + if (needToAddMD) + RD->addHiddenDecl(MD); + continue; + } + + // This branch is only reachable if MD is not a function decl (which means + // it doesn't have an ODR hash to compare). Call addedMember() to preserve + // historical behavior. RD->addedMember(MD); } PendingAddedClassMembers.clear();