[clang] [clang] Fix crash on invalid decltype specifier (PR #224844)

Rajin Khan via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 19 09:48:49 PDT 2026


https://github.com/rajin-khan created https://github.com/llvm/llvm-project/pull/224844

Fixes #165246.

When recovery sees `decltype` without an opening parenthesis while token backtracking is active, `ParseDecltypeSpecifier` returns the token's start location. `AnnotatePreviousCachedTokens` requires the annotation end to match the last location of the most recently cached token, so malformed input such as `int decltype {}` trips its assertion.

Use the last cached token location for an invalid decltype specifier after rewinding the lookahead token. This is the same recovery pattern used by the adjacent pack indexing annotation path.

The existing `decltype-crash.cpp` test now covers the brace form from the report.

Testing:

- `clang++ -cc1 -fsyntax-only -verify -std=c++11 clang/test/Parser/decltype-crash.cpp`
- `clang++ -cc1 -fsyntax-only -verify -std=c++20 clang/test/Parser/decltype-crash.cpp`
- `git diff --check`

The focused verification commands used Apple Clang 21.0.0. The assertion-specific path was reviewed against the current preprocessor cache invariant; this checkout does not contain a locally built assertions-enabled Clang.


>From 2b006ba37d7822b6e6e6e7ae7abb11b973fcbcb5 Mon Sep 17 00:00:00 2001
From: Rajin Khan <rajin.khan2001 at gmail.com>
Date: Sat, 19 Sep 2026 22:48:04 +0600
Subject: [PATCH] [clang] Fix invalid decltype annotation range

Use the last cached token location when recovering an invalid decltype specifier so the annotation range satisfies the preprocessor cache invariant.

Fixes #165246
---
 clang/lib/Parse/ParseDeclCXX.cpp     | 2 ++
 clang/test/Parser/decltype-crash.cpp | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 1eeb0d21b68d7b..dade5ab3c9e823 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1110,6 +1110,8 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
   // make sure we have a token we can turn into an annotation token
   if (PP.isBacktrackEnabled()) {
     PP.RevertCachedTokens(1);
+    if (DS.getTypeSpecType() == TST_error)
+      EndLoc = PP.getLastCachedTokenLocation();
   } else
     PP.EnterToken(Tok, /*IsReinject*/ true);
 
diff --git a/clang/test/Parser/decltype-crash.cpp b/clang/test/Parser/decltype-crash.cpp
index af4622df5e54aa..d91229b3a66924 100644
--- a/clang/test/Parser/decltype-crash.cpp
+++ b/clang/test/Parser/decltype-crash.cpp
@@ -13,3 +13,7 @@ int decltype = 0;
 int *decltype = 0;
 // expected-error at -1 {{expected '(' after 'decltype'}}
 // expected-error at -2 {{expected unqualified-id}}
+
+int decltype {}
+// expected-error at -1 {{expected '(' after 'decltype'}}
+// expected-error at -2 {{expected unqualified-id}}



More information about the cfe-commits mailing list