Author: Yassine Missoum Date: 2026-09-17T08:52:12-07:00 New Revision: 36763294ef639d8a6a4379d81da653dda1c20686
URL: https://github.com/llvm/llvm-project/commit/36763294ef639d8a6a4379d81da653dda1c20686 DIFF: https://github.com/llvm/llvm-project/commit/36763294ef639d8a6a4379d81da653dda1c20686.diff LOG: [Clang][Parser] Accept contextual _except in MS compatibility mode (#223551) Clang already accepts _try, _finally, and _leave under -fms-compatibility, but rejects the corresponding _except spelling because __except is recognized contextually by the parser rather than as a reserved token. This patch extends the contextual handler check to accept _except in Microsoft compatibility mode and uses that check consistently in SEH and C++ try-handler parsing. _except remains an ordinary identifier outside the handler position, and -fms-extensions alone does not enable the alias. The change is limited to parsing; it does not modify SEH lowering, LLVM IR, optimization, or runtime behavior. Assisted-by: Claude Opus 5 (via VS Code) --------- Co-authored-by: Adam Glass <[email protected]> Added: clang/test/Parser/ms-seh-single-underscore-strict.c clang/test/Parser/ms-seh-single-underscore.c Modified: clang/docs/ReleaseNotes.md clang/include/clang/Parse/Parser.h clang/lib/Parse/ParseStmt.cpp clang/lib/Parse/Parser.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 2be9f3bd7eb20..5128254bdea91 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -802,6 +802,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 diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 960b3c2485db0..87e8dc9808e5c 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; std::unique_ptr<CommentHandler> CommentSemaHandler; @@ -669,7 +670,7 @@ 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 5e67cd551bff8..14bea6a1a7948 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,16 +2679,13 @@ 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); - } - else { + } else { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHFinallyBlock(Loc); } @@ -2700,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 60279d5984e14..c86ed6b2ea3f9 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -48,12 +48,25 @@ class ActionCommentHandler : public CommentHandler { }; } // end anonymous namespace -IdentifierInfo *Parser::getSEHExceptKeyword() { - // __except is accepted as a (contextual) keyword +bool Parser::isTokenSEHExcept() { + if (!Tok.is(tok::identifier)) + return false; + if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) Ident__except = PP.getIdentifierInfo("__except"); - return Ident__except; + const IdentifierInfo *Identifier = Tok.getIdentifierInfo(); + if (Identifier == Ident__except) + return true; + + if (getLangOpts().MSVCCompat) { + if (!Ident_except) + Ident_except = PP.getIdentifierInfo("_except"); + if (Identifier == Ident_except) + return true; + } + + return false; } Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) @@ -548,6 +561,7 @@ void Parser::Initialize() { nullptr; Ident__except = nullptr; + Ident_except = 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
