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
