From 556f5abbcb0ccc9e313303fb83db56ba819ecbef Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Sat, 25 Oct 2025 21:17:00 +0200 Subject: [PATCH 1/5] [CIR] Upstream non-empty Try block with catch all --- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 48 +++- clang/lib/CIR/CodeGen/CIRGenCleanup.cpp | 10 +- clang/lib/CIR/CodeGen/CIRGenCleanup.h | 7 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 304 +++++++++++++++++++++- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 10 + clang/lib/CIR/CodeGen/CIRGenFunction.h | 17 +- clang/lib/CIR/CodeGen/EHScopeStack.h | 2 + clang/test/CIR/CodeGen/try-catch-tmp.cpp | 44 ++++ 8 files changed, 434 insertions(+), 8 deletions(-) create mode 100644 clang/test/CIR/CodeGen/try-catch-tmp.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 50d4c035d30a1..ea44c65636c6c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -465,12 +465,48 @@ static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, cir::FuncOp directFuncOp, - const SmallVectorImpl &cirCallArgs, + const SmallVectorImpl &cirCallArgs, bool isInvoke, const mlir::NamedAttrList &attrs) { CIRGenBuilderTy &builder = cgf.getBuilder(); assert(!cir::MissingFeatures::opCallSurroundingTry()); - assert(!cir::MissingFeatures::invokeOp()); + + if (isInvoke) { + // This call can throw, few options: + // - If this call does not have an associated cir.try, use the + // one provided by InvokeDest, + // - User written try/catch clauses require calls to handle + // exceptions under cir.try. + + // 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.createTryCallOp(callLoc, directFuncOp, cirCallArgs); + + (void)cgf.getInvokeDest(tryOp); + + return callOpWithExceptions; + } assert(builder.getInsertionBlock() && "expected valid basic block"); @@ -628,10 +664,16 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, indirectFuncVal = calleePtr->getResult(0); } + // TODO(cir): currentFunctionUsesSEHTry + // TODO(cir): check for MSVCXXPersonality + // TODO(cir): Create NoThrowAttr + bool cannotThrow = attrs.getNamed("nothrow").has_value(); + bool isInvoke = !cannotThrow && isInvokeDest(); + 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..3550a78cc1816 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp @@ -188,9 +188,17 @@ void EHScopeStack::popCleanup() { } } +bool EHScopeStack::requiresLandingPad() const { + for (stable_iterator si = getInnermostEHScope(); si != stable_end();) { + // TODO(cir): Skip lifetime markers. + assert(!cir::MissingFeatures::emitLifetimeMarkers()); + 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..4e4e913574991 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h @@ -38,6 +38,8 @@ class EHScope { }; enum { NumCommonBits = 3 }; + bool isScopeMayThrow; + protected: class CatchBitFields { friend class EHCatchScope; @@ -92,10 +94,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 isScopeMayThrow; } + void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; } + EHScopeStack::stable_iterator getEnclosingEHScope() const { return enclosingEHScope; } diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index 67f46ffde8fda..700e5e0c67c45 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -14,6 +14,7 @@ #include "CIRGenFunction.h" #include "clang/AST/StmtVisitor.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace clang::CIRGen; @@ -354,6 +355,33 @@ void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp, } } +/// 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: WASM personality"); + return; + } + + if (EHPersonality::get(cgf).usesFuncletPads()) { + cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads"); + return; + } + + assert(catchScope.mayThrow() && + "Expected catchScope that may throw exception"); + + // If there's only a single catch-all, getEHDispatchBlock returned + // that catch-all as the dispatch block. + if (catchScope.getNumHandlers() == 1 && + catchScope.getHandler(0).isCatchAll()) { + return; + } + + cgf.cgm.errorNYI("emitCatchDispatchBlock: non-catch all handler"); +} + void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { unsigned numHandlers = s.getNumHandlers(); EHCatchScope &catchScope = cast(*ehStack.begin()); @@ -382,5 +410,279 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { return; } - cgm.errorNYI("exitCXXTryStmt: Required catch"); + // Emit the structure of the EH dispatch for this catch. + emitCatchDispatchBlock(*this, catchScope, tryOp); + + // Copy the handler blocks off before we pop the EH stack. Emitting + // the handlers might scribble on this memory. + SmallVector 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(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 (unsigned i = numHandlers; i != 0; --i) { + hasCatchAll |= handlers[i - 1].isCatchAll(); + mlir::Region *catchRegion = handlers[i - 1].region; + + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToStart(&catchRegion->front()); + + const CXXCatchStmt *catchStmt = s.getHandler(i - 1); + + // Enter a cleanup scope, including the catch variable and the + // end-catch. + RunCleanupsScope catchScope(*this); + + // Initialize the catch variable and set up the cleanups. + // TODO: emitBeginCatch + + // 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"); + + // TODO(cir): This yeild should replaced by CatchParamOp once it upstreamed + 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()); +} + +mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { + assert(ehStack.requiresLandingPad()); + 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("emitLandingPad: 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 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; + } + + EHCatchScope &catchScope = cast(*i); + for (unsigned handlerIdx = 0, he = catchScope.getNumHandlers(); + handlerIdx != he; ++handlerIdx) { + EHCatchScope::Handler handler = catchScope.getHandler(handlerIdx); + 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; + goto done; + } + + cgm.errorNYI("emitLandingPad: non catch-all"); + return {}; + } + + goto done; + } + + done: + 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, + // getEHDispatchBlock is used to populate blocks for later filing during + // cleanup handling. + (void)getEHDispatchBlock(ehStack.getInnermostEHScope(), tryOp); + + return 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, we keep this around since other parts of CIRGen use +// getCachedEHDispatchBlock to infer state. +mlir::Block * +CIRGenFunction::getEHDispatchBlock(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 different 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(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); + return {}; +} + +bool CIRGenFunction::isInvokeDest() { + if (!ehStack.requiresLandingPad()) + return false; + + // 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) { + 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 true; +} + +mlir::Operation *CIRGenFunction::getInvokeDestImpl(cir::TryOp tryOp) { + assert(ehStack.requiresLandingPad()); + assert(!ehStack.empty()); + + // TODO(cir): add personality function + + // CIR does not cache landing pads. + const EHPersonality &personality = EHPersonality::get(*this); + + mlir::Operation *lp = nullptr; + if (personality.usesFuncletPads()) { + cgm.errorNYI("getInvokeDestImpl: usesFuncletPads"); + } else { + lp = emitLandingPad(tryOp); + } + + return lp; } 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..3fb6e115f946d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -929,10 +929,23 @@ class CIRGenFunction : public CIRGenTypeCache { return false; } + mlir::Block *getEHDispatchBlock(EHScopeStack::stable_iterator scope, + cir::TryOp tryOp); + /// The cleanup depth enclosing all the cleanups associated with the /// parameters. EHScopeStack::stable_iterator prologueCleanupDepth; + mlir::Operation *getInvokeDestImpl(cir::TryOp tryOp); + mlir::Operation *getInvokeDest(cir::TryOp tryOp) { + if (!ehStack.requiresLandingPad()) + return nullptr; + // Return the respective cir.try, this can be used to compute + // any other relevant information. + return getInvokeDestImpl(tryOp); + } + bool isInvokeDest(); + /// Takes the old cleanup stack size and emits the cleanup blocks /// that have been added. void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth); @@ -1076,7 +1089,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 +1643,8 @@ class CIRGenFunction : public CIRGenTypeCache { void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md); void emitLambdaStaticInvokeBody(const CXXMethodDecl *md); + mlir::Operation *emitLandingPad(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..699ef0b799c37 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 requiresLandingPad() 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 From df72bb6406de659e2ef01824effbaa658b605d42 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Wed, 5 Nov 2025 21:57:33 +0100 Subject: [PATCH 2/5] Address code review comments --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 19 ---- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 17 ++-- clang/lib/CIR/CodeGen/CIRGenCleanup.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenCleanup.h | 6 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 95 ++++++------------- clang/lib/CIR/CodeGen/CIRGenFunction.h | 17 +--- clang/lib/CIR/CodeGen/EHScopeStack.h | 2 +- 7 files changed, 46 insertions(+), 112 deletions(-) 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/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index ea44c65636c6c..d4633448010d4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -472,11 +472,11 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, assert(!cir::MissingFeatures::opCallSurroundingTry()); if (isInvoke) { - // This call can throw, few options: - // - If this call does not have an associated cir.try, use the - // one provided by InvokeDest, - // - User written try/catch clauses require calls to handle - // exceptions under cir.try. + // 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 @@ -501,10 +501,9 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, } callOpWithExceptions = - builder.createTryCallOp(callLoc, directFuncOp, cirCallArgs); - - (void)cgf.getInvokeDest(tryOp); + builder.createCallOp(callLoc, directFuncOp, cirCallArgs); + cgf.populateCatchHandlersIfRequired(tryOp); return callOpWithExceptions; } @@ -668,7 +667,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, // TODO(cir): check for MSVCXXPersonality // TODO(cir): Create NoThrowAttr bool cannotThrow = attrs.getNamed("nothrow").has_value(); - bool isInvoke = !cannotThrow && isInvokeDest(); + bool isInvoke = !cannotThrow && isCatchOrCleanupRequired(); mlir::Location callLoc = loc; cir::CIRCallOpInterface theCall = diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp index 3550a78cc1816..9be17ce3f431f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp @@ -188,7 +188,7 @@ void EHScopeStack::popCleanup() { } } -bool EHScopeStack::requiresLandingPad() const { +bool EHScopeStack::requiresCatchOrCleanup() const { for (stable_iterator si = getInnermostEHScope(); si != stable_end();) { // TODO(cir): Skip lifetime markers. assert(!cir::MissingFeatures::emitLifetimeMarkers()); diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h index 4e4e913574991..eec33aa5ad8d2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h @@ -38,7 +38,7 @@ class EHScope { }; enum { NumCommonBits = 3 }; - bool isScopeMayThrow; + bool scopeMayThrow; protected: class CatchBitFields { @@ -94,10 +94,10 @@ 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`. - return isScopeMayThrow; + return scopeMayThrow; } - void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; } + void setMayThrow(bool mayThrow) { scopeMayThrow = mayThrow; } EHScopeStack::stable_iterator getEnclosingEHScope() const { return enclosingEHScope; diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index 700e5e0c67c45..d5fb16ea58797 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -355,33 +355,6 @@ void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp, } } -/// 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: WASM personality"); - return; - } - - if (EHPersonality::get(cgf).usesFuncletPads()) { - cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads"); - return; - } - - assert(catchScope.mayThrow() && - "Expected catchScope that may throw exception"); - - // If there's only a single catch-all, getEHDispatchBlock returned - // that catch-all as the dispatch block. - if (catchScope.getNumHandlers() == 1 && - catchScope.getHandler(0).isCatchAll()) { - return; - } - - cgf.cgm.errorNYI("emitCatchDispatchBlock: non-catch all handler"); -} - void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { unsigned numHandlers = s.getNumHandlers(); EHCatchScope &catchScope = cast(*ehStack.begin()); @@ -410,9 +383,6 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { return; } - // Emit the structure of the EH dispatch for this catch. - emitCatchDispatchBlock(*this, catchScope, tryOp); - // Copy the handler blocks off before we pop the EH stack. Emitting // the handlers might scribble on this memory. SmallVector handlers( @@ -490,8 +460,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { assert(!cir::MissingFeatures::incrementProfileCounter()); } -mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { - assert(ehStack.requiresLandingPad()); +void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) { + assert(ehStack.requiresCatchOrCleanup()); assert(!cgm.getLangOpts().IgnoreExceptions && "LandingPad should not be emitted when -fignore-exceptions are in " "effect."); @@ -500,7 +470,7 @@ mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { switch (innermostEHScope.getKind()) { case EHScope::Terminate: cgm.errorNYI("emitLandingPad: terminate"); - return {}; + return; case EHScope::Catch: case EHScope::Cleanup: @@ -523,17 +493,17 @@ mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { switch (i->getKind()) { case EHScope::Cleanup: { cgm.errorNYI("emitLandingPad: Cleanup"); - return {}; + return; } case EHScope::Filter: { cgm.errorNYI("emitLandingPad: Filter"); - return {}; + return; } case EHScope::Terminate: { cgm.errorNYI("emitLandingPad: Terminate"); - return {}; + return; } case EHScope::Catch: @@ -551,22 +521,22 @@ mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { if (handler.isCatchAll()) { assert(!hasCatchAll); hasCatchAll = true; - goto done; + break; } cgm.errorNYI("emitLandingPad: non catch-all"); - return {}; + return; } - goto done; + if (hasCatchAll) + break; } - done: if (hasCatchAll) { handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext())); } else { cgm.errorNYI("emitLandingPad: non catch-all"); - return {}; + return; } // Add final array of clauses into TryOp. @@ -576,23 +546,19 @@ mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) { // In traditional LLVM codegen. this tells the backend how to generate the // landing pad by generating a branch to the dispatch block. In CIR, - // getEHDispatchBlock is used to populate blocks for later filing during + // this is used to populate blocks for later filing during // cleanup handling. - (void)getEHDispatchBlock(ehStack.getInnermostEHScope(), tryOp); - - return tryOp; + 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, we keep this around since other parts of CIRGen use -// getCachedEHDispatchBlock to infer state. -mlir::Block * -CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope, - cir::TryOp tryOp) { +// However. +void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope, + cir::TryOp tryOp) { if (EHPersonality::get(*this).usesFuncletPads()) { cgm.errorNYI("getEHDispatchBlock: usesFuncletPads"); - return {}; + return; } // Otherwise, we should look at the actual scope. @@ -606,7 +572,7 @@ CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope, // - 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 {}; + return; } if (!mayThrow) { @@ -621,34 +587,33 @@ CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope, break; } cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all"); - return {}; + return; } case EHScope::Cleanup: { cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup"); - return {}; + return; } case EHScope::Filter: { cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter"); - return {}; + return; } case EHScope::Terminate: { cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate"); - return {}; + return; } } } if (originalBlock) { cgm.errorNYI("getEHDispatchBlock: originalBlock"); - return {}; + return; } ehScope.setMayThrow(mayThrow); - return {}; } -bool CIRGenFunction::isInvokeDest() { - if (!ehStack.requiresLandingPad()) +bool CIRGenFunction::isCatchOrCleanupRequired() { + if (!ehStack.requiresCatchOrCleanup()) return false; // If exceptions are disabled/ignored and SEH is not in use, then there is no @@ -668,21 +633,17 @@ bool CIRGenFunction::isInvokeDest() { return true; } -mlir::Operation *CIRGenFunction::getInvokeDestImpl(cir::TryOp tryOp) { - assert(ehStack.requiresLandingPad()); +void CIRGenFunction::populateCatchHandlersIfRequired(cir::TryOp tryOp) { + assert(ehStack.requiresCatchOrCleanup()); assert(!ehStack.empty()); // TODO(cir): add personality function // CIR does not cache landing pads. const EHPersonality &personality = EHPersonality::get(*this); - - mlir::Operation *lp = nullptr; if (personality.usesFuncletPads()) { cgm.errorNYI("getInvokeDestImpl: usesFuncletPads"); } else { - lp = emitLandingPad(tryOp); + populateCatchHandlers(tryOp); } - - return lp; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 3fb6e115f946d..2dddf26981105 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -929,22 +929,15 @@ class CIRGenFunction : public CIRGenTypeCache { return false; } - mlir::Block *getEHDispatchBlock(EHScopeStack::stable_iterator scope, - cir::TryOp tryOp); + void populateEHCatchRegions(EHScopeStack::stable_iterator scope, + cir::TryOp tryOp); /// The cleanup depth enclosing all the cleanups associated with the /// parameters. EHScopeStack::stable_iterator prologueCleanupDepth; - mlir::Operation *getInvokeDestImpl(cir::TryOp tryOp); - mlir::Operation *getInvokeDest(cir::TryOp tryOp) { - if (!ehStack.requiresLandingPad()) - return nullptr; - // Return the respective cir.try, this can be used to compute - // any other relevant information. - return getInvokeDestImpl(tryOp); - } - bool isInvokeDest(); + bool isCatchOrCleanupRequired(); + void populateCatchHandlersIfRequired(cir::TryOp tryOp); /// Takes the old cleanup stack size and emits the cleanup blocks /// that have been added. @@ -1643,7 +1636,7 @@ class CIRGenFunction : public CIRGenTypeCache { void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md); void emitLambdaStaticInvokeBody(const CXXMethodDecl *md); - mlir::Operation *emitLandingPad(cir::TryOp tryOp); + void populateCatchHandlers(cir::TryOp tryOp); mlir::LogicalResult emitIfStmt(const clang::IfStmt &s); diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h b/clang/lib/CIR/CodeGen/EHScopeStack.h index 699ef0b799c37..6455bd8a55c83 100644 --- a/clang/lib/CIR/CodeGen/EHScopeStack.h +++ b/clang/lib/CIR/CodeGen/EHScopeStack.h @@ -217,7 +217,7 @@ class EHScopeStack { /// Determines whether the exception-scopes stack is empty. bool empty() const { return startOfData == endOfBuffer; } - bool requiresLandingPad() const; + bool requiresCatchOrCleanup() const; /// Determines whether there are any normal cleanups on the stack. bool hasNormalCleanups() const { From 7e06895abe6b0a2de627594d28d23dc0bb98d37f Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Sun, 9 Nov 2025 10:01:44 +0100 Subject: [PATCH 3/5] Address code review comments --- clang/include/clang/CIR/MissingFeatures.h | 2 +- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 2 -- clang/lib/CIR/CodeGen/CIRGenException.cpp | 9 ++++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 567c79a27c07b..b4d70171b7929 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; } @@ -349,7 +350,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; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index d4633448010d4..2712ce8bf792e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -636,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; diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index d5fb16ea58797..851ed34ec4ae6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -612,6 +612,10 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope, 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 (!ehStack.requiresCatchOrCleanup()) return false; @@ -633,11 +637,14 @@ bool CIRGenFunction::isCatchOrCleanupRequired() { return true; } +// 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()); - // TODO(cir): add personality function + assert(!cir::MissingFeatures::setFunctionPersonality()); // CIR does not cache landing pads. const EHPersonality &personality = EHPersonality::get(*this); From 90a4b02419cd46573cdcf2be6328a05b53100a73 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Sat, 15 Nov 2025 12:08:38 +0100 Subject: [PATCH 4/5] Address code review comments --- clang/include/clang/CIR/MissingFeatures.h | 4 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 7 +- clang/lib/CIR/CodeGen/CIRGenCleanup.cpp | 9 +- clang/lib/CIR/CodeGen/CIRGenCleanup.h | 15 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 46 ++- clang/lib/CodeGen/CGException.cpp | 377 +++++++++++----------- 6 files changed, 234 insertions(+), 224 deletions(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index b4d70171b7929..d93ee2675b366 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -335,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; } @@ -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 2712ce8bf792e..17f0c6dbab35c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -661,9 +661,10 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, indirectFuncVal = calleePtr->getResult(0); } - // TODO(cir): currentFunctionUsesSEHTry - // TODO(cir): check for MSVCXXPersonality - // TODO(cir): Create NoThrowAttr + assert(!cir::MissingFeatures::msvcCXXPersonality()); + assert(!cir::MissingFeatures::functionUsesSEHTry()); + assert(!cir::MissingFeatures::nothrowAttr()); + bool cannotThrow = attrs.getNamed("nothrow").has_value(); bool isInvoke = !cannotThrow && isCatchOrCleanupRequired(); diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp index 9be17ce3f431f..33f2de9137514 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp @@ -190,8 +190,13 @@ void EHScopeStack::popCleanup() { bool EHScopeStack::requiresCatchOrCleanup() const { for (stable_iterator si = getInnermostEHScope(); si != stable_end();) { - // TODO(cir): Skip lifetime markers. - assert(!cir::MissingFeatures::emitLifetimeMarkers()); + if (auto *cleanup = dyn_cast(&*find(si))) { + if (cleanup->isLifetimeMarker()) { + // Skip lifetime markers and continue from the enclosing EH scope + assert(!cir::MissingFeatures::emitLifetimeMarkers()); + continue; + } + } return true; } return false; diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h index eec33aa5ad8d2..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 { @@ -124,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; } }; @@ -150,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 { @@ -234,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 851ed34ec4ae6..765f593fe0184 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -14,6 +14,7 @@ #include "CIRGenFunction.h" #include "clang/AST/StmtVisitor.h" +#include "clang/CIR/MissingFeatures.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -344,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 @@ -385,8 +387,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { // Copy the handler blocks off before we pop the EH stack. Emitting // the handlers might scribble on this memory. - SmallVector handlers( - catchScope.begin(), catchScope.begin() + numHandlers); + SmallVector handlers(catchScope.begin(), + catchScope.begin() + numHandlers); ehStack.popCatch(); @@ -404,21 +406,20 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { } bool hasCatchAll = false; - for (unsigned i = numHandlers; i != 0; --i) { - hasCatchAll |= handlers[i - 1].isCatchAll(); - mlir::Region *catchRegion = handlers[i - 1].region; + 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()); - const CXXCatchStmt *catchStmt = s.getHandler(i - 1); - // Enter a cleanup scope, including the catch variable and the // end-catch. RunCleanupsScope catchScope(*this); // Initialize the catch variable and set up the cleanups. - // TODO: emitBeginCatch + assert(!cir::MissingFeatures::catchParamOp()); // Emit the PGO counter increment. assert(!cir::MissingFeatures::incrementProfileCounter()); @@ -428,7 +429,7 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) { emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true); assert(emitResult.succeeded() && "failed to emit catch handler block"); - // TODO(cir): This yeild should replaced by CatchParamOp once it upstreamed + assert(!cir::MissingFeatures::catchParamOp()); cir::YieldOp::create(builder, tryOp->getLoc()); // [except.handle]p11: @@ -469,7 +470,7 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) { EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope()); switch (innermostEHScope.getKind()) { case EHScope::Terminate: - cgm.errorNYI("emitLandingPad: terminate"); + cgm.errorNYI("populateCatchHandlers: terminate"); return; case EHScope::Catch: @@ -491,29 +492,25 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) { for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e; ++i) { switch (i->getKind()) { - case EHScope::Cleanup: { + case EHScope::Cleanup: cgm.errorNYI("emitLandingPad: Cleanup"); return; - } - case EHScope::Filter: { + case EHScope::Filter: cgm.errorNYI("emitLandingPad: Filter"); return; - } - case EHScope::Terminate: { + case EHScope::Terminate: cgm.errorNYI("emitLandingPad: Terminate"); return; - } case EHScope::Catch: break; - } + } // end switch EHCatchScope &catchScope = cast(*i); - for (unsigned handlerIdx = 0, he = catchScope.getNumHandlers(); - handlerIdx != he; ++handlerIdx) { - EHCatchScope::Handler handler = catchScope.getHandler(handlerIdx); + for (const EHCatchScope::Handler &handler : + llvm::make_range(catchScope.begin(), catchScope.end())) { assert(handler.type.flags == 0 && "landingpads do not support catch handler flags"); @@ -617,15 +614,14 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope, // `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may // throw exception or now. bool CIRGenFunction::isCatchOrCleanupRequired() { - if (!ehStack.requiresCatchOrCleanup()) - return false; - // 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; } @@ -634,7 +630,7 @@ bool CIRGenFunction::isCatchOrCleanupRequired() { if (lo.CUDA && lo.CUDAIsDevice) return false; - return true; + return ehStack.requiresCatchOrCleanup(); } // In classic codegen this function is equivalent to `getInvokeDestImpl`, in diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index f86af4581c345..5c0b9465272d9 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -34,7 +34,7 @@ static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) { // void __cxa_free_exception(void *thrown_exception); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } @@ -55,7 +55,7 @@ static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { // void __cxa_call_unexpected(void *thrown_exception); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } @@ -63,23 +63,19 @@ static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { llvm::FunctionCallee CodeGenModule::getTerminateFn() { // void __terminate(); - llvm::FunctionType *FTy = - llvm::FunctionType::get(VoidTy, /*isVarArg=*/false); + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, /*isVarArg=*/false); StringRef name; // In C++, use std::terminate(). - if (getLangOpts().CPlusPlus && - getTarget().getCXXABI().isItaniumFamily()) { + if (getLangOpts().CPlusPlus && getTarget().getCXXABI().isItaniumFamily()) { name = "_ZSt9terminatev"; - } else if (getLangOpts().CPlusPlus && - getTarget().getCXXABI().isMicrosoft()) { + } else if (getLangOpts().CPlusPlus && getTarget().getCXXABI().isMicrosoft()) { if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015)) name = "__std_terminate"; else name = "?terminate@@YAXXZ"; - } else if (getLangOpts().ObjC && - getLangOpts().ObjCRuntime.hasTerminate()) + } else if (getLangOpts().ObjC && getLangOpts().ObjCRuntime.hasTerminate()) name = "objc_terminate"; else name = "abort"; @@ -89,42 +85,42 @@ llvm::FunctionCallee CodeGenModule::getTerminateFn() { static llvm::FunctionCallee getCatchallRethrowFn(CodeGenModule &CGM, StringRef Name) { llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, Name); } -const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr }; -const EHPersonality -EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr }; -const EHPersonality -EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr }; -const EHPersonality -EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr }; -const EHPersonality -EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr }; -const EHPersonality -EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr }; -const EHPersonality -EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr }; -const EHPersonality -EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"}; -const EHPersonality -EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"}; -const EHPersonality -EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"}; -const EHPersonality -EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr }; -const EHPersonality -EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr }; -const EHPersonality -EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr }; -const EHPersonality -EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr }; -const EHPersonality -EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr }; -const EHPersonality -EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr }; +const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr}; +const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0", + nullptr}; +const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0", + nullptr}; +const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0", + nullptr}; +const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0", + nullptr}; +const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = { + "__gxx_personality_sj0", nullptr}; +const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = { + "__gxx_personality_seh0", nullptr}; +const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", + "objc_exception_throw"}; +const EHPersonality EHPersonality::GNU_ObjC_SJLJ = { + "__gnu_objc_personality_sj0", "objc_exception_throw"}; +const EHPersonality EHPersonality::GNU_ObjC_SEH = { + "__gnu_objc_personality_seh0", "objc_exception_throw"}; +const EHPersonality EHPersonality::GNU_ObjCXX = { + "__gnustep_objcxx_personality_v0", nullptr}; +const EHPersonality EHPersonality::GNUstep_ObjC = { + "__gnustep_objc_personality_v0", nullptr}; +const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3", + nullptr}; +const EHPersonality EHPersonality::MSVC_C_specific_handler = { + "__C_specific_handler", nullptr}; +const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = { + "__CxxFrameHandler3", nullptr}; +const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = { + "__gxx_wasm_personality_v0", nullptr}; const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1", nullptr}; const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2", @@ -270,8 +266,8 @@ static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM, llvm::AttributeList(), /*Local=*/true); } -static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, - const EHPersonality &Personality) { +static llvm::Constant * +getOpaquePersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); return cast(Fn.getCallee()); } @@ -292,10 +288,10 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { } else { // Check if any of the filter values have the ObjC prefix. llvm::Constant *CVal = cast(Val); - for (llvm::User::op_iterator - II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) { + for (llvm::User::op_iterator II = CVal->op_begin(), IE = CVal->op_end(); + II != IE; ++II) { if (llvm::GlobalVariable *GV = - cast((*II)->stripPointerCasts())) + cast((*II)->stripPointerCasts())) // ObjC EH selector entries are always global variables with // names starting like this. if (GV->getName().starts_with("OBJC_EHTYPE")) @@ -312,7 +308,8 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { for (llvm::User *U : Fn->users()) { // Conditionally white-list bitcasts. if (llvm::ConstantExpr *CE = dyn_cast(U)) { - if (CE->getOpcode() != llvm::Instruction::BitCast) return false; + if (CE->getOpcode() != llvm::Instruction::BitCast) + return false; if (!PersonalityHasOnlyCXXUses(CE)) return false; continue; @@ -320,7 +317,8 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { // Otherwise it must be a function. llvm::Function *F = dyn_cast(U); - if (!F) return false; + if (!F) + return false; for (llvm::BasicBlock &BB : *F) { if (BB.isLandingPad()) @@ -357,10 +355,12 @@ void CodeGenModule::SimplifyPersonality() { llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn); // Nothing to do if it's unused. - if (!Fn || Fn->use_empty()) return; + if (!Fn || Fn->use_empty()) + return; // Can't do the optimization if it has non-C++ uses. - if (!PersonalityHasOnlyCXXUses(Fn)) return; + if (!PersonalityHasOnlyCXXUses(Fn)) + return; // Create the C++ personality function and kill off the old // function. @@ -382,15 +382,15 @@ static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) { } namespace { - /// A cleanup to free the exception object if its initialization - /// throws. - struct FreeException final : EHScopeStack::Cleanup { - llvm::Value *exn; - FreeException(llvm::Value *exn) : exn(exn) {} - void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn); - } - }; +/// A cleanup to free the exception object if its initialization +/// throws. +struct FreeException final : EHScopeStack::Cleanup { + llvm::Value *exn; + FreeException(llvm::Value *exn) : exn(exn) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { + CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn); + } +}; } // end anonymous namespace // Emits an exception expression into the given location. This @@ -477,10 +477,10 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (!CGM.getLangOpts().CXXExceptions) return; - const FunctionDecl* FD = dyn_cast_or_null(D); + const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) { // Check if CapturedDecl is nothrow and create terminate scope for it. - if (const CapturedDecl* CD = dyn_cast_or_null(D)) { + if (const CapturedDecl *CD = dyn_cast_or_null(D)) { if (CD->isNothrow()) EHStack.pushTerminate(); } @@ -546,7 +546,8 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { static void emitFilterDispatchBlock(CodeGenFunction &CGF, EHFilterScope &filterScope) { llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock(); - if (!dispatchBlock) return; + if (!dispatchBlock) + return; if (dispatchBlock->use_empty()) { delete dispatchBlock; return; @@ -575,8 +576,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF, // according to the last landing pad the exception was thrown // into. Seriously. llvm::Value *exn = CGF.getExceptionFromSlot(); - CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn) - ->setDoesNotReturn(); + CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)->setDoesNotReturn(); CGF.Builder.CreateUnreachable(); } @@ -584,10 +584,10 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (!CGM.getLangOpts().CXXExceptions) return; - const FunctionDecl* FD = dyn_cast_or_null(D); + const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) { // Check if CapturedDecl is nothrow and pop terminate scope for it. - if (const CapturedDecl* CD = dyn_cast_or_null(D)) { + if (const CapturedDecl *CD = dyn_cast_or_null(D)) { if (CD->isNothrow() && !EHStack.empty()) EHStack.popTerminate(); } @@ -616,7 +616,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { emitFilterDispatchBlock(*this, filterScope); EHStack.popFilter(); } else if (Proto->canThrow() == CT_Cannot && - /* possible empty when under async exceptions */ + /* possible empty when under async exceptions */ !EHStack.empty()) { EHStack.popTerminate(); } @@ -695,7 +695,7 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { catchScope.getHandler(0).isCatchAll()) { dispatchBlock = catchScope.getHandler(0).Block; - // Otherwise, make a dispatch block. + // Otherwise, make a dispatch block. } else { dispatchBlock = createBasicBlock("catch.dispatch"); } @@ -798,7 +798,8 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { // Check the innermost scope for a cached landing pad. If this is // a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad. llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad(); - if (LP) return LP; + if (LP) + return LP; const EHPersonality &Personality = EHPersonality::get(*this); @@ -819,7 +820,8 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { // non-EH scope, cache the landing pad on the enclosing scope, too. for (EHScopeStack::iterator ir = EHStack.begin(); true; ++ir) { ir->setCachedLandingPad(LP); - if (!isNonEHScope(*ir)) break; + if (!isNonEHScope(*ir)) + break; } return LP; @@ -867,8 +869,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { bool hasCatchAll = false; bool hasCleanup = false; bool hasFilter = false; - SmallVector filterTypes; - llvm::SmallPtrSet catchTypes; + SmallVector filterTypes; + llvm::SmallPtrSet catchTypes; for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E; ++I) { @@ -922,23 +924,22 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { } } - done: +done: // If we have a catch-all, add null to the landingpad. assert(!(hasCatchAll && hasFilter)); if (hasCatchAll) { LPadInst->addClause(getCatchAllValue(*this)); - // If we have an EH filter, we need to add those handlers in the - // right place in the landingpad, which is to say, at the end. + // If we have an EH filter, we need to add those handlers in the + // right place in the landingpad, which is to say, at the end. } else if (hasFilter) { // Create a filter expression: a constant array indicating which filter // types there are. The personality routine only lands here if the filter // doesn't match. - SmallVector Filters; - llvm::ArrayType *AType = - llvm::ArrayType::get(!filterTypes.empty() ? - filterTypes[0]->getType() : Int8PtrTy, - filterTypes.size()); + SmallVector Filters; + llvm::ArrayType *AType = llvm::ArrayType::get( + !filterTypes.empty() ? filterTypes[0]->getType() : Int8PtrTy, + filterTypes.size()); for (llvm::Value *filterType : filterTypes) Filters.push_back(cast(filterType)); @@ -949,7 +950,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { if (hasCleanup) LPadInst->setCleanup(true); - // Otherwise, signal that we at least have cleanups. + // Otherwise, signal that we at least have cleanups. } else if (hasCleanup) { LPadInst->setCleanup(true); } @@ -1149,7 +1150,7 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, llvm::Value *selector = CGF.getSelectorFromSlot(); // Test against each of the exception types we claim to catch. - for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) { + for (unsigned i = 0, e = catchScope.getNumHandlers();; ++i) { assert(i < e && "ran off end of handlers!"); const EHCatchScope::Handler &handler = catchScope.getHandler(i); @@ -1172,13 +1173,13 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope()); nextIsEnd = true; - // If the next handler is a catch-all, we're at the end, and the - // next block is that handler. - } else if (catchScope.getHandler(i+1).isCatchAll()) { - nextBlock = catchScope.getHandler(i+1).Block; + // If the next handler is a catch-all, we're at the end, and the + // next block is that handler. + } else if (catchScope.getHandler(i + 1).isCatchAll()) { + nextBlock = catchScope.getHandler(i + 1).Block; nextIsEnd = true; - // Otherwise, we're not at the end and we need a new block. + // Otherwise, we're not at the end and we need a new block. } else { nextBlock = CGF.createBasicBlock("catch.fallthrough"); nextIsEnd = false; @@ -1186,11 +1187,11 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, // Figure out the catch type's index in the LSDA's type table. llvm::CallInst *typeIndex = - CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); + CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); typeIndex->setDoesNotThrow(); llvm::Value *matchesTypeIndex = - CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); + CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock); // If the next handler is a catch-all, we're completely done. @@ -1273,11 +1274,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { bool HasCatchAll = false; for (unsigned I = NumHandlers; I != 0; --I) { HasCatchAll |= Handlers[I - 1].isCatchAll(); - llvm::BasicBlock *CatchBlock = Handlers[I-1].Block; + llvm::BasicBlock *CatchBlock = Handlers[I - 1].Block; EmitBlockAfterUses(CatchBlock); // Catch the exception if this isn't a catch-all. - const CXXCatchStmt *C = S.getHandler(I-1); + const CXXCatchStmt *C = S.getHandler(I - 1); // Enter a cleanup scope, including the catch variable and the // end-catch. @@ -1303,7 +1304,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // constructor function-try-block's catch handler (p14), so this // really only applies to destructors. if (doImplicitRethrow && HaveInsertPoint()) { - CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false); + CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/ false); Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); } @@ -1344,96 +1345,93 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { } namespace { - struct CallEndCatchForFinally final : EHScopeStack::Cleanup { - llvm::Value *ForEHVar; - llvm::FunctionCallee EndCatchFn; - CallEndCatchForFinally(llvm::Value *ForEHVar, - llvm::FunctionCallee EndCatchFn) - : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} - - void Emit(CodeGenFunction &CGF, Flags flags) override { - llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); - llvm::BasicBlock *CleanupContBB = +struct CallEndCatchForFinally final : EHScopeStack::Cleanup { + llvm::Value *ForEHVar; + llvm::FunctionCallee EndCatchFn; + CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::FunctionCallee EndCatchFn) + : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} + + void Emit(CodeGenFunction &CGF, Flags flags) override { + llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); + llvm::BasicBlock *CleanupContBB = CGF.createBasicBlock("finally.cleanup.cont"); - llvm::Value *ShouldEndCatch = + llvm::Value *ShouldEndCatch = CGF.Builder.CreateFlagLoad(ForEHVar, "finally.endcatch"); - CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); - CGF.EmitBlock(EndCatchBB); - CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw - CGF.EmitBlock(CleanupContBB); - } - }; - - struct PerformFinally final : EHScopeStack::Cleanup { - const Stmt *Body; - llvm::Value *ForEHVar; - llvm::FunctionCallee EndCatchFn; - llvm::FunctionCallee RethrowFn; - llvm::Value *SavedExnVar; - - PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, - llvm::FunctionCallee EndCatchFn, - llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar) - : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), - RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} - - void Emit(CodeGenFunction &CGF, Flags flags) override { - // Enter a cleanup to call the end-catch function if one was provided. - if (EndCatchFn) - CGF.EHStack.pushCleanup(NormalAndEHCleanup, - ForEHVar, EndCatchFn); - - // Save the current cleanup destination in case there are - // cleanups in the finally block. - llvm::Value *SavedCleanupDest = - CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(), - "cleanup.dest.saved"); - - // Emit the finally block. - CGF.EmitStmt(Body); - - // If the end of the finally is reachable, check whether this was - // for EH. If so, rethrow. - if (CGF.HaveInsertPoint()) { - llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); - llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); - - llvm::Value *ShouldRethrow = - CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow"); - CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); - - CGF.EmitBlock(RethrowBB); - if (SavedExnVar) { - CGF.EmitRuntimeCallOrInvoke(RethrowFn, - CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, - CGF.getPointerAlign())); - } else { - CGF.EmitRuntimeCallOrInvoke(RethrowFn); - } - CGF.Builder.CreateUnreachable(); + CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); + CGF.EmitBlock(EndCatchBB); + CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw + CGF.EmitBlock(CleanupContBB); + } +}; - CGF.EmitBlock(ContBB); +struct PerformFinally final : EHScopeStack::Cleanup { + const Stmt *Body; + llvm::Value *ForEHVar; + llvm::FunctionCallee EndCatchFn; + llvm::FunctionCallee RethrowFn; + llvm::Value *SavedExnVar; + + PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, + llvm::FunctionCallee EndCatchFn, + llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar) + : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), + RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} + + void Emit(CodeGenFunction &CGF, Flags flags) override { + // Enter a cleanup to call the end-catch function if one was provided. + if (EndCatchFn) + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + ForEHVar, EndCatchFn); + + // Save the current cleanup destination in case there are + // cleanups in the finally block. + llvm::Value *SavedCleanupDest = CGF.Builder.CreateLoad( + CGF.getNormalCleanupDestSlot(), "cleanup.dest.saved"); + + // Emit the finally block. + CGF.EmitStmt(Body); + + // If the end of the finally is reachable, check whether this was + // for EH. If so, rethrow. + if (CGF.HaveInsertPoint()) { + llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); + llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); + + llvm::Value *ShouldRethrow = + CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow"); + CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); - // Restore the cleanup destination. - CGF.Builder.CreateStore(SavedCleanupDest, - CGF.getNormalCleanupDestSlot()); + CGF.EmitBlock(RethrowBB); + if (SavedExnVar) { + CGF.EmitRuntimeCallOrInvoke( + RethrowFn, CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, + CGF.getPointerAlign())); + } else { + CGF.EmitRuntimeCallOrInvoke(RethrowFn); } + CGF.Builder.CreateUnreachable(); - // Leave the end-catch cleanup. As an optimization, pretend that - // the fallthrough path was inaccessible; we've dynamically proven - // that we're not in the EH case along that path. - if (EndCatchFn) { - CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); - CGF.PopCleanupBlock(); - CGF.Builder.restoreIP(SavedIP); - } + CGF.EmitBlock(ContBB); - // Now make sure we actually have an insertion point or the - // cleanup gods will hate us. - CGF.EnsureInsertPoint(); + // Restore the cleanup destination. + CGF.Builder.CreateStore(SavedCleanupDest, CGF.getNormalCleanupDestSlot()); } - }; + + // Leave the end-catch cleanup. As an optimization, pretend that + // the fallthrough path was inaccessible; we've dynamically proven + // that we're not in the EH case along that path. + if (EndCatchFn) { + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); + CGF.PopCleanupBlock(); + CGF.Builder.restoreIP(SavedIP); + } + + // Now make sure we actually have an insertion point or the + // cleanup gods will hate us. + CGF.EnsureInsertPoint(); + } +}; } // end anonymous namespace /// Enters a finally block for an implementation using zero-cost @@ -1482,9 +1480,8 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF, const Stmt *body, CGF.Builder.CreateFlagStore(false, ForEHVar); // Enter a normal cleanup which will perform the @finally block. - CGF.EHStack.pushCleanup(NormalCleanup, body, - ForEHVar, endCatchFn, - rethrowFn, SavedExnVar); + CGF.EHStack.pushCleanup(NormalCleanup, body, ForEHVar, + endCatchFn, rethrowFn, SavedExnVar); // Enter a catch-all scope. llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall"); @@ -1516,7 +1513,8 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { // If we need to remember the exception pointer to rethrow later, do so. if (SavedExnVar) { - if (!exn) exn = CGF.getExceptionFromSlot(); + if (!exn) + exn = CGF.getExceptionFromSlot(); CGF.Builder.CreateAlignedStore(exn, SavedExnVar, CGF.getPointerAlign()); } @@ -1627,7 +1625,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() { } llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { - if (EHResumeBlock) return EHResumeBlock; + if (EHResumeBlock) + return EHResumeBlock; CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); @@ -1642,7 +1641,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { const char *RethrowName = Personality.CatchallRethrowFn; if (RethrowName != nullptr && !isCleanup) { EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName), - getExceptionFromSlot())->setDoesNotReturn(); + getExceptionFromSlot()) + ->setDoesNotReturn(); Builder.CreateUnreachable(); Builder.restoreIP(SavedIP); return EHResumeBlock; @@ -1711,7 +1711,7 @@ void CodeGenFunction::VolatilizeTryBlocks( LI->setVolatile(true); } else if (auto SI = dyn_cast(J)) { SI->setVolatile(true); - } else if (auto* MCI = dyn_cast(J)) { + } else if (auto *MCI = dyn_cast(J)) { MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1)); } } @@ -1787,9 +1787,7 @@ struct CaptureFinder : ConstStmtVisitor { : ParentCGF(ParentCGF), ParentThis(ParentThis) {} // Return true if we need to do any capturing work. - bool foundCaptures() { - return !Captures.empty() || SEHCodeSlot.isValid(); - } + bool foundCaptures() { return !Captures.empty() || SEHCodeSlot.isValid(); } void Visit(const Stmt *S) { // See if this is a capture, then recurse. @@ -1809,9 +1807,7 @@ struct CaptureFinder : ConstStmtVisitor { Captures.insert(D); } - void VisitCXXThisExpr(const CXXThisExpr *E) { - Captures.insert(ParentThis); - } + void VisitCXXThisExpr(const CXXThisExpr *E) { Captures.insert(ParentThis); } void VisitCallExpr(const CallExpr *E) { // We only need to add parent frame allocations for these builtins in x86. @@ -2057,7 +2053,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); + CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo); llvm::Function *Fn = llvm::Function::Create( @@ -2193,9 +2189,8 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // If the filter is known to evaluate to 1, then we can use the clause // "catch i8* null". We can't do this on x86 because the filter has to save // the exception code. - llvm::Constant *C = - ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(), - getContext().IntTy); + llvm::Constant *C = ConstantEmitter(*this).tryEmitAbstract( + Except->getFilterExpr(), getContext().IntTy); if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && C->isOneValue()) { CatchScope->setCatchAllHandler(0, createBasicBlock("__except")); From ee174c988a7431dc983cef24f999650cbdb9e7aa Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Sat, 15 Nov 2025 12:11:22 +0100 Subject: [PATCH 5/5] Revert CGException format --- clang/lib/CodeGen/CGException.cpp | 377 +++++++++++++++--------------- 1 file changed, 191 insertions(+), 186 deletions(-) diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 5c0b9465272d9..f86af4581c345 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -34,7 +34,7 @@ static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) { // void __cxa_free_exception(void *thrown_exception); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } @@ -55,7 +55,7 @@ static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { // void __cxa_call_unexpected(void *thrown_exception); llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } @@ -63,19 +63,23 @@ static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { llvm::FunctionCallee CodeGenModule::getTerminateFn() { // void __terminate(); - llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, /*isVarArg=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, /*isVarArg=*/false); StringRef name; // In C++, use std::terminate(). - if (getLangOpts().CPlusPlus && getTarget().getCXXABI().isItaniumFamily()) { + if (getLangOpts().CPlusPlus && + getTarget().getCXXABI().isItaniumFamily()) { name = "_ZSt9terminatev"; - } else if (getLangOpts().CPlusPlus && getTarget().getCXXABI().isMicrosoft()) { + } else if (getLangOpts().CPlusPlus && + getTarget().getCXXABI().isMicrosoft()) { if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015)) name = "__std_terminate"; else name = "?terminate@@YAXXZ"; - } else if (getLangOpts().ObjC && getLangOpts().ObjCRuntime.hasTerminate()) + } else if (getLangOpts().ObjC && + getLangOpts().ObjCRuntime.hasTerminate()) name = "objc_terminate"; else name = "abort"; @@ -85,42 +89,42 @@ llvm::FunctionCallee CodeGenModule::getTerminateFn() { static llvm::FunctionCallee getCatchallRethrowFn(CodeGenModule &CGM, StringRef Name) { llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, Name); } -const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr}; -const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0", - nullptr}; -const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0", - nullptr}; -const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0", - nullptr}; -const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0", - nullptr}; -const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = { - "__gxx_personality_sj0", nullptr}; -const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = { - "__gxx_personality_seh0", nullptr}; -const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", - "objc_exception_throw"}; -const EHPersonality EHPersonality::GNU_ObjC_SJLJ = { - "__gnu_objc_personality_sj0", "objc_exception_throw"}; -const EHPersonality EHPersonality::GNU_ObjC_SEH = { - "__gnu_objc_personality_seh0", "objc_exception_throw"}; -const EHPersonality EHPersonality::GNU_ObjCXX = { - "__gnustep_objcxx_personality_v0", nullptr}; -const EHPersonality EHPersonality::GNUstep_ObjC = { - "__gnustep_objc_personality_v0", nullptr}; -const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3", - nullptr}; -const EHPersonality EHPersonality::MSVC_C_specific_handler = { - "__C_specific_handler", nullptr}; -const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = { - "__CxxFrameHandler3", nullptr}; -const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = { - "__gxx_wasm_personality_v0", nullptr}; +const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr }; +const EHPersonality +EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr }; +const EHPersonality +EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr }; +const EHPersonality +EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr }; +const EHPersonality +EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr }; +const EHPersonality +EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr }; +const EHPersonality +EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr }; +const EHPersonality +EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"}; +const EHPersonality +EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"}; +const EHPersonality +EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"}; +const EHPersonality +EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr }; +const EHPersonality +EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr }; +const EHPersonality +EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr }; +const EHPersonality +EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr }; +const EHPersonality +EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr }; +const EHPersonality +EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr }; const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1", nullptr}; const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2", @@ -266,8 +270,8 @@ static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM, llvm::AttributeList(), /*Local=*/true); } -static llvm::Constant * -getOpaquePersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { +static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, + const EHPersonality &Personality) { llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); return cast(Fn.getCallee()); } @@ -288,10 +292,10 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { } else { // Check if any of the filter values have the ObjC prefix. llvm::Constant *CVal = cast(Val); - for (llvm::User::op_iterator II = CVal->op_begin(), IE = CVal->op_end(); - II != IE; ++II) { + for (llvm::User::op_iterator + II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) { if (llvm::GlobalVariable *GV = - cast((*II)->stripPointerCasts())) + cast((*II)->stripPointerCasts())) // ObjC EH selector entries are always global variables with // names starting like this. if (GV->getName().starts_with("OBJC_EHTYPE")) @@ -308,8 +312,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { for (llvm::User *U : Fn->users()) { // Conditionally white-list bitcasts. if (llvm::ConstantExpr *CE = dyn_cast(U)) { - if (CE->getOpcode() != llvm::Instruction::BitCast) - return false; + if (CE->getOpcode() != llvm::Instruction::BitCast) return false; if (!PersonalityHasOnlyCXXUses(CE)) return false; continue; @@ -317,8 +320,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { // Otherwise it must be a function. llvm::Function *F = dyn_cast(U); - if (!F) - return false; + if (!F) return false; for (llvm::BasicBlock &BB : *F) { if (BB.isLandingPad()) @@ -355,12 +357,10 @@ void CodeGenModule::SimplifyPersonality() { llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn); // Nothing to do if it's unused. - if (!Fn || Fn->use_empty()) - return; + if (!Fn || Fn->use_empty()) return; // Can't do the optimization if it has non-C++ uses. - if (!PersonalityHasOnlyCXXUses(Fn)) - return; + if (!PersonalityHasOnlyCXXUses(Fn)) return; // Create the C++ personality function and kill off the old // function. @@ -382,15 +382,15 @@ static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) { } namespace { -/// A cleanup to free the exception object if its initialization -/// throws. -struct FreeException final : EHScopeStack::Cleanup { - llvm::Value *exn; - FreeException(llvm::Value *exn) : exn(exn) {} - void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn); - } -}; + /// A cleanup to free the exception object if its initialization + /// throws. + struct FreeException final : EHScopeStack::Cleanup { + llvm::Value *exn; + FreeException(llvm::Value *exn) : exn(exn) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { + CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn); + } + }; } // end anonymous namespace // Emits an exception expression into the given location. This @@ -477,10 +477,10 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (!CGM.getLangOpts().CXXExceptions) return; - const FunctionDecl *FD = dyn_cast_or_null(D); + const FunctionDecl* FD = dyn_cast_or_null(D); if (!FD) { // Check if CapturedDecl is nothrow and create terminate scope for it. - if (const CapturedDecl *CD = dyn_cast_or_null(D)) { + if (const CapturedDecl* CD = dyn_cast_or_null(D)) { if (CD->isNothrow()) EHStack.pushTerminate(); } @@ -546,8 +546,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { static void emitFilterDispatchBlock(CodeGenFunction &CGF, EHFilterScope &filterScope) { llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock(); - if (!dispatchBlock) - return; + if (!dispatchBlock) return; if (dispatchBlock->use_empty()) { delete dispatchBlock; return; @@ -576,7 +575,8 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF, // according to the last landing pad the exception was thrown // into. Seriously. llvm::Value *exn = CGF.getExceptionFromSlot(); - CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)->setDoesNotReturn(); + CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn) + ->setDoesNotReturn(); CGF.Builder.CreateUnreachable(); } @@ -584,10 +584,10 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (!CGM.getLangOpts().CXXExceptions) return; - const FunctionDecl *FD = dyn_cast_or_null(D); + const FunctionDecl* FD = dyn_cast_or_null(D); if (!FD) { // Check if CapturedDecl is nothrow and pop terminate scope for it. - if (const CapturedDecl *CD = dyn_cast_or_null(D)) { + if (const CapturedDecl* CD = dyn_cast_or_null(D)) { if (CD->isNothrow() && !EHStack.empty()) EHStack.popTerminate(); } @@ -616,7 +616,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { emitFilterDispatchBlock(*this, filterScope); EHStack.popFilter(); } else if (Proto->canThrow() == CT_Cannot && - /* possible empty when under async exceptions */ + /* possible empty when under async exceptions */ !EHStack.empty()) { EHStack.popTerminate(); } @@ -695,7 +695,7 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { catchScope.getHandler(0).isCatchAll()) { dispatchBlock = catchScope.getHandler(0).Block; - // Otherwise, make a dispatch block. + // Otherwise, make a dispatch block. } else { dispatchBlock = createBasicBlock("catch.dispatch"); } @@ -798,8 +798,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { // Check the innermost scope for a cached landing pad. If this is // a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad. llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad(); - if (LP) - return LP; + if (LP) return LP; const EHPersonality &Personality = EHPersonality::get(*this); @@ -820,8 +819,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { // non-EH scope, cache the landing pad on the enclosing scope, too. for (EHScopeStack::iterator ir = EHStack.begin(); true; ++ir) { ir->setCachedLandingPad(LP); - if (!isNonEHScope(*ir)) - break; + if (!isNonEHScope(*ir)) break; } return LP; @@ -869,8 +867,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { bool hasCatchAll = false; bool hasCleanup = false; bool hasFilter = false; - SmallVector filterTypes; - llvm::SmallPtrSet catchTypes; + SmallVector filterTypes; + llvm::SmallPtrSet catchTypes; for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E; ++I) { @@ -924,22 +922,23 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { } } -done: + done: // If we have a catch-all, add null to the landingpad. assert(!(hasCatchAll && hasFilter)); if (hasCatchAll) { LPadInst->addClause(getCatchAllValue(*this)); - // If we have an EH filter, we need to add those handlers in the - // right place in the landingpad, which is to say, at the end. + // If we have an EH filter, we need to add those handlers in the + // right place in the landingpad, which is to say, at the end. } else if (hasFilter) { // Create a filter expression: a constant array indicating which filter // types there are. The personality routine only lands here if the filter // doesn't match. - SmallVector Filters; - llvm::ArrayType *AType = llvm::ArrayType::get( - !filterTypes.empty() ? filterTypes[0]->getType() : Int8PtrTy, - filterTypes.size()); + SmallVector Filters; + llvm::ArrayType *AType = + llvm::ArrayType::get(!filterTypes.empty() ? + filterTypes[0]->getType() : Int8PtrTy, + filterTypes.size()); for (llvm::Value *filterType : filterTypes) Filters.push_back(cast(filterType)); @@ -950,7 +949,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { if (hasCleanup) LPadInst->setCleanup(true); - // Otherwise, signal that we at least have cleanups. + // Otherwise, signal that we at least have cleanups. } else if (hasCleanup) { LPadInst->setCleanup(true); } @@ -1150,7 +1149,7 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, llvm::Value *selector = CGF.getSelectorFromSlot(); // Test against each of the exception types we claim to catch. - for (unsigned i = 0, e = catchScope.getNumHandlers();; ++i) { + for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) { assert(i < e && "ran off end of handlers!"); const EHCatchScope::Handler &handler = catchScope.getHandler(i); @@ -1173,13 +1172,13 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope()); nextIsEnd = true; - // If the next handler is a catch-all, we're at the end, and the - // next block is that handler. - } else if (catchScope.getHandler(i + 1).isCatchAll()) { - nextBlock = catchScope.getHandler(i + 1).Block; + // If the next handler is a catch-all, we're at the end, and the + // next block is that handler. + } else if (catchScope.getHandler(i+1).isCatchAll()) { + nextBlock = catchScope.getHandler(i+1).Block; nextIsEnd = true; - // Otherwise, we're not at the end and we need a new block. + // Otherwise, we're not at the end and we need a new block. } else { nextBlock = CGF.createBasicBlock("catch.fallthrough"); nextIsEnd = false; @@ -1187,11 +1186,11 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, // Figure out the catch type's index in the LSDA's type table. llvm::CallInst *typeIndex = - CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); + CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); typeIndex->setDoesNotThrow(); llvm::Value *matchesTypeIndex = - CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); + CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock); // If the next handler is a catch-all, we're completely done. @@ -1274,11 +1273,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { bool HasCatchAll = false; for (unsigned I = NumHandlers; I != 0; --I) { HasCatchAll |= Handlers[I - 1].isCatchAll(); - llvm::BasicBlock *CatchBlock = Handlers[I - 1].Block; + llvm::BasicBlock *CatchBlock = Handlers[I-1].Block; EmitBlockAfterUses(CatchBlock); // Catch the exception if this isn't a catch-all. - const CXXCatchStmt *C = S.getHandler(I - 1); + const CXXCatchStmt *C = S.getHandler(I-1); // Enter a cleanup scope, including the catch variable and the // end-catch. @@ -1304,7 +1303,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // constructor function-try-block's catch handler (p14), so this // really only applies to destructors. if (doImplicitRethrow && HaveInsertPoint()) { - CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/ false); + CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false); Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); } @@ -1345,93 +1344,96 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { } namespace { -struct CallEndCatchForFinally final : EHScopeStack::Cleanup { - llvm::Value *ForEHVar; - llvm::FunctionCallee EndCatchFn; - CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::FunctionCallee EndCatchFn) - : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} - - void Emit(CodeGenFunction &CGF, Flags flags) override { - llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); - llvm::BasicBlock *CleanupContBB = + struct CallEndCatchForFinally final : EHScopeStack::Cleanup { + llvm::Value *ForEHVar; + llvm::FunctionCallee EndCatchFn; + CallEndCatchForFinally(llvm::Value *ForEHVar, + llvm::FunctionCallee EndCatchFn) + : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} + + void Emit(CodeGenFunction &CGF, Flags flags) override { + llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); + llvm::BasicBlock *CleanupContBB = CGF.createBasicBlock("finally.cleanup.cont"); - llvm::Value *ShouldEndCatch = + llvm::Value *ShouldEndCatch = CGF.Builder.CreateFlagLoad(ForEHVar, "finally.endcatch"); - CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); - CGF.EmitBlock(EndCatchBB); - CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw - CGF.EmitBlock(CleanupContBB); - } -}; - -struct PerformFinally final : EHScopeStack::Cleanup { - const Stmt *Body; - llvm::Value *ForEHVar; - llvm::FunctionCallee EndCatchFn; - llvm::FunctionCallee RethrowFn; - llvm::Value *SavedExnVar; - - PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, - llvm::FunctionCallee EndCatchFn, - llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar) - : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), - RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} - - void Emit(CodeGenFunction &CGF, Flags flags) override { - // Enter a cleanup to call the end-catch function if one was provided. - if (EndCatchFn) - CGF.EHStack.pushCleanup(NormalAndEHCleanup, - ForEHVar, EndCatchFn); - - // Save the current cleanup destination in case there are - // cleanups in the finally block. - llvm::Value *SavedCleanupDest = CGF.Builder.CreateLoad( - CGF.getNormalCleanupDestSlot(), "cleanup.dest.saved"); - - // Emit the finally block. - CGF.EmitStmt(Body); - - // If the end of the finally is reachable, check whether this was - // for EH. If so, rethrow. - if (CGF.HaveInsertPoint()) { - llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); - llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); - - llvm::Value *ShouldRethrow = + CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); + CGF.EmitBlock(EndCatchBB); + CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw + CGF.EmitBlock(CleanupContBB); + } + }; + + struct PerformFinally final : EHScopeStack::Cleanup { + const Stmt *Body; + llvm::Value *ForEHVar; + llvm::FunctionCallee EndCatchFn; + llvm::FunctionCallee RethrowFn; + llvm::Value *SavedExnVar; + + PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, + llvm::FunctionCallee EndCatchFn, + llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar) + : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), + RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} + + void Emit(CodeGenFunction &CGF, Flags flags) override { + // Enter a cleanup to call the end-catch function if one was provided. + if (EndCatchFn) + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + ForEHVar, EndCatchFn); + + // Save the current cleanup destination in case there are + // cleanups in the finally block. + llvm::Value *SavedCleanupDest = + CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(), + "cleanup.dest.saved"); + + // Emit the finally block. + CGF.EmitStmt(Body); + + // If the end of the finally is reachable, check whether this was + // for EH. If so, rethrow. + if (CGF.HaveInsertPoint()) { + llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); + llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); + + llvm::Value *ShouldRethrow = CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow"); - CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); + CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); - CGF.EmitBlock(RethrowBB); - if (SavedExnVar) { - CGF.EmitRuntimeCallOrInvoke( - RethrowFn, CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, - CGF.getPointerAlign())); - } else { - CGF.EmitRuntimeCallOrInvoke(RethrowFn); - } - CGF.Builder.CreateUnreachable(); + CGF.EmitBlock(RethrowBB); + if (SavedExnVar) { + CGF.EmitRuntimeCallOrInvoke(RethrowFn, + CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, + CGF.getPointerAlign())); + } else { + CGF.EmitRuntimeCallOrInvoke(RethrowFn); + } + CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(ContBB); + CGF.EmitBlock(ContBB); - // Restore the cleanup destination. - CGF.Builder.CreateStore(SavedCleanupDest, CGF.getNormalCleanupDestSlot()); - } + // Restore the cleanup destination. + CGF.Builder.CreateStore(SavedCleanupDest, + CGF.getNormalCleanupDestSlot()); + } - // Leave the end-catch cleanup. As an optimization, pretend that - // the fallthrough path was inaccessible; we've dynamically proven - // that we're not in the EH case along that path. - if (EndCatchFn) { - CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); - CGF.PopCleanupBlock(); - CGF.Builder.restoreIP(SavedIP); - } + // Leave the end-catch cleanup. As an optimization, pretend that + // the fallthrough path was inaccessible; we've dynamically proven + // that we're not in the EH case along that path. + if (EndCatchFn) { + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); + CGF.PopCleanupBlock(); + CGF.Builder.restoreIP(SavedIP); + } - // Now make sure we actually have an insertion point or the - // cleanup gods will hate us. - CGF.EnsureInsertPoint(); - } -}; + // Now make sure we actually have an insertion point or the + // cleanup gods will hate us. + CGF.EnsureInsertPoint(); + } + }; } // end anonymous namespace /// Enters a finally block for an implementation using zero-cost @@ -1480,8 +1482,9 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF, const Stmt *body, CGF.Builder.CreateFlagStore(false, ForEHVar); // Enter a normal cleanup which will perform the @finally block. - CGF.EHStack.pushCleanup(NormalCleanup, body, ForEHVar, - endCatchFn, rethrowFn, SavedExnVar); + CGF.EHStack.pushCleanup(NormalCleanup, body, + ForEHVar, endCatchFn, + rethrowFn, SavedExnVar); // Enter a catch-all scope. llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall"); @@ -1513,8 +1516,7 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { // If we need to remember the exception pointer to rethrow later, do so. if (SavedExnVar) { - if (!exn) - exn = CGF.getExceptionFromSlot(); + if (!exn) exn = CGF.getExceptionFromSlot(); CGF.Builder.CreateAlignedStore(exn, SavedExnVar, CGF.getPointerAlign()); } @@ -1625,8 +1627,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() { } llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { - if (EHResumeBlock) - return EHResumeBlock; + if (EHResumeBlock) return EHResumeBlock; CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); @@ -1641,8 +1642,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { const char *RethrowName = Personality.CatchallRethrowFn; if (RethrowName != nullptr && !isCleanup) { EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName), - getExceptionFromSlot()) - ->setDoesNotReturn(); + getExceptionFromSlot())->setDoesNotReturn(); Builder.CreateUnreachable(); Builder.restoreIP(SavedIP); return EHResumeBlock; @@ -1711,7 +1711,7 @@ void CodeGenFunction::VolatilizeTryBlocks( LI->setVolatile(true); } else if (auto SI = dyn_cast(J)) { SI->setVolatile(true); - } else if (auto *MCI = dyn_cast(J)) { + } else if (auto* MCI = dyn_cast(J)) { MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1)); } } @@ -1787,7 +1787,9 @@ struct CaptureFinder : ConstStmtVisitor { : ParentCGF(ParentCGF), ParentThis(ParentThis) {} // Return true if we need to do any capturing work. - bool foundCaptures() { return !Captures.empty() || SEHCodeSlot.isValid(); } + bool foundCaptures() { + return !Captures.empty() || SEHCodeSlot.isValid(); + } void Visit(const Stmt *S) { // See if this is a capture, then recurse. @@ -1807,7 +1809,9 @@ struct CaptureFinder : ConstStmtVisitor { Captures.insert(D); } - void VisitCXXThisExpr(const CXXThisExpr *E) { Captures.insert(ParentThis); } + void VisitCXXThisExpr(const CXXThisExpr *E) { + Captures.insert(ParentThis); + } void VisitCallExpr(const CallExpr *E) { // We only need to add parent frame allocations for these builtins in x86. @@ -2053,7 +2057,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); + CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo); llvm::Function *Fn = llvm::Function::Create( @@ -2189,8 +2193,9 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // If the filter is known to evaluate to 1, then we can use the clause // "catch i8* null". We can't do this on x86 because the filter has to save // the exception code. - llvm::Constant *C = ConstantEmitter(*this).tryEmitAbstract( - Except->getFilterExpr(), getContext().IntTy); + llvm::Constant *C = + ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(), + getContext().IntTy); if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && C->isOneValue()) { CatchScope->setCatchAllHandler(0, createBasicBlock("__except"));