clang 23.0.0git
CIRGenException.cpp
Go to the documentation of this file.
1//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code dealing with C++ exception related code generation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenCXXABI.h"
14#include "CIRGenFunction.h"
15#include "mlir/IR/Block.h"
16#include "mlir/IR/Location.h"
17
19#include "llvm/Support/SaveAndRestore.h"
20
21using namespace clang;
22using namespace clang::CIRGen;
23
24const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};
25const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",
26 nullptr};
27const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",
28 nullptr};
29const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",
30 nullptr};
31const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",
32 nullptr};
34 "__gxx_personality_sj0", nullptr};
36 "__gxx_personality_seh0", nullptr};
37const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",
38 "objc_exception_throw"};
40 "__gnu_objc_personality_sj0", "objc_exception_throw"};
42 "__gnu_objc_personality_seh0", "objc_exception_throw"};
44 "__gnustep_objcxx_personality_v0", nullptr};
46 "__gnustep_objc_personality_v0", nullptr};
47const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",
48 nullptr};
50 "__C_specific_handler", nullptr};
52 "__CxxFrameHandler3", nullptr};
54 "__gxx_wasm_personality_v0", nullptr};
55const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
56 nullptr};
57const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
58 nullptr};
59
60static const EHPersonality &getCPersonality(const TargetInfo &target,
61 const CodeGenOptions &cgOpts) {
62 const llvm::Triple &triple = target.getTriple();
63 if (triple.isWindowsMSVCEnvironment())
65 if (cgOpts.hasSjLjExceptions())
67 if (cgOpts.hasDWARFExceptions())
69 if (cgOpts.hasSEHExceptions())
72}
73
74static const EHPersonality &getObjCPersonality(const TargetInfo &target,
75 const LangOptions &langOpts,
76 const CodeGenOptions &cgOpts) {
77 const llvm::Triple &triple = target.getTriple();
78 if (triple.isWindowsMSVCEnvironment())
80
81 switch (langOpts.ObjCRuntime.getKind()) {
83 return getCPersonality(target, cgOpts);
89 if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
91 [[fallthrough]];
94 if (cgOpts.hasSjLjExceptions())
96 if (cgOpts.hasSEHExceptions())
99 }
100 llvm_unreachable("bad runtime kind");
101}
102
103static const EHPersonality &getCXXPersonality(const TargetInfo &target,
104 const CodeGenOptions &cgOpts) {
105 const llvm::Triple &triple = target.getTriple();
106 if (triple.isWindowsMSVCEnvironment())
108 if (triple.isOSAIX())
110 if (cgOpts.hasSjLjExceptions())
112 if (cgOpts.hasDWARFExceptions())
114 if (cgOpts.hasSEHExceptions())
116 if (cgOpts.hasWasmExceptions())
119}
120
121/// Determines the personality function to use when both C++
122/// and Objective-C exceptions are being caught.
124 const LangOptions &langOpts,
125 const CodeGenOptions &cgOpts) {
126 if (target.getTriple().isWindowsMSVCEnvironment())
128
129 switch (langOpts.ObjCRuntime.getKind()) {
130 // In the fragile ABI, just use C++ exception handling and hope
131 // they're not doing crazy exception mixing.
133 return getCXXPersonality(target, cgOpts);
134
135 // The ObjC personality defers to the C++ personality for non-ObjC
136 // handlers. Unlike the C++ case, we use the same personality
137 // function on targets using (backend-driven) SJLJ EH.
139 case ObjCRuntime::iOS:
141 return getObjCPersonality(target, langOpts, cgOpts);
142
145
146 // The GCC runtime's personality function inherently doesn't support
147 // mixed EH. Use the ObjC personality just to avoid returning null.
148 case ObjCRuntime::GCC:
150 return getObjCPersonality(target, langOpts, cgOpts);
151 }
152 llvm_unreachable("bad runtime kind");
153}
154
155static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {
156 return triple.getArch() == llvm::Triple::x86
159}
160
162 const FunctionDecl *fd) {
163 const llvm::Triple &triple = cgm.getTarget().getTriple();
164 const LangOptions &langOpts = cgm.getLangOpts();
165 const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
166 const TargetInfo &target = cgm.getTarget();
167
168 // Functions using SEH get an SEH personality.
169 if (fd && fd->usesSEHTry())
170 return getSEHPersonalityMSVC(triple);
171
172 if (langOpts.ObjC) {
173 return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)
174 : getObjCPersonality(target, langOpts, cgOpts);
175 }
176 return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)
177 : getCPersonality(target, cgOpts);
178}
179
181 const auto *fg = cgf.curCodeDecl;
182 // For outlined finallys and filters, use the SEH personality in case they
183 // contain more SEH. This mostly only affects finallys. Filters could
184 // hypothetically use gnu statement expressions to sneak in nested SEH.
185 fg = fg ? fg : cgf.curSEHParent.getDecl();
186 return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));
187}
188
189static llvm::StringRef getPersonalityFn(CIRGenModule &cgm,
190 const EHPersonality &personality) {
191 // Create the personality function type: i32 (...)
192 mlir::Type i32Ty = cgm.getBuilder().getI32Type();
193 auto funcTy = cir::FuncType::get({}, i32Ty, /*isVarArg=*/true);
194
195 cir::FuncOp personalityFn = cgm.createRuntimeFunction(
196 funcTy, personality.personalityFn, {}, /*isLocal=*/true);
197
198 return personalityFn.getSymName();
199}
200
202 const llvm::Triple &triple = getTarget().getTriple();
203 if (cgm.getLangOpts().OpenMPIsTargetDevice &&
204 (triple.isNVPTX() || triple.isAMDGCN())) {
205 cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
206 return;
207 }
208
209 if (const Expr *subExpr = e->getSubExpr()) {
210 QualType throwType = subExpr->getType();
211 if (throwType->isObjCObjectPointerType()) {
212 cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
213 return;
214 }
215
216 cgm.getCXXABI().emitThrow(*this, e);
217 return;
218 }
219
220 cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
221}
222
224 // Make sure the exception object is cleaned up if there's an
225 // exception during initialization.
227
228 // __cxa_allocate_exception returns a void*; we need to cast this
229 // to the appropriate type for the object.
230 mlir::Type ty = convertTypeForMem(e->getType());
231 Address typedAddr = addr.withElementType(builder, ty);
232
233 // From LLVM's codegen:
234 // FIXME: this isn't quite right! If there's a final unelided call
235 // to a copy constructor, then according to [except.terminate]p1 we
236 // must call std::terminate() if that constructor throws, because
237 // technically that copy occurs after the exception expression is
238 // evaluated but before the exception is caught. But the best way
239 // to handle that is to teach EmitAggExpr to do the final copy
240 // differently if it can't be elided.
241 emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
242 /*isInitializer=*/true);
243
244 // Deactivate the cleanup block.
246}
247
249 const CXXCatchStmt *catchStmt, SmallVector<mlir::Attribute> &handlerAttrs) {
250 mlir::Location catchLoc = getLoc(catchStmt->getBeginLoc());
251
252 if (catchStmt->getExceptionDecl()) {
253 // FIXME: Dropping the reference type on the type into makes it
254 // impossible to correctly implement catch-by-reference
255 // semantics for pointers. Unfortunately, this is what all
256 // existing compilers do, and it's not clear that the standard
257 // personality routine is capable of doing this right. See C++ DR 388:
258 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
259 Qualifiers caughtTypeQuals;
260 QualType caughtType = cgm.getASTContext().getUnqualifiedArrayType(
261 catchStmt->getCaughtType().getNonReferenceType(), caughtTypeQuals);
262 if (caughtType->isObjCObjectPointerType()) {
263 cgm.errorNYI("addCatchHandlerAttr: caughtType ObjCObjectPointerType");
264 return;
265 }
266
267 CatchTypeInfo typeInfo = cgm.getCXXABI().getAddrOfCXXCatchHandlerType(
268 catchLoc, caughtType, catchStmt->getCaughtType());
269 handlerAttrs.push_back(typeInfo.rtti);
270 } else {
271 // No exception decl indicates '...', a catch-all.
272 handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
273 }
274}
275
276namespace {
277struct CallEndCatch final : EHScopeStack::Cleanup {
278 CallEndCatch(mlir::Value catchToken) : catchToken(catchToken) {}
279 mlir::Value catchToken;
280
281 void emit(CIRGenFunction &cgf, Flags flags) override {
282 cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken);
283 cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
284 }
285};
286} // namespace
287
288static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
289 mlir::Type exnPtrTy) {
290 auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
291 auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
292 cgf.getBuilder().getUnknownLoc(),
293 catchTokenTy, exnPtrTy, ehToken);
294
295 cgf.ehStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup,
296 beginCatch.getCatchToken());
297
298 return beginCatch.getExnPtr();
299}
300
301/// Get or create the catch-init copy thunk for \p catchParam.
302///
303/// The copy thunk has signature `void(T*, T*)` (where `T` is the catch
304/// parameter type) and contains the normal aggregate emission of the catch
305/// parameter's init expression.
306///
307/// The thunk name is keyed off the catch parameter's canonical type mangled
308/// name, so a single translation unit emits at most one thunk per catch type.
309static cir::FuncOp getOrCreateCopyThunk(CIRGenFunction &cgf,
310 const VarDecl &catchParam,
311 cir::PointerType paramAddrType,
312 mlir::Location loc) {
313 CIRGenModule &cgm = cgf.cgm;
314 CIRGenBuilderTy &builder = cgm.getBuilder();
315 mlir::ModuleOp mod = cgm.getModule();
316
317 const Expr *copyExpr = catchParam.getInit();
318 assert(copyExpr && "non-trivial copy expects a copy expression");
319
320 llvm::SmallString<128> thunkName;
321 llvm::raw_svector_ostream thunkNameStream(thunkName);
322 thunkNameStream << "__clang_cir_catch_copy_";
324 catchParam.getType(), thunkNameStream);
325
326 if (cir::FuncOp existing = cgm.lookupFuncOp(thunkName))
327 return existing;
328
329 mlir::Type voidTy = cir::VoidType::get(builder.getContext());
330 auto thunkTy = cir::FuncType::get({paramAddrType, paramAddrType}, voidTy,
331 /*isVarArg=*/false);
332
333 mlir::OpBuilder::InsertionGuard guard(builder);
334 builder.setInsertionPointToEnd(mod.getBody());
335 cir::FuncOp thunk = cir::FuncOp::create(builder, loc, thunkName, thunkTy);
336 cgm.insertGlobalSymbol(thunk);
337 thunk.setLinkage(cir::GlobalLinkageKind::LinkOnceODRLinkage);
338 thunk.setGlobalVisibility(cir::VisibilityKind::Hidden);
339 thunk->setAttr(cir::CIRDialect::getCatchCopyThunkAttrName(),
340 builder.getUnitAttr());
341
342 mlir::Block *entry = thunk.addEntryBlock();
343 builder.setInsertionPointToStart(entry);
344
345 // Use a fresh CIRGenFunction to drive the body emission. We need just enough
346 // state for emitAggExpr / emitCXXConstructorCall to compute the call-site
347 // argument attributes; the helper has no AST decl, no exception scopes, and
348 // no return value, so we bypass the full startFunction/finishFunction
349 // machinery.
350 CIRGenFunction subCgf(cgm, builder);
351 subCgf.curFn = thunk;
352
353 // Some emission paths (e.g. materializing temporaries for default args via
354 // emitAnyExprToTemp) need both a current source location and a lexical
355 // scope to anchor allocas. Since we bypass startFunction, install both
356 // explicitly for the lifetime of the thunk's body emission.
357 CIRGenFunction::SourceLocRAIIObject thunkLoc(subCgf, loc);
358 CIRGenFunction::LexicalScope thunkScope(subCgf, loc, entry);
359
360 // Bind the OpaqueValueExpr at the source position of the catch parameter's
361 // copy expression to an LValue at the thunk's `src` block argument.
362 LValue srcLV = subCgf.makeNaturalAlignAddrLValue(entry->getArgument(1),
363 catchParam.getType());
365 subCgf, OpaqueValueExpr::findInCopyConstruct(copyExpr), srcLV);
366
367 // Drive the construction into the helper's `dest` block argument via the
368 // normal aggregate-emission machinery so that `ExprWithCleanups`,
369 // converting/inheriting constructors, and any future copy-construction
370 // shapes flow through unchanged.
371 Address destAddr = subCgf.makeNaturalAddressForPointer(
372 entry->getArgument(0), catchParam.getType(), clang::CharUnits::Zero());
373 subCgf.emitAggExpr(
374 copyExpr, AggValueSlot::forAddr(
377
378 cir::ReturnOp::create(builder, loc);
379 return thunk;
380}
381
382/// A "special initializer" callback for initializing a catch
383/// parameter during catch initialization.
385 mlir::Value ehToken, const VarDecl &catchParam,
386 SourceLocation loc) {
387 CanQualType catchType =
388 cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
389 cir::InitCatchKind kind;
390 bool shouldInitFromExnDirectly;
391
392 // If we're catching by reference, we can just cast the object
393 // pointer to the appropriate pointer.
394 if (isa<ReferenceType>(catchType)) {
395 QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
396 if (const PointerType *ptr = dyn_cast<PointerType>(caughtType)) {
397 shouldInitFromExnDirectly = !ptr->getPointeeType()->isRecordType();
398 }
399 kind = cir::InitCatchKind::Reference;
400 } else {
401 cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
402 if (tek == cir::TEK_Aggregate) {
403 assert(isa<RecordType>(catchType) && "unexpected catch type!");
404 const Expr *copyExpr = catchParam.getInit();
405 kind = !copyExpr ? cir::InitCatchKind::TrivialCopy
406 : cir::InitCatchKind::NonTrivialCopy;
407 } else {
408 // Scalars and complexes.
409 if (catchType->hasPointerRepresentation()) {
410 switch (catchType.getQualifiers().getObjCLifetime()) {
413 kind = cir::InitCatchKind::Objc;
414 break;
415
419 kind = cir::InitCatchKind::Pointer;
420 break;
421 }
422 } else {
423 kind = cir::InitCatchKind::Scalar;
424 }
425 }
426 }
427
429 Address paramAddr = var.getAllocatedAddress();
430 mlir::Location mloc = cgf.getLoc(loc);
431
432 if (kind == cir::InitCatchKind::NonTrivialCopy ||
433 (kind == cir::InitCatchKind::Reference && shouldInitFromExnDirectly)) {
434 // Sanitizer-checked construction (UBSan vptr/derived-class checks, etc.)
435 // would require additional adornments that cir.construct_catch_param does
436 // not yet carry.
438
439 mlir::FlatSymbolRefAttr copyFun{};
440 if (kind == cir::InitCatchKind::NonTrivialCopy) {
441 auto paramAddrType =
442 mlir::cast<cir::PointerType>(paramAddr.getPointer().getType());
443 cir::FuncOp thunk =
444 getOrCreateCopyThunk(cgf, catchParam, paramAddrType, mloc);
445 copyFun = mlir::FlatSymbolRefAttr::get(thunk.getSymNameAttr());
446 }
447
448 cir::ConstructCatchParamOp::create(builder, mloc, ehToken,
449 paramAddr.getPointer(), kind, copyFun);
450 }
451
452 mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy());
453 cir::InitCatchParamOp::create(builder, mloc, exnPtr, paramAddr.getPointer(),
454 kind);
455 cgf.emitAutoVarCleanups(var);
456}
457
458/// Begins a catch statement by initializing the catch variable and
459/// calling __cxa_begin_catch.
461 mlir::Value ehToken) {
462 // We have to be very careful with the ordering of cleanups here:
463 // C++ [except.throw]p4:
464 // The destruction [of the exception temporary] occurs
465 // immediately after the destruction of the object declared in
466 // the exception-declaration in the handler.
467 //
468 // So the precise ordering is:
469 // 1. Construct catch variable.
470 // 2. begin_catch
471 // 3. Enter CallEndCatch cleanup
472 // 4. Enter dtor cleanup
473 //
474 VarDecl *catchParam = catchStmt->getExceptionDecl();
475 if (!catchParam) {
476 callBeginCatch(*this, ehToken, builder.getVoidPtrTy());
477 return;
478 }
479
480 // Emit the local. Make sure the alloca's superseed the current scope, since
481 // these are going to be consumed by `cir.catch`, which is not within the
482 // current scope.
483 initCatchParam(*this, builder, ehToken, *catchParam,
484 catchStmt->getBeginLoc());
485}
486
487mlir::LogicalResult
489 cxxTryBodyEmitter &bodyCallback) {
490 mlir::Location loc = getLoc(s.getSourceRange());
491
492 // Create a scope to hold try local storage for catch params.
493 mlir::OpBuilder::InsertPoint scopeIP;
494 cir::ScopeOp::create(
495 builder, loc,
496 /*scopeBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
497 scopeIP = builder.saveInsertionPoint();
498 });
499
500 // Set personality function if not already set
501 auto funcOp = mlir::cast<cir::FuncOp>(curFn);
502 if (!funcOp.getPersonality())
503 funcOp.setPersonality(getPersonalityFn(cgm, EHPersonality::get(*this)));
504
505 mlir::OpBuilder::InsertionGuard guard(builder);
506 builder.restoreInsertionPoint(scopeIP);
507
508 const llvm::Triple &t = getTarget().getTriple();
509 // If we encounter a try statement on in an OpenMP target region offloaded
510 // to a GPU, we treat it as a basic block.
511 const bool isTargetDevice =
512 (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
513 if (isTargetDevice) {
514 cgm.errorNYI("emitCXXTryStmt: OpenMP target region offloaded to GPU");
515 return mlir::success();
516 }
517
518 mlir::Location tryLoc = getLoc(s.getBeginLoc());
519 SmallVector<mlir::Attribute> handlerAttrs;
520
521 CIRGenFunction::LexicalScope tryBodyScope{*this, tryLoc,
522 builder.getInsertionBlock()};
523
524 if (getLangOpts().EHAsynch) {
525 cgm.errorNYI("enterCXXTryStmt: EHAsynch");
526 return mlir::failure();
527 }
528
529 // Create the try operation.
530 mlir::LogicalResult tryRes = mlir::success();
531 auto tryOp = cir::TryOp::create(
532 builder, tryLoc,
533 /*tryBuilder=*/
534 [&](mlir::OpBuilder &b, mlir::Location loc) {
535 // Create a RunCleanupsScope that allows us to apply any cleanups that
536 // are created for statements within the try body before exiting the
537 // try body.
538 RunCleanupsScope tryBodyCleanups(*this);
539 if (bodyCallback(*this).failed())
540 tryRes = mlir::failure();
541 tryBodyCleanups.forceCleanup();
542 cir::YieldOp::create(builder, loc);
543 },
544 /*handlersBuilder=*/
545 [&](mlir::OpBuilder &b, mlir::Location loc,
546 mlir::OperationState &result) {
547 mlir::OpBuilder::InsertionGuard guard(b);
548 bool hasCatchAll = false;
549 unsigned numHandlers = s.getNumHandlers();
550 mlir::Type ehTokenTy = cir::EhTokenType::get(&getMLIRContext());
551 for (unsigned i = 0; i != numHandlers; ++i) {
552 const CXXCatchStmt *catchStmt = s.getHandler(i);
553 if (!catchStmt->getExceptionDecl())
554 hasCatchAll = true;
555 mlir::Region *region = result.addRegion();
556 builder.createBlock(region, /*insertPt=*/{}, {ehTokenTy}, {loc});
557 addCatchHandlerAttr(catchStmt, handlerAttrs);
558 }
559 if (!hasCatchAll) {
560 // Create unwind region.
561 mlir::Region *region = result.addRegion();
562 mlir::Block *unwindBlock =
563 builder.createBlock(region, /*insertPt=*/{}, {ehTokenTy}, {loc});
564 cir::ResumeOp::create(builder, loc, unwindBlock->getArgument(0));
565 handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
566 }
567 });
568
569 if (tryRes.failed())
570 return mlir::failure();
571
572 // Add final array of clauses into TryOp.
573 tryOp.setHandlerTypesAttr(
574 mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
575
576 // Emit the catch handler bodies. This has to be done after the try op is
577 // created and in place so that we can find the insertion point for the
578 // catch parameter alloca.
579 unsigned numHandlers = s.getNumHandlers();
580 for (unsigned i = 0; i != numHandlers; ++i) {
581 const CXXCatchStmt *catchStmt = s.getHandler(i);
582 mlir::Region *handler = &tryOp.getHandlerRegions()[i];
583 mlir::Location handlerLoc = getLoc(catchStmt->getCatchLoc());
584
585 mlir::OpBuilder::InsertionGuard guard(builder);
586 builder.setInsertionPointToStart(&handler->front());
587
588 // Get the !cir.eh_token block argument from the handler region.
589 mlir::Value ehToken = handler->front().getArgument(0);
590
591 // Enter a cleanup scope, including the catch variable and the
592 // end-catch.
593 RunCleanupsScope handlerScope(*this);
594
595 // Initialize the catch variable.
596 // TODO(cir): Move this out of CXXABI.
598 emitBeginCatch(catchStmt, ehToken);
599
600 // Emit the PGO counter increment.
602
603 // Perform the body of the catch.
604 [[maybe_unused]] mlir::LogicalResult emitResult =
605 emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
606 assert(emitResult.succeeded() && "failed to emit catch handler block");
607
608 // [except.handle]p11:
609 // The currently handled exception is rethrown if control
610 // reaches the end of a handler of the function-try-block of a
611 // constructor or destructor.
612
613 // TODO(cir): Handle implicit rethrow?
614
615 // Fall out through the catch cleanups.
616 handlerScope.forceCleanup();
617
618 mlir::Block *block = &handler->getBlocks().back();
619 if (block->empty() ||
620 !block->back().hasTrait<mlir::OpTrait::IsTerminator>()) {
621 mlir::OpBuilder::InsertionGuard guard(builder);
622 builder.setInsertionPointToEnd(block);
623 builder.createYield(handlerLoc);
624 }
625 }
626
627 return mlir::success();
628}
629
630mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
631 if (s.getTryBlock()->body_empty())
632 return mlir::LogicalResult::success();
633
634 struct simpleTryBodyEmitter final : cxxTryBodyEmitter {
635 const clang::CXXTryStmt &s;
636 simpleTryBodyEmitter(const clang::CXXTryStmt &s) : s(s) {}
637
638 mlir::LogicalResult operator()(CIRGenFunction &cgf) override {
639 return cgf.emitStmt(s.getTryBlock(), /*useCurrentScope=*/true);
640 }
641 ~simpleTryBodyEmitter() override = default;
642 };
643
644 simpleTryBodyEmitter emitter{s};
645
646 return emitCXXTryStmt(s, emitter);
647}
648
649// in classic codegen this function is mapping to `isInvokeDest` previously
650// and currently it's mapping to the conditions that performs early returns in
651// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope
652// may throw exception or now.
654 // If exceptions are disabled/ignored and SEH is not in use, then there is
655 // no invoke destination. SEH "works" even if exceptions are off. In
656 // practice, this means that C++ destructors and other EH cleanups don't
657 // run, which is consistent with MSVC's behavior, except in the presence of
658 // -EHa
659 const LangOptions &lo = cgm.getLangOpts();
660 if (!lo.Exceptions || lo.IgnoreExceptions) {
661 if (!lo.Borland && !lo.MicrosoftExt)
662 return false;
663 cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
664 return false;
665 }
666
667 // CUDA device code doesn't have exceptions.
668 if (lo.CUDA && lo.CUDAIsDevice)
669 return false;
670
671 return ehStack.requiresCatchOrCleanup();
672}
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static const EHPersonality & getCXXPersonality(const TargetInfo &target, const CodeGenOptions &cgOpts)
static const EHPersonality & getCPersonality(const TargetInfo &target, const CodeGenOptions &cgOpts)
static const EHPersonality & getObjCPersonality(const TargetInfo &target, const LangOptions &langOpts, const CodeGenOptions &cgOpts)
static llvm::StringRef getPersonalityFn(CIRGenModule &cgm, const EHPersonality &personality)
static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, mlir::Type exnPtrTy)
static cir::FuncOp getOrCreateCopyThunk(CIRGenFunction &cgf, const VarDecl &catchParam, cir::PointerType paramAddrType, mlir::Location loc)
Get or create the catch-init copy thunk for catchParam.
static const EHPersonality & getObjCXXPersonality(const TargetInfo &target, const LangOptions &langOpts, const CodeGenOptions &cgOpts)
Determines the personality function to use when both C++ and Objective-C exceptions are being caught.
static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder, mlir::Value ehToken, const VarDecl &catchParam, SourceLocation loc)
A "special initializer" callback for initializing a catch parameter during catch initialization.
static const EHPersonality & getSEHPersonalityMSVC(const llvm::Triple &triple)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
mlir::Value getPointer() const
Definition Address.h:98
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
clang::MangleContext & getMangleContext()
Gets the mangle context.
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
void forceCleanup(ArrayRef< mlir::Value * > valuesToReload={})
Force the emission of cleanups now, instead of waiting until this object is destroyed.
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
const clang::LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
void addCatchHandlerAttr(const CXXCatchStmt *catchStmt, SmallVector< mlir::Attribute > &handlerAttrs)
Address makeNaturalAddressForPointer(mlir::Value ptr, QualType t, CharUnits alignment, bool forPointeeType=false, LValueBaseInfo *baseInfo=nullptr)
Construct an address with the natural alignment of T.
void emitAnyExprToExn(const Expr *e, Address addr)
LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty)
void emitBeginCatch(const CXXCatchStmt *catchStmt, mlir::Value ehToken)
Begins a catch statement by initializing the catch variable and calling __cxa_begin_catch.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
mlir::Operation * curFn
The current function or global initializer that is generated code for.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
mlir::Type convertTypeForMem(QualType t)
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback)
const clang::Decl * curCodeDecl
This is the inner-most code context, which includes blocks.
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
void emitCXXThrowExpr(const CXXThrowExpr *e)
CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext=false)
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
void emitAutoVarCleanups(const AutoVarEmission &emission)
This class organizes the cross-function state that is used while generating CIR code.
clang::ASTContext & getASTContext() const
void insertGlobalSymbol(mlir::Operation *op)
CIRGenBuilderTy & getBuilder()
cir::FuncOp lookupFuncOp(llvm::StringRef name)
O(1) lookup of a FuncOp by name in the symbol cache.
const clang::TargetInfo & getTarget() const
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
mlir::ModuleOp getModule() const
CIRGenCXXABI & getCXXABI() const
Information for lazily generating a cleanup.
CXXCatchStmt - This represents a C++ catch block.
Definition StmtCXX.h:28
SourceLocation getCatchLoc() const
Definition StmtCXX.h:48
Stmt * getHandlerBlock() const
Definition StmtCXX.h:51
SourceLocation getBeginLoc() const LLVM_READONLY
Definition StmtCXX.h:43
VarDecl * getExceptionDecl() const
Definition StmtCXX.h:49
QualType getCaughtType() const
Definition StmtCXX.cpp:19
A C++ throw-expression (C++ [except.throw]).
Definition ExprCXX.h:1212
const Expr * getSubExpr() const
Definition ExprCXX.h:1232
CXXTryStmt - A C++ try block, including all handlers.
Definition StmtCXX.h:69
Qualifiers getQualifiers() const
Retrieve all qualifiers.
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
bool hasDWARFExceptions() const
bool hasWasmExceptions() const
bool hasSjLjExceptions() const
bool hasSEHExceptions() const
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2018
bool usesSEHTry() const
Indicates the function uses __try.
Definition Decl.h:2536
const Decl * getDecl() const
Definition GlobalDecl.h:106
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
clang::ObjCRuntime ObjCRuntime
virtual void mangleCanonicalTypeName(QualType T, raw_ostream &, bool NormalizeIntegers=false)=0
Generates a unique string for an externally visible type for use with TBAA or type uniquing.
Kind getKind() const
Definition ObjCRuntime.h:77
const VersionTuple & getVersion() const
Definition ObjCRuntime.h:78
@ MacOSX
'macosx' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the non-fragile AB...
Definition ObjCRuntime.h:35
@ FragileMacOSX
'macosx-fragile' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the fragil...
Definition ObjCRuntime.h:40
@ GNUstep
'gnustep' is the modern non-fragile GNUstep runtime.
Definition ObjCRuntime.h:56
@ ObjFW
'objfw' is the Objective-C runtime included in ObjFW
Definition ObjCRuntime.h:59
@ iOS
'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS simulator; it is always non-fragil...
Definition ObjCRuntime.h:45
@ GCC
'gcc' is the Objective-C runtime shipped with GCC, implementing a fragile Objective-C ABI
Definition ObjCRuntime.h:53
@ WatchOS
'watchos' is a variant of iOS for Apple's watchOS.
Definition ObjCRuntime.h:49
static const OpaqueValueExpr * findInCopyConstruct(const Expr *expr)
Given an expression which invokes a copy constructor — i.e.
Definition Expr.cpp:5171
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3390
A (possibly-)qualified type.
Definition TypeBase.h:937
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8485
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8630
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition TypeBase.h:361
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
Definition TypeBase.h:354
@ OCL_None
There is no lifetime qualification on this type.
Definition TypeBase.h:350
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition TypeBase.h:364
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
Definition TypeBase.h:367
ObjCLifetime getObjCLifetime() const
Definition TypeBase.h:545
Encodes a location in the source.
Exposes information about the current target.
Definition TargetInfo.h:227
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isObjCObjectPointerType() const
Definition TypeBase.h:8861
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:924
const Expr * getInit() const
Definition Decl.h:1381
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool ehCleanupScope()
static bool currentFuncletPad()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the type of a catch handler,...
The exceptions personality for a function.
static const EHPersonality XL_CPlusPlus
static const EHPersonality GNU_ObjC_SJLJ
static const EHPersonality ZOS_CPlusPlus
static const EHPersonality GNUstep_ObjC
static const EHPersonality MSVC_CxxFrameHandler3
static const EHPersonality MSVC_C_specific_handler
static const EHPersonality GNU_CPlusPlus_SEH
static const EHPersonality GNU_ObjC
static const EHPersonality GNU_CPlusPlus_SJLJ
static const EHPersonality GNU_C_SJLJ
static const EHPersonality GNU_C
static const EHPersonality NeXT_ObjC
static const EHPersonality & get(CIRGenModule &cgm, const clang::FunctionDecl *fd)
static const EHPersonality GNU_CPlusPlus
static const EHPersonality GNU_ObjCXX
static const EHPersonality GNU_C_SEH
static const EHPersonality MSVC_except_handler
static const EHPersonality GNU_ObjC_SEH
static const EHPersonality GNU_Wasm_CPlusPlus