Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ struct MissingFeatures {

// Future CIR attributes
static bool optInfoAttr() { return false; }

// Maybe only needed for Windows exception handling
static bool currentFuncletPad() { return false; }
};

} // namespace cir
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ class CIRGenCXXABI {

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

virtual void emitBeginCatch(CIRGenFunction &cgf,
const CXXCatchStmt *catchStmt) = 0;

virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType ty) = 0;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
RunCleanupsScope catchScope(*this);

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

// Emit the PGO counter increment.
assert(!cir::MissingFeatures::incrementProfileCounter());
Expand Down
91 changes: 91 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;

void emitBeginCatch(CIRGenFunction &cgf,
const CXXCatchStmt *catchStmt) override;

bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const override {
// Itanium does not emit any destructor variant as an inline thunk.
Expand Down Expand Up @@ -2266,3 +2269,91 @@ Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
return Address(finalPtr, newPtr.getElementType(), finalAlignment);
}

namespace {
/// From traditional LLVM, useful info for LLVM lowering support:
/// A cleanup to call __cxa_end_catch. In many cases, the caught
/// exception type lets us state definitively that the thrown exception
/// type does not have a destructor. In particular:
/// - Catch-alls tell us nothing, so we have to conservatively
/// assume that the thrown exception might have a destructor.
/// - Catches by reference behave according to their base types.
/// - Catches of non-record types will only trigger for exceptions
/// of non-record types, which never have destructors.
/// - Catches of record types can trigger for arbitrary subclasses
/// of the caught type, so we have to assume the actual thrown
/// exception type might have a throwing destructor, even if the
/// caught type's destructor is trivial or nothrow.
struct CallEndCatch final : EHScopeStack::Cleanup {
CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
bool mightThrow;

void emit(CIRGenFunction &cgf, Flags flags) override {
if (!mightThrow) {
// Traditional LLVM codegen would emit a call to __cxa_end_catch
// here. For CIR, just let it pass since the cleanup is going
// to be emitted on a later pass when lowering the catch region.
// CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
return;
}

// Traditional LLVM codegen would emit a call to __cxa_end_catch
// here. For CIR, just let it pass since the cleanup is going
// to be emitted on a later pass when lowering the catch region.
// CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
if (!cgf.getBuilder().getBlock()->mightHaveTerminator())
cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
}
};
} // namespace

static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Type paramTy,
bool endMightThrow) {

auto catchParam = cir::CatchParamOp::create(
cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), paramTy);

cgf.ehStack.pushCleanup<CallEndCatch>(
NormalAndEHCleanup,
endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor);

return catchParam.getParam();
}

/// Begins a catch statement by initializing the catch variable and
/// calling __cxa_begin_catch.
void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
const CXXCatchStmt *catchStmt) {
// We have to be very careful with the ordering of cleanups here:
// C++ [except.throw]p4:
// The destruction [of the exception temporary] occurs
// immediately after the destruction of the object declared in
// the exception-declaration in the handler.
//
// So the precise ordering is:
// 1. Construct catch variable.
// 2. __cxa_begin_catch
// 3. Enter __cxa_end_catch cleanup
// 4. Enter dtor cleanup
//
// We do this by using a slightly abnormal initialization process.
// Delegation sequence:
// - ExitCXXTryStmt opens a RunCleanupsScope
// - EmitAutoVarAlloca creates the variable and debug info
// - InitCatchParam initializes the variable from the exception
// - CallBeginCatch calls __cxa_begin_catch
// - CallBeginCatch enters the __cxa_end_catch cleanup
// - EmitAutoVarCleanups enters the variable destructor cleanup
// - EmitCXXTryStmt emits the code for the catch body
// - EmitCXXTryStmt close the RunCleanupsScope

VarDecl *catchParam = catchStmt->getExceptionDecl();
if (!catchParam) {
callBeginCatch(cgf, cgf.getBuilder().getVoidPtrTy(),
/*endMightThrow=*/true);
return;
}

cgf.cgm.errorNYI("emitBeginCatch: catch with exception decl");
}
1 change: 1 addition & 0 deletions clang/test/CIR/CodeGen/try-catch-tmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void calling_division_inside_try_block() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
// CIR: cir.yield
// CIR: } catch all {
// CIR: %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!void>
// CIR: cir.yield
// CIR: }
// CIR: }
Expand Down