Author: Amr Hesham
Date: 2025-11-16T10:50:04+01:00
New Revision: 3d01d6ebfd23d57f4f860a3bf7a462c0c506295b

URL: 
https://github.com/llvm/llvm-project/commit/3d01d6ebfd23d57f4f860a3bf7a462c0c506295b
DIFF: 
https://github.com/llvm/llvm-project/commit/3d01d6ebfd23d57f4f860a3bf7a462c0c506295b.diff

LOG: [CIR] Upstream non-empty Try block with catch all (#165158)

Upstream support for try block and catch all block with a function call
that may throw an exception.

Issue https://github.com/llvm/llvm-project/issues/154992

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

Modified: 
    clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
    clang/include/clang/CIR/MissingFeatures.h
    clang/lib/CIR/CodeGen/CIRGenCall.cpp
    clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
    clang/lib/CIR/CodeGen/CIRGenCleanup.h
    clang/lib/CIR/CodeGen/CIRGenException.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/EHScopeStack.h

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 6c7e3d055456a..737ceac80635b 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -389,25 +389,6 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return createCallOp(loc, callee, cir::VoidType(), operands, attrs);
   }
 
-  cir::CallOp createTryCallOp(
-      mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
-      mlir::Type returnType = cir::VoidType(),
-      mlir::ValueRange operands = mlir::ValueRange(),
-      [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
-    assert(!cir::MissingFeatures::opCallCallConv());
-    assert(!cir::MissingFeatures::opCallSideEffect());
-    return createCallOp(loc, callee, returnType, operands);
-  }
-
-  cir::CallOp createTryCallOp(
-      mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands,
-      [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
-    assert(!cir::MissingFeatures::opCallCallConv());
-    assert(!cir::MissingFeatures::opCallSideEffect());
-    return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
-                           callee.getFunctionType().getReturnType(), operands);
-  }
-
   
//===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
   
//===--------------------------------------------------------------------===//

diff  --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 567c79a27c07b..d93ee2675b366 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -94,6 +94,7 @@ struct MissingFeatures {
   static bool opFuncNoReturn() { return false; }
   static bool setFunctionAttributes() { return false; }
   static bool setLLVMFunctionFEnvAttributes() { return false; }
+  static bool setFunctionPersonality() { return false; }
 
   // CallOp handling
   static bool opCallAggregateArgs() { return false; }
@@ -334,6 +335,9 @@ struct MissingFeatures {
   static bool vtableRelativeLayout() { return false; }
   static bool weakRefReference() { return false; }
   static bool writebacks() { return false; }
+  static bool msvcCXXPersonality() { return false; }
+  static bool functionUsesSEHTry() { return false; }
+  static bool nothrowAttr() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
@@ -349,7 +353,6 @@ struct MissingFeatures {
   static bool awaitOp() { return false; }
   static bool callOp() { return false; }
   static bool ifOp() { return false; }
-  static bool invokeOp() { return false; }
   static bool labelOp() { return false; }
   static bool ptrDiffOp() { return false; }
   static bool llvmLoweringPtrDiffConsidersPointee() { return false; }
@@ -359,6 +362,7 @@ struct MissingFeatures {
   static bool tryOp() { return false; }
   static bool vecTernaryOp() { return false; }
   static bool zextOp() { return false; }
+  static bool catchParamOp() { return false; }
 
   // Future CIR attributes
   static bool optInfoAttr() { return false; }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 50d4c035d30a1..17f0c6dbab35c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -465,12 +465,47 @@ static cir::CIRCallOpInterface
 emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
                cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
                cir::FuncOp directFuncOp,
-               const SmallVectorImpl<mlir::Value> &cirCallArgs,
+               const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
                const mlir::NamedAttrList &attrs) {
   CIRGenBuilderTy &builder = cgf.getBuilder();
 
   assert(!cir::MissingFeatures::opCallSurroundingTry());
-  assert(!cir::MissingFeatures::invokeOp());
+
+  if (isInvoke) {
+    // This call may throw and requires catch and/or cleanup handling.
+    // If this call does not appear within the `try` region of an existing
+    // TryOp, we must create a synthetic TryOp to contain the call. This
+    // happens when a call that may throw appears within a cleanup
+    // scope.
+
+    // In OG, we build the landing pad for this scope. In CIR, we emit a
+    // synthetic cir.try because this didn't come from code generating from a
+    // try/catch in C++.
+    assert(cgf.curLexScope && "expected scope");
+    cir::TryOp tryOp = cgf.curLexScope->getClosestTryParent();
+    if (!tryOp) {
+      cgf.cgm.errorNYI(
+          "emitCallLikeOp: call does not have an associated cir.try");
+      return {};
+    }
+
+    if (tryOp.getSynthetic()) {
+      cgf.cgm.errorNYI("emitCallLikeOp: tryOp synthetic");
+      return {};
+    }
+
+    cir::CallOp callOpWithExceptions;
+    if (indirectFuncTy) {
+      cgf.cgm.errorNYI("emitCallLikeOp: indirect function type");
+      return {};
+    }
+
+    callOpWithExceptions =
+        builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
+
+    cgf.populateCatchHandlersIfRequired(tryOp);
+    return callOpWithExceptions;
+  }
 
   assert(builder.getInsertionBlock() && "expected valid basic block");
 
@@ -601,8 +636,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo 
&funcInfo,
   assert(!cir::MissingFeatures::opCallAttrs());
   cgm.constructAttributeList(callee.getAbstractInfo(), attrs);
 
-  assert(!cir::MissingFeatures::invokeOp());
-
   cir::FuncType indirectFuncTy;
   mlir::Value indirectFuncVal;
   cir::FuncOp directFuncOp;
@@ -628,10 +661,17 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo 
&funcInfo,
     indirectFuncVal = calleePtr->getResult(0);
   }
 
+  assert(!cir::MissingFeatures::msvcCXXPersonality());
+  assert(!cir::MissingFeatures::functionUsesSEHTry());
+  assert(!cir::MissingFeatures::nothrowAttr());
+
+  bool cannotThrow = attrs.getNamed("nothrow").has_value();
+  bool isInvoke = !cannotThrow && isCatchOrCleanupRequired();
+
   mlir::Location callLoc = loc;
   cir::CIRCallOpInterface theCall =
       emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
-                     cirCallArgs, attrs);
+                     cirCallArgs, isInvoke, attrs);
 
   if (callOp)
     *callOp = theCall;

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 437db306f3369..33f2de9137514 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -188,9 +188,22 @@ void EHScopeStack::popCleanup() {
   }
 }
 
+bool EHScopeStack::requiresCatchOrCleanup() const {
+  for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
+    if (auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si))) {
+      if (cleanup->isLifetimeMarker()) {
+        // Skip lifetime markers and continue from the enclosing EH scope
+        assert(!cir::MissingFeatures::emitLifetimeMarkers());
+        continue;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
 EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
   char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
-  assert(!cir::MissingFeatures::innermostEHScope());
   EHCatchScope *scope =
       new (buffer) EHCatchScope(numHandlers, innermostEHScope);
   innermostEHScope = stable_begin();

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index a035d792ef6d1..9cc2556c05967 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -18,6 +18,7 @@
 #include "CIRGenModule.h"
 #include "EHScopeStack.h"
 #include "mlir/IR/Value.h"
+#include "clang/AST/StmtCXX.h"
 
 namespace clang::CIRGen {
 
@@ -38,6 +39,8 @@ class EHScope {
   };
   enum { NumCommonBits = 3 };
 
+  bool scopeMayThrow;
+
 protected:
   class CatchBitFields {
     friend class EHCatchScope;
@@ -92,10 +95,11 @@ class EHScope {
     // Traditional LLVM codegen also checks for `!block->use_empty()`, but
     // in CIRGen the block content is not important, just used as a way to
     // signal `hasEHBranches`.
-    assert(!cir::MissingFeatures::ehstackBranches());
-    return false;
+    return scopeMayThrow;
   }
 
+  void setMayThrow(bool mayThrow) { scopeMayThrow = mayThrow; }
+
   EHScopeStack::stable_iterator getEnclosingEHScope() const {
     return enclosingEHScope;
   }
@@ -121,6 +125,9 @@ class EHCatchScope : public EHScope {
     /// The catch handler for this type.
     mlir::Region *region;
 
+    /// The catch handler stmt.
+    const CXXCatchStmt *stmt;
+
     bool isCatchAll() const { return type.rtti == nullptr; }
   };
 
@@ -147,10 +154,13 @@ class EHCatchScope : public EHScope {
 
   unsigned getNumHandlers() const { return catchBits.numHandlers; }
 
-  void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region) {
+  void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region,
+                  const CXXCatchStmt *stmt) {
     assert(i < getNumHandlers());
-    getHandlers()[i].type = type;
-    getHandlers()[i].region = region;
+    Handler *handler = &getHandlers()[i];
+    handler->type = type;
+    handler->region = region;
+    handler->stmt = stmt;
   }
 
   const Handler &getHandler(unsigned i) const {
@@ -231,6 +241,8 @@ class alignas(EHScopeStack::ScopeStackAlignment) 
EHCleanupScope
   bool isActive() const { return cleanupBits.isActive; }
   void setActive(bool isActive) { cleanupBits.isActive = isActive; }
 
+  bool isLifetimeMarker() const { return cleanupBits.isLifetimeMarker; }
+
   unsigned getFixupDepth() const { return fixupDepth; }
   EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
     return enclosingNormal;

diff  --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 67f46ffde8fda..765f593fe0184 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -14,6 +14,8 @@
 #include "CIRGenFunction.h"
 
 #include "clang/AST/StmtVisitor.h"
+#include "clang/CIR/MissingFeatures.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 using namespace clang;
 using namespace clang::CIRGen;
@@ -343,7 +345,8 @@ void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, 
cir::TryOp tryOp,
 
     // No exception decl indicates '...', a catch-all.
     mlir::Region *handler = &tryOp.getHandlerRegions()[i];
-    catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler);
+    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
@@ -382,5 +385,268 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
     return;
   }
 
-  cgm.errorNYI("exitCXXTryStmt: Required catch");
+  // Copy the handler blocks off before we pop the EH stack.  Emitting
+  // the handlers might scribble on this memory.
+  SmallVector<EHCatchScope::Handler> handlers(catchScope.begin(),
+                                              catchScope.begin() + 
numHandlers);
+
+  ehStack.popCatch();
+
+  // Determine if we need an implicit rethrow for all these catch handlers;
+  // see the comment below.
+  bool doImplicitRethrow =
+      isFnTryBlock && isa<CXXDestructorDecl, CXXConstructorDecl>(curCodeDecl);
+
+  // Wasm uses Windows-style EH instructions, but merges all catch clauses into
+  // one big catchpad. So we save the old funclet pad here before we traverse
+  // each catch handler.
+  if (EHPersonality::get(*this).isWasmPersonality()) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality");
+    return;
+  }
+
+  bool hasCatchAll = false;
+  for (auto &handler : llvm::reverse(handlers)) {
+    hasCatchAll |= handler.isCatchAll();
+    mlir::Region *catchRegion = handler.region;
+    const CXXCatchStmt *catchStmt = handler.stmt;
+
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToStart(&catchRegion->front());
+
+    // Enter a cleanup scope, including the catch variable and the
+    // end-catch.
+    RunCleanupsScope catchScope(*this);
+
+    // Initialize the catch variable and set up the cleanups.
+    assert(!cir::MissingFeatures::catchParamOp());
+
+    // Emit the PGO counter increment.
+    assert(!cir::MissingFeatures::incrementProfileCounter());
+
+    // Perform the body of the catch.
+    mlir::LogicalResult emitResult =
+        emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
+    assert(emitResult.succeeded() && "failed to emit catch handler block");
+
+    assert(!cir::MissingFeatures::catchParamOp());
+    cir::YieldOp::create(builder, tryOp->getLoc());
+
+    // [except.handle]p11:
+    //   The currently handled exception is rethrown if control
+    //   reaches the end of a handler of the function-try-block of a
+    //   constructor or destructor.
+
+    // It is important that we only do this on fallthrough and not on
+    // return.  Note that it's illegal to put a return in a
+    // constructor function-try-block's catch handler (p14), so this
+    // really only applies to destructors.
+    if (doImplicitRethrow) {
+      cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");
+      return;
+    }
+
+    // Fall out through the catch cleanups.
+    catchScope.forceCleanup();
+  }
+
+  // Because in wasm we merge all catch clauses into one big catchpad, in case
+  // none of the types in catch handlers matches after we test against each of
+  // them, we should unwind to the next EH enclosing scope. We generate a call
+  // to rethrow function here to do that.
+  if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");
+  }
+
+  assert(!cir::MissingFeatures::incrementProfileCounter());
+}
+
+void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
+  assert(ehStack.requiresCatchOrCleanup());
+  assert(!cgm.getLangOpts().IgnoreExceptions &&
+         "LandingPad should not be emitted when -fignore-exceptions are in "
+         "effect.");
+
+  EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());
+  switch (innermostEHScope.getKind()) {
+  case EHScope::Terminate:
+    cgm.errorNYI("populateCatchHandlers: terminate");
+    return;
+
+  case EHScope::Catch:
+  case EHScope::Cleanup:
+  case EHScope::Filter:
+    // CIR does not cache landing pads.
+    break;
+  }
+
+  // If there's an existing TryOp, it means we got a `cir.try` scope
+  // that leads to this "landing pad" creation site. Otherwise, exceptions
+  // are enabled but a throwing function is called anyways (common pattern
+  // with function local static initializers).
+  mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
+  if (!handlerTypesAttr || handlerTypesAttr.empty()) {
+    // Accumulate all the handlers in scope.
+    bool hasCatchAll = false;
+    llvm::SmallVector<mlir::Attribute, 4> handlerAttrs;
+    for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
+         ++i) {
+      switch (i->getKind()) {
+      case EHScope::Cleanup:
+        cgm.errorNYI("emitLandingPad: Cleanup");
+        return;
+
+      case EHScope::Filter:
+        cgm.errorNYI("emitLandingPad: Filter");
+        return;
+
+      case EHScope::Terminate:
+        cgm.errorNYI("emitLandingPad: Terminate");
+        return;
+
+      case EHScope::Catch:
+        break;
+      } // end switch
+
+      EHCatchScope &catchScope = cast<EHCatchScope>(*i);
+      for (const EHCatchScope::Handler &handler :
+           llvm::make_range(catchScope.begin(), catchScope.end())) {
+        assert(handler.type.flags == 0 &&
+               "landingpads do not support catch handler flags");
+
+        // If this is a catch-all, register that and abort.
+        if (handler.isCatchAll()) {
+          assert(!hasCatchAll);
+          hasCatchAll = true;
+          break;
+        }
+
+        cgm.errorNYI("emitLandingPad: non catch-all");
+        return;
+      }
+
+      if (hasCatchAll)
+        break;
+    }
+
+    if (hasCatchAll) {
+      handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
+    } else {
+      cgm.errorNYI("emitLandingPad: non catch-all");
+      return;
+    }
+
+    // Add final array of clauses into TryOp.
+    tryOp.setHandlerTypesAttr(
+        mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
+  }
+
+  // In traditional LLVM codegen. this tells the backend how to generate the
+  // landing pad by generating a branch to the dispatch block. In CIR,
+  // this is used to populate blocks for later filing during
+  // cleanup handling.
+  populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);
+}
+
+// Differently from LLVM traditional codegen, there are no dispatch blocks
+// to look at given cir.try_call does not jump to blocks like invoke does.
+// However.
+void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator 
scope,
+                                            cir::TryOp tryOp) {
+  if (EHPersonality::get(*this).usesFuncletPads()) {
+    cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
+    return;
+  }
+
+  // Otherwise, we should look at the actual scope.
+  EHScope &ehScope = *ehStack.find(scope);
+  bool mayThrow = ehScope.mayThrow();
+
+  mlir::Block *originalBlock = nullptr;
+  if (mayThrow && tryOp) {
+    // If the dispatch is cached but comes from a 
diff erent tryOp, make sure:
+    // - Populate current `tryOp` with a new dispatch block regardless.
+    // - Update the map to enqueue new dispatchBlock to also get a cleanup. See
+    // code at the end of the function.
+    cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");
+    return;
+  }
+
+  if (!mayThrow) {
+    switch (ehScope.getKind()) {
+    case EHScope::Catch: {
+      // LLVM does some optimization with branches here, CIR just keep track of
+      // the corresponding calls.
+      EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
+      if (catchScope.getNumHandlers() == 1 &&
+          catchScope.getHandler(0).isCatchAll()) {
+        mayThrow = true;
+        break;
+      }
+      cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all");
+      return;
+    }
+    case EHScope::Cleanup: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
+      return;
+    }
+    case EHScope::Filter: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");
+      return;
+    }
+    case EHScope::Terminate: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");
+      return;
+    }
+    }
+  }
+
+  if (originalBlock) {
+    cgm.errorNYI("getEHDispatchBlock: originalBlock");
+    return;
+  }
+
+  ehScope.setMayThrow(mayThrow);
+}
+
+// in classic codegen this function is mapping to `isInvokeDest` previously and
+// currently it's mapping to the conditions that performs early returns in
+// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope 
may
+// throw exception or now.
+bool CIRGenFunction::isCatchOrCleanupRequired() {
+  // If exceptions are disabled/ignored and SEH is not in use, then there is no
+  // invoke destination. SEH "works" even if exceptions are off. In practice,
+  // this means that C++ destructors and other EH cleanups don't run, which is
+  // consistent with MSVC's behavior, except in the presence of -EHa
+  const LangOptions &lo = cgm.getLangOpts();
+  if (!lo.Exceptions || lo.IgnoreExceptions) {
+    if (!lo.Borland && !lo.MicrosoftExt)
+      return false;
+    cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
+    return false;
+  }
+
+  // CUDA device code doesn't have exceptions.
+  if (lo.CUDA && lo.CUDAIsDevice)
+    return false;
+
+  return ehStack.requiresCatchOrCleanup();
+}
+
+// In classic codegen this function is equivalent to `getInvokeDestImpl`, in
+// ClangIR we don't need to return to return any landing pad, we just need to
+// populate the catch handlers if they are required
+void CIRGenFunction::populateCatchHandlersIfRequired(cir::TryOp tryOp) {
+  assert(ehStack.requiresCatchOrCleanup());
+  assert(!ehStack.empty());
+
+  assert(!cir::MissingFeatures::setFunctionPersonality());
+
+  // CIR does not cache landing pads.
+  const EHPersonality &personality = EHPersonality::get(*this);
+  if (personality.usesFuncletPads()) {
+    cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");
+  } else {
+    populateCatchHandlers(tryOp);
+  }
 }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 866fda3166f41..2739469d7202e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -412,6 +412,16 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
   (void)emitReturn(localScope->endLoc);
 }
 
