https://github.com/MuellerMP updated 
https://github.com/llvm/llvm-project/pull/167176

>From 435309c27a62172ece6232e49177b90b9c168f67 Mon Sep 17 00:00:00 2001
From: MuellerMP <[email protected]>
Date: Wed, 26 Nov 2025 16:20:12 +0100
Subject: [PATCH] [WinEH] Fix try scopes leaking to caller on inline

This fixes issue #164169

When inlining functions compiled with -EHa, try scope terminators might need to 
be inserted before inlined returns.
This prevents leaking try scopes over to the caller.
Try scopes can be ended before a ret due to the unwinder forwarding exceptions 
in the seh epilog to the caller.
---
 clang/lib/CodeGen/CGCleanup.cpp               |  16 +-
 clang/lib/CodeGen/CGException.cpp             |  48 ++++-
 clang/lib/CodeGen/CodeGenFunction.h           |   5 +-
 .../test/CodeGen/windows-seh-EHa-Inline1.cpp  |  62 +++++++
 .../test/CodeGen/windows-seh-EHa-Inline2.cpp  | 103 +++++++++++
 .../test/CodeGen/windows-seh-EHa-Inline3.cpp  |  91 ++++++++++
 llvm/lib/CodeGen/WinEHPrepare.cpp             |   7 +-
 .../WinEH/wineh-statenumbering-seh-try-end.ll | 170 ++++++++++++++++++
 8 files changed, 487 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/CodeGen/windows-seh-EHa-Inline1.cpp
 create mode 100644 clang/test/CodeGen/windows-seh-EHa-Inline2.cpp
 create mode 100644 clang/test/CodeGen/windows-seh-EHa-Inline3.cpp
 create mode 100644 llvm/test/CodeGen/WinEH/wineh-statenumbering-seh-try-end.ll

diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 28ac9bf396356..fe490d215d684 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -1329,8 +1329,11 @@ void CodeGenFunction::EmitCXXTemporary(const 
CXXTemporary *Temporary,
 // Need to set "funclet" in OperandBundle properly for noThrow
 //       intrinsic (see CGCall.cpp)
 static void EmitSehScope(CodeGenFunction &CGF,
-                         llvm::FunctionCallee &SehCppScope) {
-  llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
+                         llvm::FunctionCallee &SehCppScope,
+                         llvm::BasicBlock *InvokeDest = nullptr) {
+  if (!InvokeDest)
+    InvokeDest = CGF.getInvokeDest();
+
   assert(CGF.Builder.GetInsertBlock() && InvokeDest);
   llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
   SmallVector<llvm::OperandBundleDef, 1> BundleList =
@@ -1373,11 +1376,16 @@ void CodeGenFunction::EmitSehTryScopeBegin() {
 }
 
 // Invoke a llvm.seh.try.end at the end of a SEH scope for -EHa
-void CodeGenFunction::EmitSehTryScopeEnd() {
+void CodeGenFunction::EmitSehTryScopeEnd(bool ReuseCachedInvokeDest) {
   assert(getLangOpts().EHAsynch);
   llvm::FunctionType *FTy =
       llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
   llvm::FunctionCallee SehCppScope =
       CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
-  EmitSehScope(*this, SehCppScope);
+  if (ReuseCachedInvokeDest) {
+    EmitSehScope(*this, SehCppScope, SehTryEndInvokeDest);
+    SehTryEndInvokeDest = nullptr;
+  } else {
+    EmitSehScope(*this, SehCppScope);
+  }
 }
diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index e9d20672ce185..704a144fd6af7 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -635,14 +635,24 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) 
{
     ExitCXXTryStmt(S);
 }
 
+struct TerminateTryScope final : EHScopeStack::Cleanup {
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+    CGF.EmitSehTryScopeEnd(true);
+  }
+};
+
+struct HandlerInfo {
+  CatchTypeInfo TypeInfo;
+  bool RequiresSehScope;
+};
+
 void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
   unsigned NumHandlers = S.getNumHandlers();
-  EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
-
+  unsigned NumHandlerInfos = NumHandlers > 0 ? NumHandlers - 1 : 0;
+  llvm::SmallVector<HandlerInfo> HandlerInfos;
+  HandlerInfos.reserve(NumHandlerInfos);
   for (unsigned I = 0; I != NumHandlers; ++I) {
     const CXXCatchStmt *C = S.getHandler(I);
-
-    llvm::BasicBlock *Handler = createBasicBlock("catch");
     if (C->getExceptionDecl()) {
       // FIXME: Dropping the reference type on the type into makes it
       // impossible to correctly implement catch-by-reference
@@ -660,14 +670,30 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt 
&S, bool IsFnTryBlock) {
       else
         TypeInfo = CGM.getCXXABI().getAddrOfCXXCatchHandlerType(
             CaughtType, C->getCaughtType());
-      CatchScope->setHandler(I, TypeInfo, Handler);
+      HandlerInfos.push_back({TypeInfo, false});
     } else {
+      bool HasEHa = getLangOpts().EHAsynch;
       // No exception decl indicates '...', a catch-all.
-      CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), 
Handler);
+      HandlerInfos.push_back({CGM.getCXXABI().getCatchAllTypeInfo(), HasEHa});
+      // Push, if needed, a terminator for the created SEH __try scope
+      if (HasEHa && !SehTryEndInvokeDest) {
+        EHStack.pushCleanup<TerminateTryScope>(NormalCleanup);
+      }
+    }
+  }
+
+  EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
+
+  for (unsigned I = 0; I < HandlerInfos.size(); ++I) {
+    llvm::BasicBlock *Handler = createBasicBlock("catch");
+    auto HandlerInfo = HandlerInfos[I];
+    CatchScope->setHandler(I, HandlerInfo.TypeInfo, Handler);
+    if (HandlerInfo.RequiresSehScope) {
       // Under async exceptions, catch(...) need to catch HW exception too
       // Mark scope with SehTryBegin as a SEH __try scope
-      if (getLangOpts().EHAsynch)
-        EmitSehTryScopeBegin();
+      EmitSehTryScopeBegin();
+      if (!SehTryEndInvokeDest)
+        SehTryEndInvokeDest = getInvokeDest();
     }
   }
 }
