llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Akash Manna (akash-manna-sky) <details> <summary>Changes</summary> 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. --- Full diff: https://github.com/llvm/llvm-project/pull/219799.diff 3 Files Affected: - (modified) clang/docs/ReleaseNotes.md (+5) - (modified) clang/lib/Parse/Parser.cpp (+10-1) - (added) clang/test/Parser/GH214128.cpp (+20) ``````````diff 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 `````````` </details> https://github.com/llvm/llvm-project/pull/219799 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
