On 7/17/25 11:14, Jonathan Wakely wrote:
On Thu, 17 Jul 2025 at 10:05, Luc Grosheintz <luc.groshei...@gmail.com> wrote:
On 7/8/25 16:56, Tomasz Kaminski wrote:
On Thu, Jul 3, 2025 at 12:36 PM Luc Grosheintz <luc.groshei...@gmail.com>
wrote:
This commit implements and tests the function is_sufficiently_aligned
from P2897R7.
libstdc++-v3/ChangeLog:
* include/bits/align.h (is_sufficiently_aligned): New function.
* include/bits/version.def (is_sufficiently_aligned): Add.
* include/bits/version.h: Regenerate.
* include/std/memory: Add __glibcxx_want_is_sufficiently_aligned.
* src/c++23/std.cc.in (is_sufficiently_aligned): Add.
* testsuite/20_util/is_sufficiently_aligned/1.cc: New test.
* testsuite/20_util/is_sufficiently_aligned/2.cc: New test.
---
Only one small suggestion on placement of the tests. Otherwise it looks
good.
libstdc++-v3/include/bits/align.h | 16 ++++++++++
libstdc++-v3/include/bits/version.def | 8 +++++
libstdc++-v3/include/bits/version.h | 10 ++++++
libstdc++-v3/include/std/memory | 1 +
libstdc++-v3/src/c++23/std.cc.in | 1 +
.../20_util/is_sufficiently_aligned/1.cc | 31 +++++++++++++++++++
.../20_util/is_sufficiently_aligned/2.cc | 7 +++++
7 files changed, 74 insertions(+)
create mode 100644
libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
create mode 100644
libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/2.cc
diff --git a/libstdc++-v3/include/bits/align.h
b/libstdc++-v3/include/bits/align.h
index 2b40c37e033..fbbe9cb1f9c 100644
--- a/libstdc++-v3/include/bits/align.h
+++ b/libstdc++-v3/include/bits/align.h
@@ -102,6 +102,22 @@ align(size_t __align, size_t __size, void*& __ptr,
size_t& __space) noexcept
}
#endif // __glibcxx_assume_aligned
+#ifdef __glibcxx_is_sufficiently_aligned // C++ >= 26
+ /** @brief Is @a __ptr aligned to an _Align byte boundary?
+ *
+ * @tparam _Align An alignment value
+ * @tparam _Tp An object type
+ *
+ * C++26 20.2.5 [ptr.align]
+ *
+ * @ingroup memory
+ */
+ template<size_t _Align, class _Tp>
+ bool
+ is_sufficiently_aligned(_Tp* __ptr)
+ { return reinterpret_cast<__UINTPTR_TYPE__>(__ptr) % _Align == 0; }
+#endif // __glibcxx_is_sufficiently_aligned
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/bits/version.def
b/libstdc++-v3/include/bits/version.def
index f4ba501c403..a2695e67716 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -732,6 +732,14 @@ ftms = {
};
};
+ftms = {
+ name = is_sufficiently_aligned;
+ values = {
+ v = 202411;
+ cxxmin = 26;
+ };
+};
+
ftms = {
name = atomic_flag_test;
values = {
diff --git a/libstdc++-v3/include/bits/version.h
b/libstdc++-v3/include/bits/version.h
index dc8ac07be16..1b17a965239 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -815,6 +815,16 @@
#endif /* !defined(__cpp_lib_assume_aligned) &&
defined(__glibcxx_want_assume_aligned) */
#undef __glibcxx_want_assume_aligned
+#if !defined(__cpp_lib_is_sufficiently_aligned)
+# if (__cplusplus > 202302L)
+# define __glibcxx_is_sufficiently_aligned 202411L
+# if defined(__glibcxx_want_all) ||
defined(__glibcxx_want_is_sufficiently_aligned)
+# define __cpp_lib_is_sufficiently_aligned 202411L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_is_sufficiently_aligned) &&
defined(__glibcxx_want_is_sufficiently_aligned) */
+#undef __glibcxx_want_is_sufficiently_aligned
+
#if !defined(__cpp_lib_atomic_flag_test)
# if (__cplusplus >= 202002L)
# define __glibcxx_atomic_flag_test 201907L
diff --git a/libstdc++-v3/include/std/memory
b/libstdc++-v3/include/std/memory
index 1da03b3ea6a..ff342ff35f3 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -110,6 +110,7 @@
#define __glibcxx_want_constexpr_memory
#define __glibcxx_want_enable_shared_from_this
#define __glibcxx_want_indirect
+#define __glibcxx_want_is_sufficiently_aligned
#define __glibcxx_want_make_unique
#define __glibcxx_want_out_ptr
#define __glibcxx_want_parallel_algorithm
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/
std.cc.in
index e692caaa5f9..6f4214ed3a7 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1864,6 +1864,7 @@ export namespace std
using std::allocator_arg_t;
using std::allocator_traits;
using std::assume_aligned;
+ using std::is_sufficiently_aligned;
using std::make_obj_using_allocator;
using std::pointer_traits;
using std::to_address;
diff --git a/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
new file mode 100644
index 00000000000..4c2738b57db
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <array>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ constexpr size_t N = 4;
+ constexpr size_t M = 2*N + 1;
+ alignas(N) std::array<char, M> buffer{};
+
+ auto* ptr = buffer.data();
+ VERIFY(std::is_sufficiently_aligned<1>(ptr+0));
+ VERIFY(std::is_sufficiently_aligned<1>(ptr+1));
+
+ VERIFY(std::is_sufficiently_aligned<2>(ptr+0));
+ VERIFY(!std::is_sufficiently_aligned<2>(ptr+1));
+ VERIFY(std::is_sufficiently_aligned<2>(ptr+2));
+
+ for (size_t i = 0; i < M; ++i)
+ VERIFY(std::is_sufficiently_aligned<N>(ptr + i) == (i % N == 0));
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/2.cc
b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/2.cc
new file mode 100644
index 00000000000..8e0f4c07661
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/2.cc
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+#ifndef __cpp_lib_is_sufficiently_aligned
+#error "Missing FTM"
+#endif
I would integrate that into 1.cc file directly. I do not think we need a
separate test.
Now I know they're called version.cc it's easier to find others. There's
testsuite/20_util/headers/memory/version.cc
which checks:
__cpp_lib_allocator_traits_is_always_equal
__cpp_lib_addressof_constexpr
That feels like the place to also put this one.
Yes, that makes sense.
It's use of dejagnu is
neat too:
// { dg-do preprocess { target c++17 } }
The 'preprocess' does what you'd expect, it stops after preprocessing
(so doesn't bother doing any of compiling and assembling and linking
and running):
https://gcc.gnu.org/onlinedocs/gccint/Directives.html#Specify-how-to-build-the-test
By default this test will only be tested with -std=gnu++17 but people
who run the testsuite with additional/different -std options can test
it for -std=c++26:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.run.permutations
If we really want to be sure the new macro is *always* tested by
everybody running the tests, it needs to be a separate file with {
target c++26 } so that the testsuite chooses -std=gnu++26 for it. So
that's an argument against checking the new macro in the existing
headers/memory/version.cc file. I don't feel strongly about it though,
because I test everything with every -std option several times a day,
and as long as *somebody* is doing that, we'll know it works.
And one day in the future -std=gnu++26 will be the default for all
tests anyway (but that's years away).
Thank you! This uncovered a misconception of mine, namely that
{ target c++17 }
would automatically run on C++17 and all later versions. Which is
true, by accident, for { target c++23 }. At least in my rather
default config it automatically also checks C++26 if the target
larger than or equal to C++20.
The reason I liked { target c++17 } is that it opens up the
possibility to check that the macro for a C++23 feature is not
set while compiling C++{17,20} code. Similarly, the same FTM can
have different values for different versions of the standard; and
I've seen examples that check these values. Therefore, I have the
impression that testing with multiple versions of the standard is
needed to check FTMs thoroughly.
I'm tempted to say that the code for FTMs is unlikely to break
accidentally. Hence, thorough testing is needed when first
implementing the FTM and then periodically. (Though invariably
such a statement means the unlikely happens a few days later.)
// { dg-add-options no_pch }
This prevents the test harness from adding an implicit -include
bits/stdc++.h which includes every libstdc++ header at the very start
of the file. If the test just wants to check that the macro is defined
by <memory> then including every other header first would not test
what you want to test!
That's why I liked that line; and want to add it to mdspan/version.cc.
The definition of no_pch is in testsuite/lib/dg-options.exp
Now I'm tempted to adjust mdspan/version.cc accordingly.
--
2.49.0