@@ -1675,6 +1701,8 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) 
{
       EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
       if (SEHTryEpilogueStack.size() == 1) // outermost only
         TryBB = Builder.GetInsertBlock();
+      if (!SehTryEndInvokeDest)
+        SehTryEndInvokeDest = getInvokeDest();
     }
 
     EmitStmt(S.getTryBlock());
@@ -2186,6 +2214,10 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt 
&S) {
   // Otherwise, we must have an __except block.
   const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except);
+
+  if (getLangOpts().EHAsynch && !SehTryEndInvokeDest)
+    EHStack.pushCleanup<TerminateTryScope>(NormalCleanup);
+
   EHCatchScope *CatchScope = EHStack.pushCatch(1);
   SEHCodeSlotStack.push_back(
       CreateMemTemp(getContext().IntTy, "__exception_code"));
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 8c4c1c8c2dc95..8930d784da5e4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -2129,6 +2129,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Terminate funclets keyed by parent funclet pad.
   llvm::MapVector<llvm::Value *, llvm::BasicBlock *> TerminateFunclets;
 
+  /// Unwind destination for try scope end.
+  llvm::BasicBlock *SehTryEndInvokeDest = nullptr;
+
   /// Largest vector width used in ths function. Will be used to create a
   /// function attribute.
   unsigned LargestVectorWidth = 0;
@@ -3241,7 +3244,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitSehCppScopeBegin();
   void EmitSehCppScopeEnd();
   void EmitSehTryScopeBegin();
-  void EmitSehTryScopeEnd();
+  void EmitSehTryScopeEnd(bool ReuseCachedInvokeDest = false);
 
   bool EmitLifetimeStart(llvm::Value *Addr);
   void EmitLifetimeEnd(llvm::Value *Addr);
