https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/219799
>From 713c96a7947aae84a0598914e3fbb01b61197bbc Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Sun, 30 Aug 2026 18:31:03 +0530 Subject: [PATCH 1/2] [Clang] Fix double revert of a keyword token that was cached before the first fallback An undeclared name followed by '<' starts a tentative parse that can skip to the end of the file, lexing and caching every remaining token. If those tokens include a type-trait keyword used as a struct name (e.g. 'struct __make_unsigned'), the first occurrence reverts the IdentifierInfo to an identifier, but the second, already-cached token still carries its keyword kind and reaches TryKeywordIdentFallback again, which asserts in revertTokenIDToIdentifier. Have TryKeywordIdentFallback check the IdentifierInfo, which is the source of truth, before diagnosing and reverting: if the keyword has already been made an identifier, just fix up the stale token kind. Fixes #214128 --- clang/docs/ReleaseNotes.md | 5 +++++ clang/lib/Parse/Parser.cpp | 11 ++++++++++- clang/test/Parser/GH214128.cpp | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 clang/test/Parser/GH214128.cpp 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..f112c33e0234d --- /dev/null +++ b/clang/test/Parser/GH214128.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=expected,garbage -DGARBAGE %s +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// The undeclared template-name 'foo' starts a tentative parse that caches the +// rest of the file, so the second '__make_unsigned' token keeps its keyword +// kind after the first one has already been reverted to an identifier. +#ifdef GARBAGE +foo < bar() +// garbage-error@-1 {{no template named 'foo'}} +// garbage-error@-2 {{use of undeclared identifier 'bar'}} +// garbage-error@-3 {{expected '>'}} +// garbage-note@-4 {{to match this '<'}} +#endif + +namespace N { // garbage-error {{expected unqualified-id}} +template <typename _Tp> struct __make_unsigned { typedef _Tp __type; }; +// expected-warning@-1 {{keyword '__make_unsigned' will be made available as an identifier for the remainder of the translation unit}} +struct __make_unsigned<char> { typedef char __type; }; +// expected-error@-1 {{template specialization requires 'template<>'}} +} // namespace N >From e40cd52fa2cbf79fa74c79df6a8d1497028f744a Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Mon, 31 Aug 2026 14:43:23 +0530 Subject: [PATCH 2/2] [Clang] Simplify GH214128 test --- clang/test/Parser/GH214128.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/clang/test/Parser/GH214128.cpp b/clang/test/Parser/GH214128.cpp index f112c33e0234d..a6021ce36d781 100644 --- a/clang/test/Parser/GH214128.cpp +++ b/clang/test/Parser/GH214128.cpp @@ -1,20 +1,11 @@ -// RUN: %clang_cc1 -fsyntax-only -verify=expected,garbage -DGARBAGE %s // RUN: %clang_cc1 -fsyntax-only -verify %s -// The undeclared template-name 'foo' starts a tentative parse that caches the -// rest of the file, so the second '__make_unsigned' token keeps its keyword -// kind after the first one has already been reverted to an identifier. -#ifdef GARBAGE -foo < bar() -// garbage-error@-1 {{no template named 'foo'}} -// garbage-error@-2 {{use of undeclared identifier 'bar'}} -// garbage-error@-3 {{expected '>'}} -// garbage-note@-4 {{to match this '<'}} -#endif +i < 0 +// expected-error@-1 {{no template named 'i'}} +// expected-error@-2 {{expected '>'}} +// expected-note@-3 {{to match this '<'}} -namespace N { // garbage-error {{expected unqualified-id}} -template <typename _Tp> struct __make_unsigned { typedef _Tp __type; }; -// expected-warning@-1 {{keyword '__make_unsigned' will be made available as an identifier for the remainder of the translation unit}} -struct __make_unsigned<char> { typedef char __type; }; -// expected-error@-1 {{template specialization requires 'template<>'}} -} // namespace N +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
