https://github.com/GkvJwa updated https://github.com/llvm/llvm-project/pull/172287
>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Wed, 17 Dec 2025 01:02:42 +0800 Subject: [PATCH 1/2] Add check object --- clang/lib/Sema/SemaStmt.cpp | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 1b1643250d05e..c64029f269c2b 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } +static bool containsNonTrivialObject(Sema &S, const Stmt *Node) { + (void)S; + if (!Node) + return false; + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(Node)) { + for (const Decl *D : DS->decls()) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + QualType T = VD->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) + return true; + } + } + } + } + } + + if (const Expr *E = dyn_cast<Expr>(Node)) { + QualType T = E->getType(); + if (T->isRecordType() && E->getValueKind() != VK_LValue) { + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) + return true; + } + } + } + } + + // children. + for (const Stmt *Child : Node->children()) + if (containsNonTrivialObject(S, Child)) + return true; + + return false; +} + StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) { assert(FilterExpr && Block); @@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FTy); } + if (containsNonTrivialObject(*this, Block)) { + Diag(Loc, diag::err_seh_try_outside_functions); + return StmtError(); + } return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block); } >From adfa51086425c0f9400342f04746428851b217b8 Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Wed, 17 Dec 2025 23:02:49 +0800 Subject: [PATCH 2/2] Check try block and CXXThrow --- clang/lib/Sema/SemaStmt.cpp | 106 ++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index c64029f269c2b..c312c445b1fb3 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -4515,6 +4515,58 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool IsTry) { targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : "throw"); } + +// Walk the statement subtree and return the first statement that +// contains a non-trivial C++ object that would require destruction at +// scope exit, or nullptr if none was found. +static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) { + (void)S; + if (!Node) + return nullptr; + + // Check for declarations of local variables with non-trivial destructors. + if (const DeclStmt *DS = dyn_cast<DeclStmt>(Node)) { + for (const Decl *D : DS->decls()) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + QualType T = VD->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) + return DS; + } + } + } + } + } + + // Check for expressions that materialize temporaries or otherwise + // produce prvalue/xvalue C++ objects that will require destruction. + if (const Expr *E = dyn_cast<Expr>(Node)) { + // A throw-expression creates an exception object as part of throwing and + // doesn't create a temporary that lives until the end of the handler + // scope; ignore it when checking for non-trivial temporaries. + if (isa<CXXThrowExpr>(E)) + return nullptr; + + QualType T = E->getType(); + if (T->isRecordType() && E->getValueKind() != VK_LValue) { + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) + return E; + } + } + } + } + + // Recurse into children. + for (const Stmt *Child : Node->children()) + if (const Stmt *SWith = findNonTrivialObject(S, Child)) + return SWith; + + return nullptr; +} + StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler) { assert(TryBlock && Handler); @@ -4535,6 +4587,15 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, FSI->setHasSEHTry(TryLoc); + // Disallow non-trivial C++ objects in an SEH __try block as well. If the + // try block contains temporaries or local objects with non-trivial + // destructors, emit the same diagnostic and fail parsing the try. + if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) { + Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions); + Diag(TryLoc, diag::note_conflicting_try_here) << "'__try'"; + return StmtError(); + } + // Reject __try in Obj-C methods, blocks, and captured decls, since we don't // track if they use SEH. DeclContext *DC = CurContext; @@ -4553,45 +4614,6 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } -static bool containsNonTrivialObject(Sema &S, const Stmt *Node) { - (void)S; - if (!Node) - return false; - - if (const DeclStmt *DS = dyn_cast<DeclStmt>(Node)) { - for (const Decl *D : DS->decls()) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - QualType T = VD->getType(); - if (const RecordType *RT = T->getAs<RecordType>()) { - if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { - if (RD->hasDefinition() && !RD->hasTrivialDestructor()) - return true; - } - } - } - } - } - - if (const Expr *E = dyn_cast<Expr>(Node)) { - QualType T = E->getType(); - if (T->isRecordType() && E->getValueKind() != VK_LValue) { - if (const RecordType *RT = T->getAs<RecordType>()) { - if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) { - if (RD->hasDefinition() && !RD->hasTrivialDestructor()) - return true; - } - } - } - } - - // children. - for (const Stmt *Child : Node->children()) - if (containsNonTrivialObject(S, Child)) - return true; - - return false; -} - StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) { assert(FilterExpr && Block); @@ -4601,8 +4623,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FTy); } - if (containsNonTrivialObject(*this, Block)) { - Diag(Loc, diag::err_seh_try_outside_functions); + // Disallow non-trivial C++ objects in an SEH __except handler. + if (const Stmt *Offending = findNonTrivialObject(*this, Block)) { + Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions); + Diag(Loc, diag::note_conflicting_try_here) << "'__except'"; return StmtError(); } return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
