rnk created this revision. rnk added a reviewer: rsmith. Herald added a project: clang.
DONOTSUBMIT: Uploading for feedback on approach, still have test failures: ******************** Failing Tests (1): Clang :: CXX/class.access/p4.cpp In the MS C++ ABI, complete destructors for classes with virtual bases are emitted whereever they are needed. The complete destructor calls: - the base dtor - for each vbase, its base dtor Even when a destructor is user-defined in another TU, clang needs to mark the virtual base dtors referenced in TUs that call destructors. This fixes PR38521. FIXME: What about separating base and complete dtors? i.e. what about when only base dtors are ref'd? Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77081 Files: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp
Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -15998,10 +15998,19 @@ } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(Func)) { Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl()); - if (Destructor->isDefaulted() && !Destructor->isDeleted()) { - if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>()) - return; - DefineImplicitDestructor(Loc, Destructor); + if (!Destructor->isDeleted()) { + if (Destructor->isDefaulted()) { + if (Destructor->isTrivial() && + !Destructor->hasAttr<DLLExportAttr>()) + return; + DefineImplicitDestructor(Loc, Destructor); + } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // In the MS ABI, the complete destructor is implicitly defined, + // even if the base destructor is user defined. + // FIXME: Need a way to do it only once. "setBody" seems wrong. + if (Destructor->getParent()->getNumVBases() > 0) + DefineImplicitCompleteDestructor(Loc, Destructor); + } } if (Destructor->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, Destructor->getParent()); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -13202,6 +13202,53 @@ } } +void Sema::DefineImplicitCompleteDestructor(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor) { + if (Destructor->isInvalidDecl()) + return; + + CXXRecordDecl *ClassDecl = Destructor->getParent(); + assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && + "implicit complete dtors unneeded outside MS ABI"); + assert(ClassDecl->getNumVBases() > 0 && + "complete dtor only exists for classes with vbases"); + + SynthesizedFunctionScope Scope(*this, Destructor); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + // No need to resolve the exception specification of the base destructor or + // mark vtables referenced. That will be done when the base dtor is defined. + + // Similar to what is done above in MarkBaseAndMemberDestructorsReferenced, + // but only for virtual bases. + for (const CXXBaseSpecifier &VBase : ClassDecl->vbases()) { + // Bases are always records in a well-formed non-dependent class. + CXXRecordDecl *BaseRD = VBase.getType()->getAsCXXRecordDecl(); + + // If our base class is invalid, we probably can't get its dtor anyway. + if (!BaseRD || BaseRD->isInvalidDecl() || BaseRD->hasIrrelevantDestructor()) + continue; + + CXXDestructorDecl *Dtor = LookupDestructor(BaseRD); + assert(Dtor && "No dtor found for BaseRD!"); + if (CheckDestructorAccess( + ClassDecl->getLocation(), Dtor, + PDiag(diag::err_access_dtor_vbase) + << Context.getTypeDeclType(ClassDecl) << VBase.getType(), + Context.getTypeDeclType(ClassDecl)) == AR_accessible) { + CheckDerivedToBaseConversion( + Context.getTypeDeclType(ClassDecl), VBase.getType(), + diag::err_access_dtor_vbase, 0, ClassDecl->getLocation(), + SourceRange(), DeclarationName(), nullptr); + } + + MarkFunctionReferenced(Dtor->getLocation(), Dtor); + DiagnoseUseOfDecl(Dtor, Dtor->getLocation()); + } +} + /// Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -5559,6 +5559,11 @@ void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); + /// Define an implicit complete constructor for classes with vbases in the MS + /// ABI. + void DefineImplicitCompleteDestructor(SourceLocation CurrentLocation, + CXXDestructorDecl *Dtor); + /// Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits