@@ -244,6 +244,29 @@ void CIRGenFunction::emitAnyExprToExn(const Expr *e, Address addr) {
244244 assert (!cir::MissingFeatures::ehCleanupScope ());
245245}
246246
247+ void CIRGenFunction::populateUnwindResumeBlock (bool isCleanup,
248+ cir::TryOp tryOp) {
249+ const EHPersonality &personality = EHPersonality::get (*this );
250+ // This can always be a call because we necessarily didn't find
251+ // anything on the EH stack which needs our help.
252+ const char *rethrowName = personality.catchallRethrowFn ;
253+ if (rethrowName != nullptr && !isCleanup) {
254+ cgm.errorNYI (" populateUnwindResumeBlock CatchallRethrowFn" );
255+ return ;
256+ }
257+
258+ unsigned regionsNum = tryOp->getNumRegions ();
259+ mlir::Region *unwindRegion = &tryOp->getRegion (regionsNum - 1 );
260+ mlir::Block *unwindResumeBlock = &unwindRegion->front ();
261+ if (!unwindResumeBlock->empty ())
262+ return ;
263+
264+ // Emit cir.resume into the unwind region last block
265+ mlir::OpBuilder::InsertionGuard guard (builder);
266+ builder.setInsertionPointToStart (unwindResumeBlock);
267+ cir::ResumeOp::create (builder, tryOp.getLoc ());
268+ }
269+
247270mlir::LogicalResult CIRGenFunction::emitCXXTryStmt (const CXXTryStmt &s) {
248271 if (s.getTryBlock ()->body_empty ())
249272 return mlir::LogicalResult::success ();
@@ -344,21 +367,63 @@ CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt &s) {
344367 return mlir::success ();
345368}
346369
370+ // / Emit the structure of the dispatch block for the given catch scope.
371+ // / It is an invariant that the dispatch block already exists.
372+ static void emitCatchDispatchBlock (CIRGenFunction &cgf,
373+ EHCatchScope &catchScope, cir::TryOp tryOp) {
374+ if (EHPersonality::get (cgf).isWasmPersonality ()) {
375+ cgf.cgm .errorNYI (" emitCatchDispatchBlock: WasmPersonality" );
376+ return ;
377+ }
378+
379+ if (EHPersonality::get (cgf).usesFuncletPads ()) {
380+ cgf.cgm .errorNYI (" emitCatchDispatchBlock: usesFuncletPads" );
381+ return ;
382+ }
383+
384+ assert (std::find_if (catchScope.begin (), catchScope.end (),
385+ [](const auto &handler) {
386+ return !handler.type .rtti && handler.type .flags != 0 ;
387+ }) == catchScope.end () &&
388+ " catch handler without type value or with not supported flags" );
389+
390+ // There was no catch all handler, populate th EH regions for the
391+ // enclosing scope.
392+ if (!std::prev (catchScope.end ())->isCatchAll ())
393+ cgf.populateEHCatchRegions (catchScope.getEnclosingEHScope (), tryOp);
394+ }
395+
347396void CIRGenFunction::enterCXXTryStmt (const CXXTryStmt &s, cir::TryOp tryOp,
348397 bool isFnTryBlock) {
349398 unsigned numHandlers = s.getNumHandlers ();
350399 EHCatchScope *catchScope = ehStack.pushCatch (numHandlers);
351400 for (unsigned i = 0 ; i != numHandlers; ++i) {
352401 const CXXCatchStmt *catchStmt = s.getHandler (i);
402+ mlir::Region *handler = &tryOp.getHandlerRegions ()[i];
353403 if (catchStmt->getExceptionDecl ()) {
354- cgm.errorNYI (" enterCXXTryStmt: CatchStmt with ExceptionDecl" );
355- return ;
356- }
404+ // FIXME: Dropping the reference type on the type into makes it
405+ // impossible to correctly implement catch-by-reference
406+ // semantics for pointers. Unfortunately, this is what all
407+ // existing compilers do, and it's not clear that the standard
408+ // personality routine is capable of doing this right. See C++ DR 388:
409+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
410+ Qualifiers caughtTypeQuals;
411+ QualType caughtType = cgm.getASTContext ().getUnqualifiedArrayType (
412+ catchStmt->getCaughtType ().getNonReferenceType (), caughtTypeQuals);
413+ if (caughtType->isObjCObjectPointerType ()) {
414+ cgm.errorNYI (" enterCXXTryStmt: caughtType ObjCObjectPointerType" );
415+ return ;
416+ }
357417
358- // No exception decl indicates '...', a catch-all.
359- mlir::Region *handler = &tryOp.getHandlerRegions ()[i];
360- catchScope->setHandler (i, cgm.getCXXABI ().getCatchAllTypeInfo (), handler,
361- s.getHandler (i));
418+ CatchTypeInfo typeInfo = cgm.getCXXABI ().getAddrOfCXXCatchHandlerType (
419+ getLoc (catchStmt->getSourceRange ()), caughtType,
420+ catchStmt->getCaughtType ());
421+ catchScope->setHandler (i, typeInfo, handler, catchStmt);
422+ } else {
423+ // No exception decl indicates '...', a catch-all.
424+ catchScope->setHandler (i, cgm.getCXXABI ().getCatchAllTypeInfo (), handler,
425+ s.getHandler (i));
426+ }
362427
363428 // Under async exceptions, catch(...) needs to catch HW exception too
364429 // Mark scope with SehTryBegin as a SEH __try scope
@@ -397,6 +462,9 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
397462 return ;
398463 }
399464
465+ // Emit the structure of the EH dispatch for this catch.
466+ emitCatchDispatchBlock (*this , catchScope, tryOp);
467+
400468 // Copy the handler blocks off before we pop the EH stack. Emitting
401469 // the handlers might scribble on this memory.
402470 SmallVector<EHCatchScope::Handler> handlers (catchScope.begin (),
@@ -442,9 +510,6 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
442510 emitStmt (catchStmt->getHandlerBlock (), /* useCurrentScope=*/ true );
443511 assert (emitResult.succeeded () && " failed to emit catch handler block" );
444512
445- assert (!cir::MissingFeatures::catchParamOp ());
446- cir::YieldOp::create (builder, tryOp->getLoc ());
447-
448513 // [except.handle]p11:
449514 // The currently handled exception is rethrown if control
450515 // reaches the end of a handler of the function-try-block of a
@@ -501,7 +566,8 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
501566 if (!handlerTypesAttr || handlerTypesAttr.empty ()) {
502567 // Accumulate all the handlers in scope.
503568 bool hasCatchAll = false ;
504- llvm::SmallVector<mlir::Attribute, 4 > handlerAttrs;
569+ llvm::SmallPtrSet<mlir::Attribute, 4 > catchTypes;
570+ llvm::SmallVector<mlir::Attribute> handlerAttrs;
505571 for (EHScopeStack::iterator i = ehStack.begin (), e = ehStack.end (); i != e;
506572 ++i) {
507573 switch (i->getKind ()) {
@@ -534,20 +600,25 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
534600 break ;
535601 }
536602
537- cgm.errorNYI (" emitLandingPad: non catch-all" );
538- return ;
603+ // Check whether we already have a handler for this type.
604+ // If not, keep track to later add to catch op.
605+ if (catchTypes.insert (handler.type .rtti ).second )
606+ handlerAttrs.push_back (handler.type .rtti );
539607 }
540608
541609 if (hasCatchAll)
542610 break ;
543611 }
544612
545- if (hasCatchAll) {
613+ if (hasCatchAll)
546614 handlerAttrs.push_back (cir::CatchAllAttr::get (&getMLIRContext ()));
547- } else {
548- cgm.errorNYI (" emitLandingPad: non catch-all" );
549- return ;
550- }
615+
616+ assert (!cir::MissingFeatures::ehScopeFilter ());
617+
618+ // If there's no catch_all, attach the unwind region. This needs to be the
619+ // last region in the TryOp catch list.
620+ if (!hasCatchAll)
621+ handlerAttrs.push_back (cir::UnwindAttr::get (&getMLIRContext ()));
551622
552623 // Add final array of clauses into TryOp.
553624 tryOp.setHandlerTypesAttr (
@@ -571,6 +642,13 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
571642 return ;
572643 }
573644
645+ // The dispatch block for the end of the scope chain is a block that
646+ // just resumes unwinding.
647+ if (scope == ehStack.stable_end ()) {
648+ populateUnwindResumeBlock (/* isCleanup=*/ true , tryOp);
649+ return ;
650+ }
651+
574652 // Otherwise, we should look at the actual scope.
575653 EHScope &ehScope = *ehStack.find (scope);
576654 bool mayThrow = ehScope.mayThrow ();
@@ -588,16 +666,19 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
588666 if (!mayThrow) {
589667 switch (ehScope.getKind ()) {
590668 case EHScope::Catch: {
669+ mayThrow = true ;
670+
591671 // LLVM does some optimization with branches here, CIR just keep track of
592672 // the corresponding calls.
593673 EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
594674 if (catchScope.getNumHandlers () == 1 &&
595675 catchScope.getHandler (0 ).isCatchAll ()) {
596- mayThrow = true ;
597676 break ;
598677 }
599- cgm.errorNYI (" getEHDispatchBlock: mayThrow non-catch all" );
600- return ;
678+
679+ // TODO(cir): In the incubator we create a new basic block with YieldOp
680+ // inside the attached cleanup region, but this part will be redesigned
681+ break ;
601682 }
602683 case EHScope::Cleanup: {
603684 cgm.errorNYI (" getEHDispatchBlock: mayThrow & cleanup" );
0 commit comments