https://github.com/yashaggarwal85d updated https://github.com/llvm/llvm-project/pull/236087
>From 260c694189bd573b98ebccbb3f3c957327b00210 Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <[email protected]> Date: Tue, 27 Oct 2026 10:37:51 +0000 Subject: [PATCH 1/2] [clang-format] Use 64-bit penalties in the optimizing line formatter --- clang/lib/Format/UnwrappedLineFormatter.cpp | 12 +++++++----- clang/unittests/Format/FormatTest.cpp | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index d1f68877ef0339..bb44d134f3edf4 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1425,7 +1425,7 @@ class OptimizingLineFormatter : public LineFormatter { /// In case of equal penalties, we want to prefer states that were inserted /// first. During state generation we make sure that we insert states first /// that break the line as late as possible. - typedef std::pair<unsigned, unsigned> OrderedPenalty; + typedef std::pair<uint64_t, unsigned> OrderedPenalty; /// An edge in the solution space from \c Previous->State to \c State, /// inserting a newline dependent on the \c NewLine. @@ -1468,7 +1468,7 @@ class OptimizingLineFormatter : public LineFormatter { Queue.push(QueueItem(OrderedPenalty(0, Count), RootNode)); ++Count; - unsigned Penalty = 0; + uint64_t Penalty = 0; // While not empty, take first element and follow edges. while (!Queue.empty()) { @@ -1517,14 +1517,14 @@ class OptimizingLineFormatter : public LineFormatter { << "Total number of analyzed states: " << Count << "\n"); LLVM_DEBUG(llvm::dbgs() << "---\n"); - return Penalty; + return std::min<uint64_t>(Penalty, UINT_MAX); } /// Add the following state to the analysis queue \c Queue. /// /// Assume the current state is \p PreviousNode and has been reached with a /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true. - void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode, + void addNextStateToQueue(uint64_t Penalty, StateNode *PreviousNode, bool NewLine, unsigned *Count, QueueType *Queue) { if (NewLine && !Indenter->canBreak(PreviousNode->State)) return; @@ -1533,9 +1533,11 @@ class OptimizingLineFormatter : public LineFormatter { StateNode *Node = new (Allocator.Allocate()) StateNode(PreviousNode->State, NewLine, PreviousNode); - if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty)) + unsigned ChildrenPenalty = 0; + if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, ChildrenPenalty)) return; + Penalty += ChildrenPenalty; Penalty += Indenter->addTokenToState(Node->State, NewLine, true); Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node)); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index f38287757ffba1..df971a4c513845 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -20440,6 +20440,15 @@ TEST_F(FormatTest, BreakPenaltyScopeResolution) { Style); } +TEST_F(FormatTest, PenaltyDoesNotOverflow) { + // The total penalty of this line is above 2^32. + std::string Code = "int t[] = {\n"; + for (int I = 0; I < 81; ++I) + Code += " 0x" + std::string(100, '0') + ",\n"; + Code += "};"; + verifyFormat(Code); +} + TEST_F(FormatTest, WorksFor8bitEncodings) { // FIXME: unstable test case EXPECT_EQ("\"\xce\xe4\xed\xe0\xe6\xe4\xfb \xe2 \"\n" >From 0f365b4d1f80bb319fc2101a0351c80f15505676 Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <[email protected]> Date: Sat, 31 Oct 2026 06:32:42 +0000 Subject: [PATCH 2/2] Keep penalties 64-bit through UnwrappedLineFormatter and simplify the test --- clang/lib/Format/Format.cpp | 5 ++-- clang/lib/Format/UnwrappedLineFormatter.cpp | 28 ++++++++++----------- clang/lib/Format/UnwrappedLineFormatter.h | 4 +-- clang/unittests/Format/FormatTest.cpp | 14 ++++++----- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index d83ca4a558b7f8..9b34a9d74e7d5b 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3032,7 +3032,7 @@ class Formatter : public TokenAnalyzer { ContinuationIndenter Indenter(Style, Tokens.getKeywords(), Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); - unsigned Penalty = + uint64_t Penalty = UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(), Env.getSourceManager(), Status) @@ -3045,7 +3045,8 @@ class Formatter : public TokenAnalyzer { for (const auto &R : Whitespaces.generateReplacements()) if (Result.add(R)) return std::make_pair(Result, 0); - return std::make_pair(Result, Penalty); + return std::make_pair( + Result, static_cast<unsigned>(std::min<uint64_t>(Penalty, UINT_MAX))); } private: diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index bb44d134f3edf4..f478e7d3d6a112 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1243,7 +1243,7 @@ class LineFormatter { /// Formats an \c AnnotatedLine and returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. - virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + virtual uint64_t formatLine(const AnnotatedLine &Line, unsigned FirstIndent, unsigned FirstStartColumn, bool DryRun) = 0; protected: @@ -1268,7 +1268,7 @@ class LineFormatter { /// \c UnwrappedLineFormatter, where we only have two options for each token: /// break or don't break. bool formatChildren(LineState &State, bool NewLine, bool DryRun, - unsigned &Penalty) { + uint64_t &Penalty) { const FormatToken *LBrace = State.NextToken->getPreviousNonComment(); bool HasLBrace = LBrace && LBrace->is(tok::l_brace) && LBrace->is(BK_Block); FormatToken &Previous = *State.NextToken->Previous; @@ -1348,7 +1348,7 @@ class NoColumnLimitLineFormatter : public LineFormatter { /// Formats the line, simply keeping all of the input's line breaking /// decisions. - unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + uint64_t formatLine(const AnnotatedLine &Line, unsigned FirstIndent, unsigned FirstStartColumn, bool DryRun) override { assert(!DryRun); LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn, @@ -1357,7 +1357,7 @@ class NoColumnLimitLineFormatter : public LineFormatter { bool Newline = Indenter->mustBreak(State) || (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0); - unsigned Penalty = 0; + uint64_t Penalty = 0; formatChildren(State, Newline, /*DryRun=*/false, Penalty); Indenter->addTokenToState(State, Newline, /*DryRun=*/false); } @@ -1374,9 +1374,9 @@ class NoLineBreakFormatter : public LineFormatter { : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {} /// Puts all tokens into a single line. - unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + uint64_t formatLine(const AnnotatedLine &Line, unsigned FirstIndent, unsigned FirstStartColumn, bool DryRun) override { - unsigned Penalty = 0; + uint64_t Penalty = 0; LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun); while (State.NextToken) { @@ -1399,7 +1399,7 @@ class OptimizingLineFormatter : public LineFormatter { /// Formats the line by finding the best line breaks with line lengths /// below the column limit. - unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + uint64_t formatLine(const AnnotatedLine &Line, unsigned FirstIndent, unsigned FirstStartColumn, bool DryRun) override { LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun); @@ -1454,7 +1454,7 @@ class OptimizingLineFormatter : public LineFormatter { /// to a state where all tokens are placed. Returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. - unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun) { + uint64_t analyzeSolutionSpace(LineState &InitialState, bool DryRun) { std::set<LineState *, CompareLineStatePointers> Seen; // Increasing count of \c StateNode items we have created. This is used to @@ -1517,7 +1517,7 @@ class OptimizingLineFormatter : public LineFormatter { << "Total number of analyzed states: " << Count << "\n"); LLVM_DEBUG(llvm::dbgs() << "---\n"); - return std::min<uint64_t>(Penalty, UINT_MAX); + return Penalty; } /// Add the following state to the analysis queue \c Queue. @@ -1533,11 +1533,9 @@ class OptimizingLineFormatter : public LineFormatter { StateNode *Node = new (Allocator.Allocate()) StateNode(PreviousNode->State, NewLine, PreviousNode); - unsigned ChildrenPenalty = 0; - if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, ChildrenPenalty)) + if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty)) return; - Penalty += ChildrenPenalty; Penalty += Indenter->addTokenToState(Node->State, NewLine, true); Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node)); @@ -1554,7 +1552,7 @@ class OptimizingLineFormatter : public LineFormatter { Best = Best->Previous; } for (const auto &Node : llvm::reverse(Path)) { - unsigned Penalty = 0; + uint64_t Penalty = 0; formatChildren(State, Node->NewLine, /*DryRun=*/false, Penalty); Penalty += Indenter->addTokenToState(State, Node->NewLine, false); @@ -1574,7 +1572,7 @@ class OptimizingLineFormatter : public LineFormatter { } // anonymous namespace -unsigned UnwrappedLineFormatter::format( +uint64_t UnwrappedLineFormatter::format( const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun, int AdditionalIndent, bool FixBadIndentation, unsigned FirstStartColumn, unsigned NextStartColumn, unsigned LastStartColumn) { @@ -1588,7 +1586,7 @@ unsigned UnwrappedLineFormatter::format( return CacheIt->second; assert(!Lines.empty()); - unsigned Penalty = 0; + uint64_t Penalty = 0; LevelIndentTracker IndentTracker(Style, Keywords, Lines[0]->Level, AdditionalIndent); const AnnotatedLine *PrevPrevLine = nullptr; diff --git a/clang/lib/Format/UnwrappedLineFormatter.h b/clang/lib/Format/UnwrappedLineFormatter.h index a33a4f98df2560..1761ef53c47513 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.h +++ b/clang/lib/Format/UnwrappedLineFormatter.h @@ -35,7 +35,7 @@ class UnwrappedLineFormatter { Keywords(Keywords), SourceMgr(SourceMgr), Status(Status) {} /// Format the current block and return the penalty. - unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, + uint64_t format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun = false, int AdditionalIndent = 0, bool FixBadIndentation = false, unsigned FirstStartColumn = 0, unsigned NextStartColumn = 0, unsigned LastStartColumn = 0); @@ -57,7 +57,7 @@ class UnwrappedLineFormatter { // starting from a specific additional offset. Improves performance if there // are many nested blocks. std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>, - unsigned> + uint64_t> PenaltyCache; ContinuationIndenter *Indenter; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index df971a4c513845..2be65b0d7301a7 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -20441,12 +20441,14 @@ TEST_F(FormatTest, BreakPenaltyScopeResolution) { } TEST_F(FormatTest, PenaltyDoesNotOverflow) { - // The total penalty of this line is above 2^32. - std::string Code = "int t[] = {\n"; - for (int I = 0; I < 81; ++I) - Code += " 0x" + std::string(100, '0') + ",\n"; - Code += "};"; - verifyFormat(Code); + // Indenting the rows more would make the total penalty go past 2^32. + auto Style = getLLVMStyleWithColumns(20); + Style.PenaltyExcessCharacter = 200'000'000; + verifyFormat("int t[] = {\n" + " 11111111111111111111,\n" + " 11111111111111111111,\n" + "};", + Style); } TEST_F(FormatTest, WorksFor8bitEncodings) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
