[clang] 87f09d3 - [clang] Parse `__typeof_unqual__` consistently with `__typeof__` (#198948)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 1 07:51:39 PDT 2026
Author: Conscat
Date: 2026-06-01T16:51:33+02:00
New Revision: 87f09d325da79b379723b29755861da9baf2dc7a
URL: https://github.com/llvm/llvm-project/commit/87f09d325da79b379723b29755861da9baf2dc7a
DIFF: https://github.com/llvm/llvm-project/commit/87f09d325da79b379723b29755861da9baf2dc7a.diff
LOG: [clang] Parse `__typeof_unqual__` consistently with `__typeof__` (#198948)
C23 `__typeof_unqual` and `__typeof_unqual__` are supported in all
language modes as an extension.
However, existing tests missed this form:
```cpp
int main() {
__typeof_unqual(int) x = 0;
}
```
That doesn't compile today.
```
<source>:2:4: error: expected expression
2 | __typeof_unqual(int) x = 0;
| ^
1 error generated.
Compiler returned: 1
```
I think the fix is to parse `tok::kw_typeof_unqual` everywhere that we
currently parse `tok::kw_typeof`. It simply falls through `case`s
beneath `tok::kw_typeof`, so this should handle them equivalently. No
keyword semantics are changed by this PR.
While in here I noticed Clang Format ignores the token too, so I gave
Clang Format the same parsing parity between these tokens. It now holds
true under `isTypeName()`, just like `typeof`. `__typeof_unqual` kind of
accidentally formatted correctly in C++ anyways, but not in C, so this
is a meaningful fix. Previously it had no tests at all.
In the `clang-format` release notes, I'm not sure whether this should be
considered a fix or a new feature. I've left the clang-format notes
unchanged for now.
Assisted-by: Cursor/Claude Opus
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Parse/ParseTentative.cpp
clang/test/SemaCXX/typeof.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d1c58435ab399..f1023f0cb42f8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -651,6 +651,7 @@ Bug Fixes in This Version
an array via an element-at-a-time copy loop (#GH192026)
- Fixed an issue where certain designated initializers would be rejected for constexpr variables. (#GH193373)
- Fixed a crash when ``#embed`` is used with C++ modules (#GH195350)
+- Fixed an issue where ``__typeof_unqual`` and ``__typeof_unqual__`` were rejected as a declaration specifier in block scope in C++.
- Fixed crash when checking for overflow for unary operator that can't overflow (#GH170072)
Bug Fixes to Compiler Builtins
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index e38481f05da63..2987d32d6e0d2 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1343,6 +1343,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand,
case tok::kw_auto:
case tok::kw_typename:
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
case tok::kw___vector:
case tok::kw__Accum:
case tok::kw__Fract:
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 5646597622832..ae49fc20e36f2 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2173,6 +2173,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
// GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
ParseTypeofSpecifier(DS);
DS.Finish(Actions, Policy);
return;
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index f77b1001332fe..1477fc38bcc6d 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -171,6 +171,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
}
[[fallthrough]];
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
case tok::kw___attribute:
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
#include "clang/Basic/TransformTypeTraits.def"
@@ -1525,7 +1526,8 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
return TPResult::True;
// GNU typeof support.
- case tok::kw_typeof: {
+ case tok::kw_typeof:
+ case tok::kw_typeof_unqual: {
if (NextToken().isNot(tok::l_paren))
return TPResult::True;
@@ -1590,6 +1592,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
case tok::annot_template_id:
case tok::annot_typename:
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
#include "clang/Basic/TransformTypeTraits.def"
return true;
@@ -1650,7 +1653,8 @@ bool Parser::isCXXDeclarationSpecifierAType() {
}
Parser::TPResult Parser::TryParseTypeofSpecifier() {
- assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
+ assert(Tok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) &&
+ "Expected 'typeof' or 'typeof_unqual'!");
ConsumeToken();
assert(Tok.is(tok::l_paren) && "Expected '('");
diff --git a/clang/test/SemaCXX/typeof.cpp b/clang/test/SemaCXX/typeof.cpp
index 421cfc59f5311..4db803564309b 100644
--- a/clang/test/SemaCXX/typeof.cpp
+++ b/clang/test/SemaCXX/typeof.cpp
@@ -11,3 +11,11 @@ namespace GH97646 {
!x;
}
}
+
+// Ensure that __typeof_unqual / __typeof_unqual__ parse as a declaration
+// specifier in block scope, for symmetry with __typeof__.
+void block_scope_typeof_unqual() {
+ __typeof_unqual(int) a = 0;
+ __typeof_unqual__(int) b = 0;
+ (void)a; (void)b;
+}
More information about the cfe-commits
mailing list