llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Mirko (MuellerMP)

<details>
<summary>Changes</summary>

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.

---

Patch is 30.62 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/167176.diff


8 Files Affected:

- (modified) clang/lib/CodeGen/CGCall.cpp (+77-67) 
- (modified) clang/lib/CodeGen/CGCleanup.cpp (+6-4) 
- (modified) clang/lib/CodeGen/CGException.cpp (+43-2) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+7-1) 
- (added) clang/test/CodeGen/windows-seh-EHa-Inline1.cpp (+62) 
- (added) clang/test/CodeGen/windows-seh-EHa-Inline2.cpp (+103) 
- (added) clang/test/CodeGen/windows-seh-EHa-Inline3.cpp (+87) 
- (modified) llvm/lib/CodeGen/WinEHPrepare.cpp (+1-1) 


``````````diff
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 465f3f4e670c2..44a71b67e56bc 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3982,63 +3982,41 @@ llvm::Value 
*CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src,
   return R;
 }
 
-void CodeGenFunction::EmitFunctionEpilog(
-    const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc,
-    uint64_t RetKeyInstructionsSourceAtom) {
-  if (FI.isNoReturn()) {
-    // Noreturn functions don't return.
-    EmitUnreachable(EndLoc);
-    return;
-  }
-
-  if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) {
-    // Naked functions don't have epilogues.
-    Builder.CreateUnreachable();
-    return;
-  }
-
-  // Functions with no result always return void.
-  if (!ReturnValue.isValid()) {
-    auto *I = Builder.CreateRetVoid();
-    if (RetKeyInstructionsSourceAtom)
-      addInstToSpecificSourceAtom(I, nullptr, RetKeyInstructionsSourceAtom);
-    else
-      addInstToNewSourceAtom(I, nullptr);
-    return;
-  }
-
-  llvm::DebugLoc RetDbgLoc;
-  llvm::Value *RV = nullptr;
-  QualType RetTy = FI.getReturnType();
+static void processFunctionReturnInfo(CodeGenFunction &CGF,
+                                      const CGFunctionInfo &FI,
+                                      bool EmitRetDbgLoc, SourceLocation 
EndLoc,
+                                      QualType RetTy, llvm::Value *&RV,
+                                      llvm::DebugLoc &RetDbgLoc) {
   const ABIArgInfo &RetAI = FI.getReturnInfo();
 
   switch (RetAI.getKind()) {
   case ABIArgInfo::InAlloca:
     // Aggregates get evaluated directly into the destination.  Sometimes we
     // need to return the sret value in a register, though.
-    assert(hasAggregateEvaluationKind(RetTy));
+    assert(CodeGenFunction::hasAggregateEvaluationKind(RetTy));
     if (RetAI.getInAllocaSRet()) {
-      llvm::Function::arg_iterator EI = CurFn->arg_end();
+      llvm::Function::arg_iterator EI = CGF.CurFn->arg_end();
       --EI;
       llvm::Value *ArgStruct = &*EI;
-      llvm::Value *SRet = Builder.CreateStructGEP(
+      llvm::Value *SRet = CGF.Builder.CreateStructGEP(
           FI.getArgStruct(), ArgStruct, RetAI.getInAllocaFieldIndex());
       llvm::Type *Ty =
           cast<llvm::GetElementPtrInst>(SRet)->getResultElementType();
-      RV = Builder.CreateAlignedLoad(Ty, SRet, getPointerAlign(), "sret");
+      RV = CGF.Builder.CreateAlignedLoad(Ty, SRet, CGF.getPointerAlign(),
+                                         "sret");
     }
     break;
 
   case ABIArgInfo::Indirect: {
-    auto AI = CurFn->arg_begin();
+    auto AI = CGF.CurFn->arg_begin();
     if (RetAI.isSRetAfterThis())
       ++AI;
-    switch (getEvaluationKind(RetTy)) {
+    switch (CodeGenFunction::getEvaluationKind(RetTy)) {
     case TEK_Complex: {
-      ComplexPairTy RT =
-          EmitLoadOfComplex(MakeAddrLValue(ReturnValue, RetTy), EndLoc);
-      EmitStoreOfComplex(RT, MakeNaturalAlignAddrLValue(&*AI, RetTy),
-                         /*isInit*/ true);
+      CodeGenFunction::ComplexPairTy RT = CGF.EmitLoadOfComplex(
+          CGF.MakeAddrLValue(CGF.ReturnValue, RetTy), EndLoc);
+      CGF.EmitStoreOfComplex(RT, CGF.MakeNaturalAlignAddrLValue(&*AI, RetTy),
+                             /*isInit*/ true);
       break;
     }
     case TEK_Aggregate:
@@ -4048,13 +4026,14 @@ void CodeGenFunction::EmitFunctionEpilog(
       LValueBaseInfo BaseInfo;
       TBAAAccessInfo TBAAInfo;
       CharUnits Alignment =
-          CGM.getNaturalTypeAlignment(RetTy, &BaseInfo, &TBAAInfo);
-      Address ArgAddr(&*AI, ConvertType(RetTy), Alignment);
-      LValue ArgVal =
-          LValue::MakeAddr(ArgAddr, RetTy, getContext(), BaseInfo, TBAAInfo);
-      EmitStoreOfScalar(
-          EmitLoadOfScalar(MakeAddrLValue(ReturnValue, RetTy), EndLoc), ArgVal,
-          /*isInit*/ true);
+          CGF.CGM.getNaturalTypeAlignment(RetTy, &BaseInfo, &TBAAInfo);
+      Address ArgAddr(&*AI, CGF.ConvertType(RetTy), Alignment);
+      LValue ArgVal = LValue::MakeAddr(ArgAddr, RetTy, CGF.getContext(),
+                                       BaseInfo, TBAAInfo);
+      CGF.EmitStoreOfScalar(
+          CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(CGF.ReturnValue, RetTy),
+                               EndLoc),
+          ArgVal, /*isInit*/ true);
       break;
     }
     }
@@ -4063,37 +4042,37 @@ void CodeGenFunction::EmitFunctionEpilog(
 
   case ABIArgInfo::Extend:
   case ABIArgInfo::Direct:
-    if (RetAI.getCoerceToType() == ConvertType(RetTy) &&
+    if (RetAI.getCoerceToType() == CGF.ConvertType(RetTy) &&
         RetAI.getDirectOffset() == 0) {
       // The internal return value temp always will have pointer-to-return-type
       // type, just do a load.
 
       // If there is a dominating store to ReturnValue, we can elide
       // the load, zap the store, and usually zap the alloca.
-      if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) {
+      if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(CGF)) {
         // Reuse the debug location from the store unless there is
         // cleanup code to be emitted between the store and return
         // instruction.
-        if (EmitRetDbgLoc && !AutoreleaseResult)
+        if (EmitRetDbgLoc && !CGF.AutoreleaseResult)
           RetDbgLoc = SI->getDebugLoc();
         // Get the stored value and nuke the now-dead store.
         RV = SI->getValueOperand();
         SI->eraseFromParent();
 
-      // Otherwise, we have to do a simple load.
+        // Otherwise, we have to do a simple load.
       } else {
-        RV = Builder.CreateLoad(ReturnValue);
+        RV = CGF.Builder.CreateLoad(CGF.ReturnValue);
       }
     } else {
       // If the value is offset in memory, apply the offset now.
-      Address V = emitAddressAtOffset(*this, ReturnValue, RetAI);
+      Address V = emitAddressAtOffset(CGF, CGF.ReturnValue, RetAI);
 
-      RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
+      RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), CGF);
     }
 
     // In ARC, end functions that return a retainable type with a call
     // to objc_autoreleaseReturnValue.
-    if (AutoreleaseResult) {
+    if (CGF.AutoreleaseResult) {
 #ifndef NDEBUG
       // Type::isObjCRetainabletype has to be called on a QualType that hasn't
       // been stripped of the typedefs, so we cannot use RetTy here. Get the
@@ -4101,19 +4080,19 @@ void CodeGenFunction::EmitFunctionEpilog(
       // CurCodeDecl or BlockInfo.
       QualType RT;
 
-      if (auto *FD = dyn_cast<FunctionDecl>(CurCodeDecl))
+      if (auto *FD = dyn_cast<FunctionDecl>(CGF.CurCodeDecl))
         RT = FD->getReturnType();
-      else if (auto *MD = dyn_cast<ObjCMethodDecl>(CurCodeDecl))
+      else if (auto *MD = dyn_cast<ObjCMethodDecl>(CGF.CurCodeDecl))
         RT = MD->getReturnType();
-      else if (isa<BlockDecl>(CurCodeDecl))
-        RT = BlockInfo->BlockExpression->getFunctionType()->getReturnType();
+      else if (isa<BlockDecl>(CGF.CurCodeDecl))
+        RT = 
CGF.BlockInfo->BlockExpression->getFunctionType()->getReturnType();
       else
         llvm_unreachable("Unexpected function/method type");
 
-      assert(getLangOpts().ObjCAutoRefCount && !FI.isReturnsRetained() &&
+      assert(CGF.getLangOpts().ObjCAutoRefCount && !FI.isReturnsRetained() &&
              RT->isObjCRetainableType());
 #endif
-      RV = emitAutoreleaseOfResult(*this, RV);
+      RV = emitAutoreleaseOfResult(CGF, RV);
     }
 
     break;
@@ -4128,19 +4107,19 @@ void CodeGenFunction::EmitFunctionEpilog(
 
     // Load all of the coerced elements out into results.
     llvm::SmallVector<llvm::Value *, 4> results;
-    Address addr = ReturnValue.withElementType(coercionType);
+    Address addr = CGF.ReturnValue.withElementType(coercionType);
     unsigned unpaddedIndex = 0;
     for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
       auto coercedEltType = coercionType->getElementType(i);
       if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType))
         continue;
 
-      auto eltAddr = Builder.CreateStructGEP(addr, i);
+      auto eltAddr = CGF.Builder.CreateStructGEP(addr, i);
       llvm::Value *elt = CreateCoercedLoad(
           eltAddr,
           unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
                          : unpaddedCoercionType,
-          *this);
+          CGF);
       results.push_back(elt);
     }
 
@@ -4148,27 +4127,58 @@ void CodeGenFunction::EmitFunctionEpilog(
     if (results.size() == 1) {
       RV = results[0];
 
-    // Otherwise, we need to make a first-class aggregate.
+      // Otherwise, we need to make a first-class aggregate.
     } else {
       // Construct a return type that lacks padding elements.
       llvm::Type *returnType = RetAI.getUnpaddedCoerceAndExpandType();
 
       RV = llvm::PoisonValue::get(returnType);
       for (unsigned i = 0, e = results.size(); i != e; ++i) {
-        RV = Builder.CreateInsertValue(RV, results[i], i);
+        RV = CGF.Builder.CreateInsertValue(RV, results[i], i);
       }
     }
     break;
   }
   case ABIArgInfo::TargetSpecific: {
-    Address V = emitAddressAtOffset(*this, ReturnValue, RetAI);
-    RV = CGM.getABIInfo().createCoercedLoad(V, RetAI, *this);
+    Address V = emitAddressAtOffset(CGF, CGF.ReturnValue, RetAI);
+    RV = CGF.CGM.getABIInfo().createCoercedLoad(V, RetAI, CGF);
     break;
   }
   case ABIArgInfo::Expand:
   case ABIArgInfo::IndirectAliased:
     llvm_unreachable("Invalid ABI kind for return argument");
   }
+}
+
+static bool isReturnReachable(CodeGenFunction::JumpDest &ReturnBlock) {
+  return !ReturnBlock.isValid() || !ReturnBlock.getBlock()->use_empty();
+}
+
+void CodeGenFunction::EmitFunctionEpilog(
+    const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc,
+    uint64_t RetKeyInstructionsSourceAtom) {
+  if (FI.isNoReturn()) {
+    // Noreturn functions don't return.
+    EmitUnreachable(EndLoc);
+    return;
+  }
+
+  if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) {
+    // Naked functions don't have epilogues.
+    Builder.CreateUnreachable();
+    return;
+  }
+
+  llvm::Value *RV = nullptr;
+  llvm::DebugLoc RetDbgLoc;
+  QualType RetTy = FI.getReturnType();
+
+  if (ReturnValue.isValid())
+    processFunctionReturnInfo(*this, FI, EmitRetDbgLoc, EndLoc, RetTy, RV,
+                              RetDbgLoc);
+
+  if (SehTryEndInvokeDest && isReturnReachable(ReturnBlock))
+    EmitSehTryScopeEnd(SehTryEndInvokeDest);
 
   llvm::Instruction *Ret;
   if (RV) {
@@ -4203,7 +4213,7 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value 
*RV) {
 
   // If the return block isn't reachable, neither is this check, so don't emit
   // it.
-  if (ReturnBlock.isValid() && ReturnBlock.getBlock()->use_empty())
+  if (!isReturnReachable(ReturnBlock))
     return;
 
   ReturnsNonNullAttr *RetNNAttr = nullptr;
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 28ac9bf396356..6d3bbd672517a 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -1329,8 +1329,10 @@ 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 +1375,11 @@ void CodeGenFunction::EmitSehTryScopeBegin() {
 }
 
 // Invoke a llvm.seh.try.end at the end of a SEH scope for -EHa
-void CodeGenFunction::EmitSehTryScopeEnd() {
+void CodeGenFunction::EmitSehTryScopeEnd(llvm::BasicBlock *InvokeDest) {
   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);
+  EmitSehScope(*this, SehCppScope, InvokeDest);
 }
diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index f86af4581c345..bc02264b4a58b 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -635,6 +635,37 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
     ExitCXXTryStmt(S);
 }
 
+static bool
+RequiresSehTryEnd(const CompoundStmt* S,
+                  llvm::SmallPtrSet<const Stmt *, 1> &CheckedSehTryBlockStmts) 
{
+  if (!S || CheckedSehTryBlockStmts.contains(S))
+    return false;
+
+  llvm::SmallVector<const Stmt *> WorkList;
+  WorkList.push_back(S);
+
+  while (!WorkList.empty()) {
+    auto *Next = WorkList.back();
+    WorkList.pop_back();
+    if (!Next)
+      continue;
+
+    if (isa<ReturnStmt>(Next))
+      return true;
+
+    if (auto *Try = dyn_cast<CXXTryStmt>(Next))
+      CheckedSehTryBlockStmts.insert(Try->getTryBlock());
+
+    if (auto *Try = dyn_cast<SEHTryStmt>(Next))
+      CheckedSehTryBlockStmts.insert(Try->getTryBlock());
+
+    auto Children = Next->children();
+    WorkList.insert(WorkList.end(), Children.begin(), Children.end());
+  }
+
+  return false;
+}
+
 void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
   unsigned NumHandlers = S.getNumHandlers();
   EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
@@ -666,8 +697,14 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, 
bool IsFnTryBlock) {
       CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), 
