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

Reply via email to