[clang] [Clang][Sema] Move err_seh_object_unwinding diagnostic from CodeGen to Sema (PR #199995)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 27 07:44:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: GkvJwa
<details>
<summary>Changes</summary>
Track local variables needing destruction and throwing new-expressions in FunctionScopeInfo::ObjUnwindingLocs during declaration processing,then check against usesSEHTry() at function end
---
Full diff: https://github.com/llvm/llvm-project/pull/199995.diff
7 Files Affected:
- (modified) clang/include/clang/Sema/ScopeInfo.h (+5)
- (modified) clang/lib/CodeGen/CGDecl.cpp (+1-6)
- (modified) clang/lib/CodeGen/CGException.cpp (-11)
- (modified) clang/lib/CodeGen/CGExprCXX.cpp (-12)
- (modified) clang/lib/Sema/ScopeInfo.cpp (+1)
- (modified) clang/lib/Sema/SemaDecl.cpp (+7)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+10)
``````````diff
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,
``````````
</details>
https://github.com/llvm/llvm-project/pull/199995
More information about the cfe-commits
mailing list