diff --git a/clang/test/CodeGen/windows-seh-EHa-Inline1.cpp 
b/clang/test/CodeGen/windows-seh-EHa-Inline1.cpp
new file mode 100644
index 0000000000000..26d8cc204274e
--- /dev/null
+++ b/clang/test/CodeGen/windows-seh-EHa-Inline1.cpp
@@ -0,0 +1,62 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions 
-fcxx-exceptions -fexceptions -fms-extensions -x c++ 
-Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
+// Check that the try scope of ExitOnThrow is terminated upon inlining into 
main.
+int AlwaysThrows(int);
+[[noreturn]] void Exit();
+
+int ExitOnThrow(int argc) noexcept
+{
+  try {
+    if (!argc) { throw -1; }
+    return argc;
+  } catch (...) {
+  }
+
+  Exit();
+  return 0;
+}
+
+// CHECK-LABEL: define dso_local noundef i32 @main(
+// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) 
[[TMP0:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] personality ptr 
@__CxxFrameHandler3 {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]])
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT_I:.*]] unwind label 
%[[CATCH_DISPATCH_I:.*]]
+// CHECK:       [[INVOKE_CONT_I]]:
+// CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0
+// CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label 
%[[IF_END_I:.*]]
+// CHECK:       [[IF_THEN_I]]:
+// CHECK-NEXT:    store i32 -1, ptr [[TMP_I]], align 4, !tbaa 
[[INT_TBAA7:![0-9]+]]
+// CHECK-NEXT:    invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr 
nonnull @_TI1H) #[[ATTR6:[0-9]+]]
+// CHECK-NEXT:            to label %[[UNREACHABLE_I:.*]] unwind label 
%[[CATCH_DISPATCH_I]]
+// CHECK:       [[CATCH_DISPATCH_I]]:
+// CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label 
%[[CATCH_I:.*]]] unwind to caller
+// CHECK:       [[CATCH_I]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, 
ptr null]
+// CHECK-NEXT:    catchret from [[TMP2]] to label %[[TRY_CONT_I:.*]]
+// CHECK:       [[TRY_CONT_I]]:
+// CHECK-NEXT:    call void @"?Exit@@YAXXZ"() #[[ATTR7:[0-9]+]]
+// CHECK-NEXT:    unreachable
+// CHECK:       [[IF_END_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.end()
+// CHECK-NEXT:            to label %"?ExitOnThrow@@[email protected]" unwind label 
%[[CATCH_DISPATCH_I]]
+// CHECK:       [[UNREACHABLE_I]]:
+// CHECK-NEXT:    unreachable
+// CHECK:       "?ExitOnThrow@@[email protected]":
+// CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]])
+// CHECK-NEXT:    [[CALL1:%.*]] = tail call noundef i32 
@"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]])
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]]
+// CHECK-NEXT:    ret i32 [[ADD]]
+//
+int main(int argc, char**)
+{
+  auto data = ExitOnThrow(argc);
+  return data + AlwaysThrows(data);
+}
+//.
+// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
+// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
+// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
+// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
+//.
diff --git a/clang/test/CodeGen/windows-seh-EHa-Inline2.cpp 
b/clang/test/CodeGen/windows-seh-EHa-Inline2.cpp
new file mode 100644
index 0000000000000..b7edcf00ecb7e
--- /dev/null
+++ b/clang/test/CodeGen/windows-seh-EHa-Inline2.cpp
@@ -0,0 +1,103 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions 
-fcxx-exceptions -fexceptions -fms-extensions -x c++ 
-Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
+// Check that only the outermost try scope containing a return statement is 
terminated upon inlining into main.
+void DoSth();
+int AlwaysThrows(int);
+[[noreturn]] void Exit();
+
+int ExitOnThrow(int argc) noexcept
+{
+  try {
+    try {
+      DoSth();
+    } catch(...) {}
+  } catch(...) {}
+
+  try {
+    try {
+      if (!argc) { throw -1; }
+      return argc;
+    } catch (...) {}
+  } catch (...) {}
+
+  Exit();
+  return 0;
+}
+
+// CHECK-LABEL: define dso_local noundef i32 @main(
+// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) 
[[TMP0:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] personality ptr 
@__CxxFrameHandler3 {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]])
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT_I:.*]] unwind label 
%[[CATCH_DISPATCH4_I:.*]]
+// CHECK:       [[INVOKE_CONT_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT1_I:.*]] unwind label 
%[[CATCH_DISPATCH_I:.*]]
+// CHECK:       [[INVOKE_CONT1_I]]:
+// CHECK-NEXT:    invoke void @"?DoSth@@YAXXZ"()
+// CHECK-NEXT:            to label %[[TRY_CONT7_I:.*]] unwind label 
%[[CATCH_DISPATCH_I]]
+// CHECK:       [[CATCH_DISPATCH_I]]:
+// CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label 
%[[CATCH_I:.*]]] unwind label %[[CATCH_DISPATCH4_I]]
+// CHECK:       [[CATCH_I]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, 
ptr null]
+// CHECK-NEXT:    invoke void @llvm.seh.scope.end() [ "funclet"(token 
[[TMP2]]) ]
+// CHECK-NEXT:            to label %[[INVOKE_CONT3_I:.*]] unwind label 
%[[CATCH_DISPATCH4_I]]
+// CHECK:       [[CATCH_DISPATCH4_I]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = catchswitch within none [label 
%[[CATCH5_I:.*]]] unwind to caller
+// CHECK:       [[CATCH5_I]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = catchpad within [[TMP3]] [ptr null, i32 0, 
ptr null]
+// CHECK-NEXT:    catchret from [[TMP4]] to label %[[TRY_CONT7_I]]
+// CHECK:       [[TRY_CONT7_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT8_I:.*]] unwind label 
%[[CATCH_DISPATCH15_I:.*]]
+// CHECK:       [[INVOKE_CONT8_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT9_I:.*]] unwind label 
%[[CATCH_DISPATCH10_I:.*]]
+// CHECK:       [[INVOKE_CONT9_I]]:
+// CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0
+// CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label 
%[[IF_END_I:.*]]
+// CHECK:       [[IF_THEN_I]]:
+// CHECK-NEXT:    store i32 -1, ptr [[TMP_I]], align 4, !tbaa 
[[INT_TBAA7:![0-9]+]]
+// CHECK-NEXT:    invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr 
nonnull @_TI1H) #[[ATTR7:[0-9]+]]
+// CHECK-NEXT:            to label %[[UNREACHABLE_I:.*]] unwind label 
%[[CATCH_DISPATCH10_I]]
+// CHECK:       [[CATCH_DISPATCH10_I]]:
+// CHECK-NEXT:    [[TMP5:%.*]] = catchswitch within none [label 
%[[CATCH11_I:.*]]] unwind label %[[CATCH_DISPATCH15_I]]
+// CHECK:       [[CATCH11_I]]:
+// CHECK-NEXT:    [[TMP6:%.*]] = catchpad within [[TMP5]] [ptr null, i32 0, 
ptr null]
+// CHECK-NEXT:    invoke void @llvm.seh.scope.end() [ "funclet"(token 
[[TMP6]]) ]
+// CHECK-NEXT:            to label %[[INVOKE_CONT12_I:.*]] unwind label 
%[[CATCH_DISPATCH15_I]]
+// CHECK:       [[CATCH_DISPATCH15_I]]:
+// CHECK-NEXT:    [[TMP7:%.*]] = catchswitch within none [label 
%[[CATCH16_I:.*]]] unwind to caller
+// CHECK:       [[CATCH16_I]]:
+// CHECK-NEXT:    [[TMP8:%.*]] = catchpad within [[TMP7]] [ptr null, i32 0, 
ptr null]
+// CHECK-NEXT:    catchret from [[TMP8]] to label %[[TRY_CONT18_I:.*]]
+// CHECK:       [[TRY_CONT18_I]]:
+// CHECK-NEXT:    call void @"?Exit@@YAXXZ"() #[[ATTR8:[0-9]+]]
+// CHECK-NEXT:    unreachable
+// CHECK:       [[INVOKE_CONT12_I]]:
+// CHECK-NEXT:    catchret from [[TMP6]] to label %[[TRY_CONT18_I]]
+// CHECK:       [[INVOKE_CONT3_I]]:
+// CHECK-NEXT:    catchret from [[TMP2]] to label %[[TRY_CONT7_I]]
+// CHECK:       [[IF_END_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.end()
+// CHECK-NEXT:            to label %"?ExitOnThrow@@[email protected]" unwind label 
%[[CATCH_DISPATCH4_I]]
+// CHECK:       [[UNREACHABLE_I]]:
+// CHECK-NEXT:    unreachable
+// CHECK:       "?ExitOnThrow@@[email protected]":
+// CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]])
+// CHECK-NEXT:    [[CALL1:%.*]] = tail call noundef i32 
@"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]])
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]]
+// CHECK-NEXT:    ret i32 [[ADD]]
+//
+int main(int argc, char**)
+{
+  auto data = ExitOnThrow(argc);
+  return data + AlwaysThrows(data);
+}
+//.
+// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
+// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
+// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
+// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
+//.
diff --git a/clang/test/CodeGen/windows-seh-EHa-Inline3.cpp 
b/clang/test/CodeGen/windows-seh-EHa-Inline3.cpp
new file mode 100644
index 0000000000000..0ab117b6d2bf8
--- /dev/null
+++ b/clang/test/CodeGen/windows-seh-EHa-Inline3.cpp
@@ -0,0 +1,91 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions 
-fcxx-exceptions -fexceptions -fms-extensions -x c++ 
-Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
+// Check that the outermost __try scope containing a return statement is 
terminated upon inlining into main.
+int AlwaysThrows(int);
+[[noreturn]] void Exit();
+volatile int *p{nullptr};
+
+int ExitOnThrow(int argc) noexcept
+{
+  __try {
+    __try {
+      if (!argc) { *p = 0; }
+      return argc;
+    } __except(1) {}
+  } __except(1) {}
+
+  Exit();
+  return 0;
+}
+
+// CHECK-LABEL: define dso_local noundef i32 @main(
+// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) 
[[TMP0:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] personality ptr 
@__C_specific_handler {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[ARGC_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[__EXCEPTION_CODE1_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[CLEANUP_DEST_SLOT_I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull 
[[ARGC_ADDR_I]])
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull 
[[__EXCEPTION_CODE1_I]])
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull 
[[CLEANUP_DEST_SLOT_I]])
+// CHECK-NEXT:    store i32 [[ARGC]], ptr [[ARGC_ADDR_I]], align 4, !tbaa 
[[INT_TBAA7:![0-9]+]]
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT_I:.*]] unwind label 
%[[CATCH_DISPATCH5_I:.*]]
+// CHECK:       [[INVOKE_CONT_I]]:
+// CHECK-NEXT:    invoke void @llvm.seh.try.begin()
+// CHECK-NEXT:            to label %[[INVOKE_CONT2_I:.*]] unwind label 
%[[CATCH_DISPATCH_I:.*]]
+// CHECK:       [[CATCH_DISPATCH_I]]:
+// CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label 
%[[__EXCEPT_I:.*]]] unwind label %[[CATCH_DISPATCH5_I]]
+// CHECK:       [[__EXCEPT_I]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null]
+// CHECK-NEXT:    catchret from [[TMP2]] to label %[[__EXCEPT3_I:.*]]
+// CHECK:       [[__EXCEPT3_I]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = tail call i32 @llvm.eh.exceptioncode(token 
[[TMP2]])
+// CHECK-NEXT:    store volatile i32 [[TMP3]], ptr [[__EXCEPTION_CODE1_I]], 
align 4
+// CHECK-NEXT:    invoke void @llvm.seh.try.end()
+// CHECK-NEXT:            to label %[[__TRY_CONT8_I:.*]] unwind label 
%[[CATCH_DISPATCH5_I]]
+// CHECK:       [[CATCH_DISPATCH5_I]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = catchswitch within none [label 
%[[__EXCEPT6_I:.*]]] unwind to caller
+// CHECK:       [[__EXCEPT6_I]]:
+// CHECK-NEXT:    [[TMP5:%.*]] = catchpad within [[TMP4]] [ptr null]
+// CHECK-NEXT:    catchret from [[TMP5]] to label %[[__EXCEPT7_I:.*]]
+// CHECK:       [[__EXCEPT7_I]]:
+// CHECK-NEXT:    [[TMP6:%.*]] = tail call i32 @llvm.eh.exceptioncode(token 
[[TMP5]])
+// CHECK-NEXT:    br label %[[__TRY_CONT8_I]]
+// CHECK:       [[__TRY_CONT8_I]]:
+// CHECK-NEXT:    tail call void @"?Exit@@YAXXZ"() #[[ATTR7:[0-9]+]]
+// CHECK-NEXT:    unreachable
+// CHECK:       [[INVOKE_CONT2_I]]:
+// CHECK-NEXT:    
[[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0__I:%.*]]
 = load volatile i32, ptr [[ARGC_ADDR_I]], align 4, !tbaa [[INT_TBAA7]]
+// CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 
[[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0__I]],
 0
+// CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label 
%[[IF_END_I:.*]]
+// CHECK:       [[IF_THEN_I]]:
+// CHECK-NEXT:    [[TMP7:%.*]] = load volatile ptr, ptr @"?p@@3PECHEC", align 
8, !tbaa [[INTPTR_TBAA11:![0-9]+]]
+// CHECK-NEXT:    store volatile i32 0, ptr [[TMP7]], align 4, !tbaa 
[[INT_TBAA7]]
+// CHECK-NEXT:    br label %[[IF_END_I]]
+// CHECK:       [[IF_END_I]]:
+// CHECK-NEXT:    
[[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I:%.*]]
 = load volatile i32, ptr [[ARGC_ADDR_I]], align 4, !tbaa [[INT_TBAA7]]
+// CHECK-NEXT:    store volatile i32 1, ptr [[CLEANUP_DEST_SLOT_I]], align 4
+// CHECK-NEXT:    invoke void @llvm.seh.try.end()
+// CHECK-NEXT:            to label %"?ExitOnThrow@@[email protected]" unwind label 
%[[CATCH_DISPATCH5_I]]
+// CHECK:       "?ExitOnThrow@@[email protected]":
+// CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[ARGC_ADDR_I]])
+// CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull 
[[__EXCEPTION_CODE1_I]])
+// CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull 
[[CLEANUP_DEST_SLOT_I]])
+// CHECK-NEXT:    [[CALL1:%.*]] = tail call noundef i32 
@"?AlwaysThrows@@YAHH@Z"(i32 noundef 
[[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I]])
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[CALL1]], 
[[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I]]
+// CHECK-NEXT:    ret i32 [[ADD]]
+//
+int main(int argc, char**)
+{
+  auto data = ExitOnThrow(argc);
+  return data + AlwaysThrows(data);
+}
+//.
+// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
+// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
+// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
+// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
+// CHECK: [[INTPTR_TBAA11]] = !{[[META12:![0-9]+]], [[META12]], i64 0}
+// CHECK: [[META12]] = !{!"p1 int", [[META13:![0-9]+]], i64 0}
+// CHECK: [[META13]] = !{!"any pointer", [[META9]], i64 0}
+//.
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp 
b/llvm/lib/CodeGen/WinEHPrepare.cpp
index 66d29cb5d65e4..a291354427e49 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -341,9 +341,12 @@ void llvm::calculateSEHStateForAsynchEH(const BasicBlock 
*BB, int State,
         // Retrive the new State from seh_try_begin
         State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
       else if (Fn && Fn->isIntrinsic() &&
-               Fn->getIntrinsicID() == Intrinsic::seh_try_end)
-        // end of current state, retrive new state from UnwindMap
+               Fn->getIntrinsicID() == Intrinsic::seh_try_end) {
+        // end of current state, retrieve new state through InvokeStateMap and
+        // UnwindMap
+        State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
         State = EHInfo.SEHUnwindMap[State].ToState;
+      }
     }
     // Continue push successors into worklist
     for (auto *SuccBB : successors(BB)) {
diff --git a/llvm/test/CodeGen/WinEH/wineh-statenumbering-seh-try-end.ll 
b/llvm/test/CodeGen/WinEH/wineh-statenumbering-seh-try-end.ll
new file mode 100644
index 0000000000000..c169ba5af4b53
--- /dev/null
+++ b/llvm/test/CodeGen/WinEH/wineh-statenumbering-seh-try-end.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 6
+; RUN: llc < %s | FileCheck %s
+target datalayout = 
"e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-pc"
+
+@p = dso_local global ptr null, align 8
+
+define dso_local noundef i32 @main(i32 noundef %argc, ptr noundef readnone 
captures(none) %argv) local_unnamed_addr personality ptr @__C_specific_handler {
+; CHECK-LABEL: main:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    .seh_pushreg %rbp
+; CHECK-NEXT:    pushq %rsi
+; CHECK-NEXT:    .seh_pushreg %rsi
+; CHECK-NEXT:    subq $56, %rsp
+; CHECK-NEXT:    .seh_stackalloc 56
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rbp
+; CHECK-NEXT:    .seh_setframe %rbp, 48
+; CHECK-NEXT:    .seh_endprologue
+; CHECK-NEXT:  .Ltmp0: # EH_LABEL
+; CHECK-NEXT:    nop
+; CHECK-NEXT:    movl %ecx, 4(%rbp)
+; CHECK-NEXT:  .Ltmp1: # EH_LABEL
+; CHECK-NEXT:  # %bb.1: # %invoke.cont2.i
+; CHECK-NEXT:  .Ltmp6: # EH_LABEL
+; CHECK-NEXT:    nop
+; CHECK-NEXT:    cmpl $0, 4(%rbp)
+; CHECK-NEXT:  .Ltmp7: # EH_LABEL
+; CHECK-NEXT:    jne .LBB0_3
+; CHECK-NEXT:  # %bb.2: # %if.then.i
+; CHECK-NEXT:  .Ltmp8: # EH_LABEL
+; CHECK-NEXT:    nop
+; CHECK-NEXT:    movq p(%rip), %rax
+; CHECK-NEXT:    movl $1, (%rax)
+; CHECK-NEXT:  .Ltmp9: # EH_LABEL
+; CHECK-NEXT:  .LBB0_3: # %if.end.i
+; CHECK-NEXT:  .Ltmp10: # EH_LABEL
+; CHECK-NEXT:    nop
+; CHECK-NEXT:    movl 4(%rbp), %esi
+; CHECK-NEXT:    movl $1, (%rbp)
+; CHECK-NEXT:  .Ltmp11: # EH_LABEL
+; CHECK-NEXT:  # %bb.4: # %"?ExitOnThrow@@[email protected]"
+; CHECK-NEXT:  .Ltmp12: # EH_LABEL
+; CHECK-NEXT:    leal 5(%rsi), %ecx
+; CHECK-NEXT:    callq "?AlwaysThrows@@YAHH@Z"
+; CHECK-NEXT:    # kill: def $eax killed $eax def $rax
+; CHECK-NEXT:    leal 5(%rax,%rsi), %eax
+; CHECK-NEXT:  .Ltmp13: # EH_LABEL
+; CHECK-NEXT:    .seh_startepilogue
+; CHECK-NEXT:    addq $56, %rsp
+; CHECK-NEXT:    popq %rsi
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    .seh_endepilogue
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB0_5: # %__except.i
+; CHECK-NEXT:  $ehgcr_0_5:
+; CHECK-NEXT:  .Ltmp2: # EH_LABEL
+; CHECK-NEXT:    nop
+; CHECK-NEXT:    movl %eax, -4(%rbp)
+; CHECK-NEXT:  .Ltmp3: # EH_LABEL
+; CHECK-NEXT:    jmp .LBB0_7
+; CHECK-NEXT:  .LBB0_6: # %__except6.i
+; CHECK-NEXT:  $ehgcr_0_6:
+; CHECK-NEXT:  .LBB0_7: # %__try.cont8.i
+; CHECK-NEXT:  .Ltmp4: # EH_LABEL
+; CHECK-NEXT:    callq Exit
+; CHECK-NEXT:    int3
+; CHECK-NEXT:  .Ltmp5: # EH_LABEL
+; CHECK-NEXT:  .Lfunc_end0:
+; CHECK-NEXT:    .seh_handlerdata
+; CHECK-NEXT:  .Lmain$parent_frame_offset = 48
+; CHECK-NEXT:    .long (.Llsda_end0-.Llsda_begin0)/16 # Number of call sites
+; CHECK-NEXT:  .Llsda_begin0:
+; CHECK-NEXT:    .long .Ltmp6@IMGREL # LabelStart
+; CHECK-NEXT:    .long .Ltmp11@IMGREL # LabelEnd
+; CHECK-NEXT:    .long 1 # CatchAll
+; CHECK-NEXT:    .long .LBB0_5@IMGREL # ExceptionHandler
+; CHECK-NEXT:    .long .Ltmp6@IMGREL # LabelStart
+; CHECK-NEXT:    .long .Ltmp11@IMGREL # LabelEnd
+; CHECK-NEXT:    .long 1 # CatchAll
+; CHECK-NEXT:    .long .LBB0_6@IMGREL # ExceptionHandler
+; CHECK-NEXT:    .long .Ltmp2@IMGREL # LabelStart
+; CHECK-NEXT:    .long .Ltmp3@IMGREL # LabelEnd
+; CHECK-NEXT:    .long 1 # CatchAll
+; CHECK-NEXT:    .long .LBB0_6@IMGREL # ExceptionHandler
+; CHECK-NEXT:  .Llsda_end0:
+; CHECK-NEXT:    .text
+; CHECK-NEXT:    .seh_endproc
+entry:
+  %argc.addr.i = alloca i32, align 4
+  %__exception_code1.i = alloca i32, align 4
+  %cleanup.dest.slot.i = alloca i32, align 4
+  call void @llvm.lifetime.start.p0(ptr nonnull %argc.addr.i)
+  call void @llvm.lifetime.start.p0(ptr nonnull %__exception_code1.i)
+  call void @llvm.lifetime.start.p0(ptr nonnull %cleanup.dest.slot.i)
+  store i32 %argc, ptr %argc.addr.i, align 4
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont.i unwind label %catch.dispatch5.i
+
+invoke.cont.i:                                    ; preds = %entry
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont2.i unwind label %catch.dispatch.i
+
+catch.dispatch.i:                                 ; preds = %invoke.cont.i
+  %0 = catchswitch within none [label %__except.i] unwind label 
%catch.dispatch5.i
+
+__except.i:                                       ; preds = %catch.dispatch.i
+  %1 = catchpad within %0 [ptr null]
+  catchret from %1 to label %__except3.i
+
+__except3.i:                                      ; preds = %__except.i
+  %2 = tail call i32 @llvm.eh.exceptioncode(token %1)
+  store volatile i32 %2, ptr %__exception_code1.i, align 4
+  invoke void @llvm.seh.try.end()
+          to label %__try.cont8.i unwind label %catch.dispatch5.i
+
+catch.dispatch5.i:                                ; preds = %if.end.i, 
%__except3.i, %catch.dispatch.i, %entry
+  %3 = catchswitch within none [label %__except6.i] unwind to caller
+
+__except6.i:                                      ; preds = %catch.dispatch5.i
+  %4 = catchpad within %3 [ptr null]
+  catchret from %4 to label %__except7.i
+
+__except7.i:                                      ; preds = %__except6.i
+  %5 = tail call i32 @llvm.eh.exceptioncode(token %4)
+  br label %__try.cont8.i
+
+__try.cont8.i:                                    ; preds = %__except7.i, 
%__except3.i
+  tail call void @Exit() #0
+  unreachable
+
+invoke.cont2.i:                                   ; preds = %invoke.cont.i
+  
%argc.addr.i.0.argc.addr.i.0.argc.addr.i.0.argc.addr.0.argc.addr.0.argc.addr.0..i
 = load volatile i32, ptr %argc.addr.i, align 4
+  %tobool.not.i = icmp eq i32 
%argc.addr.i.0.argc.addr.i.0.argc.addr.i.0.argc.addr.0.argc.addr.0.argc.addr.0..i,
 0
+  br i1 %tobool.not.i, label %if.then.i, label %if.end.i
+
+if.then.i:                                        ; preds = %invoke.cont2.i
+  %6 = load volatile ptr, ptr @p, align 8
+  store atomic volatile i32 1, ptr %6 release, align 4
+  br label %if.end.i
+
+if.end.i:                                         ; preds = %if.then.i, 
%invoke.cont2.i
+  
%argc.addr.i.0.argc.addr.i.0.argc.addr.i.0.argc.addr.0.argc.addr.0.argc.addr.0.10.i
 = load volatile i32, ptr %argc.addr.i, align 4
+  store volatile i32 1, ptr %cleanup.dest.slot.i, align 4
+  invoke void @llvm.seh.try.end()
+          to label %"?ExitOnThrow@@[email protected]" unwind label %catch.dispatch5.i
+
+"?ExitOnThrow@@[email protected]":                      ; preds = %if.end.i
+  %add.i = add nsw i32 
%argc.addr.i.0.argc.addr.i.0.argc.addr.i.0.argc.addr.0.argc.addr.0.argc.addr.0.10.i,
 5
+  call void @llvm.lifetime.end.p0(ptr nonnull %argc.addr.i)
+  call void @llvm.lifetime.end.p0(ptr nonnull %__exception_code1.i)
+  call void @llvm.lifetime.end.p0(ptr nonnull %cleanup.dest.slot.i)
+  %call1 = tail call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef %add.i)
+  %add = add nsw i32 %call1, %add.i
+  ret i32 %add
+}
+
+declare void @Exit()
+declare i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef %id)
+declare dso_local void @llvm.seh.try.begin()
+declare dso_local i32 @__C_specific_handler(...)
+declare i32 @llvm.eh.exceptioncode(token)
+declare dso_local void @llvm.seh.try.end()
+declare void @llvm.lifetime.start.p0(ptr captures(none))
+declare void @llvm.lifetime.end.p0(ptr captures(none))
+
+attributes #0 = { noreturn nounwind }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"eh-asynch", i32 1}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to