+cir::TryOp CIRGenFunction::LexicalScope::getClosestTryParent() {
+  LexicalScope *scope = this;
+  while (scope) {
+    if (scope->isTry())
+      return scope->getTry();
+    scope = scope->parentScope;
+  }
+  return nullptr;
+}
+
 void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
                                    cir::FuncOp fn, cir::FuncType funcType,
                                    FunctionArgList args, SourceLocation loc,

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 00f289bcd1bb2..2dddf26981105 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -929,10 +929,16 @@ class CIRGenFunction : public CIRGenTypeCache {
     return false;
   }
 
+  void populateEHCatchRegions(EHScopeStack::stable_iterator scope,
+                              cir::TryOp tryOp);
+
   /// The cleanup depth enclosing all the cleanups associated with the
   /// parameters.
   EHScopeStack::stable_iterator prologueCleanupDepth;
 
+  bool isCatchOrCleanupRequired();
+  void populateCatchHandlersIfRequired(cir::TryOp tryOp);
+
   /// Takes the old cleanup stack size and emits the cleanup blocks
   /// that have been added.
   void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth);
@@ -1076,7 +1082,7 @@ class CIRGenFunction : public CIRGenTypeCache {
     bool isSwitch() { return scopeKind == Kind::Switch; }
     bool isTernary() { return scopeKind == Kind::Ternary; }
     bool isTry() { return scopeKind == Kind::Try; }
-
+    cir::TryOp getClosestTryParent();
     void setAsGlobalInit() { scopeKind = Kind::GlobalInit; }
     void setAsSwitch() { scopeKind = Kind::Switch; }
     void setAsTernary() { scopeKind = Kind::Ternary; }
@@ -1630,6 +1636,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md);
   void emitLambdaStaticInvokeBody(const CXXMethodDecl *md);
 
