[clang] [CIR] Simplify try-catch handling (PR #180857)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 10 23:58:39 PST 2026
================
@@ -280,224 +286,87 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
scopeIP = builder.saveInsertionPoint();
});
+ // Set personality function if not already set
+ auto funcOp = mlir::cast<cir::FuncOp>(curFn);
+ if (!funcOp.getPersonality())
+ funcOp.setPersonality(getPersonalityFn(cgm, EHPersonality::get(*this)));
+
mlir::OpBuilder::InsertionGuard guard(builder);
builder.restoreInsertionPoint(scopeIP);
- mlir::LogicalResult result = emitCXXTryStmtUnderScope(s);
- cir::YieldOp::create(builder, loc);
- return result;
-}
-mlir::LogicalResult
-CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt &s) {
const llvm::Triple &t = getTarget().getTriple();
// If we encounter a try statement on in an OpenMP target region offloaded to
// a GPU, we treat it as a basic block.
const bool isTargetDevice =
(cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
if (isTargetDevice) {
- cgm.errorNYI(
- "emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU");
+ cgm.errorNYI("emitCXXTryStmt: OpenMP target region offloaded to GPU");
return mlir::success();
}
- unsigned numHandlers = s.getNumHandlers();
mlir::Location tryLoc = getLoc(s.getBeginLoc());
- mlir::OpBuilder::InsertPoint beginInsertTryBody;
+ SmallVector<mlir::Attribute> handlerAttrs;
- bool hasCatchAll = false;
- for (unsigned i = 0; i != numHandlers; ++i) {
- hasCatchAll |= s.getHandler(i)->getExceptionDecl() == nullptr;
- if (hasCatchAll)
- break;
- }
+ CIRGenFunction::LexicalScope tryBodyScope{*this, tryLoc,
+ builder.getInsertionBlock()};
- // Create the scope to represent only the C/C++ `try {}` part. However,
- // don't populate right away. Create regions for the catch handlers,
- // but don't emit the handler bodies yet. For now, only make sure the
- // scope returns the exception information.
+ // Create the try operation.
+ mlir::LogicalResult tryRes = mlir::success();
auto tryOp = cir::TryOp::create(
builder, tryLoc,
/*tryBuilder=*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
- beginInsertTryBody = builder.saveInsertionPoint();
+ if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())
+ tryRes = mlir::failure();
+ cir::YieldOp::create(builder, loc);
},
/*handlersBuilder=*/
[&](mlir::OpBuilder &b, mlir::Location loc,
mlir::OperationState &result) {
mlir::OpBuilder::InsertionGuard guard(b);
-
- // We create an extra region for an unwind catch handler in case the
- // catch-all handler doesn't exists
- unsigned numRegionsToCreate =
- hasCatchAll ? numHandlers : numHandlers + 1;
-
- for (unsigned i = 0; i != numRegionsToCreate; ++i) {
+ bool hasCatchAll = false;
+ unsigned numHandlers = s.getNumHandlers();
+ for (unsigned i = 0; i != numHandlers; ++i) {
+ const CXXCatchStmt *catchStmt = s.getHandler(i);
+ if (!catchStmt->getExceptionDecl())
+ hasCatchAll = true;
+ mlir::Region *region = result.addRegion();
+ builder.createBlock(region);
+ addCatchHandlerAttr(region, catchStmt, handlerAttrs);
+ }
+ if (!hasCatchAll) {
+ // Create unwind region.
mlir::Region *region = result.addRegion();
builder.createBlock(region);
+ cir::ResumeOp::create(builder, loc);
+ handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
}
});
- // Finally emit the body for try/catch.
- {
- mlir::Location loc = tryOp.getLoc();
- mlir::OpBuilder::InsertionGuard guard(builder);
- builder.restoreInsertionPoint(beginInsertTryBody);
- CIRGenFunction::LexicalScope tryScope{*this, loc,
- builder.getInsertionBlock()};
-
- tryScope.setAsTry(tryOp);
-
- // Attach the basic blocks for the catch regions.
- enterCXXTryStmt(s, tryOp);
-
- // Emit the body for the `try {}` part.
- {
- mlir::OpBuilder::InsertionGuard guard(builder);
- CIRGenFunction::LexicalScope tryBodyScope{*this, loc,
- builder.getInsertionBlock()};
- if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())
- return mlir::failure();
- }
+ if (tryRes.failed())
+ return mlir::failure();
- // Emit catch clauses.
- exitCXXTryStmt(s);
- }
+ // Add final array of clauses into TryOp.
+ tryOp.setHandlerTypesAttr(
+ mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
- return mlir::success();
-}
-
-/// Emit the structure of the dispatch block for the given catch scope.
-/// It is an invariant that the dispatch block already exists.
-static void emitCatchDispatchBlock(CIRGenFunction &cgf,
- EHCatchScope &catchScope, cir::TryOp tryOp) {
- if (EHPersonality::get(cgf).isWasmPersonality()) {
- cgf.cgm.errorNYI("emitCatchDispatchBlock: WasmPersonality");
- return;
- }
-
- if (EHPersonality::get(cgf).usesFuncletPads()) {
- cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
- return;
- }
-
- assert(std::find_if(catchScope.begin(), catchScope.end(),
- [](const auto &handler) {
- return !handler.type.rtti && handler.type.flags != 0;
- }) == catchScope.end() &&
- "catch handler without type value or with not supported flags");
-
- // There was no catch all handler, populate th EH regions for the
- // enclosing scope.
- if (!std::prev(catchScope.end())->isCatchAll())
- cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
-}
-
-void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
- bool isFnTryBlock) {
+ // Emit the catch handler bodies. This has to be done after the try op is
+ // created and in place so that we can find the insertion point for the
+ // catch parameter alloca.
unsigned numHandlers = s.getNumHandlers();
- EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);
for (unsigned i = 0; i != numHandlers; ++i) {
const CXXCatchStmt *catchStmt = s.getHandler(i);
mlir::Region *handler = &tryOp.getHandlerRegions()[i];
- if (catchStmt->getExceptionDecl()) {
- // FIXME: Dropping the reference type on the type into makes it
- // impossible to correctly implement catch-by-reference
- // semantics for pointers. Unfortunately, this is what all
- // existing compilers do, and it's not clear that the standard
- // personality routine is capable of doing this right. See C++ DR 388:
- // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
- Qualifiers caughtTypeQuals;
- QualType caughtType = cgm.getASTContext().getUnqualifiedArrayType(
- catchStmt->getCaughtType().getNonReferenceType(), caughtTypeQuals);
- if (caughtType->isObjCObjectPointerType()) {
- cgm.errorNYI("enterCXXTryStmt: caughtType ObjCObjectPointerType");
- return;
- }
-
- CatchTypeInfo typeInfo = cgm.getCXXABI().getAddrOfCXXCatchHandlerType(
- getLoc(catchStmt->getSourceRange()), caughtType,
- catchStmt->getCaughtType());
- catchScope->setHandler(i, typeInfo, handler, catchStmt);
- } else {
- // No exception decl indicates '...', a catch-all.
- catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,
- s.getHandler(i));
- }
-
- // Under async exceptions, catch(...) needs to catch HW exception too
- // Mark scope with SehTryBegin as a SEH __try scope
- if (getLangOpts().EHAsynch) {
----------------
xlauko wrote:
This is no longer covered enywhere. I would expect we should still report `cgm.errorNYI("enterCXXTryStmt: EHAsynch")` somewhere?
https://github.com/llvm/llvm-project/pull/180857
More information about the cfe-commits
mailing list