@@ -5289,6 +5289,100 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
52895289 return false;
52905290}
52915291
5292+ static CXXDestructorDecl *LookupDestructorIfRelevant(Sema &S,
5293+ CXXRecordDecl *Class) {
5294+ if (Class->isInvalidDecl())
5295+ return nullptr;
5296+ if (Class->hasIrrelevantDestructor())
5297+ return nullptr;
5298+
5299+ // Dtor might still be missing, e.g because it's invalid.
5300+ return S.LookupDestructor(Class);
5301+ }
5302+
5303+ static void MarkFieldDestructorReferenced(Sema &S, SourceLocation Location,
5304+ FieldDecl *Field) {
5305+ if (Field->isInvalidDecl())
5306+ return;
5307+
5308+ // Don't destroy incomplete or zero-length arrays.
5309+ if (isIncompleteOrZeroLengthArrayType(S.Context, Field->getType()))
5310+ return;
5311+
5312+ QualType FieldType = S.Context.getBaseElementType(Field->getType());
5313+
5314+ auto *FieldClassDecl = FieldType->getAsCXXRecordDecl();
5315+ if (!FieldClassDecl)
5316+ return;
5317+
5318+ // The destructor for an implicit anonymous union member is never invoked.
5319+ if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
5320+ return;
5321+
5322+ auto *Dtor = LookupDestructorIfRelevant(S, FieldClassDecl);
5323+ if (!Dtor)
5324+ return;
5325+
5326+ S.CheckDestructorAccess(Field->getLocation(), Dtor,
5327+ S.PDiag(diag::err_access_dtor_field)
5328+ << Field->getDeclName() << FieldType);
5329+
5330+ S.MarkFunctionReferenced(Location, Dtor);
5331+ S.DiagnoseUseOfDecl(Dtor, Location);
5332+ }
5333+
5334+ static void MarkBaseDestructorsReferenced(Sema &S, SourceLocation Location,
5335+ CXXRecordDecl *ClassDecl) {
5336+ if (ClassDecl->isDependentContext())
5337+ return;
5338+
5339+ // We only potentially invoke the destructors of potentially constructed
5340+ // subobjects.
5341+ bool VisitVirtualBases = !ClassDecl->isAbstract();
5342+
5343+ // If the destructor exists and has already been marked used in the MS ABI,
5344+ // then virtual base destructors have already been checked and marked used.
5345+ // Skip checking them again to avoid duplicate diagnostics.
5346+ if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
5347+ CXXDestructorDecl *Dtor = ClassDecl->getDestructor();
5348+ if (Dtor && Dtor->isUsed())
5349+ VisitVirtualBases = false;
5350+ }
5351+
5352+ llvm::SmallPtrSet<const CXXRecordDecl *, 8> DirectVirtualBases;
5353+
5354+ // Bases.
5355+ for (const auto &Base : ClassDecl->bases()) {
5356+ auto *BaseClassDecl = Base.getType()->getAsCXXRecordDecl();
5357+ if (!BaseClassDecl)
5358+ continue;
5359+
5360+ // Remember direct virtual bases.
5361+ if (Base.isVirtual()) {
5362+ if (!VisitVirtualBases)
5363+ continue;
5364+ DirectVirtualBases.insert(BaseClassDecl);
5365+ }
5366+
5367+ auto *Dtor = LookupDestructorIfRelevant(S, BaseClassDecl);
5368+ if (!Dtor)
5369+ continue;
5370+
5371+ // FIXME: caret should be on the start of the class name
5372+ S.CheckDestructorAccess(Base.getBeginLoc(), Dtor,
5373+ S.PDiag(diag::err_access_dtor_base)
5374+ << Base.getType() << Base.getSourceRange(),
5375+ S.Context.getTypeDeclType(ClassDecl));
5376+
5377+ S.MarkFunctionReferenced(Location, Dtor);
5378+ S.DiagnoseUseOfDecl(Dtor, Location);
5379+ }
5380+
5381+ if (VisitVirtualBases)
5382+ S.MarkVirtualBaseDestructorsReferenced(Location, ClassDecl,
5383+ &DirectVirtualBases);
5384+ }
5385+
52925386bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
52935387 ArrayRef<CXXCtorInitializer *> Initializers) {
52945388 if (Constructor->isDependentContext()) {
@@ -5456,10 +5550,24 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
54565550 NumInitializers * sizeof(CXXCtorInitializer*));
54575551 Constructor->setCtorInitializers(baseOrMemberInitializers);
54585552
5553+ SourceLocation Location = Constructor->getLocation();
5554+
54595555 // Constructors implicitly reference the base and member
54605556 // destructors.
5461- MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(),
5462- Constructor->getParent());
5557+
5558+ for (CXXCtorInitializer *Initializer : Info.AllToInit) {
5559+ FieldDecl *Field = Initializer->getAnyMember();
5560+ if (!Field)
5561+ continue;
5562+
5563+ // C++ [class.base.init]p12:
5564+ // In a non-delegating constructor, the destructor for each
5565+ // potentially constructed subobject of class type is potentially
5566+ // invoked.
5567+ MarkFieldDestructorReferenced(*this, Location, Field);
5568+ }
5569+
5570+ MarkBaseDestructorsReferenced(*this, Location, Constructor->getParent());
54635571 }
54645572
54655573 return HadError;
@@ -5764,9 +5872,8 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
57645872 DiagnoseUninitializedFields(*this, Constructor);
57655873}
57665874
5767- void
5768- Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
5769- CXXRecordDecl *ClassDecl) {
5875+ void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
5876+ CXXRecordDecl *ClassDecl) {
57705877 // Ignore dependent contexts. Also ignore unions, since their members never
57715878 // have destructors implicitly called.
57725879 if (ClassDecl->isDependentContext() || ClassDecl->isUnion())
@@ -5779,119 +5886,29 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
57795886
57805887 // Non-static data members.
57815888 for (auto *Field : ClassDecl->fields()) {
5782- if (Field->isInvalidDecl())
5783- continue;
5784-
5785- // Don't destroy incomplete or zero-length arrays.
5786- if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
5787- continue;
5788-
5789- QualType FieldType = Context.getBaseElementType(Field->getType());
5790-
5791- const RecordType* RT = FieldType->getAs<RecordType>();
5792- if (!RT)
5793- continue;
5794-
5795- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
5796- if (FieldClassDecl->isInvalidDecl())
5797- continue;
5798- if (FieldClassDecl->hasIrrelevantDestructor())
5799- continue;
5800- // The destructor for an implicit anonymous union member is never invoked.
5801- if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
5802- continue;
5803-
5804- CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
5805- // Dtor might still be missing, e.g because it's invalid.
5806- if (!Dtor)
5807- continue;
5808- CheckDestructorAccess(Field->getLocation(), Dtor,
5809- PDiag(diag::err_access_dtor_field)
5810- << Field->getDeclName()
5811- << FieldType);
5812-
5813- MarkFunctionReferenced(Location, Dtor);
5814- DiagnoseUseOfDecl(Dtor, Location);
5815- }
5816-
5817- // We only potentially invoke the destructors of potentially constructed
5818- // subobjects.
5819- bool VisitVirtualBases = !ClassDecl->isAbstract();
5820-
5821- // If the destructor exists and has already been marked used in the MS ABI,
5822- // then virtual base destructors have already been checked and marked used.
5823- // Skip checking them again to avoid duplicate diagnostics.
5824- if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
5825- CXXDestructorDecl *Dtor = ClassDecl->getDestructor();
5826- if (Dtor && Dtor->isUsed())
5827- VisitVirtualBases = false;
5889+ MarkFieldDestructorReferenced(*this, Location, Field);
58285890 }
58295891
5830- llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
5831-
5832- // Bases.
5833- for (const auto &Base : ClassDecl->bases()) {
5834- const RecordType *RT = Base.getType()->getAs<RecordType>();
5835- if (!RT)
5836- continue;
5837-
5838- // Remember direct virtual bases.
5839- if (Base.isVirtual()) {
5840- if (!VisitVirtualBases)
5841- continue;
5842- DirectVirtualBases.insert(RT);
5843- }
5844-
5845- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
5846- // If our base class is invalid, we probably can't get its dtor anyway.
5847- if (BaseClassDecl->isInvalidDecl())
5848- continue;
5849- if (BaseClassDecl->hasIrrelevantDestructor())
5850- continue;
5851-
5852- CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
5853- // Dtor might still be missing, e.g because it's invalid.
5854- if (!Dtor)
5855- continue;
5856-
5857- // FIXME: caret should be on the start of the class name
5858- CheckDestructorAccess(Base.getBeginLoc(), Dtor,
5859- PDiag(diag::err_access_dtor_base)
5860- << Base.getType() << Base.getSourceRange(),
5861- Context.getTypeDeclType(ClassDecl));
5862-
5863- MarkFunctionReferenced(Location, Dtor);
5864- DiagnoseUseOfDecl(Dtor, Location);
5865- }
5866-
5867- if (VisitVirtualBases)
5868- MarkVirtualBaseDestructorsReferenced(Location, ClassDecl,
5869- &DirectVirtualBases);
5892+ MarkBaseDestructorsReferenced(*this, Location, ClassDecl);
58705893}
58715894
58725895void Sema::MarkVirtualBaseDestructorsReferenced(
58735896 SourceLocation Location, CXXRecordDecl *ClassDecl,
5874- llvm::SmallPtrSetImpl<const RecordType *> *DirectVirtualBases) {
5897+ llvm::SmallPtrSetImpl<const CXXRecordDecl *> *DirectVirtualBases) {
58755898 // Virtual bases.
58765899 for (const auto &VBase : ClassDecl->vbases()) {
5877- // Bases are always records in a well-formed non-dependent class.
5878- const RecordType *RT = VBase.getType()->castAs<RecordType>();
5879-
5880- // Ignore already visited direct virtual bases.
5881- if (DirectVirtualBases && DirectVirtualBases->count(RT))
5900+ auto *BaseClassDecl = VBase.getType()->getAsCXXRecordDecl();
5901+ if (!BaseClassDecl)
58825902 continue;
58835903
5884- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
5885- // If our base class is invalid, we probably can't get its dtor anyway.
5886- if (BaseClassDecl->isInvalidDecl())
5887- continue;
5888- if (BaseClassDecl->hasIrrelevantDestructor())
5904+ // Ignore already visited direct virtual bases.
5905+ if (DirectVirtualBases && DirectVirtualBases->count(BaseClassDecl))
58895906 continue;
58905907
5891- CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
5892- // Dtor might still be missing, e.g because it's invalid.
5908+ auto *Dtor = LookupDestructorIfRelevant(*this, BaseClassDecl);
58935909 if (!Dtor)
58945910 continue;
5911+
58955912 if (CheckDestructorAccess(
58965913 ClassDecl->getLocation(), Dtor,
58975914 PDiag(diag::err_access_dtor_vbase)
0 commit comments