+  void populateCatchHandlers(cir::TryOp tryOp);
+
   mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);
 
   /// Emit code to compute the specified expression,

diff  --git a/clang/lib/CIR/CodeGen/EHScopeStack.h 
b/clang/lib/CIR/CodeGen/EHScopeStack.h
index 9005b0106b2a4..6455bd8a55c83 100644
--- a/clang/lib/CIR/CodeGen/EHScopeStack.h
+++ b/clang/lib/CIR/CodeGen/EHScopeStack.h
@@ -217,6 +217,8 @@ class EHScopeStack {
   /// Determines whether the exception-scopes stack is empty.
   bool empty() const { return startOfData == endOfBuffer; }
 
+  bool requiresCatchOrCleanup() const;
+
   /// Determines whether there are any normal cleanups on the stack.
   bool hasNormalCleanups() const {
     return innermostNormalCleanup != stable_end();

diff  --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
new file mode 100644
index 0000000000000..078447f844d9a
--- /dev/null
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+int division();
+
+void calling_division_inside_try_block() {
+  try {
+    division();
+  } catch (...) {
+  }
+}
+
+// CIR: cir.scope {
+// CIR:   cir.try {
+// CIR:       %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
+// CIR:       cir.yield
+// CIR:   } catch all {
+// CIR:       cir.yield
+// CIR:   }
+// CIR: }
+
+// OGCG:   %[[EXN_OBJ_ADDR:.*]] = alloca ptr, align 8
+// OGCG:   %[[EH_SELECTOR_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// OGCG:           to label %[[INVOKE_CONT:.*]] unwind label 
%[[LANDING_PAD:.*]]
+// OGCG: [[INVOKE_CONT]]:
+// OGCG:   br label %[[TRY_CONT:.*]]
+// OGCG: [[LANDING_PAD]]:
+// OGCG:   %[[LP:.*]] = landingpad { ptr, i32 }
+// OGCG:           catch ptr null
+// OGCG:   %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
+// OGCG:   store ptr %[[EXN_OBJ]], ptr %[[EXN_OBJ_ADDR]], align 8
+// OGCG:   %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
+// OGCG:   store i32 %[[EH_SELECTOR_VAL]], ptr %[[EH_SELECTOR_ADDR]], align 4
+// OGCG:   br label %[[CATCH:.*]]
+// OGCG: [[CATCH]]:
+// OGCG:   %[[EXN_OBJ:.*]] = load ptr, ptr %[[EXN_OBJ_ADDR]], align 8
+// OGCG:   %[[CATCH_BEGIN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ]])
+// OGCG:   call void @__cxa_end_catch()
+// OGCG:   br label %[[TRY_CONT]]
+// OGCG: [[TRY_CONT]]:
+// OGCG:   ret void


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to