https://github.com/GkvJwa created 
https://github.com/llvm/llvm-project/pull/199995

Track local variables needing destruction and throwing new-expressions in 
FunctionScopeInfo::ObjUnwindingLocs during declaration processing,then check 
against usesSEHTry() at function end

>From 9822fb954d7a09516dbd0a61621a4db19b52d84e Mon Sep 17 00:00:00 2001
From: GkvJwa <[email protected]>
Date: Wed, 27 May 2026 22:26:19 +0800
Subject: [PATCH] [Clang][Sema] Move err_seh_object_unwinding diagnostic from
 CodeGen to Sema

Track local variables needing destruction and throwing
new-expressions in FunctionScopeInfo::ObjUnwindingLocs
during declaration processing,then check against
usesSEHTry() at function end
---
 clang/include/clang/Sema/ScopeInfo.h |  5 +++++
 clang/lib/CodeGen/CGDecl.cpp         |  7 +------
 clang/lib/CodeGen/CGException.cpp    | 11 -----------
 clang/lib/CodeGen/CGExprCXX.cpp      | 12 ------------
 clang/lib/Sema/ScopeInfo.cpp         |  1 +
 clang/lib/Sema/SemaDecl.cpp          |  7 +++++++
 clang/lib/Sema/SemaExprCXX.cpp       | 10 ++++++++++
 7 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/clang/include/clang/Sema/ScopeInfo.h 
b/clang/include/clang/Sema/ScopeInfo.h
index f334f58ebd0a7..28ce8bcc645c0 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -238,6 +238,11 @@ class FunctionScopeInfo {
   /// prior to being emitted.
   SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
 
+  /// Source locations of declarations or expressions that require object
+  /// unwinding (non-trivial destruction or throwing new-expressions).
+  /// Checked against SEH __try usage at function end.
+  SmallVector<SourceLocation, 4> ObjUnwindingLocs;
+
   /// A list of parameters which have the nonnull attribute and are
   /// modified in the function.
   llvm::SmallPtrSet<const ParmVarDecl *, 8> ModifiedNonNullParams;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 7608f8cb6fc7a..caf2c902cc851 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2228,13 +2228,8 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // 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
-    if (getLangOpts().CXXExceptions && currentFunctionUsesSEHTry())
-      getContext().getDiagnostics().Report(D.getLocation(),
-                                           diag::err_seh_object_unwinding);
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
     emitAutoVarTypeCleanup(emission, dtorKind);
-  }
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index 99dfaa80be429..c4904fc508f37 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -2247,17 +2247,6 @@ 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/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 0dc2e0bb82114..e98015cb8fabb 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1720,18 +1720,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const 
CXXNewExpr *E) {
   llvm::Instruction *cleanupDominator = nullptr;
   if (E->getOperatorDelete() &&
       !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
-    // A potentially-throwing constructor inside __try requires C++ object
-    // unwinding, which is incompatible with SEH.
-    if (getLangOpts().CXXExceptions && currentFunctionUsesSEHTry()) {
-      if (const auto *ConstructExpr = E->getConstructExpr()) {
-        const auto *FPT = ConstructExpr->getConstructor()
-                              ->getType()
-                              ->castAs<FunctionProtoType>();
-        if (!FPT->isNothrow())
-          getContext().getDiagnostics().Report(E->getBeginLoc(),
-                                               diag::err_seh_object_unwinding);
-      }
-    }
     EnterNewDeleteCleanup(*this, E, TypeIdentityArg, allocation, allocSize,
                           allocAlign, allocatorArgs);
     operatorDeleteCleanup = EHStack.stable_begin();
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index d089836fa36dd..a4159f4495ba3 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -54,6 +54,7 @@ void FunctionScopeInfo::Clear() {
   ErrorTrap.reset();
   PossiblyUnreachableDiags.clear();
   WeakObjectUses.clear();
+  ObjUnwindingLocs.clear();
   ModifiedNonNullParams.clear();
   Blocks.clear();
   ByrefBlockVars.clear();
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 62cb9360d1322..52b8f9dfa6667 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14931,6 +14931,9 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl 
*var) {
       var->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
     setFunctionHasBranchProtectedScope();
 
+  if (var->hasLocalStorage() && var->needsDestruction(Context))
+    getCurFunction()->ObjUnwindingLocs.push_back(var->getLocation());
+
   // Warn about externally-visible variables being defined without a
   // prior declaration.  We only want to do this for global
   // declarations, but we also specifically need to avoid doing it for
@@ -16670,6 +16673,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt 
*Body, bool IsInstantiation,
       AnalysisWarnings.getPolicyInEffectAt(AnalysisLoc);
   sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
 
+  if (getLangOpts().CXXExceptions && FD && FD->usesSEHTry())
+    for (SourceLocation Loc : FSI->ObjUnwindingLocs)
+      Diag(Loc, diag::err_seh_object_unwinding);
+
   // If we skip function body, we can't tell if a function is a coroutine.
   if (getLangOpts().Coroutines && FD && !FD->hasSkippedBody()) {
     if (FSI->isCoroutine())
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index a60e1b84d3e4b..639487518ea2d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2671,6 +2671,16 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool 
UseGlobal,
     }
   }
 
+  if (OperatorDelete &&
+      !OperatorDelete->isReservedGlobalPlacementOperator()) {
+    if (const auto *CCE = dyn_cast_or_null<CXXConstructExpr>(Initializer)) {
+      const auto *FPT =
+          CCE->getConstructor()->getType()->castAs<FunctionProtoType>();
+      if (!FPT->isNothrow())
+        getCurFunction()->ObjUnwindingLocs.push_back(StartLoc);
+    }
+  }
+
   return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
                             IAP, UsualArrayDeleteWantsSize, PlacementArgs,
                             TypeIdParens, ArraySize, InitStyle, Initializer,

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

Reply via email to