https://github.com/mygitljf updated 
https://github.com/llvm/llvm-project/pull/199112

>From 386bd07039544dd83749e99e816ed413e9fabd15 Mon Sep 17 00:00:00 2001
From: mygitljf <[email protected]>
Date: Thu, 21 May 2026 20:59:39 +0000
Subject: [PATCH] [clang-format] Fix assertion in alignChainedConditionals

The pointer-alignment compensation block in AlignTokenSequence
unconditionally inserts -Shift spaces in front of any token whose
predecessor is annotated TT_PointerOrReference. It assumed that
the +Shift had just been added to that token's Spaces by the
preceding increment, but the +Shift is gated on the token being
the matched anchor (or a continuation in a nested scope). On a
non-anchor token that gate is skipped, and the unconditional
-Shift drops Spaces below zero, tripping the assertion in
IncrementChangeSpaces.

Make the compensation share the same gate as the +Shift it is
meant to balance, so a -Shift only ever runs when the matching
+Shift did.

Fixes #199027
---
 clang/lib/Format/WhitespaceManager.cpp   | 10 +++++++---
 clang/unittests/Format/AlignmentTest.cpp | 11 +++++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/WhitespaceManager.cpp 
b/clang/lib/Format/WhitespaceManager.cpp
index 4a72abbfa9ec3..61524a56cbbbb 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -415,9 +415,11 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
     // This is for lines that are split across multiple lines, as mentioned in
     // the ScopeStack comment. The stack size being 1 means that the token is
     // not in a scope that should not move.
-    if ((!Matches.empty() && Matches[0] == i) ||
+    const bool ShiftAppliedToCurrent =
+        (!Matches.empty() && Matches[0] == i) ||
         (ScopeStack.size() == 1u && CurrentChange.NewlinesBefore > 0 &&
-         InsideNestedScope)) {
+         InsideNestedScope);
+    if (ShiftAppliedToCurrent) {
       CurrentChange.IndentedFromColumn += Shift;
       IncrementChangeSpaces(i, Shift, Changes);
     }
@@ -430,7 +432,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
 
     // If PointerAlignment is PAS_Right, keep *s or &s next to the token,
     // except if the token is equal, then a space is needed.
-    if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
+    // Only run when the matching +Shift was applied above.
+    if (ShiftAppliedToCurrent &&
+        (Style.PointerAlignment == FormatStyle::PAS_Right ||
          Style.ReferenceAlignment == FormatStyle::RAS_Right) &&
         CurrentChange.Spaces != 0 &&
         CurrentChange.Tok->isNoneOf(tok::equal, tok::r_paren,
diff --git a/clang/unittests/Format/AlignmentTest.cpp 
b/clang/unittests/Format/AlignmentTest.cpp
index fbc0cb4d825ea..aeb77e1affe02 100644
--- a/clang/unittests/Format/AlignmentTest.cpp
+++ b/clang/unittests/Format/AlignmentTest.cpp
@@ -3630,6 +3630,17 @@ TEST_F(AlignmentTest, ContinuedAligned) {
                Style);
 }
 
+TEST_F(AlignmentTest, AlignChainedConditionalsNoCrashOnPointerLikeOperator) {
+  // Regression test for https://github.com/llvm/llvm-project/issues/199027.
+  // When alignChainedConditionals shifts a `?` right, the pointer-alignment
+  // compensation in AlignTokenSequence used to run for any later token whose
+  // previous token was annotated as TT_PointerOrReference, even when that
+  // token had not received the corresponding +Shift. Removing -Shift spaces
+  // it never had triggered an assertion in IncrementChangeSpaces.
+  verifyNoCrash(
+      "  #xxxx??x<xxxxxxx||??x<xxxxxxx and 
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+}
+
 } // namespace
 } // namespace test
 } // namespace format

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

Reply via email to