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
