https://github.com/yasster updated https://github.com/llvm/llvm-project/pull/223551
>From 02789db5e1b8f41fb3421df3ffdeb563b5444e19 Mon Sep 17 00:00:00 2001 From: Yassine Missoum <[email protected]> Date: Mon, 14 Sep 2026 11:55:01 -0700 Subject: [PATCH 1/3] [Clang][Parser] Accept contextual _except in MS compatibility mode Recognize _except as an SEH handler when Microsoft compatibility is enabled, matching the existing _try, _finally and _leave aliases. Keep _except usable as an ordinary identifier outside the handler position. Add C and C++ parser coverage for mixed spellings, malformed handlers, ordinary identifier uses and rejection without Microsoft compatibility. Co-authored-by: Adam Glass <[email protected]> --- clang/include/clang/Parse/Parser.h | 3 ++ clang/lib/Parse/ParseStmt.cpp | 9 ++-- clang/lib/Parse/Parser.cpp | 19 ++++++++ .../Parser/ms-seh-single-underscore-strict.c | 20 +++++++++ clang/test/Parser/ms-seh-single-underscore.c | 44 +++++++++++++++++++ 5 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 clang/test/Parser/ms-seh-single-underscore-strict.c create mode 100644 clang/test/Parser/ms-seh-single-underscore.c diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6913c42884a36..b3f6be017523c 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -661,6 +661,7 @@ class Parser : public CodeCompletionHandler { /// Contextual keywords for Microsoft extensions. IdentifierInfo *Ident__except; + IdentifierInfo *Ident__except_single; std::unique_ptr<CommentHandler> CommentSemaHandler; @@ -671,6 +672,8 @@ class Parser : public CodeCompletionHandler { IdentifierInfo *getSEHExceptKeyword(); + bool isTokenSEHExcept(); + /// Whether to skip parsing of function bodies. /// /// This option can be used, for example, to speed up searches for diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 5e67cd551bff8..4e88710eac19c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -611,8 +611,7 @@ StmtResult Parser::ParseSEHTryBlock() { return TryBlock; StmtResult Handler; - if (Tok.is(tok::identifier) && - Tok.getIdentifierInfo() == getSEHExceptKeyword()) { + if (isTokenSEHExcept()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } else if (Tok.is(tok::kw___finally)) { @@ -2680,12 +2679,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { // Borland allows SEH-handlers with 'try' - if ((Tok.is(tok::identifier) && - Tok.getIdentifierInfo() == getSEHExceptKeyword()) || - Tok.is(tok::kw___finally)) { + if (isTokenSEHExcept() || Tok.is(tok::kw___finally)) { // TODO: Factor into common return ParseSEHHandlerCommon(...) StmtResult Handler; - if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { + if (isTokenSEHExcept()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index da5f23c4ca30e..a9454b19b167b 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -56,6 +56,24 @@ IdentifierInfo *Parser::getSEHExceptKeyword() { return Ident__except; } +bool Parser::isTokenSEHExcept() { + if (!Tok.is(tok::identifier)) + return false; + + const IdentifierInfo *Identifier = Tok.getIdentifierInfo(); + if (Identifier == getSEHExceptKeyword()) + return true; + + if (getLangOpts().MSVCCompat) { + if (!Ident__except_single) + Ident__except_single = PP.getIdentifierInfo("_except"); + if (Identifier == Ident__except_single) + return true; + } + + return false; +} + Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) : PP(pp), PreferredType(&actions.getASTContext(), pp.isCodeCompletionEnabled()), @@ -548,6 +566,7 @@ void Parser::Initialize() { nullptr; Ident__except = nullptr; + Ident__except_single = nullptr; Ident__exception_code = Ident__exception_info = nullptr; Ident__abnormal_termination = Ident___exception_code = nullptr; diff --git a/clang/test/Parser/ms-seh-single-underscore-strict.c b/clang/test/Parser/ms-seh-single-underscore-strict.c new file mode 100644 index 0000000000000..c00ede66e9cd7 --- /dev/null +++ b/clang/test/Parser/ms-seh-single-underscore-strict.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -fsyntax-only -fms-extensions -verify +// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -x c++ -fsyntax-only -fms-extensions -verify + +int _except(int); + +int use_except_identifier(int value) { + return _except(value); +} + +void double_except(void) { + __try { + } __except(1) { + } +} + +void single_except(void) { + __try { + } _except(1) { // expected-error {{expected '__except' or '__finally' block}} expected-error {{expected ';' after expression}} + } +} \ No newline at end of file diff --git a/clang/test/Parser/ms-seh-single-underscore.c b/clang/test/Parser/ms-seh-single-underscore.c new file mode 100644 index 0000000000000..c3d7067e5a1c9 --- /dev/null +++ b/clang/test/Parser/ms-seh-single-underscore.c @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -fsyntax-only -fms-compatibility -Wmicrosoft -verify +// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -x c++ -fsyntax-only -fms-compatibility -Wmicrosoft -verify + +int _except(int); + +int use_except_identifier(int value) { + int (*handler)(int) = _except; + return handler(value) + _except(value); +} + +void single_except(void) { + _try { + _leave; + } _except(1) { + } +} + +void single_finally(void) { + _try { + } _finally { + } +} + +void mixed_spellings(void) { + _try { + __leave; + } __except(1) { + } + + __try { + } _except(1) { + } + + __try { + } _finally { + } +} + +void bad_except(void) { + int value; + + _try { + } _except(1) value; // expected-error {{expected '{'}} expected-warning {{expression result unused}} +} \ No newline at end of file >From c891334299cf89a80bf561719fab32c85eb197a0 Mon Sep 17 00:00:00 2001 From: Yassine Missoum <[email protected]> Date: Mon, 14 Sep 2026 17:27:13 -0700 Subject: [PATCH 2/3] [Clang][Parser] Simplify contextual SEH keyword checks Inline the single-use __except lookup into isTokenSEHExcept, use Ident_except for the single-underscore spelling, and fix formatting in the C++ try-handler parsing path. --- clang/include/clang/Parse/Parser.h | 4 +--- clang/lib/Parse/ParseStmt.cpp | 6 ++---- clang/lib/Parse/Parser.cpp | 21 ++++++++------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index b3f6be017523c..af05afe374a6d 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -661,7 +661,7 @@ class Parser : public CodeCompletionHandler { /// Contextual keywords for Microsoft extensions. IdentifierInfo *Ident__except; - IdentifierInfo *Ident__except_single; + IdentifierInfo *Ident_except; std::unique_ptr<CommentHandler> CommentSemaHandler; @@ -670,8 +670,6 @@ class Parser : public CodeCompletionHandler { /// function call. bool CalledSignatureHelp = false; - IdentifierInfo *getSEHExceptKeyword(); - bool isTokenSEHExcept(); /// Whether to skip parsing of function bodies. diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 4e88710eac19c..14bea6a1a7948 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2685,8 +2685,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (isTokenSEHExcept()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); - } - else { + } else { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHFinallyBlock(Loc); } @@ -2697,8 +2696,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { TryLoc, TryBlock.get(), Handler.get()); - } - else { + } else { StmtVector Handlers; // C++11 attributes can't appear here, despite this context seeming diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a9454b19b167b..3fed2dead6362 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -48,26 +48,21 @@ class ActionCommentHandler : public CommentHandler { }; } // end anonymous namespace -IdentifierInfo *Parser::getSEHExceptKeyword() { - // __except is accepted as a (contextual) keyword - if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) - Ident__except = PP.getIdentifierInfo("__except"); - - return Ident__except; -} - bool Parser::isTokenSEHExcept() { if (!Tok.is(tok::identifier)) return false; + if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) + Ident__except = PP.getIdentifierInfo("__except"); + const IdentifierInfo *Identifier = Tok.getIdentifierInfo(); - if (Identifier == getSEHExceptKeyword()) + if (Identifier == Ident__except) return true; if (getLangOpts().MSVCCompat) { - if (!Ident__except_single) - Ident__except_single = PP.getIdentifierInfo("_except"); - if (Identifier == Ident__except_single) + if (!Ident_except) + Ident_except = PP.getIdentifierInfo("_except"); + if (Identifier == Ident_except) return true; } @@ -566,7 +561,7 @@ void Parser::Initialize() { nullptr; Ident__except = nullptr; - Ident__except_single = nullptr; + Ident_except = nullptr; Ident__exception_code = Ident__exception_info = nullptr; Ident__abnormal_termination = Ident___exception_code = nullptr; >From 68e6fb575b32d0099237eb2230daa50288ce0b01 Mon Sep 17 00:00:00 2001 From: Yassine Missoum <[email protected]> Date: Tue, 15 Sep 2026 11:20:58 -0700 Subject: [PATCH 3/3] [Clang] Document contextual _except support in release notes --- clang/docs/ReleaseNotes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 043a0ddae2a6c..9fbe62eeb9bf1 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -756,6 +756,11 @@ features cannot lower the translation-unit ABI level; #### Windows Support +- Clang now accepts ``_except`` as an alias for ``__except`` in SEH handler + position when ``-fms-compatibility`` is enabled, matching the existing + ``_try``, ``_finally``, and ``_leave`` aliases. ``_except`` remains an ordinary + identifier outside that context. + - Fixed ``setjmp`` on 32-bit Arm passing the frame pointer, rather than the stack pointer as it was on entry to the function, as the frame value the CRT stores in the ``jmp_buf``. Clang now uses ``llvm.sponentry`` there, as it _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
