[libcxx-commits] [libcxx] [libc++] Avoid heap allocation for default-precision double formatting (PR #212502)

Adib Pathan via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 28 07:05:08 PDT 2026


https://github.com/adxb-pxthxn created https://github.com/llvm/llvm-project/pull/212502

Fixes #211909.

## Summary

When formatting floating-point values with unspecified precision (`{}`), libc++ initializes `__float_buffer` precision to `_Traits::__max_fractional`. For `double`, that inflates the computed buffer size beyond the stack buffer threshold and causes an unnecessary heap allocation on the default path.

This patch uses the Standard's default precision (`6`) when no precision is specified, so the common `double` formatting path stays within the stack buffer.

Discussion on #211909 noted that simply increasing `__stack_buffer_size` is not ideal. @philnik777 suggested keeping the common case stack-backed rather than pessimistically reserving worst-case space (format into the stack buffer first, and only allocate if needed). This change follows that direction for the default-precision case by avoiding worst-case precision sizing up front.

## Test plan

- [x] Added regression in `libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp`
- [x] Test verifies `std::format("{}", 1.23)` does not allocate (via `count_new.h`)
- [x] `ninja -C build runtimes-test-depends`
- [x] `build/bin/llvm-lit -sv build/runtimes/runtimes-bins/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp`

Made with [Cursor](https://cursor.com)

>From 2b56c48635fc5fcd744fa6390943138bf129e8fa Mon Sep 17 00:00:00 2001
From: Adib <adibpathan280 at gmail.com>
Date: Tue, 28 Jul 2026 23:30:12 +0930
Subject: [PATCH] [libc++] Avoid heap allocation for default-precision double
 formatting

Use the standard default precision for unspecified floating-point formatting so the common double path stays within the stack buffer, and add a regression test that forbids allocations for `std::format("{}", 1.23)`.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 libcxx/include/__format/formatter_floating_point.h     |  2 +-
 .../formatter.floating_point.pass.cpp                  | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index f4de8b927651a..8728f996e78f9 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -154,7 +154,7 @@ class __float_buffer {
   // may be too much for some platforms. For these cases a better estimate is
   // required.
   explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision)
-      : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) {
+      : __precision_(__precision != -1 ? __precision : 6) {
     // When the precision is larger than _Traits::__max_fractional the digits in
     // the range (_Traits::__max_fractional, precision] will contain the value
     // zero. There's no need to request to_chars to write these zeros:
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
index 3ad84577b90d2..fb410591ab7c5 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -42,6 +42,7 @@
 #include "test_format_context.h"
 #include "test_macros.h"
 #include "make_string.h"
+#include "count_new.h"
 
 #define STR(S) MAKE_STRING(CharT, S)
 
@@ -562,11 +563,20 @@ void test_all_float_types() {
   test_float_type<long double, CharT>();
 }
 
+void test_default_precision_double_does_not_allocate() {
+  globalMemCounter.reset();
+  DisableAllocationGuard g;
+  std::string result = std::format("{}", 1.23);
+  g.release();
+  assert(result == "1.23");
+}
+
 int main(int, char**) {
   test_all_float_types<char>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test_all_float_types<wchar_t>();
 #endif
+  test_default_precision_double_does_not_allocate();
 
   return 0;
 }



More information about the libcxx-commits mailing list