Skip to content

Commit 5160a05

Browse files
authored
[CIR] Emit CatchParamOp in the catch region (#171169)
Emit structured CatchParamOp in the catch region Issue #154992
1 parent 2d65bdb commit 5160a05

File tree

5 files changed

+100
-1
lines changed

5 files changed

+100
-1
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ struct MissingFeatures {
380380

381381
// Future CIR attributes
382382
static bool optInfoAttr() { return false; }
383+
384+
// Maybe only needed for Windows exception handling
385+
static bool currentFuncletPad() { return false; }
383386
};
384387

385388
} // namespace cir

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
126126

127127
virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
128128

129+
virtual void emitBeginCatch(CIRGenFunction &cgf,
130+
const CXXCatchStmt *catchStmt) = 0;
131+
129132
virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
130133
QualType ty) = 0;
131134

clang/lib/CIR/CodeGen/CIRGenException.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
419419
RunCleanupsScope catchScope(*this);
420420

421421
// Initialize the catch variable and set up the cleanups.
422-
assert(!cir::MissingFeatures::catchParamOp());
422+
assert(!cir::MissingFeatures::currentFuncletPad());
423+
cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
423424

424425
// Emit the PGO counter increment.
425426
assert(!cir::MissingFeatures::incrementProfileCounter());

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

clang/test/CIR/CodeGen/try-catch-tmp.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ void calling_division_inside_try_block() {
1717
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
1818
// CIR: cir.yield
1919
// CIR: } catch all {
20+
// CIR: %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!void>
2021
// CIR: cir.yield
2122
// CIR: }
2223
// CIR: }

0 commit comments

Comments
 (0)