https://github.com/adams381 created https://github.com/llvm/llvm-project/pull/229579
When a handler catches a reference to a pointer, __cxa_begin_catch returns the caught pointer by value instead of the address of the exception object, and how the reference is bound depends on whether the pointer points to a class. The CIR type of the catch parameter cannot always tell whether it is a reference to a pointer, or whether the pointee is a class. CIRGen now records both facts from the AST in two new InitCatchKind values, reference_to_pointer and reference_to_record_pointer. The Itanium EH lowering switches on the kind alone, the way classic codegen does. Assisted-by: Claude Code / Claude Opus 5.5 >From 4a44b71157e4fe58dc598b6cd415693ec5d4905d Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Tue, 6 Oct 2026 14:50:44 -0700 Subject: [PATCH] [CIR] Classify reference-to-pointer catch parameters in CIRGen When a handler catches a reference to a pointer, __cxa_begin_catch returns the caught pointer by value instead of the address of the exception object, and how the reference is bound depends on whether the pointer points to a class. The CIR type of the catch parameter cannot always tell whether it is a reference to a pointer, or whether the pointee is a class. CIRGen now records both facts from the AST in two new InitCatchKind values, reference_to_pointer and reference_to_record_pointer. The Itanium EH lowering switches on the kind alone, the way classic codegen does. Assisted-by: Claude Code / Claude Opus 5.5 --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 23 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 16 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 107 ++++++++ .../CIR/Dialect/Transforms/EHABILowering.cpp | 65 +++-- clang/test/CIR/CodeGen/try-catch.cpp | 206 +++++++++++++- clang/test/CIR/IR/construct-catch-param.cir | 173 ++++++++++++ .../CIR/IR/invalid-construct-catch-param.cir | 62 +++++ .../test/CIR/IR/invalid-init-catch-param.cir | 258 ++++++++++++++++++ .../eh-abi-lowering-catch-param-ref.cir | 216 +++++++++++++++ ...h-abi-lowering-construct-catch-invalid.cir | 88 +++++- 10 files changed, 1173 insertions(+), 41 deletions(-) create mode 100644 clang/test/CIR/IR/invalid-init-catch-param.cir create mode 100644 clang/test/CIR/Transforms/eh-abi-lowering-catch-param-ref.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 985cc3712c581d..e14ffdfdac3922 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -8700,6 +8700,7 @@ def CIR_TryOp : CIR_RegionBranchOpBase<"try", [ ]; let hasVerifier = 1; + let hasRegionVerifier = 1; let hasLLVMLowering = false; } @@ -9286,6 +9287,8 @@ def CIR_InitCatchKind : CIR_I32Enum< I32EnumCase<"Objc", 3, "objc">, I32EnumCase<"TrivialCopy", 4, "trivial_copy">, I32EnumCase<"NonTrivialCopy", 5, "non_trivial_copy">, + I32EnumCase<"ReferenceToPointer", 6, "reference_to_pointer">, + I32EnumCase<"ReferenceToRecordPointer", 7, "reference_to_record_pointer">, ]>; def CIR_InitCatchKindAttr : CIR_EnumAttr<CIR_InitCatchKind, "init_catch">; @@ -9304,6 +9307,16 @@ def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> { types, an aggregate copy for record types, or a call to a copy constructor when one is required). + A catch parameter that is a reference to a pointer uses the + `reference_to_record_pointer` kind when the pointer's source-level pointee + type is a record (class, struct, or union), and `reference_to_pointer` + otherwise. A reference to any other type uses `reference`. + + A `reference_to_pointer` or `non_trivial_copy` operation requires its catch + handler to start with a `cir.construct_catch_param` of the same kind on the + same parameter. When the handler starts with a `cir.construct_catch_param` + on the parameter of the operation, the two must have the same kind. + Example: ``` @@ -9326,6 +9339,7 @@ def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> { qualified(type($exn_ptr)) `,` qualified(type($param_addr)) attr-dict }]; + let hasVerifier = 1; let hasLLVMLowering = false; } @@ -9349,9 +9363,11 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [ copy of the object before `__cxa_begin_catch` is invoked. This operation takes a `!cir.eh_token` that represents the in-flight - exception and the alloca value that is used for the local copy of the - exception object. The `copy_fn` attribute is a flat symbol reference to a - `cir.func` thunk that copies the exception object to a local alloca value. + exception and the alloca value for the catch parameter. The optional + `copy_fn` attribute, present for `non_trivial_copy`, is a flat symbol + reference to a `cir.func` thunk that copies the exception object to a + local alloca value. For `reference_to_pointer`, the operation binds the + reference to the exception object itself. This operation is replaced with a target-specific representation during the EHABI lowering pass. For some targets, such as the Microsoft ABI, @@ -9377,6 +9393,7 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [ qualified(type($param_addr)) attr-dict }]; + let hasVerifier = 1; let hasLLVMLowering = false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index bd3e2014756e68..a2665798a37fd0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -512,16 +512,16 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder, CanQualType catchType = cgf.cgm.getASTContext().getCanonicalType(catchParam.getType()); cir::InitCatchKind kind; - bool shouldInitFromExnDirectly = false; - // If we're catching by reference, we can just cast the object - // pointer to the appropriate pointer. if (isa<ReferenceType>(catchType)) { QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType(); - if (const PointerType *ptr = dyn_cast<PointerType>(caughtType)) { - shouldInitFromExnDirectly = !ptr->getPointeeType()->isRecordType(); - } - kind = cir::InitCatchKind::Reference; + const PointerType *ptr = dyn_cast<PointerType>(caughtType); + if (!ptr) + kind = cir::InitCatchKind::Reference; + else if (ptr->getPointeeType()->isRecordType()) + kind = cir::InitCatchKind::ReferenceToRecordPointer; + else + kind = cir::InitCatchKind::ReferenceToPointer; } else { cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType); if (tek == cir::TEK_Aggregate) { @@ -555,7 +555,7 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder, mlir::Location mloc = cgf.getLoc(loc); if (kind == cir::InitCatchKind::NonTrivialCopy || - (kind == cir::InitCatchKind::Reference && shouldInitFromExnDirectly)) { + kind == cir::InitCatchKind::ReferenceToPointer) { // Sanitizer-checked construction (UBSan vptr/derived-class checks, etc.) // would require additional adornments that cir.construct_catch_param does // not yet carry. diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 51b5bd1c58f4bd..520565476cf7a4 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -4995,6 +4995,62 @@ void cir::TryOp::getSuccessorRegions( regions.push_back(mlir::RegionSuccessor(&handlerRegion)); } +/// Return the cir.construct_catch_param that starts the catch handler with +/// entry block \p entryBlock, or null if there is none. The handler must +/// already have passed cir::TryOp::verify. +static cir::ConstructCatchParamOp +getLeadingConstructCatchParam(mlir::Block &entryBlock) { + mlir::Operation *firstOp = &entryBlock.front(); + if (mlir::isa<cir::LifetimeStartOp>(firstOp)) { + auto lifetimeScope = + mlir::cast<cir::CleanupScopeOp>(firstOp->getNextNode()); + firstOp = &lifetimeScope.getBodyRegion().front().front(); + } + return mlir::dyn_cast<cir::ConstructCatchParamOp>(firstOp); +} + +/// Verify that each cir.init_catch_param in \p handlerRegion, outside any +/// nested cir.try, agrees with the handler's leading cir.construct_catch_param +/// \p constructOp, which may be null. A cir.init_catch_param of kind +/// reference_to_pointer or non_trivial_copy needs \p constructOp on its +/// parameter, and a cir.init_catch_param on the parameter of \p constructOp +/// must have the kind of \p constructOp. +static LogicalResult +verifyCatchParamPairing(mlir::Region &handlerRegion, + cir::ConstructCatchParamOp constructOp) { + mlir::WalkResult result = + handlerRegion.walk<mlir::WalkOrder::PreOrder>([&](mlir::Operation *op) { + if (mlir::isa<cir::TryOp>(op)) + return mlir::WalkResult::skip(); + auto initOp = mlir::dyn_cast<cir::InitCatchParamOp>(op); + if (!initOp) + return mlir::WalkResult::advance(); + + cir::InitCatchKind kind = initOp.getKind(); + bool sameParam = + constructOp && constructOp.getParamAddr() == initOp.getParamAddr(); + if (sameParam && constructOp.getKind() != kind) { + initOp.emitOpError("kind '") + << cir::stringifyInitCatchKind(kind) + << "' does not match the kind '" + << cir::stringifyInitCatchKind(constructOp.getKind()) + << "' of the preceding 'cir.construct_catch_param'"; + return mlir::WalkResult::interrupt(); + } + if ((kind == cir::InitCatchKind::ReferenceToPointer || + kind == cir::InitCatchKind::NonTrivialCopy) && + !sameParam) { + initOp.emitOpError("'") + << cir::stringifyInitCatchKind(kind) + << "' requires a preceding 'cir.construct_catch_param' of the " + "same kind on the same parameter"; + return mlir::WalkResult::interrupt(); + } + return mlir::WalkResult::advance(); + }); + return failure(result.wasInterrupted()); +} + LogicalResult cir::TryOp::verify() { mlir::ArrayAttr handlerTypes = getHandlerTypes(); if (!handlerTypes) { @@ -5098,6 +5154,26 @@ LogicalResult cir::TryOp::verify() { return success(); } +LogicalResult cir::TryOp::verifyRegions() { + mlir::ArrayAttr handlerTypes = getHandlerTypes(); + if (!handlerTypes) + return success(); + + for (const auto &[typeAttr, handlerRegion] : + llvm::zip(handlerTypes, getHandlerRegions())) { + if (mlir::isa<cir::UnwindAttr, cir::EhFilterAttr, cir::EhUnexpectedAttr>( + typeAttr)) + continue; + mlir::Block &entryBlock = handlerRegion.front(); + if (mlir::isa<cir::EhTerminateOp>(entryBlock.front())) + continue; + if (failed(verifyCatchParamPairing( + handlerRegion, getLeadingConstructCatchParam(entryBlock)))) + return failure(); + } + return success(); +} + static void printTryHandlerRegions(mlir::OpAsmPrinter &printer, cir::TryOp op, mlir::MutableArrayRef<mlir::Region> handlerRegions, @@ -5344,10 +5420,41 @@ LogicalResult cir::MemChrOp::verify() { cir::CIRDialect::getSizeTypeWidthAttrName()); } +//===----------------------------------------------------------------------===// +// InitCatchParamOp +//===----------------------------------------------------------------------===// + +/// For the reference_to_pointer and reference_to_record_pointer kinds, emit an +/// error on \p op unless \p paramAddrType is the type of the address of a +/// reference to a pointer. Any other \p kind is accepted. +static LogicalResult verifyCatchParamAddr(mlir::Operation *op, + cir::InitCatchKind kind, + cir::PointerType paramAddrType) { + if (kind != cir::InitCatchKind::ReferenceToPointer && + kind != cir::InitCatchKind::ReferenceToRecordPointer) + return success(); + + auto refType = mlir::dyn_cast<cir::PointerType>(paramAddrType.getPointee()); + if (!refType || !mlir::isa<cir::PointerType>(refType.getPointee())) + return op->emitOpError("'") + << cir::stringifyInitCatchKind(kind) + << "' requires 'param_addr' to be the address of a reference to a " + "pointer"; + return success(); +} + +LogicalResult cir::InitCatchParamOp::verify() { + return verifyCatchParamAddr(*this, getKind(), getParamAddr().getType()); +} + //===----------------------------------------------------------------------===// // ConstructCatchParamOp //===----------------------------------------------------------------------===// +LogicalResult cir::ConstructCatchParamOp::verify() { + return verifyCatchParamAddr(*this, getKind(), getParamAddr().getType()); +} + LogicalResult cir::ConstructCatchParamOp::verifySymbolUses( SymbolTableCollection &symbolTable) { auto copyFnAttr = getCopyFnAttr(); diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp index 77ce7434c8ed31..72a8cffc3b0606 100644 --- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp @@ -22,7 +22,9 @@ // - cir.resume → cir.resume.flat // - !cir.eh_token values → (!cir.ptr<!void>, !u32i) value pairs // - cir.construct_catch_param → __cxa_get_exception_ptr + inlined -// catch-copy thunk body +// catch-copy thunk body, or a store of the +// exception object address for +// reference_to_pointer // - personality function set on functions requiring EH // //===----------------------------------------------------------------------===// @@ -31,6 +33,7 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/IRMapping.h" #include "mlir/IR/PatternMatch.h" +#include "clang/CIR/Dialect/IR/CIRDataLayout.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" @@ -828,7 +831,7 @@ ItaniumEHLowering::lowerConstructCatchParam(cir::ConstructCatchParamOp op, cir::PointerType paramAddrType = mlir::cast<cir::PointerType>(paramAddr.getType()); - if (op.getKind() == cir::InitCatchKind::Reference) { + if (op.getKind() == cir::InitCatchKind::ReferenceToPointer) { assert(!MissingFeatures::sizeOfUnwindException()); constexpr unsigned headerSize = 32; @@ -848,8 +851,8 @@ ItaniumEHLowering::lowerConstructCatchParam(cir::ConstructCatchParamOp op, } if (op.getKind() != cir::InitCatchKind::NonTrivialCopy) - return op.emitError( - "ConstructCatchParam: only non_trivial_copy is supported"); + return op.emitOpError("only reference_to_pointer and non_trivial_copy " + "kinds are supported"); ensureRuntimeDecls(loc); ensureClangCallTerminate(loc); @@ -976,9 +979,14 @@ mlir::LogicalResult ItaniumEHLowering::lowerTryThrow(cir::TryThrowOp op) { /// pointer returned by __cxa_begin_catch. The shape of the lowering /// depends on the init catch kind: /// -/// - Reference: the begin_catch result is -/// the pointer value itself, so just bitcast and store it into the alloca -/// except if it reference of pointer of record. +/// - Reference: the begin_catch result is the adjusted exception object +/// pointer, so just bitcast and store it into the alloca. +/// - ReferenceToPointer: the companion `cir.construct_catch_param` +/// already bound the reference to the exception object, so this lowering +/// is a no-op. +/// - ReferenceToRecordPointer: the begin_catch result is the adjusted +/// pointer value itself, so store it into a temporary and bind the +/// reference to the temporary. /// - Pointer: the begin_catch result is /// the pointer value itself, so just bitcast and store it into the /// alloca. @@ -1002,24 +1010,41 @@ void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) { switch (kind) { case InitCatchKind::Reference: { - // We have no way to tell the personality function that we're - // catching by reference, so if we're catching a pointer, - // __cxa_begin_catch will actually return that pointer by value. - if (const auto ref = mlir::dyn_cast<cir::PointerType>(elementType)) { - // When catching by reference, generally we should just ignore - // this by-value pointer and use the exception object instead. - if (auto ptr = mlir::dyn_cast<cir::PointerType>(ref.getPointee())) - if (!mlir::isa<cir::RecordType>(ptr.getPointee())) - // Extracting and storing the actual exception object was performed by - // cir.construct_catch_param before cir.begin_catch. - break; - } - mlir::Value casted = cir::CastOp::create(builder, loc, elementType, cir::CastKind::bitcast, exnPtr); cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {}, {}); break; } + case InitCatchKind::ReferenceToPointer: + // The reference was bound to the exception object by the matching + // cir.construct_catch_param before cir.begin_catch. + break; + case InitCatchKind::ReferenceToRecordPointer: { + // __cxa_begin_catch returns the caught pointer by value, and the + // personality function may have adjusted it. Store the adjusted pointer + // into a temporary and bind the reference to it. Assigning to the catch + // parameter then changes the temporary, not the exception object, which + // departs from the language semantics. + auto caughtType = mlir::cast<cir::PointerType>( + mlir::cast<cir::PointerType>(elementType).getPointee()); + cir::AllocaOp byRefTmp; + { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToStart( + &op->getParentOfType<cir::FuncOp>().getBody().front()); + cir::CIRDataLayout dataLayout(mod); + uint64_t alignment = + dataLayout.getAlignment(caughtType, /*useABIAlign=*/true).value(); + byRefTmp = + cir::AllocaOp::create(builder, loc, elementType, "exn.byref.tmp", + builder.getI64IntegerAttr(alignment)); + } + mlir::Value casted = cir::CastOp::create(builder, loc, caughtType, + cir::CastKind::bitcast, exnPtr); + cir::StoreOp::create(builder, loc, casted, byRefTmp, {}, {}, {}, {}, {}); + cir::StoreOp::create(builder, loc, byRefTmp, paramAddr, {}, {}, {}, {}, {}); + break; + } case InitCatchKind::TrivialCopy: { mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType, cir::CastKind::bitcast, exnPtr); diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp index 2b4108ca0d270e..8f34a2987c216e 100644 --- a/clang/test/CIR/CodeGen/try-catch.cpp +++ b/clang/test/CIR/CodeGen/try-catch.cpp @@ -1,9 +1,9 @@ // 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 -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefixes=LLVM,SHARED // 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 +// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,SHARED void empty_try_block_with_catch_all() { try {} catch (...) {} @@ -1121,9 +1121,9 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIP6Record> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) // CIR: cir.cleanup.scope { -// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> +// CIR: cir.init_catch_param reference_to_record_pointer %[[EXN_PTR]] to %[[E_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token @@ -1136,6 +1136,8 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // CIR: } // LLVM: define {{.*}} void @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[EXN_BYREF_TMP:.*]] = alloca ptr, align 8 +// LLVM: %[[E_ADDR:.*]] = alloca ptr, align 8 // LLVM: br label %[[TRY_SCOPE:.*]] // LLVM: [[TRY_SCOPE]]: // LLVM: br label %[[TRY_BEGIN:.*]] @@ -1163,10 +1165,12 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // LLVM: [[BEGIN_CATCH]]: // LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ] // LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ] -// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) +// LLVM-NEXT: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: br label %[[END_CATCH:.*]] +// LLVM-NEXT: store ptr %[[TOKEN]], ptr %[[EXN_BYREF_TMP]], align 8 +// LLVM-NEXT: store ptr %[[EXN_BYREF_TMP]], ptr %[[E_ADDR]], align 8 +// LLVM-NEXT: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() // LLVM: br label %[[END_DISPATCH:.*]] @@ -1638,10 +1642,10 @@ int init_catch_param_with_ref_to_ptr_to_non_record() { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { -// CIR: cir.construct_catch_param reference %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: cir.construct_catch_param reference_to_pointer %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> // CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) // CIR: cir.cleanup.scope { -// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: cir.init_catch_param reference_to_pointer %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> // CIR: %[[TMP_P:.*]] = cir.load %[[P_ADDR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> // CIR: %[[DEREF_P:.*]] = cir.load deref {{.*}} %[[TMP_P]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> // CIR: %[[P_VAL:.*]] = cir.load {{.*}} %[[DEREF_P]] : !cir.ptr<!s32i>, !s32i @@ -1862,3 +1866,189 @@ void direct_inside_try_catch_with_exception_type() { // OGCG: resume { ptr, i32 } // OGCG: [[UNREACHABLE]]: // OGCG: unreachable + +const void *init_catch_param_with_ref_to_nullptr() { + try { + division(); + } catch (const decltype(nullptr) &n) { + return &n; + } + return nullptr; +} + +// CIR: cir.func {{.*}} @_Z36init_catch_param_with_ref_to_nullptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[N_ADDR:.*]] = cir.alloca "n" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!void>>> +// CIR: } catch [type #cir.global_view<@_ZTIDn> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %[[N_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>> + +// SHARED: define {{.*}} ptr @_Z36init_catch_param_with_ref_to_nullptrv() {{.*}} personality ptr @__gxx_personality_v0 +// SHARED: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %{{.*}}) +// SHARED: store ptr %[[EXN_PTR]], ptr %[[N_ADDR:.*]], align 8 +// SHARED-NEXT: %[[N:.*]] = load ptr, ptr %[[N_ADDR]], align 8 +// SHARED-NEXT: store ptr %[[N]], ptr %{{.*}}, align 8 + +const void *init_catch_param_with_ref_to_void_ptr() { + try { + division(); + } catch (void *const &p) { + return &p; + } + return nullptr; +} + +// CIR: cir.func {{.*}} @_Z37init_catch_param_with_ref_to_void_ptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!void>>> +// CIR: } catch [type #cir.global_view<@_ZTIPv> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: cir.construct_catch_param reference_to_pointer %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!void>>> +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference_to_pointer %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>> + +// SHARED: define {{.*}} ptr @_Z37init_catch_param_with_ref_to_void_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN:.*]], i64 32 +// LLVM-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// LLVM-NEXT: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN]]) +// LLVM-NEXT: br label %[[CATCH_BODY:.+]] +// LLVM: [[CATCH_BODY]]: +// LLVM-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +// OGCG: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN:.*]]) +// OGCG-NEXT: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN]], i32 32 +// OGCG-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// OGCG-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +const void *init_catch_param_with_ref_to_atomic_record_ptr() { + try { + division(); + } catch (_Atomic(Record) *const &p) { + return &p; + } + return nullptr; +} + +// CIR: cir.func {{.*}} @_Z46init_catch_param_with_ref_to_atomic_record_ptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> +// CIR: } catch [type #cir.global_view<@_ZTIPU7_Atomic6Record> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: cir.construct_catch_param reference_to_pointer %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference_to_pointer %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> + +// SHARED: define {{.*}} ptr @_Z46init_catch_param_with_ref_to_atomic_record_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN:.*]], i64 32 +// LLVM-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// LLVM-NEXT: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN]]) +// LLVM-NEXT: br label %[[CATCH_BODY:.+]] +// LLVM: [[CATCH_BODY]]: +// LLVM-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +// OGCG: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN:.*]]) +// OGCG-NEXT: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN]], i32 32 +// OGCG-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// OGCG-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +const void *init_catch_param_with_ref_to_ptr_to_member_function_ptr() { + try { + division(); + } catch (int (Record::**const &p)()) { + return &p; + } + return nullptr; +} + +// CIR: cir.func {{.*}} @_Z55init_catch_param_with_ref_to_ptr_to_member_function_ptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!rec_anon_struct>>> +// CIR: } catch [type #cir.global_view<@_ZTIPM6RecordFivE> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: cir.construct_catch_param reference_to_pointer %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!rec_anon_struct>>> +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference_to_pointer %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_anon_struct>>> + +// SHARED: define {{.*}} ptr @_Z55init_catch_param_with_ref_to_ptr_to_member_function_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN:.*]], i64 32 +// LLVM-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// LLVM-NEXT: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN]]) +// LLVM-NEXT: br label %[[CATCH_BODY:.+]] +// LLVM: [[CATCH_BODY]]: +// LLVM-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +// OGCG: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN:.*]]) +// OGCG-NEXT: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN]], i32 32 +// OGCG-NEXT: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR:.+]], align 8 +// OGCG-NEXT: %{{.+}} = load ptr, ptr %[[P_ADDR]], align 8 + +Record gr; + +int init_catch_param_with_ref_to_member_function_ptr() { + try { + division(); + } catch (int (Record::*const &mfp)()) { + return (gr.*mfp)(); + } + return 0; +} + +// CIR: cir.func {{.*}} @_Z48init_catch_param_with_ref_to_member_function_ptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[MFP_ADDR:.*]] = cir.alloca "mfp" {{.*}} const : !cir.ptr<!cir.ptr<!rec_anon_struct>> +// CIR: } catch [type #cir.global_view<@_ZTIM6RecordFivE> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %[[MFP_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!rec_anon_struct>> + +// SHARED: define {{.*}} i32 @_Z48init_catch_param_with_ref_to_member_function_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// SHARED: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %{{.*}}) +// SHARED: store ptr %[[EXN_PTR]], ptr %[[MFP_ADDR:.*]], align 8 +// SHARED-NEXT: %[[MFP:.*]] = load ptr, ptr %[[MFP_ADDR]], align 8 +// SHARED-NEXT: %{{.*}} = load { i64, i64 }, ptr %[[MFP]], align 8 + +void init_catch_param_with_ref_to_ptr_to_ptr_to_record() { + try { + division(); + } catch (Record **&pp) { + } +} + +// CIR: cir.func {{.*}} @_Z49init_catch_param_with_ref_to_ptr_to_ptr_to_recordv(){{.*}} personality(@__gxx_personality_v0) +// CIR: %[[PP_ADDR:.*]] = cir.alloca "pp" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>> +// CIR: } catch [type #cir.global_view<@_ZTIPP6Record> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: cir.construct_catch_param reference_to_pointer %[[TOKEN]] to %[[PP_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>> +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference_to_pointer %[[EXN_PTR]] to %[[PP_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>> + +// SHARED: define {{.*}} void @_Z49init_catch_param_with_ref_to_ptr_to_ptr_to_recordv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[PP_ADDR:.*]] = alloca ptr, align 8 +// LLVM: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN:.*]], i64 32 +// LLVM-NEXT: store ptr %[[EXN_OBJ]], ptr %[[PP_ADDR]], align 8 +// LLVM-NEXT: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN]]) +// LLVM-NEXT: br label %[[CATCH_BODY:.+]] +// LLVM: [[CATCH_BODY]]: +// LLVM-NEXT: br label +// OGCG: %{{.*}} = alloca i32, align 4 +// OGCG-NEXT: %[[PP_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %{{.*}} = call ptr @__cxa_begin_catch(ptr %[[EXN:.*]]) +// OGCG-NEXT: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN]], i32 32 +// OGCG-NEXT: store ptr %[[EXN_OBJ]], ptr %[[PP_ADDR]], align 8 + +union Union { + int i; +}; + +void init_catch_param_with_ref_to_union_ptr() { + try { + division(); + } catch (Union *&up) { + } +} + +// CIR: cir.func {{.*}} @_Z38init_catch_param_with_ref_to_union_ptrv(){{.*}} personality(@__gxx_personality_v0) +// CIR: %[[UP_ADDR:.*]] = cir.alloca "up" {{.*}} const : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Union>>> +// CIR: } catch [type #cir.global_view<@_ZTIP5Union> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) { +// CIR-NEXT: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) +// CIR: cir.init_catch_param reference_to_record_pointer %[[EXN_PTR]] to %[[UP_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Union>>> + +// SHARED: define {{.*}} void @_Z38init_catch_param_with_ref_to_union_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[TMP:.*]] = alloca ptr, align 8 +// LLVM-NEXT: %[[UP_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %{{.*}} = alloca i32, align 4 +// OGCG-NEXT: %[[UP_ADDR:.*]] = alloca ptr, align 8 +// OGCG-NEXT: %[[TMP:.*]] = alloca ptr, align 8 +// SHARED: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %{{.*}}) +// SHARED: store ptr %[[EXN_PTR]], ptr %[[TMP]], align 8 +// SHARED-NEXT: store ptr %[[TMP]], ptr %[[UP_ADDR]], align 8 diff --git a/clang/test/CIR/IR/construct-catch-param.cir b/clang/test/CIR/IR/construct-catch-param.cir index b72eee2e8d0283..63d630231c860f 100644 --- a/clang/test/CIR/IR/construct-catch-param.cir +++ b/clang/test/CIR/IR/construct-catch-param.cir @@ -60,4 +60,177 @@ cir.func @construct_catch_param_basic() { // CHECK-SAME: using @__clang_cir_catch_copy__ZTS1E : !cir.ptr<!rec_E> // CHECK: cir.begin_catch %[[EH]] +// A reference to a pointer to a non-record, bound before `cir.begin_catch`. +cir.func @construct_catch_param_ref_to_ptr() { + cir.scope { + %param = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %eh_token to %param + using : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.cleanup.scope { + cir.init_catch_param reference_to_pointer %exn_ptr to %param + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.yield + } cleanup eh { + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + cir.yield + } + } + cir.return +} + +// CHECK-LABEL: cir.func @construct_catch_param_ref_to_ptr() +// CHECK: %[[P:.*]] = cir.alloca "p" {{.*}} : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> +// CHECK: } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] +// CHECK-SAME: (%[[EH:.*]]: !cir.eh_token) { +// CHECK: cir.construct_catch_param reference_to_pointer %[[EH]] to %[[P]] using : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> +// CHECK: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %[[EH]] +// CHECK: cir.init_catch_param reference_to_pointer %[[EXN]] to %[[P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + +// A reference to a pointer to a record, bound by `cir.init_catch_param`. +cir.func @init_catch_param_ref_to_record_ptr() { + cir.scope { + %param = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.cleanup.scope { + cir.init_catch_param reference_to_record_pointer %exn_ptr to %param + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> + cir.yield + } cleanup eh { + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + cir.yield + } + } + cir.return +} + +// CHECK-LABEL: cir.func @init_catch_param_ref_to_record_ptr() +// CHECK: %[[P:.*]] = cir.alloca "p" {{.*}} : !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> +// CHECK: %{{.*}}, %[[EXN:.*]] = cir.begin_catch +// CHECK: cir.init_catch_param reference_to_record_pointer %[[EXN]] to %[[P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> + +// A `cir.construct_catch_param` in the handler of a nested `cir.try`. +cir.func @construct_catch_param_nested_try() { + cir.scope { + %r = cir.alloca "r" align(8) : !cir.ptr<!cir.ptr<!rec_E>> + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.cleanup.scope { + cir.init_catch_param reference %exn_ptr to %r + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!rec_E>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%inner_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %inner_token to %p + using : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + %inner_catch, %inner_exn = cir.begin_catch %inner_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_pointer %inner_exn to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.end_catch %inner_catch : !cir.catch_token + cir.yield + } + cir.yield + } cleanup eh { + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + cir.yield + } + } + cir.return +} + +// CHECK-LABEL: cir.func @construct_catch_param_nested_try() +// CHECK: %[[R:.*]] = cir.alloca "r" {{.*}} : !cir.ptr<!cir.ptr<!rec_E>> +// CHECK: %[[P:.*]] = cir.alloca "p" {{.*}} : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> +// CHECK: cir.init_catch_param reference %{{.*}} to %[[R]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!rec_E>> +// CHECK: cir.construct_catch_param reference_to_pointer %{{.*}} to %[[P]] using +// CHECK: cir.init_catch_param reference_to_pointer %{{.*}} to %[[P]] + +// A `cir.init_catch_param` on a parameter with no `cir.construct_catch_param`. +cir.func @construct_catch_param_other_param() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + %r = cir.alloca "r" align(8) : !cir.ptr<!cir.ptr<!rec_E>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %eh_token to %p + using : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_pointer %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.init_catch_param reference %exn_ptr to %r + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!rec_E>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +// CHECK-LABEL: cir.func @construct_catch_param_other_param() +// CHECK: %[[P:.*]] = cir.alloca "p" {{.*}} : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> +// CHECK: %[[R:.*]] = cir.alloca "r" {{.*}} : !cir.ptr<!cir.ptr<!rec_E>> +// CHECK: cir.init_catch_param reference_to_pointer %{{.*}} to %[[P]] +// CHECK: cir.init_catch_param reference %{{.*}} to %[[R]] + +// A `cir.construct_catch_param` inside the lifetime cleanup scope. +cir.func @construct_catch_param_in_lifetime_scope() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.lifetime.start %p : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.cleanup.scope { + cir.construct_catch_param reference_to_pointer %eh_token to %p + using : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_pointer %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } cleanup all { + cir.lifetime.end %p : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> + cir.yield + } + cir.yield + } + } + cir.return +} + +// CHECK-LABEL: cir.func @construct_catch_param_in_lifetime_scope() +// CHECK: %[[P:.*]] = cir.alloca "p" {{.*}} : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>> +// CHECK: cir.lifetime.start %[[P]] +// CHECK: cir.cleanup.scope { +// CHECK-NEXT: cir.construct_catch_param reference_to_pointer %{{.*}} to %[[P]] using +// CHECK: cir.init_catch_param reference_to_pointer %{{.*}} to %[[P]] + } diff --git a/clang/test/CIR/IR/invalid-construct-catch-param.cir b/clang/test/CIR/IR/invalid-construct-catch-param.cir index 86c4c6d6612aa1..5df28816755379 100644 --- a/clang/test/CIR/IR/invalid-construct-catch-param.cir +++ b/clang/test/CIR/IR/invalid-construct-catch-param.cir @@ -248,3 +248,65 @@ cir.func @construct_not_followed_by_begin_catch() { } } + +// ----- + +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_E = !cir.struct<"E" {pad !u8i}> + +module { + +cir.global "private" constant external @_ZTIP1E : !cir.ptr<!u8i> + +cir.func @ref_to_record_ptr_referent_not_a_pointer() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!rec_E>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTIP1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + // expected-error @below {{'cir.construct_catch_param' op 'reference_to_record_pointer' requires 'param_addr' to be the address of a reference to a pointer}} + cir.construct_catch_param reference_to_record_pointer %eh_token to %p using + : !cir.ptr<!cir.ptr<!rec_E>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_E = !cir.struct<"E" {pad !u8i}> + +module { + +cir.global "private" constant external @_ZTIP1E : !cir.ptr<!u8i> + +cir.func @ref_to_ptr_not_a_reference() { + cir.scope { + %p = cir.alloca "p" align(1) : !cir.ptr<!rec_E> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTIP1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + // expected-error @below {{'cir.construct_catch_param' op 'reference_to_pointer' requires 'param_addr' to be the address of a reference to a pointer}} + cir.construct_catch_param reference_to_pointer %eh_token to %p using + : !cir.ptr<!rec_E> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} diff --git a/clang/test/CIR/IR/invalid-init-catch-param.cir b/clang/test/CIR/IR/invalid-init-catch-param.cir new file mode 100644 index 00000000000000..556e0edf9840eb --- /dev/null +++ b/clang/test/CIR/IR/invalid-init-catch-param.cir @@ -0,0 +1,258 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!s32i = !cir.int<s, 32> +!void = !cir.void + +cir.func @ref_to_ptr_not_a_reference(%exn: !cir.ptr<!void>) { + %0 = cir.alloca "p" align(4) : !cir.ptr<!s32i> + // expected-error @below {{'cir.init_catch_param' op 'reference_to_pointer' requires 'param_addr' to be the address of a reference to a pointer}} + cir.init_catch_param reference_to_pointer %exn to %0 : !cir.ptr<!void>, !cir.ptr<!s32i> + cir.return +} + +// ----- + +!s32i = !cir.int<s, 32> +!void = !cir.void + +cir.func @ref_to_record_ptr_not_a_pointer(%exn: !cir.ptr<!void>) { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!s32i>> + // expected-error @below {{'cir.init_catch_param' op 'reference_to_record_pointer' requires 'param_addr' to be the address of a reference to a pointer}} + cir.init_catch_param reference_to_record_pointer %exn to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!s32i>> + cir.return +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @ref_to_ptr_without_construct() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op 'reference_to_pointer' requires a preceding 'cir.construct_catch_param' of the same kind on the same parameter}} + cir.init_catch_param reference_to_pointer %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @construct_kind_mismatch() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %eh_token to %p using + : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op kind 'reference' does not match the kind 'reference_to_pointer' of the preceding 'cir.construct_catch_param'}} + cir.init_catch_param reference %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_E = !cir.struct<"E" {pad !u8i}> + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @non_trivial_copy_without_construct() { + cir.scope { + %e = cir.alloca "e" align(1) : !cir.ptr<!rec_E> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op 'non_trivial_copy' requires a preceding 'cir.construct_catch_param' of the same kind on the same parameter}} + cir.init_catch_param non_trivial_copy %exn_ptr to %e + : !cir.ptr<!void>, !cir.ptr<!rec_E> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @same_kind_different_param() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %q = cir.alloca "q" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %eh_token to %q using + : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op 'reference_to_pointer' requires a preceding 'cir.construct_catch_param' of the same kind on the same parameter}} + cir.init_catch_param reference_to_pointer %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @construct_kind_mismatch_needs_construct() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param non_trivial_copy %eh_token to %p using + : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op kind 'reference_to_pointer' does not match the kind 'non_trivial_copy' of the preceding 'cir.construct_catch_param'}} + cir.init_catch_param reference_to_pointer %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @init_operand_count() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.construct_catch_param reference_to_pointer %eh_token to %p using + : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op expected 2 operands, but found 1}} + "cir.init_catch_param"(%exn_ptr) <{kind = #cir.init_catch<reference_to_pointer>}> + : (!cir.ptr<!void>) -> () + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void + +module { + +cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i> + +cir.func @construct_kind_mismatch_in_lifetime_scope() { + cir.scope { + %p = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try { + cir.yield + } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>] + (%eh_token: !cir.eh_token) { + cir.lifetime.start %p : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.cleanup.scope { + cir.construct_catch_param reference_to_pointer %eh_token to %p using + : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + // expected-error @below {{'cir.init_catch_param' op kind 'reference' does not match the kind 'reference_to_pointer' of the preceding 'cir.construct_catch_param'}} + cir.init_catch_param reference %exn_ptr to %p + : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.yield + } cleanup all { + cir.lifetime.end %p : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.yield + } + cir.yield + } + } + cir.return +} + +} diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-catch-param-ref.cir b/clang/test/CIR/Transforms/eh-abi-lowering-catch-param-ref.cir new file mode 100644 index 00000000000000..93f1c109d36d54 --- /dev/null +++ b/clang/test/CIR/Transforms/eh-abi-lowering-catch-param-ref.cir @@ -0,0 +1,216 @@ +// RUN: cir-opt %s -cir-eh-abi-lowering -split-input-file -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_Rec = !cir.struct<"Rec" {data !s32i}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + +cir.global "private" external @_ZTIPi : !cir.ptr<!u8i> +cir.global "private" external @_ZTIP3Rec : !cir.ptr<!u8i> +cir.global "private" external @_ZTIDn : !cir.ptr<!u8i> +cir.global "private" external @_ZTIPU7_Atomic3Rec : !cir.ptr<!u8i> + +cir.func private @_Z8mayThrowv() + +// Reference to a pointer to a record: bound to an exn.byref.tmp temporary. +cir.func @ref_to_record_ptr() personality(@__gxx_personality_v0) { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb5 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%2: !cir.eh_token): + cir.eh.dispatch %2 : !cir.eh_token [ + catch(#cir.global_view<@_ZTIP3Rec> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb6 + ] +^bb4(%3: !cir.eh_token): + %catch_token, %exn_ptr = cir.begin_catch %3 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_record_pointer %exn_ptr to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.end_catch %catch_token : !cir.catch_token + cir.br ^bb5 +^bb5: + cir.return +^bb6(%4: !cir.eh_token): + cir.resume %4 : !cir.eh_token +} + +// CHECK-LABEL: cir.func @ref_to_record_ptr() +// CHECK: %[[TMP:.*]] = cir.alloca "exn.byref.tmp" align(8) : !cir.ptr<!cir.ptr<!rec_Rec>> +// CHECK: %[[P:.*]] = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> +// CHECK: cir.brcond %{{[0-9]+}} ^[[CATCH:bb[0-9]+]]( +// CHECK: ^[[CATCH]](%[[EXN_ARG:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i): +// CHECK-NEXT: %[[EXN:.*]] = cir.call @__cxa_begin_catch(%[[EXN_ARG]]) : (!cir.ptr<!void>) -> !cir.ptr<!u8i> +// CHECK-NEXT: %[[EXN_VOID:.*]] = cir.cast bitcast %[[EXN]] : !cir.ptr<!u8i> -> !cir.ptr<!void> +// CHECK-NEXT: %[[ADJUSTED:.*]] = cir.cast bitcast %[[EXN_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_Rec> +// CHECK-NEXT: cir.store %[[ADJUSTED]], %[[TMP]] : !cir.ptr<!rec_Rec>, !cir.ptr<!cir.ptr<!rec_Rec>> +// CHECK-NEXT: cir.store %[[TMP]], %[[P]] : !cir.ptr<!cir.ptr<!rec_Rec>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> +// CHECK-NEXT: cir.call @__cxa_end_catch() + +// Reference to a pointer to a non-record: bound before __cxa_begin_catch. +cir.func @ref_to_int_ptr() personality(@__gxx_personality_v0) { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb5 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%2: !cir.eh_token): + cir.eh.dispatch %2 : !cir.eh_token [ + catch(#cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb6 + ] +^bb4(%3: !cir.eh_token): + cir.construct_catch_param reference_to_pointer %3 to %0 using : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + %catch_token, %exn_ptr = cir.begin_catch %3 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_pointer %exn_ptr to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> + cir.end_catch %catch_token : !cir.catch_token + cir.br ^bb5 +^bb5: + cir.return +^bb6(%4: !cir.eh_token): + cir.resume %4 : !cir.eh_token +} + +// CHECK-LABEL: cir.func @ref_to_int_ptr() +// CHECK-NOT: exn.byref.tmp +// CHECK: %[[P:.*]] = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CHECK: cir.brcond %{{[0-9]+}} ^[[CATCH:bb[0-9]+]]( +// CHECK: ^[[CATCH]](%[[EXN:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i): +// CHECK-NEXT: %[[HEADER:.*]] = cir.const #cir.int<32> : !u32i +// CHECK-NEXT: %[[OBJ:.*]] = cir.ptr_stride %[[EXN]], %[[HEADER]] : (!cir.ptr<!void>, !u32i) -> !cir.ptr<!void> +// CHECK-NEXT: %[[OBJ_CAST:.*]] = cir.cast bitcast %[[OBJ]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!s32i>> +// CHECK-NEXT: cir.store %[[OBJ_CAST]], %[[P]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CHECK-NEXT: %[[ADJUSTED:.*]] = cir.call @__cxa_begin_catch(%[[EXN]]) : (!cir.ptr<!void>) -> !cir.ptr<!u8i> +// CHECK-NEXT: cir.cast bitcast %[[ADJUSTED]] : !cir.ptr<!u8i> -> !cir.ptr<!void> +// CHECK-NEXT: cir.call @__cxa_end_catch() + +// Reference to an _Atomic(Rec) pointer: bound before __cxa_begin_catch. +cir.func @ref_to_ptr_record_shaped() personality(@__gxx_personality_v0) { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb5 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%2: !cir.eh_token): + cir.eh.dispatch %2 : !cir.eh_token [ + catch(#cir.global_view<@_ZTIPU7_Atomic3Rec> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb6 + ] +^bb4(%3: !cir.eh_token): + cir.construct_catch_param reference_to_pointer %3 to %0 using : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + %catch_token, %exn_ptr = cir.begin_catch %3 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_pointer %exn_ptr to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.end_catch %catch_token : !cir.catch_token + cir.br ^bb5 +^bb5: + cir.return +^bb6(%4: !cir.eh_token): + cir.resume %4 : !cir.eh_token +} + +// CHECK-LABEL: cir.func @ref_to_ptr_record_shaped() +// CHECK-NOT: exn.byref.tmp +// CHECK: %[[P:.*]] = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> +// CHECK: cir.brcond %{{[0-9]+}} ^[[CATCH:bb[0-9]+]]( +// CHECK: ^[[CATCH]](%[[EXN:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i): +// CHECK-NEXT: %[[HEADER:.*]] = cir.const #cir.int<32> : !u32i +// CHECK-NEXT: %[[OBJ:.*]] = cir.ptr_stride %[[EXN]], %[[HEADER]] : (!cir.ptr<!void>, !u32i) -> !cir.ptr<!void> +// CHECK-NEXT: %[[OBJ_CAST:.*]] = cir.cast bitcast %[[OBJ]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!rec_Rec>> +// CHECK-NEXT: cir.store %[[OBJ_CAST]], %[[P]] : !cir.ptr<!cir.ptr<!rec_Rec>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> +// CHECK-NEXT: %[[ADJUSTED:.*]] = cir.call @__cxa_begin_catch(%[[EXN]]) : (!cir.ptr<!void>) -> !cir.ptr<!u8i> +// CHECK-NEXT: cir.cast bitcast %[[ADJUSTED]] : !cir.ptr<!u8i> -> !cir.ptr<!void> +// CHECK-NEXT: cir.call @__cxa_end_catch() + +// Reference to std::nullptr_t: bound to the __cxa_begin_catch result. +cir.func @ref_to_nullptr() personality(@__gxx_personality_v0) { + %0 = cir.alloca "n" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!void>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb5 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%2: !cir.eh_token): + cir.eh.dispatch %2 : !cir.eh_token [ + catch(#cir.global_view<@_ZTIDn> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb6 + ] +^bb4(%3: !cir.eh_token): + %catch_token, %exn_ptr = cir.begin_catch %3 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference %exn_ptr to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>> + cir.end_catch %catch_token : !cir.catch_token + cir.br ^bb5 +^bb5: + cir.return +^bb6(%4: !cir.eh_token): + cir.resume %4 : !cir.eh_token +} + +// CHECK-LABEL: cir.func @ref_to_nullptr() +// CHECK-NOT: exn.byref.tmp +// CHECK: %[[N:.*]] = cir.alloca "n" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!void>>> +// CHECK: cir.brcond %{{[0-9]+}} ^[[CATCH:bb[0-9]+]]( +// CHECK: ^[[CATCH]](%[[EXN_ARG:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i): +// CHECK-NEXT: %[[EXN:.*]] = cir.call @__cxa_begin_catch(%[[EXN_ARG]]) : (!cir.ptr<!void>) -> !cir.ptr<!u8i> +// CHECK-NEXT: %[[EXN_VOID:.*]] = cir.cast bitcast %[[EXN]] : !cir.ptr<!u8i> -> !cir.ptr<!void> +// CHECK-NEXT: %[[EXN_CAST:.*]] = cir.cast bitcast %[[EXN_VOID]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!void>> +// CHECK-NEXT: cir.store %[[EXN_CAST]], %[[N]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>> +// CHECK-NEXT: cir.call @__cxa_end_catch() + +} + +// ----- + +!s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_Rec = !cir.struct<"Rec" {data !s32i}> + +module attributes {cir.triple = "i386-unknown-linux-gnu", + dlti.dl_spec = #dlti.dl_spec< + #dlti.dl_entry<!cir.ptr<!cir.void>, + #cir.ptr_spec<size = 32, abi = 32, + preferred = 32, index = 32>>>} { + +cir.global "private" external @_ZTIP3Rec : !cir.ptr<!u8i> + +cir.func private @_Z8mayThrowv() + +// The exn.byref.tmp temporary takes the target's pointer alignment. +cir.func @ref_to_record_ptr_32() personality(@__gxx_personality_v0) { + %0 = cir.alloca "p" align(4) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb5 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%2: !cir.eh_token): + cir.eh.dispatch %2 : !cir.eh_token [ + catch(#cir.global_view<@_ZTIP3Rec> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb6 + ] +^bb4(%3: !cir.eh_token): + %catch_token, %exn_ptr = cir.begin_catch %3 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.init_catch_param reference_to_record_pointer %exn_ptr to %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Rec>>> + cir.end_catch %catch_token : !cir.catch_token + cir.br ^bb5 +^bb5: + cir.return +^bb6(%4: !cir.eh_token): + cir.resume %4 : !cir.eh_token +} + +// CHECK-LABEL: cir.func @ref_to_record_ptr_32() +// CHECK: cir.alloca "exn.byref.tmp" align(4) : !cir.ptr<!cir.ptr<!rec_Rec>> + +} diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir index 8d191bb05c8ac7..a0c194fdf95b94 100644 --- a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir +++ b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir @@ -30,7 +30,7 @@ cir.func linkonce_odr hidden @__clang_cir_catch_copy__ZTS1E_ok( cir.return } -// Only non_trivial_copy is currently supported on Itanium. +// Only reference_to_pointer and non_trivial_copy are supported on Itanium. cir.func @bad_kind() { %0 = cir.alloca "e" align(1) : !cir.ptr<!rec_E> cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () @@ -45,7 +45,7 @@ cir.func @bad_kind() { unwind : ^bb5 ] ^bb4(%eh_token.1: !cir.eh_token): - // expected-error @below {{ConstructCatchParam: only non_trivial_copy is supported}} + // expected-error @below {{'cir.construct_catch_param' op only reference_to_pointer and non_trivial_copy kinds are supported}} cir.construct_catch_param trivial_copy %eh_token.1 to %0 using @__clang_cir_catch_copy__ZTS1E_ok : !cir.ptr<!rec_E> %ct, %exn = cir.begin_catch %eh_token.1 @@ -173,3 +173,87 @@ cir.func @multi_block_thunk() { } } + +// ----- + +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_E = !cir.struct<"E" {pad !u8i}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + +cir.global "private" external @_ZTIP1E : !cir.ptr<!u8i> + +cir.func private @_Z8mayThrowv() + +// reference_to_record_pointer has no cir.construct_catch_param lowering. +cir.func @ref_to_record_ptr_kind() { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb6 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%eh_token: !cir.eh_token): + cir.eh.dispatch %eh_token : !cir.eh_token [ + catch(#cir.global_view<@_ZTIP1E> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb5 + ] +^bb4(%eh_token.1: !cir.eh_token): + // expected-error @below {{'cir.construct_catch_param' op only reference_to_pointer and non_trivial_copy kinds are supported}} + cir.construct_catch_param reference_to_record_pointer %eh_token.1 to %0 + using : !cir.ptr<!cir.ptr<!cir.ptr<!rec_E>>> + %ct, %exn = cir.begin_catch %eh_token.1 + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.end_catch %ct : !cir.catch_token + cir.br ^bb6 +^bb5(%eh_token.2: !cir.eh_token): + cir.resume %eh_token.2 : !cir.eh_token +^bb6: + cir.return +} + +} + +// ----- + +!u8i = !cir.int<u, 8> +!void = !cir.void +!rec_E = !cir.struct<"E" {pad !u8i}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + +cir.global "private" external @_ZTI1E : !cir.ptr<!u8i> + +cir.func private @_Z8mayThrowv() + +// reference has no cir.construct_catch_param lowering. +cir.func @ref_kind() { + %0 = cir.alloca "p" align(8) : !cir.ptr<!cir.ptr<!rec_E>> + cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> () +^bb1: + cir.br ^bb6 +^bb2: + %1 = cir.eh.initiate : !cir.eh_token + cir.br ^bb3(%1 : !cir.eh_token) +^bb3(%eh_token: !cir.eh_token): + cir.eh.dispatch %eh_token : !cir.eh_token [ + catch(#cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>) : ^bb4, + unwind : ^bb5 + ] +^bb4(%eh_token.1: !cir.eh_token): + // expected-error @below {{'cir.construct_catch_param' op only reference_to_pointer and non_trivial_copy kinds are supported}} + cir.construct_catch_param reference %eh_token.1 to %0 + using : !cir.ptr<!cir.ptr<!rec_E>> + %ct, %exn = cir.begin_catch %eh_token.1 + : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>) + cir.end_catch %ct : !cir.catch_token + cir.br ^bb6 +^bb5(%eh_token.2: !cir.eh_token): + cir.resume %eh_token.2 : !cir.eh_token +^bb6: + cir.return +} + +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
