[clang] 8da581d - [WinEH] Diagnose SEH object unwinding in skipped __except bodies (#187718)

via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 28 18:48:40 PDT 2026


Author: GkvJwa
Date: 2026-04-29T09:48:35+08:00
New Revision: 8da581d58abd5b1921d3959b04dcf9e1c1feeb34

URL: https://github.com/llvm/llvm-project/commit/8da581d58abd5b1921d3959b04dcf9e1c1feeb34
DIFF: https://github.com/llvm/llvm-project/commit/8da581d58abd5b1921d3959b04dcf9e1c1feeb34.diff

LOG: [WinEH] Diagnose SEH object unwinding in skipped __except bodies (#187718)

When an SEH __except block has no EH branches, CodeGen skips emitting the handler
body. This also skipped the existing diagnostic for local variables that require destruction
under C++ exceptions

Diagnose those variables before dropping the skipped handler body, and add coverage
for both sync and async exception modes

Added: 
    

Modified: 
    clang/lib/CodeGen/CGDecl.cpp
    clang/lib/CodeGen/CGException.cpp
    clang/test/CodeGenCXX/exceptions-seh.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 419b3c477e7b2..a7479809d219e 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2230,8 +2230,6 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
   // Check the type for a cleanup.
   if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
     // Check if we're in a SEH block with /EH, prevent it
-    // TODO: /EHs* 
diff ers from /EHa, the former may not be executed to this
-    // point.
     if (getLangOpts().CXXExceptions && currentFunctionUsesSEHTry())
       getContext().getDiagnostics().Report(D.getLocation(),
                                            diag::err_seh_object_unwinding);

diff  --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index a83a05d01121f..f7c6f7521c98e 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -2245,6 +2245,17 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
   // TODO: Model unwind edges from instructions, either with iload / istore or
   // a try body function.
   if (!CatchScope.hasEHBranches()) {
+    // Even though we skip emitting the __except body, diagnose variables
+    // with non-trivial destructors that would normally be caught by
+    // EmitAutoVarCleanups.
+    if (getLangOpts().CXXExceptions && currentFunctionUsesSEHTry())
+      for (const Stmt *S : Except->getBlock()->body())
+        if (const auto *DS = dyn_cast<DeclStmt>(S))
+          for (const Decl *D : DS->decls())
+            if (const auto *VD = dyn_cast<VarDecl>(D))
+              if (VD->needsDestruction(getContext()))
+                getContext().getDiagnostics().Report(
+                    VD->getLocation(), diag::err_seh_object_unwinding);
     CatchScope.clearHandlerBlocks();
     EHStack.popCatch();
     SEHCodeSlotStack.pop_back();

diff  --git a/clang/test/CodeGenCXX/exceptions-seh.cpp b/clang/test/CodeGenCXX/exceptions-seh.cpp
index 270b249f700fa..c4b191377b844 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -5,13 +5,17 @@
 // RUN:         -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN:         FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
 // RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions \
-// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR1
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_ASYNC1
 // RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions \
-// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR2
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_ASYNC2
 // RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions \
-// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR3
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_ASYNC3
 // RUN: %clang_cc1 -triple x86_64-windows -fcxx-exceptions -fexceptions \
-// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR4
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_SYNC1
+// RUN: %clang_cc1 -triple x86_64-windows -fcxx-exceptions -fexceptions \
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_SYNC2
+// RUN: %clang_cc1 -triple x86_64-windows -fcxx-exceptions -fexceptions \
+// RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DERR_SYNC3
 // RUN: %clang_cc1 -triple x86_64-windows \
 // RUN:         -fms-extensions -x c++ -emit-llvm-only -verify %s -DNOERR
 
@@ -186,34 +190,27 @@ void use_inline() {
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
 
-#if defined(ERR1)
+#if defined(ERR_ASYNC1) || defined(ERR_SYNC1)
 void seh_unwinding() {
   __try {
     HasCleanup x; // expected-error{{'__try' is not permitted in functions that require object unwinding}}
   } __except (1) {
   }
 }
-#elif defined(ERR2)
+#elif defined(ERR_ASYNC2) || defined(ERR_SYNC2)
 void seh_unwinding() {
   __try {
   } __except (1) {
     HasCleanup x; // expected-error{{'__try' is not permitted in functions that require object unwinding}}
   }
 }
-#elif defined(ERR3)
+#elif defined(ERR_ASYNC3) || defined(ERR_SYNC3)
 void seh_unwinding() {
   HasCleanup x; // expected-error{{'__try' is not permitted in functions that require object unwinding}}
   __try {
   } __except (1) {
   }
 }
-#elif defined(ERR4)
-void seh_unwinding() {
-  __try {
-    HasCleanup x; // expected-error{{'__try' is not permitted in functions that require object unwinding}}
-  } __except (1) {
-  }
-}
 #elif defined(NOERR)
 void seh_unwinding() {
   __try {


        


More information about the cfe-commits mailing list