Handler);
       // Under async exceptions, catch(...) need to catch HW exception too
       // Mark scope with SehTryBegin as a SEH __try scope
-      if (getLangOpts().EHAsynch)
+      if (getLangOpts().EHAsynch) {
         EmitSehTryScopeBegin();
+        auto *TryBlock = S.getTryBlock();
+
+        if (!SehTryEndInvokeDest &&
+            RequiresSehTryEnd(TryBlock, CheckedSehTryBlockStmts))
+          SehTryEndInvokeDest = getInvokeDest();
+      }
     }
   }
 }
@@ -1670,14 +1707,18 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt 
&S) {
     SEHTryEpilogueStack.push_back(&TryExit);
 
     llvm::BasicBlock *TryBB = nullptr;
+    auto *TryBlock = S.getTryBlock();
     // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa
     if (getLangOpts().EHAsynch) {
       EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
       if (SEHTryEpilogueStack.size() == 1) // outermost only
         TryBB = Builder.GetInsertBlock();
+      if (!SehTryEndInvokeDest &&
+          RequiresSehTryEnd(TryBlock, CheckedSehTryBlockStmts))
+        SehTryEndInvokeDest = getInvokeDest();
     }
 
-    EmitStmt(S.getTryBlock());
+    EmitStmt(TryBlock);
 
     // Volatilize all blocks in Try, till current insert point
     if (TryBB) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 8c4c1c8c2dc95..1920e8d562674 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -2129,6 +2129,12 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Terminate funclets keyed by parent funclet pad.
   llvm::MapVector<llvm::Value *, llvm::BasicBlock *> TerminateFunclets;
 
+  /// Visited try block statements that do not need a scope end.
+  llvm::SmallPtrSet<const Stmt *, 1> CheckedSehTryBlockStmts;
+
+  /// 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 +3247,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitSehCppScopeBegin();
   void EmitSehCppScopeEnd();
   void EmitSehTryScopeBegin();
-  void EmitSehTryScopeEnd();
+  void EmitSehTryScopeEnd(llvm::BasicBlock *InvokeDest = nullptr);
 
   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..f8539cb315dfb
--- /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; }
+      retu...
[truncated]

``````````

</details>


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

Reply via email to