653 lines · cpp
1//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This contains code dealing with C++ exception related code generation.10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenCXXABI.h"14#include "CIRGenFunction.h"15 16#include "clang/AST/StmtVisitor.h"17#include "clang/CIR/MissingFeatures.h"18#include "llvm/Support/SaveAndRestore.h"19 20using namespace clang;21using namespace clang::CIRGen;22 23const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};24const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",25 nullptr};26const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",27 nullptr};28const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",29 nullptr};30const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",31 nullptr};32const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = {33 "__gxx_personality_sj0", nullptr};34const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = {35 "__gxx_personality_seh0", nullptr};36const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",37 "objc_exception_throw"};38const EHPersonality EHPersonality::GNU_ObjC_SJLJ = {39 "__gnu_objc_personality_sj0", "objc_exception_throw"};40const EHPersonality EHPersonality::GNU_ObjC_SEH = {41 "__gnu_objc_personality_seh0", "objc_exception_throw"};42const EHPersonality EHPersonality::GNU_ObjCXX = {43 "__gnustep_objcxx_personality_v0", nullptr};44const EHPersonality EHPersonality::GNUstep_ObjC = {45 "__gnustep_objc_personality_v0", nullptr};46const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",47 nullptr};48const EHPersonality EHPersonality::MSVC_C_specific_handler = {49 "__C_specific_handler", nullptr};50const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = {51 "__CxxFrameHandler3", nullptr};52const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = {53 "__gxx_wasm_personality_v0", nullptr};54const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",55 nullptr};56const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",57 nullptr};58 59static const EHPersonality &getCPersonality(const TargetInfo &target,60 const CodeGenOptions &cgOpts) {61 const llvm::Triple &triple = target.getTriple();62 if (triple.isWindowsMSVCEnvironment())63 return EHPersonality::MSVC_CxxFrameHandler3;64 if (cgOpts.hasSjLjExceptions())65 return EHPersonality::GNU_C_SJLJ;66 if (cgOpts.hasDWARFExceptions())67 return EHPersonality::GNU_C;68 if (cgOpts.hasSEHExceptions())69 return EHPersonality::GNU_C_SEH;70 return EHPersonality::GNU_C;71}72 73static const EHPersonality &getObjCPersonality(const TargetInfo &target,74 const LangOptions &langOpts,75 const CodeGenOptions &cgOpts) {76 const llvm::Triple &triple = target.getTriple();77 if (triple.isWindowsMSVCEnvironment())78 return EHPersonality::MSVC_CxxFrameHandler3;79 80 switch (langOpts.ObjCRuntime.getKind()) {81 case ObjCRuntime::FragileMacOSX:82 return getCPersonality(target, cgOpts);83 case ObjCRuntime::MacOSX:84 case ObjCRuntime::iOS:85 case ObjCRuntime::WatchOS:86 return EHPersonality::NeXT_ObjC;87 case ObjCRuntime::GNUstep:88 if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))89 return EHPersonality::GNUstep_ObjC;90 [[fallthrough]];91 case ObjCRuntime::GCC:92 case ObjCRuntime::ObjFW:93 if (cgOpts.hasSjLjExceptions())94 return EHPersonality::GNU_ObjC_SJLJ;95 if (cgOpts.hasSEHExceptions())96 return EHPersonality::GNU_ObjC_SEH;97 return EHPersonality::GNU_ObjC;98 }99 llvm_unreachable("bad runtime kind");100}101 102static const EHPersonality &getCXXPersonality(const TargetInfo &target,103 const CodeGenOptions &cgOpts) {104 const llvm::Triple &triple = target.getTriple();105 if (triple.isWindowsMSVCEnvironment())106 return EHPersonality::MSVC_CxxFrameHandler3;107 if (triple.isOSAIX())108 return EHPersonality::XL_CPlusPlus;109 if (cgOpts.hasSjLjExceptions())110 return EHPersonality::GNU_CPlusPlus_SJLJ;111 if (cgOpts.hasDWARFExceptions())112 return EHPersonality::GNU_CPlusPlus;113 if (cgOpts.hasSEHExceptions())114 return EHPersonality::GNU_CPlusPlus_SEH;115 if (cgOpts.hasWasmExceptions())116 return EHPersonality::GNU_Wasm_CPlusPlus;117 return EHPersonality::GNU_CPlusPlus;118}119 120/// Determines the personality function to use when both C++121/// and Objective-C exceptions are being caught.122static const EHPersonality &getObjCXXPersonality(const TargetInfo &target,123 const LangOptions &langOpts,124 const CodeGenOptions &cgOpts) {125 if (target.getTriple().isWindowsMSVCEnvironment())126 return EHPersonality::MSVC_CxxFrameHandler3;127 128 switch (langOpts.ObjCRuntime.getKind()) {129 // In the fragile ABI, just use C++ exception handling and hope130 // they're not doing crazy exception mixing.131 case ObjCRuntime::FragileMacOSX:132 return getCXXPersonality(target, cgOpts);133 134 // The ObjC personality defers to the C++ personality for non-ObjC135 // handlers. Unlike the C++ case, we use the same personality136 // function on targets using (backend-driven) SJLJ EH.137 case ObjCRuntime::MacOSX:138 case ObjCRuntime::iOS:139 case ObjCRuntime::WatchOS:140 return getObjCPersonality(target, langOpts, cgOpts);141 142 case ObjCRuntime::GNUstep:143 return EHPersonality::GNU_ObjCXX;144 145 // The GCC runtime's personality function inherently doesn't support146 // mixed EH. Use the ObjC personality just to avoid returning null.147 case ObjCRuntime::GCC:148 case ObjCRuntime::ObjFW:149 return getObjCPersonality(target, langOpts, cgOpts);150 }151 llvm_unreachable("bad runtime kind");152}153 154static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {155 return triple.getArch() == llvm::Triple::x86156 ? EHPersonality::MSVC_except_handler157 : EHPersonality::MSVC_C_specific_handler;158}159 160const EHPersonality &EHPersonality::get(CIRGenModule &cgm,161 const FunctionDecl *fd) {162 const llvm::Triple &triple = cgm.getTarget().getTriple();163 const LangOptions &langOpts = cgm.getLangOpts();164 const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();165 const TargetInfo &target = cgm.getTarget();166 167 // Functions using SEH get an SEH personality.168 if (fd && fd->usesSEHTry())169 return getSEHPersonalityMSVC(triple);170 171 if (langOpts.ObjC) {172 return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)173 : getObjCPersonality(target, langOpts, cgOpts);174 }175 return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)176 : getCPersonality(target, cgOpts);177}178 179const EHPersonality &EHPersonality::get(CIRGenFunction &cgf) {180 const auto *fg = cgf.curCodeDecl;181 // For outlined finallys and filters, use the SEH personality in case they182 // contain more SEH. This mostly only affects finallys. Filters could183 // hypothetically use gnu statement expressions to sneak in nested SEH.184 fg = fg ? fg : cgf.curSEHParent.getDecl();185 return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));186}187 188void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {189 const llvm::Triple &triple = getTarget().getTriple();190 if (cgm.getLangOpts().OpenMPIsTargetDevice &&191 (triple.isNVPTX() || triple.isAMDGCN())) {192 cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");193 return;194 }195 196 if (const Expr *subExpr = e->getSubExpr()) {197 QualType throwType = subExpr->getType();198 if (throwType->isObjCObjectPointerType()) {199 cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");200 return;201 }202 203 cgm.getCXXABI().emitThrow(*this, e);204 return;205 }206 207 cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);208}209 210void CIRGenFunction::emitAnyExprToExn(const Expr *e, Address addr) {211 // Make sure the exception object is cleaned up if there's an212 // exception during initialization.213 assert(!cir::MissingFeatures::ehCleanupScope());214 215 // __cxa_allocate_exception returns a void*; we need to cast this216 // to the appropriate type for the object.217 mlir::Type ty = convertTypeForMem(e->getType());218 Address typedAddr = addr.withElementType(builder, ty);219 220 // From LLVM's codegen:221 // FIXME: this isn't quite right! If there's a final unelided call222 // to a copy constructor, then according to [except.terminate]p1 we223 // must call std::terminate() if that constructor throws, because224 // technically that copy occurs after the exception expression is225 // evaluated but before the exception is caught. But the best way226 // to handle that is to teach EmitAggExpr to do the final copy227 // differently if it can't be elided.228 emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),229 /*isInitializer=*/true);230 231 // Deactivate the cleanup block.232 assert(!cir::MissingFeatures::ehCleanupScope());233}234 235mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {236 if (s.getTryBlock()->body_empty())237 return mlir::LogicalResult::success();238 239 mlir::Location loc = getLoc(s.getSourceRange());240 // Create a scope to hold try local storage for catch params.241 242 mlir::OpBuilder::InsertPoint scopeIP;243 cir::ScopeOp::create(244 builder, loc,245 /*scopeBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {246 scopeIP = builder.saveInsertionPoint();247 });248 249 mlir::OpBuilder::InsertionGuard guard(builder);250 builder.restoreInsertionPoint(scopeIP);251 mlir::LogicalResult result = emitCXXTryStmtUnderScope(s);252 cir::YieldOp::create(builder, loc);253 return result;254}255 256mlir::LogicalResult257CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt &s) {258 const llvm::Triple &t = getTarget().getTriple();259 // If we encounter a try statement on in an OpenMP target region offloaded to260 // a GPU, we treat it as a basic block.261 const bool isTargetDevice =262 (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));263 if (isTargetDevice) {264 cgm.errorNYI(265 "emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU");266 return mlir::success();267 }268 269 unsigned numHandlers = s.getNumHandlers();270 mlir::Location tryLoc = getLoc(s.getBeginLoc());271 mlir::OpBuilder::InsertPoint beginInsertTryBody;272 273 bool hasCatchAll = false;274 for (unsigned i = 0; i != numHandlers; ++i) {275 hasCatchAll |= s.getHandler(i)->getExceptionDecl() == nullptr;276 if (hasCatchAll)277 break;278 }279 280 // Create the scope to represent only the C/C++ `try {}` part. However,281 // don't populate right away. Create regions for the catch handlers,282 // but don't emit the handler bodies yet. For now, only make sure the283 // scope returns the exception information.284 auto tryOp = cir::TryOp::create(285 builder, tryLoc,286 /*tryBuilder=*/287 [&](mlir::OpBuilder &b, mlir::Location loc) {288 beginInsertTryBody = builder.saveInsertionPoint();289 },290 /*handlersBuilder=*/291 [&](mlir::OpBuilder &b, mlir::Location loc,292 mlir::OperationState &result) {293 mlir::OpBuilder::InsertionGuard guard(b);294 295 // We create an extra region for an unwind catch handler in case the296 // catch-all handler doesn't exists297 unsigned numRegionsToCreate =298 hasCatchAll ? numHandlers : numHandlers + 1;299 300 for (unsigned i = 0; i != numRegionsToCreate; ++i) {301 mlir::Region *region = result.addRegion();302 builder.createBlock(region);303 }304 });305 306 // Finally emit the body for try/catch.307 {308 mlir::Location loc = tryOp.getLoc();309 mlir::OpBuilder::InsertionGuard guard(builder);310 builder.restoreInsertionPoint(beginInsertTryBody);311 CIRGenFunction::LexicalScope tryScope{*this, loc,312 builder.getInsertionBlock()};313 314 tryScope.setAsTry(tryOp);315 316 // Attach the basic blocks for the catch regions.317 enterCXXTryStmt(s, tryOp);318 319 // Emit the body for the `try {}` part.320 {321 mlir::OpBuilder::InsertionGuard guard(builder);322 CIRGenFunction::LexicalScope tryBodyScope{*this, loc,323 builder.getInsertionBlock()};324 if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())325 return mlir::failure();326 }327 328 // Emit catch clauses.329 exitCXXTryStmt(s);330 }331 332 return mlir::success();333}334 335void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,336 bool isFnTryBlock) {337 unsigned numHandlers = s.getNumHandlers();338 EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);339 for (unsigned i = 0; i != numHandlers; ++i) {340 const CXXCatchStmt *catchStmt = s.getHandler(i);341 if (catchStmt->getExceptionDecl()) {342 cgm.errorNYI("enterCXXTryStmt: CatchStmt with ExceptionDecl");343 return;344 }345 346 // No exception decl indicates '...', a catch-all.347 mlir::Region *handler = &tryOp.getHandlerRegions()[i];348 catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,349 s.getHandler(i));350 351 // Under async exceptions, catch(...) needs to catch HW exception too352 // Mark scope with SehTryBegin as a SEH __try scope353 if (getLangOpts().EHAsynch) {354 cgm.errorNYI("enterCXXTryStmt: EHAsynch");355 return;356 }357 }358}359 360void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {361 unsigned numHandlers = s.getNumHandlers();362 EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());363 assert(catchScope.getNumHandlers() == numHandlers);364 cir::TryOp tryOp = curLexScope->getTry();365 366 // If the catch was not required, bail out now.367 if (!catchScope.mayThrow()) {368 catchScope.clearHandlerBlocks();369 ehStack.popCatch();370 371 // Drop all basic block from all catch regions.372 SmallVector<mlir::Block *> eraseBlocks;373 for (mlir::Region &handlerRegion : tryOp.getHandlerRegions()) {374 if (handlerRegion.empty())375 continue;376 377 for (mlir::Block &b : handlerRegion.getBlocks())378 eraseBlocks.push_back(&b);379 }380 381 for (mlir::Block *b : eraseBlocks)382 b->erase();383 384 tryOp.setHandlerTypesAttr({});385 return;386 }387 388 // Copy the handler blocks off before we pop the EH stack. Emitting389 // the handlers might scribble on this memory.390 SmallVector<EHCatchScope::Handler> handlers(catchScope.begin(),391 catchScope.begin() + numHandlers);392 393 ehStack.popCatch();394 395 // Determine if we need an implicit rethrow for all these catch handlers;396 // see the comment below.397 bool doImplicitRethrow =398 isFnTryBlock && isa<CXXDestructorDecl, CXXConstructorDecl>(curCodeDecl);399 400 // Wasm uses Windows-style EH instructions, but merges all catch clauses into401 // one big catchpad. So we save the old funclet pad here before we traverse402 // each catch handler.403 if (EHPersonality::get(*this).isWasmPersonality()) {404 cgm.errorNYI("exitCXXTryStmt: WASM personality");405 return;406 }407 408 bool hasCatchAll = false;409 for (auto &handler : llvm::reverse(handlers)) {410 hasCatchAll |= handler.isCatchAll();411 mlir::Region *catchRegion = handler.region;412 const CXXCatchStmt *catchStmt = handler.stmt;413 414 mlir::OpBuilder::InsertionGuard guard(builder);415 builder.setInsertionPointToStart(&catchRegion->front());416 417 // Enter a cleanup scope, including the catch variable and the418 // end-catch.419 RunCleanupsScope catchScope(*this);420 421 // Initialize the catch variable and set up the cleanups.422 assert(!cir::MissingFeatures::catchParamOp());423 424 // Emit the PGO counter increment.425 assert(!cir::MissingFeatures::incrementProfileCounter());426 427 // Perform the body of the catch.428 [[maybe_unused]] mlir::LogicalResult emitResult =429 emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);430 assert(emitResult.succeeded() && "failed to emit catch handler block");431 432 assert(!cir::MissingFeatures::catchParamOp());433 cir::YieldOp::create(builder, tryOp->getLoc());434 435 // [except.handle]p11:436 // The currently handled exception is rethrown if control437 // reaches the end of a handler of the function-try-block of a438 // constructor or destructor.439 440 // It is important that we only do this on fallthrough and not on441 // return. Note that it's illegal to put a return in a442 // constructor function-try-block's catch handler (p14), so this443 // really only applies to destructors.444 if (doImplicitRethrow) {445 cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");446 return;447 }448 449 // Fall out through the catch cleanups.450 catchScope.forceCleanup();451 }452 453 // Because in wasm we merge all catch clauses into one big catchpad, in case454 // none of the types in catch handlers matches after we test against each of455 // them, we should unwind to the next EH enclosing scope. We generate a call456 // to rethrow function here to do that.457 if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {458 cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");459 }460 461 assert(!cir::MissingFeatures::incrementProfileCounter());462}463 464void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {465 assert(ehStack.requiresCatchOrCleanup());466 assert(!cgm.getLangOpts().IgnoreExceptions &&467 "LandingPad should not be emitted when -fignore-exceptions are in "468 "effect.");469 470 EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());471 switch (innermostEHScope.getKind()) {472 case EHScope::Terminate:473 cgm.errorNYI("populateCatchHandlers: terminate");474 return;475 476 case EHScope::Catch:477 case EHScope::Cleanup:478 case EHScope::Filter:479 // CIR does not cache landing pads.480 break;481 }482 483 // If there's an existing TryOp, it means we got a `cir.try` scope484 // that leads to this "landing pad" creation site. Otherwise, exceptions485 // are enabled but a throwing function is called anyways (common pattern486 // with function local static initializers).487 mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();488 if (!handlerTypesAttr || handlerTypesAttr.empty()) {489 // Accumulate all the handlers in scope.490 bool hasCatchAll = false;491 llvm::SmallVector<mlir::Attribute, 4> handlerAttrs;492 for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;493 ++i) {494 switch (i->getKind()) {495 case EHScope::Cleanup:496 cgm.errorNYI("emitLandingPad: Cleanup");497 return;498 499 case EHScope::Filter:500 cgm.errorNYI("emitLandingPad: Filter");501 return;502 503 case EHScope::Terminate:504 cgm.errorNYI("emitLandingPad: Terminate");505 return;506 507 case EHScope::Catch:508 break;509 } // end switch510 511 EHCatchScope &catchScope = cast<EHCatchScope>(*i);512 for (const EHCatchScope::Handler &handler :513 llvm::make_range(catchScope.begin(), catchScope.end())) {514 assert(handler.type.flags == 0 &&515 "landingpads do not support catch handler flags");516 517 // If this is a catch-all, register that and abort.518 if (handler.isCatchAll()) {519 assert(!hasCatchAll);520 hasCatchAll = true;521 break;522 }523 524 cgm.errorNYI("emitLandingPad: non catch-all");525 return;526 }527 528 if (hasCatchAll)529 break;530 }531 532 if (hasCatchAll) {533 handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));534 } else {535 cgm.errorNYI("emitLandingPad: non catch-all");536 return;537 }538 539 // Add final array of clauses into TryOp.540 tryOp.setHandlerTypesAttr(541 mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));542 }543 544 // In traditional LLVM codegen. this tells the backend how to generate the545 // landing pad by generating a branch to the dispatch block. In CIR,546 // this is used to populate blocks for later filing during547 // cleanup handling.548 populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);549}550 551// Differently from LLVM traditional codegen, there are no dispatch blocks552// to look at given cir.try_call does not jump to blocks like invoke does.553// However.554void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,555 cir::TryOp tryOp) {556 if (EHPersonality::get(*this).usesFuncletPads()) {557 cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");558 return;559 }560 561 // Otherwise, we should look at the actual scope.562 EHScope &ehScope = *ehStack.find(scope);563 bool mayThrow = ehScope.mayThrow();564 565 mlir::Block *originalBlock = nullptr;566 if (mayThrow && tryOp) {567 // If the dispatch is cached but comes from a different tryOp, make sure:568 // - Populate current `tryOp` with a new dispatch block regardless.569 // - Update the map to enqueue new dispatchBlock to also get a cleanup. See570 // code at the end of the function.571 cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");572 return;573 }574 575 if (!mayThrow) {576 switch (ehScope.getKind()) {577 case EHScope::Catch: {578 // LLVM does some optimization with branches here, CIR just keep track of579 // the corresponding calls.580 EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);581 if (catchScope.getNumHandlers() == 1 &&582 catchScope.getHandler(0).isCatchAll()) {583 mayThrow = true;584 break;585 }586 cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all");587 return;588 }589 case EHScope::Cleanup: {590 cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");591 return;592 }593 case EHScope::Filter: {594 cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");595 return;596 }597 case EHScope::Terminate: {598 cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");599 return;600 }601 }602 }603 604 if (originalBlock) {605 cgm.errorNYI("getEHDispatchBlock: originalBlock");606 return;607 }608 609 ehScope.setMayThrow(mayThrow);610}611 612// in classic codegen this function is mapping to `isInvokeDest` previously and613// currently it's mapping to the conditions that performs early returns in614// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may615// throw exception or now.616bool CIRGenFunction::isCatchOrCleanupRequired() {617 // If exceptions are disabled/ignored and SEH is not in use, then there is no618 // invoke destination. SEH "works" even if exceptions are off. In practice,619 // this means that C++ destructors and other EH cleanups don't run, which is620 // consistent with MSVC's behavior, except in the presence of -EHa621 const LangOptions &lo = cgm.getLangOpts();622 if (!lo.Exceptions || lo.IgnoreExceptions) {623 if (!lo.Borland && !lo.MicrosoftExt)624 return false;625 cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");626 return false;627 }628 629 // CUDA device code doesn't have exceptions.630 if (lo.CUDA && lo.CUDAIsDevice)631 return false;632 633 return ehStack.requiresCatchOrCleanup();634}635 636// In classic codegen this function is equivalent to `getInvokeDestImpl`, in637// ClangIR we don't need to return to return any landing pad, we just need to638// populate the catch handlers if they are required639void CIRGenFunction::populateCatchHandlersIfRequired(cir::TryOp tryOp) {640 assert(ehStack.requiresCatchOrCleanup());641 assert(!ehStack.empty());642 643 assert(!cir::MissingFeatures::setFunctionPersonality());644 645 // CIR does not cache landing pads.646 const EHPersonality &personality = EHPersonality::get(*this);647 if (personality.usesFuncletPads()) {648 cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");649 } else {650 populateCatchHandlers(tryOp);651 }652}653