Author: Akash Manna Date: 2026-08-31T09:56:50Z New Revision: 5702fda2aed05e98ca2578a9682996ff520df093
URL: https://github.com/llvm/llvm-project/commit/5702fda2aed05e98ca2578a9682996ff520df093 DIFF: https://github.com/llvm/llvm-project/commit/5702fda2aed05e98ca2578a9682996ff520df093.diff LOG: [Clang] Fix double revert of a keyword token that was cached before the first fallback (#219799) Fixes #214128 When an undeclared name is followed by `<`, the parser tentatively looks for a template-argument list and, on invalid input, can skip all the way to the end of the file. Every token after that point is lexed and cached while the type-trait keywords still have their keyword kind. The first `struct __make_unsigned` then reverts the keyword to an identifier, but the second `struct __make_unsigned` is replayed from the cache with the stale keyword kind, so `TryKeywordIdentFallback` tries to revert the same `IdentifierInfo` again and trips the assertion in `revertTokenIDToIdentifier`. The same thing can happen with any keyword this hack covers (`__is_pod`, `__is_signed`, the transform traits) and with any cached token, since a `Token` is just a snapshot of the classification at lex time. `TryKeywordIdentFallback` now asks the `IdentifierInfo`, which is the source of truth, before doing anything: if the keyword has already been made an identifier for the remainder of the translation unit, the token kind is simply fixed up and no diagnostic or revert happens a second time. First encounters behave exactly as before. LLM tools were used for this contribution. I've reviewed, built, and tested the change myself before pushing to GitHub. Added: clang/test/Parser/GH214128.cpp Modified: clang/docs/ReleaseNotes.md clang/lib/Parse/Parser.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index bdbabf2cd98d0..4056e01f559aa 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -551,6 +551,11 @@ features cannot lower the translation-unit ABI level; inside a union caused the union to be treated as a polymorphic class. (#GH213854) +- Fixed an assertion when a type-trait keyword that had already been made + available as an identifier (e.g. `struct __make_unsigned`) was seen again + in a token that was lexed and cached before the first occurrence was parsed. + (#GH214128) + #### Bug Fixes to AST Handling - Fixed a non-deterministic ordering of unused local typedefs that made diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index bad81ea92cd2d..84059a41238cc 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1849,11 +1849,20 @@ SourceLocation Parser::getEndOfPreviousToken() const { bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { assert(Tok.isNot(tok::identifier)); + IdentifierInfo *II = Tok.getIdentifierInfo(); + + // A token lexed and cached before an earlier fallback reverted this keyword + // still carries the stale keyword kind; it is already an identifier. + if (II->getTokenID() == tok::identifier) { + Tok.setKind(tok::identifier); + return true; + } + Diag(Tok, diag::ext_keyword_as_ident) << PP.getSpelling(Tok) << DisableKeyword; if (DisableKeyword) - Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); + II->revertTokenIDToIdentifier(); Tok.setKind(tok::identifier); return true; } diff --git a/clang/test/Parser/GH214128.cpp b/clang/test/Parser/GH214128.cpp new file mode 100644 index 0000000000000..a6021ce36d781 --- /dev/null +++ b/clang/test/Parser/GH214128.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +i < 0 +// expected-error@-1 {{no template named 'i'}} +// expected-error@-2 {{expected '>'}} +// expected-note@-3 {{to match this '<'}} + +void f() { + struct __is_pod; // expected-warning {{keyword '__is_pod' will be made available as an identifier for the remainder of the translation unit}} + struct __is_pod; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
