@@ -463,7 +463,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
463463 startFunction (gd, retTy, fn, funcType, args, loc, bodyRange.getBegin ());
464464
465465 if (isa<CXXDestructorDecl>(funcDecl)) {
466- getCIRGenModule (). errorNYI (bodyRange, " C++ destructor definition " );
466+ emitDestructorBody (args );
467467 } else if (isa<CXXConstructorDecl>(funcDecl)) {
468468 emitConstructorBody (args);
469469 } else if (getLangOpts ().CUDA && !getLangOpts ().CUDAIsDevice &&
@@ -540,6 +540,96 @@ void CIRGenFunction::emitConstructorBody(FunctionArgList &args) {
540540 }
541541}
542542
543+ // / Emits the body of the current destructor.
544+ void CIRGenFunction::emitDestructorBody (FunctionArgList &args) {
545+ const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(curGD.getDecl ());
546+ CXXDtorType dtorType = curGD.getDtorType ();
547+
548+ // For an abstract class, non-base destructors are never used (and can't
549+ // be emitted in general, because vbase dtors may not have been validated
550+ // by Sema), but the Itanium ABI doesn't make them optional and Clang may
551+ // in fact emit references to them from other compilations, so emit them
552+ // as functions containing a trap instruction.
553+ if (dtorType != Dtor_Base && dtor->getParent ()->isAbstract ()) {
554+ cgm.errorNYI (dtor->getSourceRange (), " abstract base class destructors" );
555+ return ;
556+ }
557+
558+ Stmt *body = dtor->getBody ();
559+ assert (body && !cir::MissingFeatures::incrementProfileCounter ());
560+
561+ // The call to operator delete in a deleting destructor happens
562+ // outside of the function-try-block, which means it's always
563+ // possible to delegate the destructor body to the complete
564+ // destructor. Do so.
565+ if (dtorType == Dtor_Deleting) {
566+ cgm.errorNYI (dtor->getSourceRange (), " deleting destructor" );
567+ return ;
568+ }
569+
570+ // If the body is a function-try-block, enter the try before
571+ // anything else.
572+ const bool isTryBody = isa_and_nonnull<CXXTryStmt>(body);
573+ if (isTryBody)
574+ cgm.errorNYI (dtor->getSourceRange (), " function-try-block destructor" );
575+
576+ assert (!cir::MissingFeatures::sanitizers ());
577+ assert (!cir::MissingFeatures::dtorCleanups ());
578+
579+ // If this is the complete variant, just invoke the base variant;
580+ // the epilogue will destruct the virtual bases. But we can't do
581+ // this optimization if the body is a function-try-block, because
582+ // we'd introduce *two* handler blocks. In the Microsoft ABI, we
583+ // always delegate because we might not have a definition in this TU.
584+ switch (dtorType) {
585+ case Dtor_Comdat:
586+ llvm_unreachable (" not expecting a COMDAT" );
587+ case Dtor_Deleting:
588+ llvm_unreachable (" already handled deleting case" );
589+
590+ case Dtor_Complete:
591+ assert ((body || getTarget ().getCXXABI ().isMicrosoft ()) &&
592+ " can't emit a dtor without a body for non-Microsoft ABIs" );
593+
594+ assert (!cir::MissingFeatures::dtorCleanups ());
595+
596+ // TODO(cir): A complete destructor is supposed to call the base destructor.
597+ // Since we have to emit both dtor kinds we just fall through for now and.
598+ // As long as we don't support virtual bases this should be functionally
599+ // equivalent.
600+ assert (!cir::MissingFeatures::completeDtors ());
601+
602+ // Fallthrough: act like we're in the base variant.
603+ [[fallthrough]];
604+
605+ case Dtor_Base:
606+ assert (body);
607+
608+ assert (!cir::MissingFeatures::dtorCleanups ());
609+ assert (!cir::MissingFeatures::vtableInitialization ());
610+
611+ if (isTryBody) {
612+ cgm.errorNYI (dtor->getSourceRange (), " function-try-block destructor" );
613+ } else if (body) {
614+ (void )emitStmt (body, /* useCurrentScope=*/ true );
615+ } else {
616+ assert (dtor->isImplicit () && " bodyless dtor not implicit" );
617+ // nothing to do besides what's in the epilogue
618+ }
619+ // -fapple-kext must inline any call to this dtor into
620+ // the caller's body.
621+ assert (!cir::MissingFeatures::appleKext ());
622+
623+ break ;
624+ }
625+
626+ assert (!cir::MissingFeatures::dtorCleanups ());
627+
628+ // Exit the try if applicable.
629+ if (isTryBody)
630+ cgm.errorNYI (dtor->getSourceRange (), " function-try-block destructor" );
631+ }
632+
543633// / Given a value of type T* that may not be to a complete object, construct
544634// / an l-vlaue withi the natural pointee alignment of T.
545635LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue (mlir::Value val,
0 commit comments