https://github.com/ianayl created 
https://github.com/llvm/llvm-project/pull/220462

This PR fixes codegen for statements that branch out of SEH handlers causing 
compiler crashes in LLVM, i.e. see current behavior as of 23.1.0: 
https://godbolt.org/z/ns3o3h84e
```c
int main() {
  __try {
  } __finally {
    goto illegal_jmp;
  }
illegal_jmp:
  return 0;
}
```
Instead, this PR tries to adhere to [MSVC 
C4532](https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4532)
 and emits `unreachable` when a statement leads to a `br` out of the immediate 
SEH handler statement / outlined function. As visible in aforementioned Godbolt 
link, Sema already contains code emitting warnings on these jumps out of SEH 
handlers, it's moreso a matter of preventing the compiler crash and adhereing 
to what's specified in C4532.

>From 3a3863ff81cd51223bf8526c219ae37243db7314 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 1 Sep 2026 18:59:02 -0700
Subject: [PATCH] MSVC C4532: Generate "unreachable" if outlined SEH helper has
 gotos jumping out of the function

---
 clang/lib/CodeGen/CGException.cpp   |  7 ++++---
 clang/lib/CodeGen/CGStmt.cpp        | 28 +++++++++++++++++++++++++++-
 clang/lib/CodeGen/CodeGenFunction.h | 13 ++++++++++---
 3 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index b0fb3b4d85d15..109a02c3b48fe 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -1739,8 +1739,8 @@ struct PerformSEHFinally final : EHScopeStack::Cleanup {
     // Compute the two argument values.
     QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
     llvm::Value *FP = nullptr;
-    // If CFG.IsOutlinedSEHHelper is true, then we are within a finally block.
-    if (CGF.IsOutlinedSEHHelper) {
+    // If CFG.IsOutlinedSEHHelper() is true, then we are within a finally 
block.
+    if (CGF.IsOutlinedSEHHelper()) {
       FP = &CGF.CurFn->arg_begin()[1];
     } else {
       llvm::Function *LocalAddrFn =
@@ -2083,7 +2083,8 @@ void 
CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
   llvm::Function *Fn = llvm::Function::Create(
       FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
 
-  IsOutlinedSEHHelper = true;
+  // Indicate the current function is an outlined SEH helper.
+  OutlinedSEHStmt = OutlinedStmt;
 
   StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
                 OutlinedStmt->getBeginLoc(), OutlinedStmt->getBeginLoc());
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index bf6e6eb50f555..f979786126c6c 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -848,6 +848,23 @@ void CodeGenFunction::EmitAttributedStmt(const 
AttributedStmt &S) {
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
 
+static bool StmtContainsLabelDecl(const Stmt *S, const LabelDecl *Target) {
+  if (!S)
+    return false;
+  if (const auto *LS = dyn_cast<LabelStmt>(S))
+    if (LS->getDecl() == Target)
+      return true;
+  for (const Stmt *Child : S->children())
+    if (StmtContainsLabelDecl(Child, Target))
+      return true;
+  return false;
+}
+
+bool CodeGenFunction::IsLabelWithinSEHHelper(const LabelDecl *Label) const {
+  assert(IsOutlinedSEHHelper() && "Not in an outlined SEH helper");
+  return StmtContainsLabelDecl(OutlinedSEHStmt, Label);
+}
+
 void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
   // If this code is reachable then emit a stop point (if generating
   // debug info). We have to do this ourselves because we are on the
@@ -855,6 +872,15 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
   if (HaveInsertPoint())
     EmitStopPoint(&S);
 
+  // MSVC C4532: jumping out of an outlined SEH helper is UB, but jumping
+  // internally should be fine. Sema has a warn for this already.
+  // `br` should not jump out of the current function anyway, so a jump out of
+  // the outlined SEH helper will cause a compiler crash.
+  if (IsOutlinedSEHHelper() && !IsLabelWithinSEHHelper(S.getLabel())) {
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+  }
+
   ApplyAtomGroup Grp(getDebugInfo());
   EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
 }
@@ -1627,7 +1653,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) 
{
   }
 
   // Returning from an outlined SEH helper is UB, and we already warn on it.
-  if (IsOutlinedSEHHelper) {
+  if (IsOutlinedSEHHelper()) {
     Builder.CreateUnreachable();
     Builder.ClearInsertionPoint();
   }
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index dfb6f2ff65a7d..9ff301bf4cd60 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -605,9 +605,16 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   GlobalDecl CurSEHParent;
 
-  /// True if the current function is an outlined SEH helper. This can be a
-  /// finally block or filter expression.
-  bool IsOutlinedSEHHelper = false;
+  /// Pointer to the outlined SEH helper statement if current function is an
+  /// outlined SEH helper, nullptr otherwise. This can be a finally block or
+  /// a filter expression.
+  const Stmt *OutlinedSEHStmt = nullptr;
+
+  /// True if the current function is an outlined SEH helper.
+  bool IsOutlinedSEHHelper() const { return OutlinedSEHStmt != nullptr; }
+
+  /// True if Label is found within OutlinedSEHStmt.
+  bool IsLabelWithinSEHHelper(const LabelDecl *Label) const;
 
   /// True if CodeGen currently emits code inside presereved access index
   /// region.

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

Reply via email to