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; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
