https://github.com/Cons-Cat updated 
https://github.com/llvm/llvm-project/pull/200970

>From 4e83a18ff09fe3b491a2222f66c0adeb48ec8f75 Mon Sep 17 00:00:00 2001
From: Lilian Gooch <[email protected]>
Date: Mon, 1 Jun 2026 16:29:25 -0700
Subject: [PATCH] [clang-format] Don't rotate const past __typeof_unqual

QualifierAlignmentFixer skipped const/volatile rotation for
decltype(...), typeof(...), and _Atomic(...) but not for
typeof_unqual(...). In C23 mode this produced invalid code:

  const typeof_unqual(foo)  ->  typeof_unqual const(foo)

Add tok::kw_typeof_unqual to the skip case in QualifierAlignmentFixer
and to TT_TypeDeclarationParen detection in TokenAnnotator, mirroring
typeof. Also add it to Token::isSimpleTypeSpecifier so it is recognised
as a type by FormatToken::isTypeName.

The reachable spelling depends on language mode: typeof_unqual is a C23
keyword, while __typeof_unqual / __typeof_unqual__ are KEYALL alias
spellings. Cover all three in the C-mode test.

Assisted-by: Cursor/Claude Opus
---
 clang/lib/Format/QualifierAlignmentFixer.cpp  |  5 ++++-
 clang/lib/Format/TokenAnnotator.cpp           |  6 ++++--
 clang/lib/Lex/Lexer.cpp                       |  1 +
 clang/unittests/Format/QualifierFixerTest.cpp | 18 ++++++++++++++++++
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp 
b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 3d1a9dc868208..b03f4098ee140 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -289,9 +289,12 @@ const FormatToken 
*LeftRightQualifierAlignmentFixer::analyzeRight(
   if (TypeToken->isTypeName(LangOpts)) {
     // The case `const decltype(foo)` -> `const decltype(foo)`
     // The case `const typeof(foo)` -> `const typeof(foo)`
+    // The case `const typeof_unqual(foo)` -> `const typeof_unqual(foo)`
     // The case `const _Atomic(foo)` -> `const _Atomic(foo)`
-    if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
+    if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof,
+                           tok::kw_typeof_unqual, tok::kw__Atomic)) {
       return Tok;
+    }
 
     const FormatToken *LastSimpleTypeSpecifier = TypeToken;
     while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index 43e4f6796b6dd..970aed0ddb941 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -447,14 +447,16 @@ class AnnotatingParser {
       if (PrevNonComment->isAttribute()) {
         OpeningParen.setType(TT_AttributeLParen);
       } else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype,
-                                         tok::kw_typeof,
+                                         tok::kw_typeof, tok::kw_typeof_unqual,
 #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
 #include "clang/Basic/TransformTypeTraits.def"
                                          tok::kw__Atomic)) {
         OpeningParen.setType(TT_TypeDeclarationParen);
         // decltype() and typeof() usually contain expressions.
-        if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof))
+        if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof,
+                                    tok::kw_typeof_unqual)) {
           Contexts.back().IsExpression = true;
+        }
       }
     }
 
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 2797212c229f5..4bfaa4a0831ad 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -120,6 +120,7 @@ bool Token::isSimpleTypeSpecifier(const LangOptions 
&LangOpts) const {
   case tok::kw_char16_t:
   case tok::kw_char32_t:
   case tok::kw_typeof:
+  case tok::kw_typeof_unqual:
   case tok::kw_decltype:
   case tok::kw_char8_t:
     return getIdentifierInfo()->isKeyword(LangOpts);
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp 
b/clang/unittests/Format/QualifierFixerTest.cpp
index edde7bb3b5c97..584bd15d04e22 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -847,6 +847,24 @@ TEST_F(QualifierFixerTest, LeftQualifier) {
   verifyFormat("const float (C::*p)(int);", "float const (C::*p)(int);", 
Style);
 }
 
+TEST_F(QualifierFixerTest, TypeofUnqualC) {
+  FormatStyle Style = getLLVMStyle(FormatStyle::LK_C);
+  Style.QualifierAlignment = FormatStyle::QAS_Right;
+  Style.QualifierOrder = {"type", "const", "volatile"};
+
+  // Don't move past typeof_unqual or its alternate spellings.
+  verifyFormat("const typeof_unqual(foo)", Style);
+  verifyFormat("const __typeof_unqual(foo)", Style);
+  verifyFormat("const __typeof_unqual__(foo)", Style);
+
+  Style.QualifierAlignment = FormatStyle::QAS_Left;
+  Style.QualifierOrder = {"const", "volatile", "type"};
+
+  verifyFormat("typeof_unqual(foo) const", Style);
+  verifyFormat("__typeof_unqual(foo) const", Style);
+  verifyFormat("__typeof_unqual__(foo) const", Style);
+}
+
 TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) {
   FormatStyle Style = getLLVMStyle();
   Style.QualifierAlignment = FormatStyle::QAS_Left;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to