[libcxx-commits] [libcxx] [libc++] Base string's alignment on __STDCPP_DEFAULT_NEW_ALIGNMENT__ (PR #171785)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Feb 4 03:28:58 PST 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/171785
>From 54b243d1fadc6fb2fec7f28980dd6ecf90e1ed66 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 11 Dec 2025 10:14:52 +0100
Subject: [PATCH] [libc++] Base string's alignment on
__STDCPP_DEFAULT_NEW_ALIGNMENT__
---
libcxx/include/__cxx03/string | 13 +++++++-
libcxx/include/string | 12 +++++++-
.../string.capacity/allocation_size.pass.cpp | 7 +++--
.../string.capacity/max_size.pass.cpp | 7 +++--
.../strings/basic.string/new_alignment.sh.cpp | 30 +++++++++++++++++++
.../string.capacity/allocation_size.pass.cpp | 7 +++--
.../string.capacity/max_size.pass.cpp | 5 +++-
.../string.capacity/max_size.pass.cpp | 4 +++
8 files changed, 76 insertions(+), 9 deletions(-)
create mode 100644 libcxx/test/libcxx/strings/basic.string/new_alignment.sh.cpp
diff --git a/libcxx/include/__cxx03/string b/libcxx/include/__cxx03/string
index 6c43fca08f109..73372b61b00ed 100644
--- a/libcxx/include/__cxx03/string
+++ b/libcxx/include/__cxx03/string
@@ -1620,7 +1620,18 @@ private:
static _LIBCPP_HIDE_FROM_ABI size_type __align_it(size_type __s) _NOEXCEPT {
return (__s + (__a - 1)) & ~(__a - 1);
}
- enum { __alignment = 8 };
+
+ // GCC currently doesn't define __STDCPP_DEFAULT_NEW_ALIGNMENT__ unconditionally
+ // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123872
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ static inline const size_t
+ __alignment = __is_default_allocator<allocator_type>::value && __STDCPP_DEFAULT_NEW_ALIGNMENT__ > sizeof(void*)
+ ? __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ : sizeof(void*);
+#else
+ static inline const size_t __alignment = sizeof(void*);
+#endif
+
static _LIBCPP_HIDE_FROM_ABI size_type __recommend(size_type __s) _NOEXCEPT {
if (__s < __min_cap) {
return static_cast<size_type>(__min_cap) - 1;
diff --git a/libcxx/include/string b/libcxx/include/string
index c4bf970e55004..1029e9958f42e 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -2364,7 +2364,17 @@ private:
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT {
return (__s + (__a - 1)) & ~(__a - 1);
}
- enum { __alignment = 8 };
+
+ // GCC currently doesn't define __STDCPP_DEFAULT_NEW_ALIGNMENT__ unconditionally
+ // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123872
+# ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ static inline const size_t
+ __alignment = __is_std_allocator_v<allocator_type> && __STDCPP_DEFAULT_NEW_ALIGNMENT__ > sizeof(void*)
+ ? __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ : sizeof(void*);
+# else
+ static inline const size_t __alignment = sizeof(void*);
+# endif
// This makes sure that we're using a capacity with some extra alignment, since allocators almost always over-align
// the allocations anyways, improving memory usage. More importantly, this ensures that the lowest bit is never set
diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp
index 77da29225957b..367a58897cec0 100644
--- a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp
+++ b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp
@@ -15,8 +15,11 @@
#include "test_macros.h"
-// alignment of the string heap buffer is hardcoded to 8
-const std::size_t alignment = 8;
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+static const std::size_t alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#else
+static const std::size_t alginment = 8;
+#endif
int main(int, char**) {
std::string input_string;
diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
index 73825ef4845f2..15736e4a1ceed 100644
--- a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -17,8 +17,11 @@
#include "test_macros.h"
-// alignment of the string heap buffer is hardcoded to 8
-static const std::size_t alignment = 8;
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+static const std::size_t alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#else
+static const std::size_t alginment = 8;
+#endif
template <class = int>
TEST_CONSTEXPR_CXX20 void full_size() {
diff --git a/libcxx/test/libcxx/strings/basic.string/new_alignment.sh.cpp b/libcxx/test/libcxx/strings/basic.string/new_alignment.sh.cpp
new file mode 100644
index 0000000000000..f8906c9fb9827
--- /dev/null
+++ b/libcxx/test/libcxx/strings/basic.string/new_alignment.sh.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Check that std::string bases its alignment on __STDCPP_DEFAULT_NEW_ALIGNMENT__
+
+// UNSUPPORTED: c++03
+
+// RUN: %{build} -faligned-new=32 -DALIGN=32
+// RUN: %{run}
+// RUN: %{build} -faligned-new=16 -DALIGN=16
+// RUN: %{run}
+// RUN: %{build} -faligned-new=8 -DALIGN=8
+// RUN: %{run}
+
+#include <cassert>
+#include <string>
+
+int main(int, char**) {
+ std::string str;
+ str.reserve(25);
+
+ assert(str.capacity() % ALIGN == ALIGN - 1);
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
index 77da29225957b..f2208f5ae6934 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
@@ -15,8 +15,11 @@
#include "test_macros.h"
-// alignment of the string heap buffer is hardcoded to 8
-const std::size_t alignment = 8;
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+static const std::size_t alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#else
+static const std::size_t alignment = 8;
+#endif
int main(int, char**) {
std::string input_string;
diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
index 6bfcb5d4bfcd8..11bd1a5928d4a 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -17,8 +17,11 @@
#include "test_macros.h"
-// alignment of the string heap buffer is hardcoded to 8
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+static const std::size_t alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#else
static const std::size_t alignment = 8;
+#endif
template <class = int>
TEST_CONSTEXPR_CXX20 void full_size() {
diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
index 45a52acab464e..449d0fc71cdca 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -8,6 +8,10 @@
// UNSUPPORTED: no-exceptions
+// This test is sensitive what __STDCPP_DEFAULT_NEW_ALIGNMENT__ is set to. Enabled algined-new for GCC so that GCC
+// defines the macro
+// ADDITIONAL_COMPILE_FLAGS(gcc): -faligned-new
+
// <string>
// size_type max_size() const; // constexpr since C++20
More information about the libcxx-commits
mailing list