@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
8181 void emitRethrow (CIRGenFunction &cgf, bool isNoReturn) override ;
8282 void emitThrow (CIRGenFunction &cgf, const CXXThrowExpr *e) override ;
8383
84+ void emitBeginCatch (CIRGenFunction &cgf,
85+ const CXXCatchStmt *catchStmt) override ;
86+
8487 bool useThunkForDtorVariant (const CXXDestructorDecl *dtor,
8588 CXXDtorType dt) const override {
8689 // Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,91 @@ Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
22662269 CharUnits finalAlignment = baseAlignment.alignmentAtOffset (cookieSize);
22672270 return Address (finalPtr, newPtr.getElementType (), finalAlignment);
22682271}
2272+
2273+ namespace {
2274+ // / From traditional LLVM, useful info for LLVM lowering support:
2275+ // / A cleanup to call __cxa_end_catch. In many cases, the caught
2276+ // / exception type lets us state definitively that the thrown exception
2277+ // / type does not have a destructor. In particular:
2278+ // / - Catch-alls tell us nothing, so we have to conservatively
2279+ // / assume that the thrown exception might have a destructor.
2280+ // / - Catches by reference behave according to their base types.
2281+ // / - Catches of non-record types will only trigger for exceptions
2282+ // / of non-record types, which never have destructors.
2283+ // / - Catches of record types can trigger for arbitrary subclasses
2284+ // / of the caught type, so we have to assume the actual thrown
2285+ // / exception type might have a throwing destructor, even if the
2286+ // / caught type's destructor is trivial or nothrow.
2287+ struct CallEndCatch final : EHScopeStack::Cleanup {
2288+ CallEndCatch (bool mightThrow) : mightThrow(mightThrow) {}
2289+ bool mightThrow;
2290+
2291+ void emit (CIRGenFunction &cgf, Flags flags) override {
2292+ if (!mightThrow) {
2293+ // Traditional LLVM codegen would emit a call to __cxa_end_catch
2294+ // here. For CIR, just let it pass since the cleanup is going
2295+ // to be emitted on a later pass when lowering the catch region.
2296+ // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
2297+ cir::YieldOp::create (cgf.getBuilder (), *cgf.currSrcLoc );
2298+ return ;
2299+ }
2300+
2301+ // Traditional LLVM codegen would emit a call to __cxa_end_catch
2302+ // here. For CIR, just let it pass since the cleanup is going
2303+ // to be emitted on a later pass when lowering the catch region.
2304+ // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
2305+ if (!cgf.getBuilder ().getBlock ()->mightHaveTerminator ())
2306+ cir::YieldOp::create (cgf.getBuilder (), *cgf.currSrcLoc );
2307+ }
2308+ };
2309+ } // namespace
2310+
2311+ static mlir::Value callBeginCatch (CIRGenFunction &cgf, mlir::Type paramTy,
2312+ bool endMightThrow) {
2313+
2314+ auto catchParam = cir::CatchParamOp::create (
2315+ cgf.getBuilder (), cgf.getBuilder ().getUnknownLoc (), paramTy);
2316+
2317+ cgf.ehStack .pushCleanup <CallEndCatch>(
2318+ NormalAndEHCleanup,
2319+ endMightThrow && !cgf.cgm .getLangOpts ().AssumeNothrowExceptionDtor );
2320+
2321+ return catchParam.getParam ();
2322+ }
2323+
2324+ // / Begins a catch statement by initializing the catch variable and
2325+ // / calling __cxa_begin_catch.
2326+ void CIRGenItaniumCXXABI::emitBeginCatch (CIRGenFunction &cgf,
2327+ const CXXCatchStmt *catchStmt) {
2328+ // We have to be very careful with the ordering of cleanups here:
2329+ // C++ [except.throw]p4:
2330+ // The destruction [of the exception temporary] occurs
2331+ // immediately after the destruction of the object declared in
2332+ // the exception-declaration in the handler.
2333+ //
2334+ // So the precise ordering is:
2335+ // 1. Construct catch variable.
2336+ // 2. __cxa_begin_catch
2337+ // 3. Enter __cxa_end_catch cleanup
2338+ // 4. Enter dtor cleanup
2339+ //
2340+ // We do this by using a slightly abnormal initialization process.
2341+ // Delegation sequence:
2342+ // - ExitCXXTryStmt opens a RunCleanupsScope
2343+ // - EmitAutoVarAlloca creates the variable and debug info
2344+ // - InitCatchParam initializes the variable from the exception
2345+ // - CallBeginCatch calls __cxa_begin_catch
2346+ // - CallBeginCatch enters the __cxa_end_catch cleanup
2347+ // - EmitAutoVarCleanups enters the variable destructor cleanup
2348+ // - EmitCXXTryStmt emits the code for the catch body
2349+ // - EmitCXXTryStmt close the RunCleanupsScope
2350+
2351+ VarDecl *catchParam = catchStmt->getExceptionDecl ();
2352+ if (!catchParam) {
2353+ callBeginCatch (cgf, cgf.getBuilder ().getVoidPtrTy (),
2354+ /* endMightThrow=*/ true );
2355+ return ;
2356+ }
2357+
2358+ cgf.cgm .errorNYI (" emitBeginCatch: catch with exception decl" );
2359+ }
0 commit comments