diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -532,6 +532,14 @@ int b[0]; // NOT a flexible array member. }; +- :option:`-fstrict-noexcept` and + :option:`-fno-strict-noexcept` - + By default, if an exception tries to escape out of a function with C++'s + ``noexcept`` exception specification, the program will be terminated. + This option (default off), allows to opt-in into a language dialect, + where such an exception escape causes Undefined Behaviour instead. + + Deprecated Compiler Flags ------------------------- - ``-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang`` diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1787,6 +1787,12 @@ * ``16`` - Forces ``_Float16`` operations to be emitted without using excess precision arithmetic. +.. option:: `-fstrict-noexcept` + By default, if an exception tries to escape out of a function with C++'s + ``noexcept`` exception specification, the program will be terminated. + This option (default off), allows to opt-in into a language dialect, + where such an exception escape causes Undefined Behaviour instead. + .. _crtfastmath.o: A note about ``crtfastmath.o`` diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -504,6 +504,10 @@ /// non-deleting destructors. (No effect on Microsoft ABI.) CODEGENOPT(CtorDtorReturnThis, 1, 0) +/// When enabled, redefines exception escape out of an `noexcept` function +/// from causing program termination to causing UB (default off). +CODEGENOPT(StrictNoexcept, 1, 0) + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1578,6 +1578,14 @@ def fignore_exceptions : Flag<["-"], "fignore-exceptions">, Group, Flags<[CC1Option]>, HelpText<"Enable support for ignoring exception handling constructs">, MarshallingInfoFlag>; +defm strict_noexcept : BoolFOption<"strict-noexcept", + CodeGenOpts<"StrictNoexcept">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[CoreOption]>>; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group, HelpText<"Allows control over excess precision on targets where native " "support for the precision types is not available. By default, excess " diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5411,6 +5411,9 @@ llvm::CallBase *CI; if (!InvokeDest) { CI = Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList); + if (EHStack.wouldUnwindBeUB()) + Attrs = Attrs.addFnAttribute(getLLVMContext(), + llvm::Attribute::AttrKind::NoUnwind); } else { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); CI = Builder.CreateInvoke(IRFuncTy, CalleePtr, Cont, InvokeDest, IRCallArgs, diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -86,6 +86,13 @@ unsigned CleanupSize : 12; }; + class UBBitFields { + friend class EHUBScope; + unsigned : NumCommonBits; + + unsigned IsSanitized : 32 - NumCommonBits; + }; + class FilterBitFields { friend class EHFilterScope; unsigned : NumCommonBits; @@ -97,16 +104,18 @@ CommonBitFields CommonBits; CatchBitFields CatchBits; CleanupBitFields CleanupBits; + UBBitFields UBBits; FilterBitFields FilterBits; }; public: - enum Kind { Cleanup, Catch, Terminate, Filter }; + enum Kind { Cleanup, Catch, Terminate, UB, Filter }; EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr), EnclosingEHScope(enclosingEHScope) { CommonBits.Kind = kind; + assert(CommonBits.Kind == kind && "Kind overflow?"); } Kind getKind() const { return static_cast(CommonBits.Kind); } @@ -487,6 +496,22 @@ } }; +/// An exceptions scope which causes UB if any exception reaches it. +class EHUBScope : public EHScope { +public: + EHUBScope(bool isSanitized, EHScopeStack::stable_iterator enclosingEHScope) + : EHScope(UB, enclosingEHScope) { + UBBits.IsSanitized = isSanitized; + assert(UBBits.IsSanitized == isSanitized && "IsSanitized overflow?"); + } + + bool getIsSanitized() const { return UBBits.IsSanitized; } + + static size_t getSize() { return sizeof(EHUBScope); } + + static bool classof(const EHScope *scope) { return scope->getKind() == UB; } +}; + /// A non-stable pointer into the scope stack. class EHScopeStack::iterator { char *Ptr; @@ -524,6 +549,10 @@ case EHScope::Terminate: Size = EHTerminateScope::getSize(); break; + + case EHScope::UB: + Size = EHUBScope::getSize(); + break; } Ptr += llvm::alignTo(Size, ScopeStackAlignment); return *this; @@ -572,6 +601,14 @@ deallocate(EHTerminateScope::getSize()); } +inline void EHScopeStack::popUB() { + assert(!empty() && "popping exception stack when not empty"); + + EHUBScope &scope = cast(*begin()); + InnermostEHScope = scope.getEnclosingEHScope(); + deallocate(EHUBScope::getSize()); +} + inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { assert(sp.isValid() && "finding invalid savepoint"); assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -152,7 +152,7 @@ return true; } -bool EHScopeStack::requiresLandingPad() const { +EHScopeStack::iterator EHScopeStack::getInnermostEHScopeForUnwind() const { for (stable_iterator si = getInnermostEHScope(); si != stable_end(); ) { // Skip lifetime markers. if (auto *cleanup = dyn_cast(&*find(si))) @@ -160,10 +160,30 @@ si = cleanup->getEnclosingEHScope(); continue; } - return true; + return find(si); } - return false; + return end(); +} + +bool EHScopeStack::wouldUnwindBeUB() const { + EHScopeStack::iterator it = getInnermostEHScopeForUnwind(); + if (it == end()) + return false; + + // If we are in exception scope which causes UB if any exception reaches it, + // and we are not sanitizing for that UB, then the unwind would indeed be UB. + // because the callee will not unwind and the landing pad won't be reached. + auto *ub = dyn_cast(&*it); + return ub && !ub->getIsSanitized(); +} + +bool EHScopeStack::requiresLandingPad() const { + EHScopeStack::iterator it = getInnermostEHScopeForUnwind(); + if (it == end()) + return false; + + return !wouldUnwindBeUB(); } EHScopeStack::stable_iterator @@ -188,9 +208,15 @@ // some, or all cleanups are called before std::terminate. Thus, when // terminate is the current EH scope, we may skip adding any EH cleanup // scopes. - if (InnermostEHScope != stable_end() && - find(InnermostEHScope)->getKind() == EHScope::Terminate) - IsEHCleanup = false; + // + // Likewise, if the exception escaping out of the function would be UB, + // skip adding any EH cleanup scopes. + if (InnermostEHScope != stable_end()) { + if (EHScope::Kind InnermostEHScopeKind = find(InnermostEHScope)->getKind(); + InnermostEHScopeKind == EHScope::Terminate || + InnermostEHScopeKind == EHScope::UB) + IsEHCleanup = false; + } EHCleanupScope *Scope = new (Buffer) EHCleanupScope(IsNormalCleanup, @@ -240,7 +266,8 @@ } EHFilterScope *EHScopeStack::pushFilter(unsigned numFilters) { - assert(getInnermostEHScope() == stable_end()); + assert(getInnermostEHScope() == stable_end() || + isa(*find(getInnermostEHScope()))); char *buffer = allocate(EHFilterScope::getSizeForNumFilters(numFilters)); EHFilterScope *filter = new (buffer) EHFilterScope(numFilters); InnermostEHScope = stable_begin(); @@ -270,6 +297,12 @@ InnermostEHScope = stable_begin(); } +void EHScopeStack::pushUB(bool isSanitized) { + char *Buffer = allocate(EHUBScope::getSize()); + new (Buffer) EHUBScope(isSanitized, InnermostEHScope); + InnermostEHScope = stable_begin(); +} + /// Remove any 'null' fixups on the stack. However, we can't pop more /// fixups than the fixup depth on the innermost normal cleanup, or /// else fixups that we try to add to that cleanup will end up in the diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -459,80 +459,12 @@ EmitBlock(createBasicBlock("throw.cont")); } -void CodeGenFunction::EmitStartEHSpec(const Decl *D) { - if (!CGM.getLangOpts().CXXExceptions) - return; - - const FunctionDecl* FD = dyn_cast_or_null(D); - if (!FD) { - // Check if CapturedDecl is nothrow and create terminate scope for it. - if (const CapturedDecl* CD = dyn_cast_or_null(D)) { - if (CD->isNothrow()) - EHStack.pushTerminate(); - } - return; - } - const FunctionProtoType *Proto = FD->getType()->getAs(); - if (!Proto) - return; - - ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - // In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way - // as noexcept. In earlier standards, it is handled in this block, along with - // 'throw(X...)'. - if (EST == EST_Dynamic || - (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { - // TODO: Revisit exception specifications for the MS ABI. There is a way to - // encode these in an object file but MSVC doesn't do anything with it. - if (getTarget().getCXXABI().isMicrosoft()) - return; - // In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In - // case of throw with types, we ignore it and print a warning for now. - // TODO Correctly handle exception specification in Wasm EH - if (CGM.getLangOpts().hasWasmExceptions()) { - if (EST == EST_DynamicNone) - EHStack.pushTerminate(); - else - CGM.getDiags().Report(D->getLocation(), - diag::warn_wasm_dynamic_exception_spec_ignored) - << FD->getExceptionSpecSourceRange(); - return; - } - // Currently Emscripten EH only handles 'throw()' but not 'throw' with - // types. 'throw()' handling will be done in JS glue code so we don't need - // to do anything in that case. Just print a warning message in case of - // throw with types. - // TODO Correctly handle exception specification in Emscripten EH - if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly && - CGM.getLangOpts().getExceptionHandling() == - LangOptions::ExceptionHandlingKind::None && - EST == EST_Dynamic) - CGM.getDiags().Report(D->getLocation(), - diag::warn_wasm_dynamic_exception_spec_ignored) - << FD->getExceptionSpecSourceRange(); - - unsigned NumExceptions = Proto->getNumExceptions(); - EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); - - for (unsigned I = 0; I != NumExceptions; ++I) { - QualType Ty = Proto->getExceptionType(I); - QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, - /*ForEH=*/true); - Filter->setFilter(I, EHType); - } - } else if (Proto->canThrow() == CT_Cannot) { - // noexcept functions are simple terminate scopes. - if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur - EHStack.pushTerminate(); - } -} - /// Emit the dispatch block for a filter scope if necessary. static void emitFilterDispatchBlock(CodeGenFunction &CGF, EHFilterScope &filterScope) { llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock(); - if (!dispatchBlock) return; + if (!dispatchBlock) + return; if (dispatchBlock->use_empty()) { delete dispatchBlock; return; @@ -556,56 +488,147 @@ CGF.EmitBlock(unexpectedBB); } - // Call __cxa_call_unexpected. This doesn't need to be an invoke - // because __cxa_call_unexpected magically filters exceptions - // according to the last landing pad the exception was thrown - // into. Seriously. - llvm::Value *exn = CGF.getExceptionFromSlot(); - CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn) - ->setDoesNotReturn(); + if (!CGF.CGM.getCodeGenOpts().StrictNoexcept) { + // Call __cxa_call_unexpected. This doesn't need to be an invoke + // because __cxa_call_unexpected magically filters exceptions + // according to the last landing pad the exception was thrown + // into. Seriously. + llvm::Value *exn = CGF.getExceptionFromSlot(); + CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)->setDoesNotReturn(); + } + + // FIXME: UBSan handling. CGF.Builder.CreateUnreachable(); } +bool CodeGenFunction::ExceptionEscapeIsProgramTermination(const Decl *D, + bool IsStart) { + assert(CGM.getLangOpts().CXXExceptions && "Only for CXX-Exceptions mode."); + + const FunctionDecl *FD = dyn_cast_or_null(D); + if (!FD) { + // Check if CapturedDecl is nothrow and create terminate scope for it. + if (const CapturedDecl *CD = dyn_cast_or_null(D)) { + if (CD->isNothrow()) + return true; + } + return false; + } + + const FunctionProtoType *Proto = FD->getType()->getAs(); + if (!Proto) + return false; + + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + // In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way + // as noexcept. In earlier standards, it is handled in this block, along with + // 'throw(X...)'. + if (EST == EST_Dynamic || + (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { + // TODO: Revisit exception specifications for the MS ABI. There is a way to + // encode these in an object file but MSVC doesn't do anything with it. + if (getTarget().getCXXABI().isMicrosoft()) + return false; + // In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In + // case of throw with types, we ignore it and print a warning for now. + // TODO Correctly handle exception specification in Wasm EH + if (CGM.getLangOpts().hasWasmExceptions()) { + if (EST == EST_DynamicNone) + return true; + else if (IsStart) + CGM.getDiags().Report(D->getLocation(), + diag::warn_wasm_dynamic_exception_spec_ignored) + << FD->getExceptionSpecSourceRange(); + return false; + } + // Currently Emscripten EH only handles 'throw()' but not 'throw' with + // types. 'throw()' handling will be done in JS glue code so we don't need + // to do anything in that case. Just print a warning message in case of + // throw with types. + // TODO Correctly handle exception specification in Emscripten EH + if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly && + CGM.getLangOpts().getExceptionHandling() == + LangOptions::ExceptionHandlingKind::None && + EST == EST_Dynamic && IsStart) + CGM.getDiags().Report(D->getLocation(), + diag::warn_wasm_dynamic_exception_spec_ignored) + << FD->getExceptionSpecSourceRange(); + + // As a language dialect (under `-fstrict-noexcept`), + // C++ dynamic exception specifications are treated as no-ops. + // FIXME: revisit when adding UBSan bits. + if (!CGM.getCodeGenOpts().StrictNoexcept) { + if (IsStart) { + unsigned NumExceptions = Proto->getNumExceptions(); + EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); + + for (unsigned I = 0; I != NumExceptions; ++I) { + QualType Ty = Proto->getExceptionType(I); + QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, + /*ForEH=*/true); + Filter->setFilter(I, EHType); + } + } else { + EHFilterScope &filterScope = cast(*EHStack.begin()); + emitFilterDispatchBlock(*this, filterScope); + EHStack.popFilter(); + } + } + } else if (Proto->canThrow() == CT_Cannot) { + // noexcept functions are simple terminate scopes. + if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur + return true; + } + return false; +} + +void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + if (!CGM.getLangOpts().CXXExceptions) + return; + + // If the LLVM IR function is marked as non-unwinding, + // then exception escape is UB. UBSan might be interested in this. + // FIXME: why is -EHa special? This seems broken. + if (CurFn->hasFnAttribute(llvm::Attribute::NoUnwind) && + !getLangOpts().EHAsynch) + EHStack.pushUB(/*isSanitized=*/false); // FIXME: implement UBSan bits. + + // Does the EH Specification for the current function mandate that the + // exception escaping out of the current function is required to cause + // program termination? + if (ExceptionEscapeIsProgramTermination(D, /*IsStart=*/true)) { + assert(CurFn->hasFnAttribute(llvm::Attribute::NoUnwind) && + "Forgot to manifest nounwind function attribute in LLVM IR."); + // Are we *NOT* in the language dialect where this situation is allowed to + // cause Undefined Behaviour instead of guaranteed program termination? + if (!CGM.getCodeGenOpts().StrictNoexcept) + EHStack.pushTerminate(); + } +} + void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (!CGM.getLangOpts().CXXExceptions) return; - const FunctionDecl* FD = dyn_cast_or_null(D); - if (!FD) { - // Check if CapturedDecl is nothrow and pop terminate scope for it. - if (const CapturedDecl* CD = dyn_cast_or_null(D)) { - if (CD->isNothrow() && !EHStack.empty()) - EHStack.popTerminate(); - } - return; + // Does the EH Specification for the current function mandate that the + // exception escaping out of the current function is required to cause + // program termination? + if (ExceptionEscapeIsProgramTermination(D, /*IsStart=*/false)) { + assert(CurFn->hasFnAttribute(llvm::Attribute::NoUnwind) && + "Forgot to manifest nounwind function attribute in LLVM IR."); + // Are we *NOT* in the language dialect where this situation is allowed to + // cause Undefined Behaviour instead of guaranteed program termination? + if (!CGM.getCodeGenOpts().StrictNoexcept) + EHStack.popTerminate(); } - const FunctionProtoType *Proto = FD->getType()->getAs(); - if (!Proto) - return; - ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (EST == EST_Dynamic || - (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { - // TODO: Revisit exception specifications for the MS ABI. There is a way to - // encode these in an object file but MSVC doesn't do anything with it. - if (getTarget().getCXXABI().isMicrosoft()) - return; - // In wasm we currently treat 'throw()' in the same way as 'noexcept'. In - // case of throw with types, we ignore it and print a warning for now. - // TODO Correctly handle exception specification in wasm - if (CGM.getLangOpts().hasWasmExceptions()) { - if (EST == EST_DynamicNone) - EHStack.popTerminate(); - return; - } - EHFilterScope &filterScope = cast(*EHStack.begin()); - emitFilterDispatchBlock(*this, filterScope); - EHStack.popFilter(); - } else if (Proto->canThrow() == CT_Cannot && - /* possible empty when under async exceptions */ - !EHStack.empty()) { - EHStack.popTerminate(); - } + // If the LLVM IR function is marked as non-unwinding, + // then exception escape is UB. UBSan might be interested in this. + // FIXME: why is -EHa special? This seems broken. + if (CurFn->hasFnAttribute(llvm::Attribute::NoUnwind) && + !getLangOpts().EHAsynch) + EHStack.popUB(); } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { @@ -692,6 +715,11 @@ case EHScope::Terminate: dispatchBlock = getTerminateHandler(); break; + + case EHScope::UB: + assert(!cast(scope).getIsSanitized()); + dispatchBlock = getUnreachableBlock(); + break; } scope.setCachedEHDispatchBlock(dispatchBlock); } @@ -733,6 +761,10 @@ case EHScope::Terminate: DispatchBlock->setName("terminate"); break; + + case EHScope::UB: + llvm_unreachable("Will never be called."); + break; } EHS.setCachedEHDispatchBlock(DispatchBlock); return DispatchBlock; @@ -748,6 +780,7 @@ case EHScope::Filter: case EHScope::Catch: case EHScope::Terminate: + case EHScope::UB: return false; } @@ -813,6 +846,9 @@ switch (innermostEHScope.getKind()) { case EHScope::Terminate: return getTerminateLandingPad(); + case EHScope::UB: + llvm_unreachable("Will never be called."); + break; case EHScope::Catch: case EHScope::Cleanup: @@ -858,7 +894,8 @@ continue; case EHScope::Filter: { - assert(I.next() == EHStack.end() && "EH filter is not end of EH stack"); + assert((I.next() == EHStack.end() || isa(*I.next())) && + "EH filter is not end of EH stack"); assert(!hasCatchAll && "EH filter reached after catch-all"); // Filter scopes get added to the landingpad in weird ways. @@ -872,7 +909,8 @@ } case EHScope::Terminate: - // Terminate scopes are basically catch-alls. + case EHScope::UB: + // Terminate/UB scopes are basically catch-alls. assert(!hasCatchAll); hasCatchAll = true; goto done; @@ -943,7 +981,7 @@ Builder.restoreIP(savedIP); return lpad; -} + } static void emitCatchPadBlock(CodeGenFunction &CGF, EHCatchScope &CatchScope) { llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2382,6 +2382,9 @@ /// Emit a test that checks if the return value \p RV is nonnull. void EmitReturnValueCheck(llvm::Value *RV); + /// Internal to `EmitStartEHSpec()`/`EmitEndEHSpec()`, do not use directly. + bool ExceptionEscapeIsProgramTermination(const Decl *D, bool IsStart); + /// EmitStartEHSpec - Emit the start of the exception spec. void EmitStartEHSpec(const Decl *D); diff --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h --- a/clang/lib/CodeGen/EHScopeStack.h +++ b/clang/lib/CodeGen/EHScopeStack.h @@ -342,6 +342,12 @@ /// Pops a terminate handler off the stack. void popTerminate(); + /// Push a UB handler on the stack. + void pushUB(bool isSanitized); + + /// Pops a UB handler off the stack. + void popUB(); + // Returns true iff the current scope is either empty or contains only // lifetime markers, i.e. no real cleanup code bool containsOnlyLifetimeMarkers(stable_iterator Old) const; @@ -349,6 +355,12 @@ /// Determines whether the exception-scopes stack is empty. bool empty() const { return StartOfData == EndOfBuffer; } + /// An unstable reference to a scope-stack depth. Invalidated by + /// pushes but not pops. + class iterator; + + EHScopeStack::iterator getInnermostEHScopeForUnwind() const; + bool wouldUnwindBeUB() const; bool requiresLandingPad() const; /// Determines whether there are any normal cleanups on the stack. @@ -367,11 +379,6 @@ return InnermostEHScope; } - - /// An unstable reference to a scope-stack depth. Invalidated by - /// pushes but not pops. - class iterator; - /// Returns an iterator pointing to the innermost EH scope. iterator begin() const; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -371,6 +371,10 @@ CmdArgs.push_back("-fcxx-exceptions"); EH = true; + + if (Args.hasFlag(options::OPT_fstrict_noexcept, + options::OPT_fno_strict_noexcept, false)) + CmdArgs.push_back("-fstrict-noexcept"); } } diff --git a/clang/test/CodeGenCXX/exception-escape-as-ub-cleanups.cpp b/clang/test/CodeGenCXX/exception-escape-as-ub-cleanups.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/exception-escape-as-ub-cleanups.cpp @@ -0,0 +1,550 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-NO-EXCEPTIONS +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-NORMAL-NOEXCEPT +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions -fstrict-noexcept | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-STRICT-NOEXCEPT + +void will_throw(int line = __builtin_LINE()); +void might_throw(int line = __builtin_LINE()); +void will_not_throw(int line = __builtin_LINE()) noexcept; + +struct RAIIStruct { + RAIIStruct(int line = __builtin_LINE()); + ~RAIIStruct(); +}; + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE3:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE7:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NO-EXCEPTIONS: if.then: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z11might_throwi(i32 noundef 200) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR3:[0-9]+]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END]] +// CHECK-NO-EXCEPTIONS: if.end: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]] +// CHECK-NO-EXCEPTIONS: if.then2: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]], i32 noundef 300) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z11might_throwi(i32 noundef 400) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END4]] +// CHECK-NO-EXCEPTIONS: if.end4: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP5:%.*]] = icmp eq i32 [[TMP2]], 2 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP5]], label [[IF_THEN6:%.*]], label [[IF_END8:%.*]] +// CHECK-NO-EXCEPTIONS: if.then6: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE7]], i32 noundef 600) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 700) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE7]]) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END8]] +// CHECK-NO-EXCEPTIONS: if.end8: +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE4:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE11:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 200) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont1: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-NORMAL-NOEXCEPT: if.end: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END8:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then3: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE4]], i32 noundef 300) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont5: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 400) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont7: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE4]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad6: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE4]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH]] +// CHECK-NORMAL-NOEXCEPT: catch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP8:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR6:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: try.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END8]] +// CHECK-NORMAL-NOEXCEPT: if.end8: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP9:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP9]], 2 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END14:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then10: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE11]], i32 noundef 600) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT12:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont12: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 700) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT13:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont13: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE11]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END14]] +// CHECK-NORMAL-NOEXCEPT: if.end14: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: terminate.lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP10:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP11:%.*]] = extractvalue { ptr, i32 } [[TMP10]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP11]]) #[[ATTR7:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: unreachable: +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE3:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE9:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) #[[ATTR5:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z11might_throwi(i32 noundef 200) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-STRICT-NOEXCEPT: if.end: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END6:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then2: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]], i32 noundef 300) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 400) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont5: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad4: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH]] +// CHECK-STRICT-NOEXCEPT: catch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP8:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__cxa_rethrow() #[[ATTR6:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// CHECK-STRICT-NOEXCEPT: try.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END6]] +// CHECK-STRICT-NOEXCEPT: if.end6: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP9:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP7:%.*]] = icmp eq i32 [[TMP9]], 2 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP7]], label [[IF_THEN8:%.*]], label [[IF_END10:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then8: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE9]], i32 noundef 600) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 700) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE9]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END10]] +// CHECK-STRICT-NOEXCEPT: if.end10: +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// +void exception_escape_is_program_termination_or_ub(int x) noexcept { + if(x == 0) { +#line 100 + RAIIStruct state; +#line 200 + might_throw(); + } + if(x == 1) { + try { +#line 300 + RAIIStruct state; +#line 400 + might_throw(); + } catch (...) { +#line 500 + throw; + } + } + if(x == 2) { +#line 600 + RAIIStruct state; +#line 700 + will_throw(); + } +} + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE3:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: [[STATE7:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NO-EXCEPTIONS: if.then: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z11might_throwi(i32 noundef 200) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END]] +// CHECK-NO-EXCEPTIONS: if.end: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]] +// CHECK-NO-EXCEPTIONS: if.then2: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]], i32 noundef 300) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z11might_throwi(i32 noundef 400) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END4]] +// CHECK-NO-EXCEPTIONS: if.end4: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP5:%.*]] = icmp eq i32 [[TMP2]], 2 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP5]], label [[IF_THEN6:%.*]], label [[IF_END8:%.*]] +// CHECK-NO-EXCEPTIONS: if.then6: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE7]], i32 noundef 600) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 700) +// CHECK-NO-EXCEPTIONS-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE7]]) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END8]] +// CHECK-NO-EXCEPTIONS: if.end8: +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE3:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[STATE13:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 200) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-NORMAL-NOEXCEPT: lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: cleanup +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.end: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP4:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP4]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END10:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then2: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]], i32 noundef 300) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont5: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 400) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont7: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad4: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad6: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH]] +// CHECK-NORMAL-NOEXCEPT: catch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP11:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD8:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad8: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP12:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: cleanup +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP13]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP14:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP14]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_end_catch() +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont9: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-NORMAL-NOEXCEPT: try.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END10]] +// CHECK-NORMAL-NOEXCEPT: if.end10: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP15:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP11:%.*]] = icmp eq i32 [[TMP15]], 2 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP11]], label [[IF_THEN12:%.*]], label [[IF_END16:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then12: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]], i32 noundef 600) +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 700) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT15:%.*]] unwind label [[LPAD14:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont15: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END16]] +// CHECK-NORMAL-NOEXCEPT: lpad14: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP16:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: cleanup +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP17:%.*]] = extractvalue { ptr, i32 } [[TMP16]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP17]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP18:%.*]] = extractvalue { ptr, i32 } [[TMP16]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP18]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]]) #[[ATTR5]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-NORMAL-NOEXCEPT: if.end16: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: eh.resume: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN17:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN17]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL18:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: resume { ptr, i32 } [[LPAD_VAL18]] +// CHECK-NORMAL-NOEXCEPT: terminate.lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP19:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP20:%.*]] = extractvalue { ptr, i32 } [[TMP19]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP20]]) #[[ATTR7]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: unreachable: +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR3:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE:%.*]] = alloca [[STRUCT_RAIISTRUCT:%.*]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE3:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: [[STATE13:%.*]] = alloca [[STRUCT_RAIISTRUCT]], align 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]], i32 noundef 100) +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 200) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-STRICT-NOEXCEPT: lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: cleanup +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-STRICT-NOEXCEPT: if.end: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP4:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP4]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END10:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then2: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]], i32 noundef 300) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont5: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 400) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont7: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad4: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad6: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE3]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH]] +// CHECK-STRICT-NOEXCEPT: catch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP11:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD8:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad8: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP12:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: cleanup +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP13]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP14:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP14]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @__cxa_end_catch() +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont9: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-STRICT-NOEXCEPT: try.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END10]] +// CHECK-STRICT-NOEXCEPT: if.end10: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP15:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP11:%.*]] = icmp eq i32 [[TMP15]], 2 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP11]], label [[IF_THEN12:%.*]], label [[IF_END16:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then12: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructC1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]], i32 noundef 600) +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 700) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT15:%.*]] unwind label [[LPAD14:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont15: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END16]] +// CHECK-STRICT-NOEXCEPT: lpad14: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP16:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: cleanup +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP17:%.*]] = extractvalue { ptr, i32 } [[TMP16]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP17]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP18:%.*]] = extractvalue { ptr, i32 } [[TMP16]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP18]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_ZN10RAIIStructD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[STATE13]]) #[[ATTR5]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-STRICT-NOEXCEPT: if.end16: +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// CHECK-STRICT-NOEXCEPT: eh.resume: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN17:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN17]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: [[LPAD_VAL18:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: resume { ptr, i32 } [[LPAD_VAL18]] +// CHECK-STRICT-NOEXCEPT: terminate.lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP19:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP20:%.*]] = extractvalue { ptr, i32 } [[TMP19]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP20]]) #[[ATTR7:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// CHECK-STRICT-NOEXCEPT: unreachable: +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// +void exception_escape_is_ok(int x) { + if(x == 0) { +#line 100 + RAIIStruct state; +#line 200 + might_throw(); + } + if(x == 1) { + try { +#line 300 + RAIIStruct state; +#line 400 + might_throw(); + } catch (...) { +#line 500 + throw; + } + } + if(x == 2) { +#line 600 + RAIIStruct state; +#line 700 + will_throw(); + } +} +//. +// CHECK-NO-EXCEPTIONS: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #3 = { nounwind } +//. +// CHECK-NORMAL-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #2 = { noinline noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #3 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #4 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #5 = { nounwind } +// CHECK-NORMAL-NOEXCEPT: attributes #6 = { noreturn } +// CHECK-NORMAL-NOEXCEPT: attributes #7 = { noreturn nounwind } +//. +// CHECK-STRICT-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #3 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #4 = { noinline noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #5 = { nounwind } +// CHECK-STRICT-NOEXCEPT: attributes #6 = { noreturn } +// CHECK-STRICT-NOEXCEPT: attributes #7 = { noreturn nounwind } +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// CHECK-ALL: {{.*}} +// CHECK-EXCEPTIONS: {{.*}} diff --git a/clang/test/CodeGenCXX/exception-escape.cpp b/clang/test/CodeGenCXX/exception-escape.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/exception-escape.cpp @@ -0,0 +1,632 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-NO-EXCEPTIONS +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-NORMAL-NOEXCEPT +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions -fstrict-noexcept | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-STRICT-NOEXCEPT + +void will_throw(int line = __builtin_LINE()); +void might_throw(int line = __builtin_LINE()); +void will_not_throw(int line = __builtin_LINE()) noexcept; + +//. +// CHECK-ALL: @_ZTIi = external constant ptr +//. +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NO-EXCEPTIONS: if.then: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END]] +// CHECK-NO-EXCEPTIONS: if.end: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR3:[0-9]+]] +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +// CHECK-NO-EXCEPTIONS: if.then2: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 300) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END3]] +// CHECK-NO-EXCEPTIONS: if.end3: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP4:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP4]], label [[IF_THEN5:%.*]], label [[IF_END6:%.*]] +// CHECK-NO-EXCEPTIONS: if.then5: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 500) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END6]] +// CHECK-NO-EXCEPTIONS: if.end6: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP3:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP7:%.*]] = icmp eq i32 [[TMP3]], 5 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP7]], label [[IF_THEN8:%.*]], label [[IF_END9:%.*]] +// CHECK-NO-EXCEPTIONS: if.then8: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 900) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END9]] +// CHECK-NO-EXCEPTIONS: if.end9: +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X15:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-NORMAL-NOEXCEPT: if.end: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR6:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then2: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 300) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont3: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END4]] +// CHECK-NORMAL-NOEXCEPT: if.end4: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP5:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP5]], label [[IF_THEN6:%.*]], label [[IF_END9:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then6: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 500) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont7: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP3:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP4]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP5]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: catch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP6:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 600) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 700) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont8: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR7:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: try.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END9]] +// CHECK-NORMAL-NOEXCEPT: if.end9: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP7:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP10:%.*]] = icmp eq i32 [[TMP7]], 5 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP10]], label [[IF_THEN11:%.*]], label [[IF_END18:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then11: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 900) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT13:%.*]] unwind label [[LPAD12:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont13: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT17:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad12: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr @_ZTIi +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH_DISPATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: catch.dispatch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP11:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP11]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[MATCHES]], label [[CATCH14:%.*]], label [[TERMINATE_HANDLER:%.*]] +// CHECK-NORMAL-NOEXCEPT: catch14: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN16:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP12:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN16]]) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP12]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP13]], ptr [[X15]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXCEPTION:%.*]] = call ptr @__cxa_allocate_exception(i64 4) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP14:%.*]] = load i32, ptr [[X15]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP14]], ptr [[EXCEPTION]], align 16 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR7]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE]] unwind label [[TERMINATE_LPAD]] +// CHECK-NORMAL-NOEXCEPT: try.cont17: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END18]] +// CHECK-NORMAL-NOEXCEPT: if.end18: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: terminate.lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP15:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP16:%.*]] = extractvalue { ptr, i32 } [[TMP15]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP16]]) #[[ATTR8:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: terminate.handler: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN19:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[EXN19]]) #[[ATTR8]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: unreachable: +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z45exception_escape_is_program_termination_or_ubi +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[X12:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) #[[ATTR6:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-STRICT-NOEXCEPT: if.end: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then2: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 300) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END3]] +// CHECK-STRICT-NOEXCEPT: if.end3: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP4:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP4]], label [[IF_THEN5:%.*]], label [[IF_END6:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then5: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 500) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP3:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP4]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP5]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: catch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP6:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 600) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z11might_throwi(i32 noundef 700) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__cxa_rethrow() #[[ATTR7:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// CHECK-STRICT-NOEXCEPT: try.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END6]] +// CHECK-STRICT-NOEXCEPT: if.end6: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP7:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP7:%.*]] = icmp eq i32 [[TMP7]], 5 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP7]], label [[IF_THEN8:%.*]], label [[IF_END15:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then8: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 900) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT10:%.*]] unwind label [[LPAD9:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont10: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT14:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad9: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr @_ZTIi +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH_DISPATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: catch.dispatch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP11:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP11]] +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[MATCHES]], label [[CATCH11:%.*]], label [[UNREACHABLE:%.*]] +// CHECK-STRICT-NOEXCEPT: catch11: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN13:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP12:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN13]]) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP12]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP13]], ptr [[X12]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXCEPTION:%.*]] = call ptr @__cxa_allocate_exception(i64 4) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP14:%.*]] = load i32, ptr [[X12]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP14]], ptr [[EXCEPTION]], align 16 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR7]] +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// CHECK-STRICT-NOEXCEPT: try.cont14: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END15]] +// CHECK-STRICT-NOEXCEPT: if.end15: +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// CHECK-STRICT-NOEXCEPT: unreachable: +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// +void exception_escape_is_program_termination_or_ub(int x) noexcept { + if (x == 2) { +#line 100 + will_throw(); + } +#line 200 + will_not_throw(); + if (x == 3) { +#line 300 + will_throw(); + } + if (x == 4) { + try { +#line 400 + will_not_throw(); +#line 500 + will_throw(); + } catch (...) { +#line 600 + will_not_throw(); +#line 700 + might_throw(); +#line 800 + throw; + } + } + if (x == 5) { + try { +#line 900 + will_throw(); + } catch (int x) { +#line 1000 + throw x; + } + } +} + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NO-EXCEPTIONS: if.then: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END]] +// CHECK-NO-EXCEPTIONS: if.end: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +// CHECK-NO-EXCEPTIONS: if.then2: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 300) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END3]] +// CHECK-NO-EXCEPTIONS: if.end3: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP4:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP4]], label [[IF_THEN5:%.*]], label [[IF_END6:%.*]] +// CHECK-NO-EXCEPTIONS: if.then5: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR3]] +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 500) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END6]] +// CHECK-NO-EXCEPTIONS: if.end6: +// CHECK-NO-EXCEPTIONS-NEXT: [[TMP3:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: [[CMP7:%.*]] = icmp eq i32 [[TMP3]], 5 +// CHECK-NO-EXCEPTIONS-NEXT: br i1 [[CMP7]], label [[IF_THEN8:%.*]], label [[IF_END9:%.*]] +// CHECK-NO-EXCEPTIONS: if.then8: +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 900) +// CHECK-NO-EXCEPTIONS-NEXT: br label [[IF_END9]] +// CHECK-NO-EXCEPTIONS: if.end9: +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR5:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X15:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-NORMAL-NOEXCEPT: if.end: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then2: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 300) +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END3]] +// CHECK-NORMAL-NOEXCEPT: if.end3: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP4:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP4]], label [[IF_THEN5:%.*]], label [[IF_END9:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then5: +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 500) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP3:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP4]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP5]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: catch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP6:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 600) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 700) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont7: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR7]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD6]] +// CHECK-NORMAL-NOEXCEPT: lpad6: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP7:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: cleanup +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP8]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP9]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_end_catch() +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont8: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-NORMAL-NOEXCEPT: try.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END9]] +// CHECK-NORMAL-NOEXCEPT: if.end9: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP10:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[CMP10:%.*]] = icmp eq i32 [[TMP10]], 5 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[CMP10]], label [[IF_THEN11:%.*]], label [[IF_END19:%.*]] +// CHECK-NORMAL-NOEXCEPT: if.then11: +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 900) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT13:%.*]] unwind label [[LPAD12:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont13: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[TRY_CONT18:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad12: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr @_ZTIi +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP12]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP13]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[CATCH_DISPATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: catch.dispatch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP14:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP14]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[MATCHES]], label [[CATCH14:%.*]], label [[EH_RESUME]] +// CHECK-NORMAL-NOEXCEPT: catch14: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN16:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP15:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN16]]) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP16]], ptr [[X15]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXCEPTION:%.*]] = call ptr @__cxa_allocate_exception(i64 4) #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP17:%.*]] = load i32, ptr [[X15]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP17]], ptr [[EXCEPTION]], align 16 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR7]] +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[UNREACHABLE]] unwind label [[LPAD17:%.*]] +// CHECK-NORMAL-NOEXCEPT: lpad17: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP18:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: cleanup +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP19:%.*]] = extractvalue { ptr, i32 } [[TMP18]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP19]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP20:%.*]] = extractvalue { ptr, i32 } [[TMP18]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP20]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__cxa_end_catch() #[[ATTR6]] +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-NORMAL-NOEXCEPT: try.cont18: +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[IF_END19]] +// CHECK-NORMAL-NOEXCEPT: if.end19: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: eh.resume: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN20:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL21:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN20]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL22:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL21]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: resume { ptr, i32 } [[LPAD_VAL22]] +// CHECK-NORMAL-NOEXCEPT: terminate.lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP21:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP22:%.*]] = extractvalue { ptr, i32 } [[TMP21]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP22]]) #[[ATTR8]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: unreachable: +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[X15:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 2 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END]] +// CHECK-STRICT-NOEXCEPT: if.end: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 200) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 3 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then2: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 300) +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END3]] +// CHECK-STRICT-NOEXCEPT: if.end3: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP2:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP4:%.*]] = icmp eq i32 [[TMP2]], 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP4]], label [[IF_THEN5:%.*]], label [[IF_END9:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then5: +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 400) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 500) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP3:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP4]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP5]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: catch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP6:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z14will_not_throwi(i32 noundef 600) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z11might_throwi(i32 noundef 700) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont7: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @__cxa_rethrow() #[[ATTR7]] +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD6]] +// CHECK-STRICT-NOEXCEPT: lpad6: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP7:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: cleanup +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP8]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP9]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @__cxa_end_catch() +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont8: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-STRICT-NOEXCEPT: try.cont: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END9]] +// CHECK-STRICT-NOEXCEPT: if.end9: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP10:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[CMP10:%.*]] = icmp eq i32 [[TMP10]], 5 +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[CMP10]], label [[IF_THEN11:%.*]], label [[IF_END19:%.*]] +// CHECK-STRICT-NOEXCEPT: if.then11: +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 900) +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[INVOKE_CONT13:%.*]] unwind label [[LPAD12:%.*]] +// CHECK-STRICT-NOEXCEPT: invoke.cont13: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[TRY_CONT18:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad12: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr @_ZTIi +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP12]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP13]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[CATCH_DISPATCH:%.*]] +// CHECK-STRICT-NOEXCEPT: catch.dispatch: +// CHECK-STRICT-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP14:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP14]] +// CHECK-STRICT-NOEXCEPT-NEXT: br i1 [[MATCHES]], label [[CATCH14:%.*]], label [[EH_RESUME]] +// CHECK-STRICT-NOEXCEPT: catch14: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN16:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP15:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN16]]) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP16]], ptr [[X15]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXCEPTION:%.*]] = call ptr @__cxa_allocate_exception(i64 4) #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP17:%.*]] = load i32, ptr [[X15]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP17]], ptr [[EXCEPTION]], align 16 +// CHECK-STRICT-NOEXCEPT-NEXT: invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR7]] +// CHECK-STRICT-NOEXCEPT-NEXT: to label [[UNREACHABLE]] unwind label [[LPAD17:%.*]] +// CHECK-STRICT-NOEXCEPT: lpad17: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP18:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: cleanup +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP19:%.*]] = extractvalue { ptr, i32 } [[TMP18]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: store ptr [[TMP19]], ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP20:%.*]] = extractvalue { ptr, i32 } [[TMP18]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[TMP20]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__cxa_end_catch() #[[ATTR6]] +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[EH_RESUME]] +// CHECK-STRICT-NOEXCEPT: try.cont18: +// CHECK-STRICT-NOEXCEPT-NEXT: br label [[IF_END19]] +// CHECK-STRICT-NOEXCEPT: if.end19: +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// CHECK-STRICT-NOEXCEPT: eh.resume: +// CHECK-STRICT-NOEXCEPT-NEXT: [[EXN20:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-STRICT-NOEXCEPT-NEXT: [[SEL21:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN20]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: [[LPAD_VAL22:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL21]], 1 +// CHECK-STRICT-NOEXCEPT-NEXT: resume { ptr, i32 } [[LPAD_VAL22]] +// CHECK-STRICT-NOEXCEPT: terminate.lpad: +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP21:%.*]] = landingpad { ptr, i32 } +// CHECK-STRICT-NOEXCEPT-NEXT: catch ptr null +// CHECK-STRICT-NOEXCEPT-NEXT: [[TMP22:%.*]] = extractvalue { ptr, i32 } [[TMP21]], 0 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP22]]) #[[ATTR8:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// CHECK-STRICT-NOEXCEPT: unreachable: +// CHECK-STRICT-NOEXCEPT-NEXT: unreachable +// +void exception_escape_is_ok(int x) { + if (x == 2) { +#line 100 + will_throw(); + } +#line 200 + will_not_throw(); + if (x == 3) { +#line 300 + will_throw(); + } + if (x == 4) { + try { +#line 400 + will_not_throw(); +#line 500 + will_throw(); + } catch (...) { +#line 600 + will_not_throw(); +#line 700 + might_throw(); +#line 800 + throw; + } + } + if (x == 5) { + try { +#line 900 + will_throw(); + } catch (int x) { +#line 1000 + throw x; + } + } +} +//. +// CHECK-NO-EXCEPTIONS: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #3 = { nounwind } +//. +// CHECK-NORMAL-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #2 = { noinline noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #3 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #4 = { nounwind memory(none) } +// CHECK-NORMAL-NOEXCEPT: attributes #5 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #6 = { nounwind } +// CHECK-NORMAL-NOEXCEPT: attributes #7 = { noreturn } +// CHECK-NORMAL-NOEXCEPT: attributes #8 = { noreturn nounwind } +//. +// CHECK-STRICT-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #3 = { nounwind memory(none) } +// CHECK-STRICT-NOEXCEPT: attributes #4 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #5 = { noinline noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #6 = { nounwind } +// CHECK-STRICT-NOEXCEPT: attributes #7 = { noreturn } +// CHECK-STRICT-NOEXCEPT: attributes #8 = { noreturn nounwind } +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// CHECK-ALL: {{.*}} +// CHECK-EXCEPTIONS: {{.*}} diff --git a/clang/test/CodeGenCXX/strict-noexcept-with-dynamic-exception-specification.cpp b/clang/test/CodeGenCXX/strict-noexcept-with-dynamic-exception-specification.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/strict-noexcept-with-dynamic-exception-specification.cpp @@ -0,0 +1,105 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -std=c++14 -fcxx-exceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-NO-EXCEPTIONS +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -std=c++14 -fcxx-exceptions -fexceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-NORMAL-NOEXCEPT +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -std=c++14 -fcxx-exceptions -fexceptions -fstrict-noexcept | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-STRICT-NOEXCEPT + +void will_throw_float(int line = __builtin_LINE()); + +//. +// CHECK-NO-EXCEPTIONS: @_ZTIi = external constant ptr +//. +// CHECK-NORMAL-NOEXCEPT: @_ZTIi = external constant ptr +//. +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z16will_throw_floati(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z16will_throw_floati(i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: filter [1 x ptr] [ptr @_ZTIi] +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[TMP2]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: br label [[FILTER_DISPATCH:%.*]] +// CHECK-NORMAL-NOEXCEPT: filter.dispatch: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EHSPEC_FAILS:%.*]] = icmp slt i32 [[SEL]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: br i1 [[EHSPEC_FAILS]], label [[EHSPEC_UNEXPECTED:%.*]], label [[EH_RESUME:%.*]] +// CHECK-NORMAL-NOEXCEPT: ehspec.unexpected: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__cxa_call_unexpected(ptr [[EXN]]) #[[ATTR2:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// CHECK-NORMAL-NOEXCEPT: eh.resume: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[EXN1:%.*]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[SEL2:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN1]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL2]], 1 +// CHECK-NORMAL-NOEXCEPT-NEXT: resume { ptr, i32 } [[LPAD_VAL3]] +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z16will_throw_floati(i32 noundef 100) +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// +void exception_escape_is_termination_or_ub(int x) throw(int) { +#line 100 + will_throw_float(); +} + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z16will_throw_floati(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-EXCEPTIONS: Function Attrs: mustprogress noinline optnone +// CHECK-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-EXCEPTIONS-NEXT: entry: +// CHECK-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-EXCEPTIONS-NEXT: call void @_Z16will_throw_floati(i32 noundef 100) +// CHECK-EXCEPTIONS-NEXT: ret void +// +void exception_escape_is_ok(int x) { +#line 100 + will_throw_float(); +} +//. +// CHECK-NO-EXCEPTIONS: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +//. +// CHECK-NORMAL-NOEXCEPT: attributes #0 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #2 = { noreturn } +//. +// CHECK-STRICT-NOEXCEPT: attributes #0 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// CHECK-ALL: {{.*}} diff --git a/clang/test/CodeGenCXX/strict-noexcept.cpp b/clang/test/CodeGenCXX/strict-noexcept.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/strict-noexcept.cpp @@ -0,0 +1,97 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-NO-EXCEPTIONS +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-NORMAL-NOEXCEPT +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu -fcxx-exceptions -fexceptions -fstrict-noexcept | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-EXCEPTIONS,CHECK-STRICT-NOEXCEPT + +void will_throw(int line = __builtin_LINE()); + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: invoke void @_Z10will_throwi(i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-NORMAL-NOEXCEPT: invoke.cont: +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// CHECK-NORMAL-NOEXCEPT: terminate.lpad: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 } +// CHECK-NORMAL-NOEXCEPT-NEXT: catch ptr null +// CHECK-NORMAL-NOEXCEPT-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @__clang_call_terminate(ptr [[TMP1]]) #[[ATTR4:[0-9]+]] +// CHECK-NORMAL-NOEXCEPT-NEXT: unreachable +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z37exception_escape_is_termination_or_ubi +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) #[[ATTR3:[0-9]+]] +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// +void exception_escape_is_termination_or_ub(int x) noexcept { +#line 100 + will_throw(); +} + +// CHECK-NO-EXCEPTIONS: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-NO-EXCEPTIONS-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NO-EXCEPTIONS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NO-EXCEPTIONS-NEXT: entry: +// CHECK-NO-EXCEPTIONS-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NO-EXCEPTIONS-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NO-EXCEPTIONS-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NO-EXCEPTIONS-NEXT: ret void +// +// CHECK-NORMAL-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-NORMAL-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-NORMAL-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR3:[0-9]+]] { +// CHECK-NORMAL-NOEXCEPT-NEXT: entry: +// CHECK-NORMAL-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NORMAL-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-NORMAL-NOEXCEPT-NEXT: ret void +// +// CHECK-STRICT-NOEXCEPT: Function Attrs: mustprogress noinline optnone +// CHECK-STRICT-NOEXCEPT-LABEL: define {{[^@]+}}@_Z22exception_escape_is_oki +// CHECK-STRICT-NOEXCEPT-SAME: (i32 noundef [[X:%.*]]) #[[ATTR2:[0-9]+]] { +// CHECK-STRICT-NOEXCEPT-NEXT: entry: +// CHECK-STRICT-NOEXCEPT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-STRICT-NOEXCEPT-NEXT: call void @_Z10will_throwi(i32 noundef 100) +// CHECK-STRICT-NOEXCEPT-NEXT: ret void +// +void exception_escape_is_ok(int x) { +#line 100 + will_throw(); +} +//. +// CHECK-NO-EXCEPTIONS: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NO-EXCEPTIONS: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +//. +// CHECK-NORMAL-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #2 = { noinline noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #3 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-NORMAL-NOEXCEPT: attributes #4 = { noreturn nounwind } +// CHECK-NORMAL-NOEXCEPT: attributes #5 = { nounwind } +//. +// CHECK-STRICT-NOEXCEPT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #2 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK-STRICT-NOEXCEPT: attributes #3 = { nounwind } +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// CHECK-ALL: {{.*}} +// CHECK-EXCEPTIONS: {{.*}}