diff options
| author | Reid Kleckner <reid@kleckner.net> | 2015-02-05 18:56:03 +0000 |
|---|---|---|
| committer | Reid Kleckner <reid@kleckner.net> | 2015-02-05 18:56:03 +0000 |
| commit | deeddeced312a21b8454336cfab9fe2b58863cf8 (patch) | |
| tree | 87170d3e4cedf4bc76f9916cbdd5d74f33e676e1 | |
| parent | c9dd02066cc0528da28bd887e8dbdb3bd9c68165 (diff) | |
| download | bcm5719-llvm-deeddeced312a21b8454336cfab9fe2b58863cf8.tar.gz bcm5719-llvm-deeddeced312a21b8454336cfab9fe2b58863cf8.zip | |
Re-land r228258 and make clang-cl's /EHs- disable -fexceptions again
After r228258, Clang started emitting C++ EH IR that LLVM wasn't ready
to deal with, even when exceptions were disabled with /EHs-. This time,
make /EHs- turn off -fexceptions while still emitting exceptional
constructs in functions using __try. Since Sema rejects C++ exception
handling constructs before CodeGen, landingpads should only appear in
such functions as the result of a __try.
llvm-svn: 228329
| -rw-r--r-- | clang/include/clang/AST/Decl.h | 11 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 56 | ||||
| -rw-r--r-- | clang/lib/Driver/Tools.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 33 | ||||
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh-finally.c | 2 | ||||
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh-leave.c | 2 | ||||
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh.c | 2 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/exceptions-seh.cpp | 95 | ||||
| -rw-r--r-- | clang/test/Driver/cl-eh.cpp | 4 | ||||
| -rw-r--r-- | clang/test/SemaCXX/exceptions-seh.cpp | 47 |
11 files changed, 216 insertions, 44 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 4580cba113c..84ed2862f3f 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1482,6 +1482,9 @@ private: bool IsLateTemplateParsed : 1; bool IsConstexpr : 1; + /// \brief Indicates if the function uses __try. + bool UsesSEHTry : 1; + /// \brief Indicates if the function was a definition but its body was /// skipped. unsigned HasSkippedBody : 1; @@ -1570,8 +1573,8 @@ protected: HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), - IsConstexpr(isConstexprSpecified), HasSkippedBody(false), - EndRangeLoc(NameInfo.getEndLoc()), + IsConstexpr(isConstexprSpecified), UsesSEHTry(false), + HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1751,6 +1754,10 @@ public: bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } + /// Whether this is a (C++11) constexpr function or constexpr constructor. + bool usesSEHTry() const { return UsesSEHTry; } + void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } + /// \brief Whether this function has been deleted. /// /// A function that is "deleted" (via the C++0x "= delete" syntax) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4f68d101351..5c66952979a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5466,6 +5466,8 @@ def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; +def err_seh_try_outside_functions : Error< + "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< "cannot use C++ 'try' in the same function as SEH '__try'">; def note_conflicting_try_here : Note< diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index e148227c39a..5ddd3bbb82b 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -128,7 +128,12 @@ namespace { // This function must have prototype void(void*). const char *CatchallRethrowFn; - static const EHPersonality &get(CodeGenModule &CGM); + static const EHPersonality &get(CodeGenModule &CGM, + const FunctionDecl *FD); + static const EHPersonality &get(CodeGenFunction &CGF) { + return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(CGF.CurCodeDecl)); + } + static const EHPersonality GNU_C; static const EHPersonality GNU_C_SJLJ; static const EHPersonality GNU_C_SEH; @@ -141,6 +146,7 @@ namespace { static const EHPersonality GNU_CPlusPlus_SEH; static const EHPersonality MSVC_except_handler; static const EHPersonality MSVC_C_specific_handler; + static const EHPersonality MSVC_CxxFrameHandler3; }; } @@ -167,6 +173,8 @@ const EHPersonality EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr }; const EHPersonality EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr }; +const EHPersonality +EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr }; /// On Win64, use libgcc's SEH personality function. We fall back to dwarf on /// other platforms, unless the user asked for SjLj exceptions. @@ -239,35 +247,27 @@ static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T, llvm_unreachable("bad runtime kind"); } -static const EHPersonality &getCPersonalityMSVC(const llvm::Triple &T, - const LangOptions &L) { - if (L.SjLjExceptions) - return EHPersonality::GNU_C_SJLJ; - +static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) { if (T.getArch() == llvm::Triple::x86) return EHPersonality::MSVC_except_handler; return EHPersonality::MSVC_C_specific_handler; } -static const EHPersonality &getCXXPersonalityMSVC(const llvm::Triple &T, - const LangOptions &L) { - if (L.SjLjExceptions) - return EHPersonality::GNU_CPlusPlus_SJLJ; - // FIXME: Implement C++ exceptions. - return getCPersonalityMSVC(T, L); -} - -const EHPersonality &EHPersonality::get(CodeGenModule &CGM) { +const EHPersonality &EHPersonality::get(CodeGenModule &CGM, + const FunctionDecl *FD) { const llvm::Triple &T = CGM.getTarget().getTriple(); const LangOptions &L = CGM.getLangOpts(); + // Try to pick a personality function that is compatible with MSVC if we're // not compiling Obj-C. Obj-C users better have an Obj-C runtime that supports // the GCC-style personality function. if (T.isWindowsMSVCEnvironment() && !L.ObjC1) { - if (L.CPlusPlus) - return getCXXPersonalityMSVC(T, L); + if (L.SjLjExceptions) + return EHPersonality::GNU_CPlusPlus_SJLJ; + else if (FD && FD->usesSEHTry()) + return getSEHPersonalityMSVC(T); else - return getCPersonalityMSVC(T, L); + return EHPersonality::MSVC_CxxFrameHandler3; } if (L.CPlusPlus && L.ObjC1) @@ -354,7 +354,7 @@ void CodeGenModule::SimplifyPersonality() { if (!LangOpts.ObjCRuntime.isNeXTFamily()) return; - const EHPersonality &ObjCXX = EHPersonality::get(*this); + const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr); const EHPersonality &CXX = getCXXPersonality(getTarget().getTriple(), LangOpts); if (&ObjCXX == &CXX) @@ -737,8 +737,16 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { assert(EHStack.requiresLandingPad()); assert(!EHStack.empty()); - if (!CGM.getLangOpts().Exceptions) - return nullptr; + // If exceptions are disabled, there are usually no landingpads. However, when + // SEH is enabled, functions using SEH still get landingpads. + const LangOptions &LO = CGM.getLangOpts(); + if (!LO.Exceptions) { + if (!LO.Borland && !LO.MicrosoftExt) + return nullptr; + const auto *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl); + if (!FD || !FD->usesSEHTry()) + return nullptr; + } // Check the innermost scope for a cached landing pad. If this is // a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad. @@ -778,7 +786,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation); - const EHPersonality &personality = EHPersonality::get(CGM); + const EHPersonality &personality = EHPersonality::get(*this); // Create and configure the landing pad. llvm::BasicBlock *lpad = createBasicBlock("lpad"); @@ -1595,7 +1603,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { Builder.SetInsertPoint(TerminateLandingPad); // Tell the backend that this is a landing pad. - const EHPersonality &Personality = EHPersonality::get(CGM); + const EHPersonality &Personality = EHPersonality::get(*this); llvm::LandingPadInst *LPadInst = Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr), getOpaquePersonalityFn(CGM, Personality), 0); @@ -1654,7 +1662,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { EHResumeBlock = createBasicBlock("eh.resume"); Builder.SetInsertPoint(EHResumeBlock); - const EHPersonality &Personality = EHPersonality::get(CGM); + const EHPersonality &Personality = EHPersonality::get(*this); // This can always be a call because we necessarily didn't find // anything on the EH stack which needs our help. diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index d24375b3d78..8634ed604c6 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -4877,10 +4877,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); EHFlags EH = parseClangCLEHFlags(D, Args); // FIXME: Do something with NoExceptC. - if (EH.Synch || EH.Asynch) + if (EH.Synch || EH.Asynch) { CmdArgs.push_back("-fcxx-exceptions"); - // Always add -fexceptions to allow SEH __try. - CmdArgs.push_back("-fexceptions"); + CmdArgs.push_back("-fexceptions"); + } // /EP should expand to -E -P. if (Args.hasArg(options::OPT__SLASH_EP)) { diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d17cf227011..4761c32f78d 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3303,11 +3303,12 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try"; + sema::FunctionScopeInfo *FSI = getCurFunction(); + // C++ try is incompatible with SEH __try. - if (!getLangOpts().Borland && getCurFunction()->FirstSEHTryLoc.isValid()) { + if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) { Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); - Diag(getCurFunction()->FirstSEHTryLoc, diag::note_conflicting_try_here) - << "'__try'"; + Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; } const unsigned NumHandlers = Handlers.size(); @@ -3352,7 +3353,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, } } - getCurFunction()->setHasCXXTry(TryLoc); + FSI->setHasCXXTry(TryLoc); // FIXME: We should detect handlers that cannot catch anything because an // earlier handler catches a superclass. Need to find a method that is not @@ -3367,15 +3368,29 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler) { assert(TryBlock && Handler); + sema::FunctionScopeInfo *FSI = getCurFunction(); + // SEH __try is incompatible with C++ try. Borland appears to support this, // however. - if (!getLangOpts().Borland && getCurFunction()->FirstCXXTryLoc.isValid()) { - Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); - Diag(getCurFunction()->FirstCXXTryLoc, diag::note_conflicting_try_here) - << "'try'"; + if (!getLangOpts().Borland) { + if (FSI->FirstCXXTryLoc.isValid()) { + Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); + Diag(FSI->FirstCXXTryLoc, diag::note_conflicting_try_here) << "'try'"; + } } - getCurFunction()->setHasSEHTry(TryLoc); + FSI->setHasSEHTry(TryLoc); + + // Reject __try in Obj-C methods, blocks, and captured decls, since we don't + // track if they use SEH. + DeclContext *DC = CurContext; + while (DC && !DC->isFunctionOrMethod()) + DC = DC->getParent(); + FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DC); + if (FD) + FD->setUsesSEHTry(true); + else + Diag(TryLoc, diag::err_seh_try_outside_functions); return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } diff --git a/clang/test/CodeGen/exceptions-seh-finally.c b/clang/test/CodeGen/exceptions-seh-finally.c index 722fc377495..4cd82d0972e 100644 --- a/clang/test/CodeGen/exceptions-seh-finally.c +++ b/clang/test/CodeGen/exceptions-seh-finally.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s void abort(void) __attribute__((noreturn)); void might_crash(void); diff --git a/clang/test/CodeGen/exceptions-seh-leave.c b/clang/test/CodeGen/exceptions-seh-leave.c index 86161f297e4..2033c87105f 100644 --- a/clang/test/CodeGen/exceptions-seh-leave.c +++ b/clang/test/CodeGen/exceptions-seh-leave.c @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s // This is a codegen test because we only emit the diagnostic when we start // generating code. diff --git a/clang/test/CodeGen/exceptions-seh.c b/clang/test/CodeGen/exceptions-seh.c index fcd90b99132..98b9de5d59d 100644 --- a/clang/test/CodeGen/exceptions-seh.c +++ b/clang/test/CodeGen/exceptions-seh.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s // FIXME: Perform this outlining automatically CodeGen. void try_body(int numerator, int denominator, int *myres) { diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp b/clang/test/CodeGenCXX/exceptions-seh.cpp new file mode 100644 index 00000000000..e76f0ea5c07 --- /dev/null +++ b/clang/test/CodeGenCXX/exceptions-seh.cpp @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \ +// RUN: -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | \ +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CXXEH +// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \ +// RUN: -o - -mconstructor-aliases | \ +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX + +extern "C" void might_throw(); + +struct HasCleanup { + HasCleanup(); + ~HasCleanup(); + int padding; +}; + +extern "C" void use_cxx() { + HasCleanup x; + might_throw(); +} + +// Make sure we use __CxxFrameHandler3 for C++ EH. + +// CXXEH-LABEL: define void @use_cxx() +// CXXEH: call %struct.HasCleanup* @"\01??0HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) +// CXXEH: invoke void @might_throw() +// CXXEH: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// +// CXXEH: [[cont]] +// CXXEH: call void @"\01??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) +// CXXEH: ret void +// +// CXXEH: [[lpad]] +// CXXEH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) +// CXXEH-NEXT: cleanup +// CXXEH: call void @"\01??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) +// CXXEH: br label %[[resume:[^ ]*]] +// +// CXXEH: [[resume]] +// CXXEH: resume + +// NOCXX-LABEL: define void @use_cxx() +// NOCXX-NOT: invoke +// NOCXX: call %struct.HasCleanup* @"\01??0HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) +// NOCXX-NOT: invoke +// NOCXX: call void @might_throw() +// NOCXX-NOT: invoke +// NOCXX: call void @"\01??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) +// NOCXX-NOT: invoke +// NOCXX: ret void + +extern "C" void use_seh() { + __try { + might_throw(); + } __except(1) { + } +} + +// Make sure we use __C_specific_handler for SEH. + +// CHECK-LABEL: define void @use_seh() +// CHECK: invoke void @might_throw() +// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// +// CHECK: [[cont]] +// CHECK: br label %[[ret:[^ ]*]] +// +// CHECK: [[lpad]] +// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// CHECK-NEXT: catch i8* +// +// CHECK: br label %[[ret]] +// +// CHECK: [[ret]] +// CHECK: ret void + +void use_seh_in_lambda() { + ([]() { + __try { + might_throw(); + } __except(1) { + } + })(); + HasCleanup x; + might_throw(); +} + +// CXXEH-LABEL: define void @"\01?use_seh_in_lambda@@YAXXZ"() +// CXXEH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + +// NOCXX-LABEL: define void @"\01?use_seh_in_lambda@@YAXXZ"() +// NOCXX-NOT: invoke +// NOCXX: ret void + +// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?use_seh_in_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this) +// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) diff --git a/clang/test/Driver/cl-eh.cpp b/clang/test/Driver/cl-eh.cpp index c9cb90350b2..a71491edeaf 100644 --- a/clang/test/Driver/cl-eh.cpp +++ b/clang/test/Driver/cl-eh.cpp @@ -10,11 +10,11 @@ // RUN: %clang_cl /c /EHs-c- -### -- %s 2>&1 | FileCheck -check-prefix=EHs_c_ %s // EHs_c_-NOT: "-fcxx-exceptions" -// EHs_c_: "-fexceptions" +// EHs_c_-NOT: "-fexceptions" // RUN: %clang_cl /c /EHs- /EHc- -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHc_ %s // EHs_EHc_-NOT: "-fcxx-exceptions" -// EHs_EHc_: "-fexceptions" +// EHs_EHc_-NOT: "-fexceptions" // RUN: %clang_cl /c /EHs- /EHs -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHs %s // EHs_EHs: "-fcxx-exceptions" diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index dd00c11590a..7375ec9bf81 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++03 -fblocks -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++11 -fblocks -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -fexceptions -fcxx-exceptions -verify %s // Basic usage should work. int safe_div(int n, int d) { @@ -37,6 +38,7 @@ void instantiate_bad_scope_tmpl() { bad_builtin_scope_template<might_crash>(); } +#if __cplusplus < 201103L // FIXME: Diagnose this case. For now we produce undef in codegen. template <typename T, T FN()> T func_template() { @@ -46,6 +48,7 @@ void inject_builtins() { func_template<void *, __exception_info>(); func_template<unsigned long, __exception_code>(); } +#endif void use_seh_after_cxx() { try { // expected-note {{conflicting 'try' here}} @@ -68,3 +71,45 @@ void use_cxx_after_seh() { } catch (int) { } } + +#if __cplusplus >= 201103L +void use_seh_in_lambda() { + ([]() { + __try { + might_crash(); + } __except(1) { + } + })(); + try { + might_crash(); + } catch (int) { + } +} +#endif + +void use_seh_in_block() { + void (^b)() = ^{ + __try { // expected-error {{cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls}} + might_crash(); + } __except(1) { + } + }; + try { + b(); + } catch (int) { + } +} + +void (^use_seh_in_global_block)() = ^{ + __try { // expected-error {{cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls}} + might_crash(); + } __except(1) { + } +}; + +void (^use_cxx_in_global_block)() = ^{ + try { + might_crash(); + } catch(int) { + } +}; |

