[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