https://github.com/GkvJwa updated https://github.com/llvm/llvm-project/pull/172287
>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Thu, 18 Dec 2025 00:30:02 +0800 Subject: [PATCH 1/4] Add test and skip Borland --- clang/lib/Sema/SemaStmt.cpp | 70 +++++++++++++++++++++++++++ clang/test/SemaCXX/exceptions-seh.cpp | 30 ++++++++++++ 2 files changed, 100 insertions(+) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 1b1643250d05e..c562d15b0338c 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -4515,6 +4515,57 @@ 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 +4586,17 @@ 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. Skip + // this diagnostic when Borland extensions are enabled. + if (!getLangOpts().Borland) { + if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) { + return StmtError( + Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions)); + } + } + // Reject __try in Obj-C methods, blocks, and captured decls, since we don't // track if they use SEH. DeclContext *DC = CurContext; @@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FTy); } + // Disallow non-trivial C++ objects in an SEH __except handler. Skip + // this diagnostic when Borland extensions are enabled. + if (!getLangOpts().Borland) { + if (const Stmt *Offending = findNonTrivialObject(*this, Block)) { + return StmtError( + Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions)); + } + } return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block); } diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index 02bb786160dcf..0a008aeb5721e 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -126,3 +126,33 @@ void instantiate_dependent_filter() { dependent_filter<int>(); dependent_filter<NotInteger>(); // expected-note {{requested here}} } + +int puts(const char *); +class CheckError { +public: + static CheckError Check(const char* msg); + + ~CheckError(); +}; + +int foo__try(const int* f) { + int e; + __try { + CheckError::Check("null pointer"); // expected-error{{cannot use SEH '__try' in blocks}} + e = *f; + } __except (1) { + puts("Caught a C-based exception."); + } + return e; +} + +int foo__except(const int* f) { + int e; + __try { + puts("null pointer"); + e = *f; + } __except (1) { + CheckError::Check("Caught a C-based exception."); // expected-error{{cannot use SEH '__try' in blocks}} + } + return e; +} \ No newline at end of file >From 7c12341708516032754e2f5a68518e1efaeb1654 Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Thu, 18 Dec 2025 00:33:23 +0800 Subject: [PATCH 2/4] Add throw --- clang/test/SemaCXX/exceptions-seh.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index 0a008aeb5721e..5c6222ab63551 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -155,4 +155,16 @@ int foo__except(const int* f) { CheckError::Check("Caught a C-based exception."); // expected-error{{cannot use SEH '__try' in blocks}} } return e; +} + +// has throw should work +int foo__except_with_throw(const int* f) { + int e; + __try { + puts("null pointer"); + e = *f; + } __except (1) { + throw(CheckError::Check("Caught a C-based exception.")); + } + return e; } \ No newline at end of file >From ac93f64132b69e974983c9d5a5a741807d02afca Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Thu, 18 Dec 2025 00:34:19 +0800 Subject: [PATCH 3/4] Add space --- clang/test/SemaCXX/exceptions-seh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index 5c6222ab63551..bdc369ff767da 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -167,4 +167,4 @@ int foo__except_with_throw(const int* f) { throw(CheckError::Check("Caught a C-based exception.")); } return e; -} \ No newline at end of file +} >From 2ada21bfecb75c887a4bb8a61ea3f69ffe4a301a Mon Sep 17 00:00:00 2001 From: GkvJwa <[email protected]> Date: Fri, 19 Dec 2025 12:22:59 +0800 Subject: [PATCH 4/4] Use stack --- clang/lib/Sema/SemaStmt.cpp | 84 +++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index c562d15b0338c..3732179e368eb 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -4518,50 +4518,48 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool IsTry) { // 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) +static const Stmt *findNonTrivialObject(const Stmt *S) { + if (!S) 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; - } - } - } - } - } + llvm::SmallVector<const Stmt *, 32> Worklist; + Worklist.push_back(S); + + while (!Worklist.empty()) { + const Stmt *Cur = Worklist.pop_back_val(); + if (!Cur) + continue; - // 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)) + if (isa<CXXThrowExpr>(Cur)) 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; + if (isa<CXXConstructExpr>(Cur) || isa<CXXTemporaryObjectExpr>(Cur) || + isa<CXXNewExpr>(Cur)) { + return Cur; + } + + if (isa<CXXBindTemporaryExpr>(Cur) || isa<CXXDeleteExpr>(Cur)) { + return Cur; + } + + if (const auto *DS = dyn_cast<DeclStmt>(Cur)) { + for (const Decl *D : DS->decls()) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { + QualType QT = VD->getType(); + if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) { + if (const CXXDestructorDecl *DD = RD->getDestructor()) { + if (!DD->isTrivial()) + return DS; + } + } } } } - } - // Recurse into children. - for (const Stmt *Child : Node->children()) - if (const Stmt *SWith = findNonTrivialObject(S, Child)) - return SWith; + for (const Stmt *Child : Cur->children()) + if (Child) + Worklist.push_back(Child); + } return nullptr; } @@ -4582,21 +4580,15 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, ? "'try'" : "'@try'"); } - } - - 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. Skip - // this diagnostic when Borland extensions are enabled. - if (!getLangOpts().Borland) { - if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) { + + if (const Stmt *Offending = findNonTrivialObject(TryBlock)) { return StmtError( Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions)); } } + FSI->setHasSEHTry(TryLoc); + // Reject __try in Obj-C methods, blocks, and captured decls, since we don't // track if they use SEH. DeclContext *DC = CurContext; @@ -4627,7 +4619,7 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, // Disallow non-trivial C++ objects in an SEH __except handler. Skip // this diagnostic when Borland extensions are enabled. if (!getLangOpts().Borland) { - if (const Stmt *Offending = findNonTrivialObject(*this, Block)) { + if (const Stmt *Offending = findNonTrivialObject(Block)) { return StmtError( Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions)); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
