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 if (!builder.getBlock()->mightHaveTerminator() ||
543 !builder.getBlock()->getTerminator())
544 cir::YieldOp::create(builder, loc);
545 },
546 /*handlersBuilder=*/
547 [&](mlir::OpBuilder &b, mlir::Location loc,
548 mlir::OperationState &result) {
549 mlir::OpBuilder::InsertionGuard guard(b);
550 bool hasCatchAll = false;
551 unsigned numHandlers = s.getNumHandlers();
552 mlir::Type ehTokenTy = cir::EhTokenType::get(&getMLIRContext());
553 for (unsigned i = 0; i != numHandlers; ++i) {
554 const CXXCatchStmt *catchStmt = s.getHandler(i);
555 if (!catchStmt->getExceptionDecl())
556 hasCatchAll = true;
557 mlir::Region *region = result.addRegion();
558 builder.createBlock(region, /*insertPt=*/{}, {ehTokenTy}, {loc});
559 addCatchHandlerAttr(catchStmt, handlerAttrs);
560 }
561 if (!hasCatchAll) {
562 // Create unwind region.
563 mlir::Region *region = result.addRegion();
564 mlir::Block *unwindBlock =
565 builder.createBlock(region, /*insertPt=*/{}, {ehTokenTy}, {loc});
566 cir::ResumeOp::create(builder, loc, unwindBlock->getArgument(0));
567 handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
568 }
569 });
570
571 if (tryRes.failed())
572 return mlir::failure();
573
574 // Add final array of clauses into TryOp.
575 tryOp.setHandlerTypesAttr(
576 mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
577
578 // Emit the catch handler bodies. This has to be done after the try op is
579 // created and in place so that we can find the insertion point for the
580 // catch parameter alloca.
581 unsigned numHandlers = s.getNumHandlers();
582 for (unsigned i = 0; i != numHandlers; ++i) {
583 const CXXCatchStmt *catchStmt = s.getHandler(i);
584 mlir::Region *handler = &tryOp.getHandlerRegions()[i];
585 mlir::Location handlerLoc = getLoc(catchStmt->getCatchLoc());
586
587 mlir::OpBuilder::InsertionGuard guard(builder);
588 builder.setInsertionPointToStart(&handler->front());
589
590 // Get the !cir.eh_token block argument from the handler region.
591 mlir::Value ehToken = handler->front().getArgument(0);
592
593 // Enter a cleanup scope, including the catch variable and the
594 // end-catch.
595 RunCleanupsScope handlerScope(*this);
596
597 // Initialize the catch variable.
598 // TODO(cir): Move this out of CXXABI.
600 emitBeginCatch(catchStmt, ehToken);
601
602 // Emit the PGO counter increment.
604
605 // Perform the body of the catch.
606 [[maybe_unused]] mlir::LogicalResult emitResult =
607 emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
608 assert(emitResult.succeeded() && "failed to emit catch handler block");
609
610 // [except.handle]p11:
611 // The currently handled exception is rethrown if control
612 // reaches the end of a handler of the function-try-block of a
613 // constructor or destructor.
614
615 // TODO(cir): Handle implicit rethrow?
616
617 // Fall out through the catch cleanups.
618 handlerScope.forceCleanup();
619
620 mlir::Block *block = &handler->getBlocks().back();
621 if (block->empty() ||
622 !block->back().hasTrait<mlir::OpTrait::IsTerminator>()) {
623 mlir::OpBuilder::InsertionGuard guard(builder);
624 builder.setInsertionPointToEnd(block);
625 builder.createYield(handlerLoc);
626 }
627 }
628
629 return mlir::success();
630}
631
632mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
633 if (s.getTryBlock()->body_empty())
634 return mlir::LogicalResult::success();
635
636 struct simpleTryBodyEmitter final : cxxTryBodyEmitter {
637 const clang::CXXTryStmt &s;
638 simpleTryBodyEmitter(const clang::CXXTryStmt &s) : s(s) {}
639
640 mlir::LogicalResult operator()(CIRGenFunction &cgf) override {
641 return cgf.emitStmt(s.getTryBlock(), /*useCurrentScope=*/true);
642 }
643 ~simpleTryBodyEmitter() override = default;
644 };
645
646 simpleTryBodyEmitter emitter{s};
647
648 return emitCXXTryStmt(s, emitter);
649}
650
651// in classic codegen this function is mapping to `isInvokeDest` previously
652// and currently it's mapping to the conditions that performs early returns in
653// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope
654// may throw exception or now.
656 // If exceptions are disabled/ignored and SEH is not in use, then there is
657 // no invoke destination. SEH "works" even if exceptions are off. In
658 // practice, this means that C++ destructors and other EH cleanups don't
659 // run, which is consistent with MSVC's behavior, except in the presence of
660 // -EHa
661 const LangOptions &lo = cgm.getLangOpts();
662 if (!lo.Exceptions || lo.IgnoreExceptions) {
663 if (!lo.Borland && !lo.MicrosoftExt)
664 return false;
665 cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
666 return false;
667 }
668
669 // CUDA device code doesn't have exceptions.
670 if (lo.CUDA && lo.CUDAIsDevice)
671 return false;
672
673 return ehStack.requiresCatchOrCleanup();
674}
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
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
CXXCatchStmt * getHandler(unsigned i)
Definition StmtCXX.h:108
unsigned getNumHandlers() const
Definition StmtCXX.h:107
SourceLocation getBeginLoc() const LLVM_READONLY
Definition StmtCXX.h:93
CompoundStmt * getTryBlock()
Definition StmtCXX.h:100
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
bool body_empty() const
Definition Stmt.h:1794
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:5173
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3392
A (possibly-)qualified type.
Definition TypeBase.h:937
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8487
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:8632
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.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
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:8863
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