[libcxx-commits] [libcxx] [libc++] Implement P0528R3 `std::atomic` CAS for types with paddings (PR #76180)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jul 25 13:18:09 PDT 2026


https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/76180

>From 5abb10d6487326a00e3cad43c2cbad86d84707aa Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Thu, 21 Dec 2023 20:31:29 +0000
Subject: [PATCH 01/36] [libc++] make std::atomic works with types with
 paddings

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__atomic/support/c11.h         |  83 ++++--
 libcxx/include/__atomic/support/common.h      |  75 ++++++
 .../atomics.types.generic/padding.pass.cpp    | 241 ++++++++++++++++++
 4 files changed, 375 insertions(+), 25 deletions(-)
 create mode 100644 libcxx/include/__atomic/support/common.h
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fcea3b7601182..4533ad3c1ae41 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -226,6 +226,7 @@ set(files
   __atomic/kill_dependency.h
   __atomic/memory_order.h
   __atomic/support.h
+  __atomic/support/common.h
   __atomic/support/c11.h
   __atomic/support/gcc.h
   __atomic/to_gcc_order.h
diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index 899502422570a..4ae0f6a28637a 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ATOMIC_SUPPORT_C11_H
 
 #include <__atomic/memory_order.h>
+#include <__atomic/support/common.h>
 #include <__config>
 #include <__cstddef/ptrdiff_t.h>
 #include <__memory/addressof.h>
@@ -32,11 +33,24 @@ struct __cxx_atomic_base_impl {
   _LIBCPP_HIDE_FROM_ABI
 #ifndef _LIBCPP_CXX03_LANG
   __cxx_atomic_base_impl() _NOEXCEPT = default;
+
+#  if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+  __cxx_atomic_base_impl() noexcept
+    requires __needs_clear_padding<_Tp>::value
+      : __a_value() {
+    if (!__builtin_is_constant_evaluated()) {
+      __builtin_clear_padding(__a_value);
+    }
+  }
+#  endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+
 #else
   __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
 #endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {}
+  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
+    std::__clear_padding_if_needed(__a_value);
+  }
   _Atomic(_Tp) __a_value;
 };
 
@@ -52,21 +66,25 @@ _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order
 
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT {
+  std::__clear_padding_if_needed(__val);
   __c11_atomic_init(std::addressof(__a->__a_value), __val);
 }
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) _NOEXCEPT {
+  std::__clear_padding_if_needed(__val);
   __c11_atomic_init(std::addressof(__a->__a_value), __val);
 }
 
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT {
+  std::__clear_padding_if_needed(__val);
   __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order));
 }
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) _NOEXCEPT {
+  std::__clear_padding_if_needed(__val);
   __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order));
 }
 
@@ -102,12 +120,14 @@ __cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const* __a, _Tp* __dst, me
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT {
+  std::__clear_padding_if_needed(__value);
   return __c11_atomic_exchange(
       std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order));
 }
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) _NOEXCEPT {
+  std::__clear_padding_if_needed(__value);
   return __c11_atomic_exchange(
       std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order));
 }
@@ -126,23 +146,29 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     _Tp __value,
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
-  return __c11_atomic_compare_exchange_strong(
-      std::addressof(__a->__a_value),
-      __expected,
-      __value,
-      static_cast<__memory_order_underlying_t>(__success),
-      static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __c11_atomic_compare_exchange_strong(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            __value_maybe_padding_cleared,
+            static_cast<__memory_order_underlying_t>(__success),
+            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+      });
 }
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
-  return __c11_atomic_compare_exchange_strong(
-      std::addressof(__a->__a_value),
-      __expected,
-      __value,
-      static_cast<__memory_order_underlying_t>(__success),
-      static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __c11_atomic_compare_exchange_strong(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            __value_maybe_padding_cleared,
+            static_cast<__memory_order_underlying_t>(__success),
+            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+      });
 }
 
 template <class _Tp>
@@ -152,23 +178,30 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     _Tp __value,
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
-  return __c11_atomic_compare_exchange_weak(
-      std::addressof(__a->__a_value),
-      __expected,
-      __value,
-      static_cast<__memory_order_underlying_t>(__success),
-      static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __c11_atomic_compare_exchange_weak(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            __value_maybe_padding_cleared,
+            static_cast<__memory_order_underlying_t>(__success),
+            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+      });
 }
+
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
-  return __c11_atomic_compare_exchange_weak(
-      std::addressof(__a->__a_value),
-      __expected,
-      __value,
-      static_cast<__memory_order_underlying_t>(__success),
-      static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __c11_atomic_compare_exchange_weak(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            __value_maybe_padding_cleared,
+            static_cast<__memory_order_underlying_t>(__success),
+            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+      });
 }
 
 template <class _Tp>
diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/support/common.h
new file mode 100644
index 0000000000000..fe02e3736f88c
--- /dev/null
+++ b/libcxx/include/__atomic/support/common.h
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ATOMIC_SUPPORT_COMMON_H
+#define _LIBCPP___ATOMIC_SUPPORT_COMMON_H
+
+#include <__config>
+#include <__memory/addressof.h>
+#include <__type_traits/conjunction.h>
+#include <__type_traits/has_unique_object_representation.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/negation.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/forward.h>
+#include <cstring>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+
+template <class _Tp>
+struct __needs_clear_padding
+    : _And<_Not<has_unique_object_representations<_Tp>>, _Not<is_same<_Tp, float>>, _Not<is_same<_Tp, double>>> {};
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp&& __obj) noexcept {
+  if constexpr (__needs_clear_padding<remove_cvref_t<_Tp>>::value) {
+    if (!__builtin_is_constant_evaluated()) {
+      __builtin_clear_padding(std::addressof(__obj));
+    }
+  }
+}
+
+template <class _Tp, class _Up, class _CasFunc>
+_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {
+  if constexpr (!__needs_clear_padding<remove_cv_t<_Tp>>::value) {
+    return __cas_func(__expected, std::forward<_Up>(__value));
+  } else {
+    std::__clear_padding_if_needed(__value);
+    remove_cv_t<_Tp> __expected_copy = *__expected;
+    std::__clear_padding_if_needed(__expected_copy);
+    if (__cas_func(std::addressof(__expected_copy), std::forward<_Up>(__value))) {
+      return true;
+    } else {
+      std::memcpy(__expected, std::addressof(__expected_copy), sizeof(remove_cv_t<_Tp>));
+      return false;
+    }
+  }
+}
+
+#else // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void __clear_padding_if_needed(_Tp&&) noexcept {}
+
+template <class _Tp, class _Up, class _CasFunc>
+_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {
+  return __cas_func(__expected, std::forward<_Up>(__value));
+}
+
+#endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ATOMIC_SUPPORT_COMMON_H
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
new file mode 100644
index 0000000000000..e8ea1ecbddd81
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -0,0 +1,241 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// XFAIL: !has-64-bit-atomics
+
+// atomic_init is deprecated
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+#include <atomic>
+#include <cassert>
+#include <cstring>
+#include <type_traits>
+
+struct Foo {
+  int i;
+  char c;
+};
+
+static_assert(!std::has_unique_object_representations_v<Foo>);
+static_assert(sizeof(Foo) > sizeof(int) + sizeof(char));
+
+Foo make_foo(int i, char c, unsigned char pad_byte) {
+  Foo f;
+  std::memset(&f, pad_byte, sizeof(Foo));
+  f.i = i;
+  f.c = c;
+  return f;
+}
+
+void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+  alignas(Foo) unsigned char buf[sizeof(Foo)];
+  std::memset(buf, pad_byte, sizeof(Foo));
+  Foo& reference = *reinterpret_cast<Foo*>(buf);
+  reference.i    = f.i;
+  reference.c    = f.c;
+  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
+}
+
+#if __has_builtin(__builtin_clear_padding)
+
+void test_default_constructor() {
+  std::atomic<Foo> a;
+  Foo loaded = a.load();
+  assert(loaded.i == 0);
+  assert(loaded.c == '\0');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_value_constructor() {
+  Foo init = make_foo(10, 'a', 0xBB);
+  assert_foo_padding(init, 0xBB);
+  std::atomic<Foo> a(init);
+  Foo loaded = a.load();
+  assert(loaded.i == 10);
+  assert(loaded.c == 'a');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_store() {
+  std::atomic<Foo> a;
+  Foo value = make_foo(5, 'x', 0xAB);
+  assert_foo_padding(value, 0xAB);
+  a.store(value);
+  Foo loaded = a.load();
+  assert(loaded.i == 5);
+  assert(loaded.c == 'x');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_exchange() {
+  Foo initial = make_foo(1, 'a', 0x00);
+  assert_foo_padding(initial, 0x00);
+  std::atomic<Foo> a(initial);
+  Foo new_val = make_foo(2, 'b', 0xCD);
+  assert_foo_padding(new_val, 0xCD);
+  Foo old = a.exchange(new_val);
+  assert(old.i == 1);
+  assert(old.c == 'a');
+  assert_foo_padding(old, 0);
+  Foo loaded = a.load();
+  assert(loaded.i == 2);
+  assert(loaded.c == 'b');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_atomic_init() {
+  std::atomic<Foo> a;
+  Foo init = make_foo(7, 'z', 0xEF);
+  assert_foo_padding(init, 0xEF);
+  std::atomic_init(&a, init);
+  Foo loaded = a.load();
+  assert(loaded.i == 7);
+  assert(loaded.c == 'z');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_compare_exchange_strong_success_padding_only() {
+  // CAS should succeed when only padding differs in expected; expected is unchanged.
+  std::atomic<Foo> a;
+
+  Foo init = make_foo(10, 'a', 0xBB);
+  assert_foo_padding(init, 0xBB);
+  a.store(init);
+
+  Foo expected = make_foo(10, 'a', 0xAA);
+  assert_foo_padding(expected, 0xAA);
+
+  alignas(Foo) char original_expected[sizeof(Foo)];
+  std::memcpy(original_expected, &expected, sizeof(Foo));
+
+  Foo new_value = make_foo(42, 'b', 0xCC);
+  assert_foo_padding(new_value, 0xCC);
+
+  bool r = a.compare_exchange_strong(expected, new_value);
+
+  assert(r);
+  assert(std::memcmp(&expected, original_expected, sizeof(Foo)) == 0);
+  Foo loaded = a.load();
+  assert(loaded.i == 42);
+  assert(loaded.c == 'b');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_compare_exchange_strong_failure() {
+  std::atomic<Foo> a;
+  Foo stored = make_foo(10, 'a', 0xBB);
+  assert_foo_padding(stored, 0xBB);
+  a.store(stored);
+
+  Foo expected = make_foo(99, 'a', 0xAA);
+  assert_foo_padding(expected, 0xAA);
+  Foo new_value = make_foo(42, 'b', 0xCC);
+  assert_foo_padding(new_value, 0xCC);
+
+  bool r = a.compare_exchange_strong(expected, new_value);
+
+  assert(!r);
+  assert(expected.i == 10);
+  assert(expected.c == 'a');
+  assert_foo_padding(expected, 0);
+  Foo loaded = a.load();
+  assert(loaded.i == 10);
+  assert(loaded.c == 'a');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_compare_exchange_weak_success_padding_only() {
+  std::atomic<Foo> a;
+  Foo stored = make_foo(10, 'a', 0xBB);
+  assert_foo_padding(stored, 0xBB);
+  a.store(stored);
+
+  Foo new_value = make_foo(42, 'b', 0xCC);
+  assert_foo_padding(new_value, 0xCC);
+
+  Foo original_expected = make_foo(10, 'a', 0xAA);
+  assert_foo_padding(original_expected, 0xAA);
+
+  bool r = false;
+  while (!r) {
+    Foo expected = make_foo(10, 'a', 0xAA);
+    assert_foo_padding(expected, 0xAA);
+    r = a.compare_exchange_weak(expected, new_value);
+    if (r) {
+      assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+    } else {
+      // Spurious failure: expected is updated to the current atomic value.
+      assert(expected.i == 10);
+      assert(expected.c == 'a');
+      assert_foo_padding(expected, 0);
+    }
+  }
+
+  Foo loaded = a.load();
+  assert(loaded.i == 42);
+  assert(loaded.c == 'b');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_compare_exchange_weak_failure() {
+  std::atomic<Foo> a;
+  Foo stored = make_foo(10, 'a', 0xBB);
+  assert_foo_padding(stored, 0xBB);
+  a.store(stored);
+
+  Foo expected = make_foo(99, 'a', 0xAA);
+  assert_foo_padding(expected, 0xAA);
+  Foo new_value = make_foo(42, 'b', 0xCC);
+  assert_foo_padding(new_value, 0xCC);
+
+  bool r = a.compare_exchange_weak(expected, new_value);
+
+  assert(!r);
+  assert(expected.i == 10);
+  assert(expected.c == 'a');
+  assert_foo_padding(expected, 0);
+  Foo loaded = a.load();
+  assert(loaded.i == 10);
+  assert(loaded.c == 'a');
+  assert_foo_padding(loaded, 0);
+}
+
+void test_no_padding_type() {
+  // Types with unique object representations skip the padding-clearing path.
+  std::atomic<int> a(1);
+  int expected = 1;
+  assert(a.compare_exchange_strong(expected, 2));
+  assert(expected == 1);
+  assert(a.load() == 2);
+
+  expected = 3;
+  assert(!a.compare_exchange_strong(expected, 4));
+  assert(expected == 2);
+  assert(a.load() == 2);
+}
+
+int main(int, char**) {
+  test_default_constructor();
+  test_value_constructor();
+  test_store();
+  test_exchange();
+  test_atomic_init();
+  test_compare_exchange_strong_success_padding_only();
+  test_compare_exchange_strong_failure();
+  test_compare_exchange_weak_success_padding_only();
+  test_compare_exchange_weak_failure();
+  test_no_padding_type();
+
+  return 0;
+}
+
+#else // !__has_builtin(__builtin_clear_padding)
+
+int main(int, char**) { return 0; }
+
+#endif // __has_builtin(__builtin_clear_padding)

>From 19872aafff697e6019febab2c1175b4deff746ef Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 7 Jun 2026 22:08:54 +0100
Subject: [PATCH 02/36] gcc

---
 libcxx/include/__atomic/support/gcc.h         | 89 +++++++++++++------
 .../atomics.types.generic/padding.pass.cpp    |  5 +-
 2 files changed, 64 insertions(+), 30 deletions(-)

diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 37c38d25012c6..78e27d9ef9781 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ATOMIC_SUPPORT_GCC_H
 
 #include <__atomic/memory_order.h>
+#include <__atomic/support/common.h>
 #include <__atomic/to_gcc_order.h>
 #include <__config>
 #include <__memory/addressof.h>
@@ -48,21 +49,35 @@ struct __cxx_atomic_base_impl {
   _LIBCPP_HIDE_FROM_ABI
 #ifndef _LIBCPP_CXX03_LANG
   __cxx_atomic_base_impl() _NOEXCEPT = default;
+
+#  if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+  __cxx_atomic_base_impl() noexcept
+    requires __needs_clear_padding<_Tp>::value
+      : __a_value() {
+    if (!__builtin_is_constant_evaluated()) {
+      __builtin_clear_padding(__a_value);
+    }
+  }
+#  endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
 #else
   __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
 #endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {}
+  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {
+    std::__clear_padding_if_needed(__a_value);
+  }
   _Tp __a_value;
 };
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
+  std::__clear_padding_if_needed(__val);
   __cxx_atomic_assign_volatile(__a->__a_value, __val);
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
+  std::__clear_padding_if_needed(__val);
   __a->__a_value = __val;
 }
 
@@ -77,11 +92,13 @@ _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
+  std::__clear_padding_if_needed(__val);
   __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
+  std::__clear_padding_if_needed(__val);
   __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
 }
 
@@ -115,6 +132,7 @@ template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) {
   _Tp __ret;
+  std::__clear_padding_if_needed(__value);
   __atomic_exchange(
       std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
   return __ret;
@@ -123,6 +141,7 @@ __cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, me
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) {
   _Tp __ret;
+  std::__clear_padding_if_needed(__value);
   __atomic_exchange(
       std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
   return __ret;
@@ -135,25 +154,31 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     _Tp __value,
     memory_order __success,
     memory_order __failure) {
-  return __atomic_compare_exchange(
-      std::addressof(__a->__a_value),
-      __expected,
-      std::addressof(__value),
-      false,
-      __to_gcc_order(__success),
-      __to_gcc_failure_order(__failure));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __atomic_compare_exchange(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            std::addressof(__value_maybe_padding_cleared),
+            false,
+            __to_gcc_order(__success),
+            __to_gcc_failure_order(__failure));
+      });
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
-  return __atomic_compare_exchange(
-      std::addressof(__a->__a_value),
-      __expected,
-      std::addressof(__value),
-      false,
-      __to_gcc_order(__success),
-      __to_gcc_failure_order(__failure));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __atomic_compare_exchange(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            std::addressof(__value_maybe_padding_cleared),
+            false,
+            __to_gcc_order(__success),
+            __to_gcc_failure_order(__failure));
+      });
 }
 
 template <typename _Tp>
@@ -163,25 +188,31 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     _Tp __value,
     memory_order __success,
     memory_order __failure) {
-  return __atomic_compare_exchange(
-      std::addressof(__a->__a_value),
-      __expected,
-      std::addressof(__value),
-      true,
-      __to_gcc_order(__success),
-      __to_gcc_failure_order(__failure));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __atomic_compare_exchange(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            std::addressof(__value_maybe_padding_cleared),
+            true,
+            __to_gcc_order(__success),
+            __to_gcc_failure_order(__failure));
+      });
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
-  return __atomic_compare_exchange(
-      std::addressof(__a->__a_value),
-      __expected,
-      std::addressof(__value),
-      true,
-      __to_gcc_order(__success),
-      __to_gcc_failure_order(__failure));
+  return __atomic_cas_with_clear_padding(
+      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+        return __atomic_compare_exchange(
+            std::addressof(__a->__a_value),
+            __expected_or_copy,
+            std::addressof(__value_maybe_padding_cleared),
+            true,
+            __to_gcc_order(__success),
+            __to_gcc_failure_order(__failure));
+      });
 }
 
 template <typename _Tp>
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index e8ea1ecbddd81..a66fd3e74bfc6 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -13,6 +13,7 @@
 
 #include <atomic>
 #include <cassert>
+#include <chrono>
 #include <cstring>
 #include <type_traits>
 
@@ -161,8 +162,10 @@ void test_compare_exchange_weak_success_padding_only() {
   Foo original_expected = make_foo(10, 'a', 0xAA);
   assert_foo_padding(original_expected, 0xAA);
 
-  bool r = false;
+  bool r              = false;
+  const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(3);
   while (!r) {
+    assert(std::chrono::steady_clock::now() < deadline && "compare_exchange_weak did not succeed within 3 seconds");
     Foo expected = make_foo(10, 'a', 0xAA);
     assert_foo_padding(expected, 0xAA);
     r = a.compare_exchange_weak(expected, new_value);

>From a132f0dbaecca286a44edf03a7f72ffd825dd51c Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 13 Jun 2026 09:42:18 +0100
Subject: [PATCH 03/36] lint

---
 libcxx/include/CMakeLists.txt                                | 2 +-
 libcxx/include/__atomic/support/common.h                     | 2 +-
 libcxx/include/__atomic/support/gcc.h                        | 5 ++++-
 libcxx/include/module.modulemap.in                           | 1 +
 .../test/std/atomics/atomics.types.generic/padding.pass.cpp  | 1 -
 5 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 4533ad3c1ae41..afbd3a3215d9f 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -226,8 +226,8 @@ set(files
   __atomic/kill_dependency.h
   __atomic/memory_order.h
   __atomic/support.h
-  __atomic/support/common.h
   __atomic/support/c11.h
+  __atomic/support/common.h
   __atomic/support/gcc.h
   __atomic/to_gcc_order.h
   __bit/bit_cast.h
diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/support/common.h
index fe02e3736f88c..c8a1a3a0f6876 100644
--- a/libcxx/include/__atomic/support/common.h
+++ b/libcxx/include/__atomic/support/common.h
@@ -61,7 +61,7 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&
 #else // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void __clear_padding_if_needed(_Tp&&) noexcept {}
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void __clear_padding_if_needed(_Tp&&) _NOEXCEPT {}
 
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {
diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 78e27d9ef9781..640f6e5e916ca 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -63,8 +63,11 @@ struct __cxx_atomic_base_impl {
   __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
 #endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {
+  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
+    // gcc c++11 mode constexpr constructor requires empty body
+#if _LIBCPP_STD_VER >= 14
     std::__clear_padding_if_needed(__a_value);
+#endif
   }
   _Tp __a_value;
 };
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index e3b9e5ac09cb3..3fcb803796f0e 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -896,6 +896,7 @@ module std {
     module support {
       header "__atomic/support.h"
       textual header "__atomic/support/c11.h"
+      textual header "__atomic/support/common.h"
       textual header "__atomic/support/gcc.h"
     }
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index a66fd3e74bfc6..e759c20214241 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,7 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: !has-64-bit-atomics
 
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS

>From bf9fd088db6335e6306d2405bc38859b4853fedc Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 21 Jun 2026 10:51:35 +0100
Subject: [PATCH 04/36] gcc c++11 ci

---
 libcxx/include/__atomic/support/c11.h    | 2 ++
 libcxx/include/__atomic/support/common.h | 8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index 4ae0f6a28637a..c496ecf5ac742 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -49,7 +49,9 @@ struct __cxx_atomic_base_impl {
   }
 #endif // _LIBCPP_CXX03_LANG
   _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
+#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
     std::__clear_padding_if_needed(__a_value);
+#endif
   }
   _Atomic(_Tp) __a_value;
 };
diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/support/common.h
index c8a1a3a0f6876..672ff0a6b2683 100644
--- a/libcxx/include/__atomic/support/common.h
+++ b/libcxx/include/__atomic/support/common.h
@@ -61,7 +61,13 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&
 #else // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void __clear_padding_if_needed(_Tp&&) _NOEXCEPT {}
+_LIBCPP_HIDE_FROM_ABI
+#  if _LIBCPP_STD_VER >= 14
+// c++11 does not allow constexpr functions to return void
+constexpr
+#  endif
+    void __clear_padding_if_needed(_Tp&&) _NOEXCEPT {
+}
 
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {

>From bfe1fdba39fd816ff475d47c1932fd7666105e3e Mon Sep 17 00:00:00 2001
From: Hui <hui.xie1990 at gmail.com>
Date: Sat, 4 Jul 2026 09:47:30 +0100
Subject: [PATCH 05/36] Update
 libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 .../test/std/atomics/atomics.types.generic/padding.pass.cpp   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index e759c20214241..38b4428f3a271 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -110,8 +110,8 @@ void test_compare_exchange_strong_success_padding_only() {
   Foo expected = make_foo(10, 'a', 0xAA);
   assert_foo_padding(expected, 0xAA);
 
-  alignas(Foo) char original_expected[sizeof(Foo)];
-  std::memcpy(original_expected, &expected, sizeof(Foo));
+Foo original_expected; // make a copy including padding bits
+std::memcpy(&original_expected, expected, sizeof(Foo));
 
   Foo new_value = make_foo(42, 'b', 0xCC);
   assert_foo_padding(new_value, 0xCC);

>From bc7578f1dd677026ed4afe2a4b2bc92e5360b015 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie1990 at gmail.com>
Date: Sat, 4 Jul 2026 09:47:57 +0100
Subject: [PATCH 06/36] Update libcxx/include/__atomic/support/c11.h

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 libcxx/include/__atomic/support/c11.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index c496ecf5ac742..c55de19cd4b59 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -148,7 +148,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     _Tp __value,
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __c11_atomic_compare_exchange_strong(
             std::addressof(__a->__a_value),

>From 78d045d7ac8f02cf5199b88eb9c4c36695fdd669 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie1990 at gmail.com>
Date: Sat, 4 Jul 2026 09:48:20 +0100
Subject: [PATCH 07/36] Update libcxx/include/__atomic/support/common.h

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 libcxx/include/__atomic/support/common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/support/common.h
index 672ff0a6b2683..16bb21e46f88e 100644
--- a/libcxx/include/__atomic/support/common.h
+++ b/libcxx/include/__atomic/support/common.h
@@ -42,7 +42,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp&& __obj) noex
 }
 
 template <class _Tp, class _Up, class _CasFunc>
-_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {
+_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
   if constexpr (!__needs_clear_padding<remove_cv_t<_Tp>>::value) {
     return __cas_func(__expected, std::forward<_Up>(__value));
   } else {

>From eeba3a79262faf7875f31d516b5a5835e7e774eb Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 4 Jul 2026 15:31:21 +0100
Subject: [PATCH 08/36] review comments batch 1

---
 libcxx/include/__atomic/support/c11.h         |   6 +-
 libcxx/include/__atomic/support/common.h      |  18 +-
 libcxx/include/__atomic/support/gcc.h         |  13 +-
 .../atomics.types.generic/padding.pass.cpp    | 114 +++++++
 .../atomics.types.generic/padding.pass.cpp    | 316 ++++++++----------
 5 files changed, 266 insertions(+), 201 deletions(-)
 create mode 100644 libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp

diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index c55de19cd4b59..0cf50d7ebd1ec 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -162,7 +162,7 @@ template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __c11_atomic_compare_exchange_strong(
             std::addressof(__a->__a_value),
@@ -180,7 +180,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     _Tp __value,
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __c11_atomic_compare_exchange_weak(
             std::addressof(__a->__a_value),
@@ -195,7 +195,7 @@ template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __c11_atomic_compare_exchange_weak(
             std::addressof(__a->__a_value),
diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/support/common.h
index 16bb21e46f88e..308302f8754a5 100644
--- a/libcxx/include/__atomic/support/common.h
+++ b/libcxx/include/__atomic/support/common.h
@@ -33,7 +33,7 @@ struct __needs_clear_padding
     : _And<_Not<has_unique_object_representations<_Tp>>, _Not<is_same<_Tp, float>>, _Not<is_same<_Tp, double>>> {};
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp&& __obj) noexcept {
+_LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp& __obj) noexcept {
   if constexpr (__needs_clear_padding<remove_cvref_t<_Tp>>::value) {
     if (!__builtin_is_constant_evaluated()) {
       __builtin_clear_padding(std::addressof(__obj));
@@ -44,12 +44,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp&& __obj) noex
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
   if constexpr (!__needs_clear_padding<remove_cv_t<_Tp>>::value) {
-    return __cas_func(__expected, std::forward<_Up>(__value));
+    return __cas_func(__expected, __value);
   } else {
     std::__clear_padding_if_needed(__value);
     remove_cv_t<_Tp> __expected_copy = *__expected;
     std::__clear_padding_if_needed(__expected_copy);
-    if (__cas_func(std::addressof(__expected_copy), std::forward<_Up>(__value))) {
+    if (__cas_func(std::addressof(__expected_copy), __value)) {
       return true;
     } else {
       std::memcpy(__expected, std::addressof(__expected_copy), sizeof(remove_cv_t<_Tp>));
@@ -61,17 +61,11 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up
 #else // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI
-#  if _LIBCPP_STD_VER >= 14
-// c++11 does not allow constexpr functions to return void
-constexpr
-#  endif
-    void __clear_padding_if_needed(_Tp&&) _NOEXCEPT {
-}
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __clear_padding_if_needed(_Tp&) _NOEXCEPT {}
 
 template <class _Tp, class _Up, class _CasFunc>
-_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up&& __value, _CasFunc&& __cas_func) {
-  return __cas_func(__expected, std::forward<_Up>(__value));
+_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
+  return __cas_func(__expected, __value);
 }
 
 #endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 640f6e5e916ca..44f1229f859b3 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -63,11 +63,8 @@ struct __cxx_atomic_base_impl {
   __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
 #endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
-    // gcc c++11 mode constexpr constructor requires empty body
-#if _LIBCPP_STD_VER >= 14
+  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
     std::__clear_padding_if_needed(__a_value);
-#endif
   }
   _Tp __a_value;
 };
@@ -157,7 +154,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     _Tp __value,
     memory_order __success,
     memory_order __failure) {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __atomic_compare_exchange(
             std::addressof(__a->__a_value),
@@ -172,7 +169,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __atomic_compare_exchange(
             std::addressof(__a->__a_value),
@@ -191,7 +188,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     _Tp __value,
     memory_order __success,
     memory_order __failure) {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __atomic_compare_exchange(
             std::addressof(__a->__a_value),
@@ -206,7 +203,7 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) {
-  return __atomic_cas_with_clear_padding(
+  return std::__atomic_cas_with_clear_padding(
       __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
         return __atomic_compare_exchange(
             std::addressof(__a->__a_value),
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
new file mode 100644
index 0000000000000..78674a3f85204
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// atomic_init is deprecated
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// atomic<T>::compare_exchange_weak
+// atomic<T>::compare_exchange_strong
+// libc++ maintains the invariant of the atomic to have zero for all padding bits
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <type_traits>
+
+struct Foo {
+  int i;
+  char c;
+};
+
+static_assert(!std::has_unique_object_representations_v<Foo>);
+static_assert(sizeof(Foo) > sizeof(int) + sizeof(char));
+
+Foo make_foo(int i, char c, unsigned char pad_byte) {
+  Foo f;
+  std::memset(&f, pad_byte, sizeof(Foo));
+  f.i = i;
+  f.c = c;
+  return f;
+}
+
+void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+  alignas(Foo) unsigned char buf[sizeof(Foo)];
+  std::memset(buf, pad_byte, sizeof(Foo));
+  Foo& reference = *reinterpret_cast<Foo*>(buf);
+  reference.i    = f.i;
+  reference.c    = f.c;
+  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
+}
+
+void test() {
+  {
+    // atomic();
+    std::atomic<Foo> a;
+    Foo loaded = a.load();
+    assert(loaded.i == 0);
+    assert(loaded.c == '\0');
+    assert_foo_padding(loaded, 0);
+  }
+
+  {
+    // atomic(T);
+    Foo init = make_foo(10, 'a', 0xBB);
+    assert_foo_padding(init, 0xBB);
+    std::atomic<Foo> a(init);
+    Foo loaded = a.load();
+    assert(loaded.i == 10);
+    assert(loaded.c == 'a');
+    assert_foo_padding(loaded, 0);
+  }
+  {
+    // atomic::store
+    std::atomic<Foo> a;
+    Foo value = make_foo(5, 'x', 0xAB);
+    assert_foo_padding(value, 0xAB);
+    a.store(value);
+    Foo loaded = a.load();
+    assert(loaded.i == 5);
+    assert(loaded.c == 'x');
+    assert_foo_padding(loaded, 0);
+  }
+  {
+    // atomic::exchange
+    Foo initial = make_foo(1, 'a', 0x00);
+    assert_foo_padding(initial, 0x00);
+    std::atomic<Foo> a(initial);
+    Foo new_val = make_foo(2, 'b', 0xCD);
+    assert_foo_padding(new_val, 0xCD);
+    Foo old = a.exchange(new_val);
+    assert(old.i == 1);
+    assert(old.c == 'a');
+    assert_foo_padding(old, 0);
+    Foo loaded = a.load();
+    assert(loaded.i == 2);
+    assert(loaded.c == 'b');
+    assert_foo_padding(loaded, 0);
+  }
+  {
+    // atomic_init
+    std::atomic<Foo> a;
+    Foo init = make_foo(7, 'z', 0xEF);
+    assert_foo_padding(init, 0xEF);
+    std::atomic_init(&a, init);
+    Foo loaded = a.load();
+    assert(loaded.i == 7);
+    assert(loaded.c == 'z');
+    assert_foo_padding(loaded, 0);
+  }
+}
+
+int main(int, char**) {
+// TODO(LLVM-23): Switch to XFAIL: clang-22
+#if __has_builtin(__builtin_clear_padding)
+  test();
+#endif
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 38b4428f3a271..e5fa3b96fc1d0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -10,9 +10,12 @@
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
 
+// atomic<T>::compare_exchange_weak
+// atomic<T>::compare_exchange_strong
+// CAS should work on types with padding bits
+
 #include <atomic>
 #include <cassert>
-#include <chrono>
 #include <cstring>
 #include <type_traits>
 
@@ -41,203 +44,160 @@ void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
   assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
 }
 
-#if __has_builtin(__builtin_clear_padding)
-
-void test_default_constructor() {
-  std::atomic<Foo> a;
-  Foo loaded = a.load();
-  assert(loaded.i == 0);
-  assert(loaded.c == '\0');
-  assert_foo_padding(loaded, 0);
-}
-
-void test_value_constructor() {
-  Foo init = make_foo(10, 'a', 0xBB);
-  assert_foo_padding(init, 0xBB);
-  std::atomic<Foo> a(init);
-  Foo loaded = a.load();
-  assert(loaded.i == 10);
-  assert(loaded.c == 'a');
-  assert_foo_padding(loaded, 0);
-}
-
-void test_store() {
-  std::atomic<Foo> a;
-  Foo value = make_foo(5, 'x', 0xAB);
-  assert_foo_padding(value, 0xAB);
-  a.store(value);
-  Foo loaded = a.load();
-  assert(loaded.i == 5);
-  assert(loaded.c == 'x');
-  assert_foo_padding(loaded, 0);
-}
-
-void test_exchange() {
-  Foo initial = make_foo(1, 'a', 0x00);
-  assert_foo_padding(initial, 0x00);
-  std::atomic<Foo> a(initial);
-  Foo new_val = make_foo(2, 'b', 0xCD);
-  assert_foo_padding(new_val, 0xCD);
-  Foo old = a.exchange(new_val);
-  assert(old.i == 1);
-  assert(old.c == 'a');
-  assert_foo_padding(old, 0);
-  Foo loaded = a.load();
-  assert(loaded.i == 2);
-  assert(loaded.c == 'b');
-  assert_foo_padding(loaded, 0);
+void libcpp_assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+#ifdef _LIBCPP_VERSION
+  assert_foo_padding(f, pad_byte);
+#else
+  (void)f;
+  (void)pad_byte;
+#endif
 }
 
-void test_atomic_init() {
-  std::atomic<Foo> a;
-  Foo init = make_foo(7, 'z', 0xEF);
-  assert_foo_padding(init, 0xEF);
-  std::atomic_init(&a, init);
-  Foo loaded = a.load();
-  assert(loaded.i == 7);
-  assert(loaded.c == 'z');
-  assert_foo_padding(loaded, 0);
-}
+void test() {
+  {
+    // compare_exchange_strong
+    // CAS should succeed when only padding differs in expected; expected is unchanged.
+    std::atomic<Foo> a;
 
-void test_compare_exchange_strong_success_padding_only() {
-  // CAS should succeed when only padding differs in expected; expected is unchanged.
-  std::atomic<Foo> a;
+    Foo init = make_foo(10, 'a', 0xBB);
+    assert_foo_padding(init, 0xBB);
+    a.store(init);
 
-  Foo init = make_foo(10, 'a', 0xBB);
-  assert_foo_padding(init, 0xBB);
-  a.store(init);
+    Foo expected = make_foo(10, 'a', 0xAA);
+    assert_foo_padding(expected, 0xAA);
 
-  Foo expected = make_foo(10, 'a', 0xAA);
-  assert_foo_padding(expected, 0xAA);
+    Foo original_expected; // make a copy including padding bits
+    std::memcpy(&original_expected, &expected, sizeof(Foo));
 
-Foo original_expected; // make a copy including padding bits
-std::memcpy(&original_expected, expected, sizeof(Foo));
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    assert_foo_padding(new_value, 0xCC);
 
-  Foo new_value = make_foo(42, 'b', 0xCC);
-  assert_foo_padding(new_value, 0xCC);
+    bool r = a.compare_exchange_strong(expected, new_value);
 
-  bool r = a.compare_exchange_strong(expected, new_value);
+    assert(r);
+    assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+    Foo loaded = a.load();
+    assert(loaded.i == 42);
+    assert(loaded.c == 'b');
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+  }
 
-  assert(r);
-  assert(std::memcmp(&expected, original_expected, sizeof(Foo)) == 0);
-  Foo loaded = a.load();
-  assert(loaded.i == 42);
-  assert(loaded.c == 'b');
-  assert_foo_padding(loaded, 0);
-}
+  {
+    // compare_exchange_strong
+    // atomic and expected values are different; failure
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    assert_foo_padding(stored, 0xBB);
+    a.store(stored);
 
-void test_compare_exchange_strong_failure() {
-  std::atomic<Foo> a;
-  Foo stored = make_foo(10, 'a', 0xBB);
-  assert_foo_padding(stored, 0xBB);
-  a.store(stored);
-
-  Foo expected = make_foo(99, 'a', 0xAA);
-  assert_foo_padding(expected, 0xAA);
-  Foo new_value = make_foo(42, 'b', 0xCC);
-  assert_foo_padding(new_value, 0xCC);
-
-  bool r = a.compare_exchange_strong(expected, new_value);
-
-  assert(!r);
-  assert(expected.i == 10);
-  assert(expected.c == 'a');
-  assert_foo_padding(expected, 0);
-  Foo loaded = a.load();
-  assert(loaded.i == 10);
-  assert(loaded.c == 'a');
-  assert_foo_padding(loaded, 0);
-}
+    Foo expected = make_foo(99, 'a', 0xAA);
+    assert_foo_padding(expected, 0xAA);
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    assert_foo_padding(new_value, 0xCC);
+
+    bool r = a.compare_exchange_strong(expected, new_value);
+
+    assert(!r);
+    assert(expected.i == 10);
+    assert(expected.c == 'a');
+    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    libcpp_assert_foo_padding(expected, 0);
+    Foo loaded = a.load();
+    assert(loaded.i == 10);
+    assert(loaded.c == 'a');
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+  }
 
-void test_compare_exchange_weak_success_padding_only() {
-  std::atomic<Foo> a;
-  Foo stored = make_foo(10, 'a', 0xBB);
-  assert_foo_padding(stored, 0xBB);
-  a.store(stored);
+  {
+    // compare_exchange_weak
+    // atomic and expected only differs in padding bits. It should either succeed or spuriously fail
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    assert_foo_padding(stored, 0xBB);
+    a.store(stored);
+
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    assert_foo_padding(new_value, 0xCC);
+
+    Foo original_expected = make_foo(10, 'a', 0xAA);
+    assert_foo_padding(original_expected, 0xAA);
+
+    bool r                  = false;
+    const auto max_attempts = 100;
+    auto current_attempt    = 0;
+    while (!r) {
+      ++current_attempt;
+      assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
+      Foo expected = make_foo(10, 'a', 0xAA);
+      assert_foo_padding(expected, 0xAA);
+      r = a.compare_exchange_weak(expected, new_value);
+      if (r) {
+        assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+      } else {
+        // Spurious failure: expected is updated to the current atomic value.
+        assert(expected.i == 10);
+        assert(expected.c == 'a');
+        // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+        libcpp_assert_foo_padding(expected, 0);
+      }
+    }
 
-  Foo new_value = make_foo(42, 'b', 0xCC);
-  assert_foo_padding(new_value, 0xCC);
+    Foo loaded = a.load();
+    assert(loaded.i == 42);
+    assert(loaded.c == 'b');
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+  }
 
-  Foo original_expected = make_foo(10, 'a', 0xAA);
-  assert_foo_padding(original_expected, 0xAA);
+  {
+    // compare_exchange_strong
+    // atomic and expected values are different; failure
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    assert_foo_padding(stored, 0xBB);
+    a.store(stored);
 
-  bool r              = false;
-  const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(3);
-  while (!r) {
-    assert(std::chrono::steady_clock::now() < deadline && "compare_exchange_weak did not succeed within 3 seconds");
-    Foo expected = make_foo(10, 'a', 0xAA);
+    Foo expected = make_foo(99, 'a', 0xAA);
     assert_foo_padding(expected, 0xAA);
-    r = a.compare_exchange_weak(expected, new_value);
-    if (r) {
-      assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
-    } else {
-      // Spurious failure: expected is updated to the current atomic value.
-      assert(expected.i == 10);
-      assert(expected.c == 'a');
-      assert_foo_padding(expected, 0);
-    }
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    assert_foo_padding(new_value, 0xCC);
+
+    bool r = a.compare_exchange_weak(expected, new_value);
+
+    assert(!r);
+    assert(expected.i == 10);
+    assert(expected.c == 'a');
+    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    libcpp_assert_foo_padding(expected, 0);
+    Foo loaded = a.load();
+    assert(loaded.i == 10);
+    assert(loaded.c == 'a');
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
   }
 
-  Foo loaded = a.load();
-  assert(loaded.i == 42);
-  assert(loaded.c == 'b');
-  assert_foo_padding(loaded, 0);
-}
-
-void test_compare_exchange_weak_failure() {
-  std::atomic<Foo> a;
-  Foo stored = make_foo(10, 'a', 0xBB);
-  assert_foo_padding(stored, 0xBB);
-  a.store(stored);
-
-  Foo expected = make_foo(99, 'a', 0xAA);
-  assert_foo_padding(expected, 0xAA);
-  Foo new_value = make_foo(42, 'b', 0xCC);
-  assert_foo_padding(new_value, 0xCC);
-
-  bool r = a.compare_exchange_weak(expected, new_value);
-
-  assert(!r);
-  assert(expected.i == 10);
-  assert(expected.c == 'a');
-  assert_foo_padding(expected, 0);
-  Foo loaded = a.load();
-  assert(loaded.i == 10);
-  assert(loaded.c == 'a');
-  assert_foo_padding(loaded, 0);
-}
-
-void test_no_padding_type() {
-  // Types with unique object representations skip the padding-clearing path.
-  std::atomic<int> a(1);
-  int expected = 1;
-  assert(a.compare_exchange_strong(expected, 2));
-  assert(expected == 1);
-  assert(a.load() == 2);
-
-  expected = 3;
-  assert(!a.compare_exchange_strong(expected, 4));
-  assert(expected == 2);
-  assert(a.load() == 2);
+  {
+    // Types with unique object representations skip the padding-clearing path.
+    std::atomic<int> a(1);
+    int expected = 1;
+    assert(a.compare_exchange_strong(expected, 2));
+    assert(expected == 1);
+    assert(a.load() == 2);
+
+    expected = 3;
+    assert(!a.compare_exchange_strong(expected, 4));
+    assert(expected == 2);
+    assert(a.load() == 2);
+  }
 }
 
 int main(int, char**) {
-  test_default_constructor();
-  test_value_constructor();
-  test_store();
-  test_exchange();
-  test_atomic_init();
-  test_compare_exchange_strong_success_padding_only();
-  test_compare_exchange_strong_failure();
-  test_compare_exchange_weak_success_padding_only();
-  test_compare_exchange_weak_failure();
-  test_no_padding_type();
+// TODO(LLVM-23): Switch to XFAIL: clang-22
+#if __has_builtin(__builtin_clear_padding)
+  test();
+#endif // __has_builtin(__builtin_clear_padding)
 
   return 0;
 }
-
-#else // !__has_builtin(__builtin_clear_padding)
-
-int main(int, char**) { return 0; }
-
-#endif // __has_builtin(__builtin_clear_padding)

>From 3fa879ba2c3283983e2da249ed5c994bf51fa319 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 6 Jul 2026 15:26:28 +0100
Subject: [PATCH 09/36] batch2

---
 libcxx/include/CMakeLists.txt                 |  2 +-
 .../{support/common.h => clear_padding.h}     | 27 ++++++++++---------
 libcxx/include/__atomic/support/c11.h         | 25 ++++-------------
 libcxx/include/__atomic/support/gcc.h         | 20 +++-----------
 libcxx/include/module.modulemap.in            |  2 +-
 .../atomics.types.generic/padding.pass.cpp    |  7 ++---
 .../atomics.types.generic/padding.pass.cpp    |  5 ++--
 7 files changed, 29 insertions(+), 59 deletions(-)
 rename libcxx/include/__atomic/{support/common.h => clear_padding.h} (69%)

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index afbd3a3215d9f..c0270f1bff484 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -219,6 +219,7 @@ set(files
   __atomic/atomic_sync_timed.h
   __atomic/atomic_waitable_traits.h
   __atomic/check_memory_order.h
+  __atomic/clear_padding.h
   __atomic/contention_t.h
   __atomic/fence.h
   __atomic/floating_point_helper.h
@@ -227,7 +228,6 @@ set(files
   __atomic/memory_order.h
   __atomic/support.h
   __atomic/support/c11.h
-  __atomic/support/common.h
   __atomic/support/gcc.h
   __atomic/to_gcc_order.h
   __bit/bit_cast.h
diff --git a/libcxx/include/__atomic/support/common.h b/libcxx/include/__atomic/clear_padding.h
similarity index 69%
rename from libcxx/include/__atomic/support/common.h
rename to libcxx/include/__atomic/clear_padding.h
index 308302f8754a5..ac83939d6ec16 100644
--- a/libcxx/include/__atomic/support/common.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -6,13 +6,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___ATOMIC_SUPPORT_COMMON_H
-#define _LIBCPP___ATOMIC_SUPPORT_COMMON_H
+#ifndef _LIBCPP___ATOMIC_CLEAR_PADDING_H
+#define _LIBCPP___ATOMIC_CLEAR_PADDING_H
 
 #include <__config>
 #include <__memory/addressof.h>
 #include <__type_traits/conjunction.h>
 #include <__type_traits/has_unique_object_representation.h>
+#include <__type_traits/integral_constant.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/negation.h>
 #include <__type_traits/remove_cv.h>
@@ -26,15 +27,17 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+#if __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
 struct __needs_clear_padding
-    : _And<_Not<has_unique_object_representations<_Tp>>, _Not<is_same<_Tp, float>>, _Not<is_same<_Tp, double>>> {};
+    : _And<_Not<integral_constant<bool, __has_unique_object_representations(_Tp)>>,
+           _Not<is_same<_Tp, float>>,
+           _Not<is_same<_Tp, double>>> {};
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp& __obj) noexcept {
-  if constexpr (__needs_clear_padding<remove_cvref_t<_Tp>>::value) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __clear_padding_if_needed(_Tp& __obj) noexcept {
+  if constexpr (__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
     if (!__builtin_is_constant_evaluated()) {
       __builtin_clear_padding(std::addressof(__obj));
     }
@@ -43,22 +46,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __clear_padding_if_needed(_Tp& __obj) noexc
 
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
-  if constexpr (!__needs_clear_padding<remove_cv_t<_Tp>>::value) {
+  if constexpr (!__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
     return __cas_func(__expected, __value);
   } else {
     std::__clear_padding_if_needed(__value);
-    remove_cv_t<_Tp> __expected_copy = *__expected;
+    __remove_cvref_t<_Tp> __expected_copy = *__expected;
     std::__clear_padding_if_needed(__expected_copy);
     if (__cas_func(std::addressof(__expected_copy), __value)) {
       return true;
     } else {
-      std::memcpy(__expected, std::addressof(__expected_copy), sizeof(remove_cv_t<_Tp>));
+      std::memcpy(__expected, std::addressof(__expected_copy), sizeof(__remove_cvref_t<_Tp>));
       return false;
     }
   }
 }
 
-#else // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+#else // __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __clear_padding_if_needed(_Tp&) _NOEXCEPT {}
@@ -68,8 +71,8 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up
   return __cas_func(__expected, __value);
 }
 
-#endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+#endif // __has_builtin(__builtin_clear_padding)
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP___ATOMIC_SUPPORT_COMMON_H
+#endif // _LIBCPP___ATOMIC_CLEAR_PADDING_H
diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index 0cf50d7ebd1ec..05b22d04962fa 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -9,8 +9,8 @@
 #ifndef _LIBCPP___ATOMIC_SUPPORT_C11_H
 #define _LIBCPP___ATOMIC_SUPPORT_C11_H
 
+#include <__atomic/clear_padding.h>
 #include <__atomic/memory_order.h>
-#include <__atomic/support/common.h>
 #include <__config>
 #include <__cstddef/ptrdiff_t.h>
 #include <__memory/addressof.h>
@@ -30,29 +30,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <typename _Tp>
 struct __cxx_atomic_base_impl {
-  _LIBCPP_HIDE_FROM_ABI
-#ifndef _LIBCPP_CXX03_LANG
-  __cxx_atomic_base_impl() _NOEXCEPT = default;
-
-#  if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
-  __cxx_atomic_base_impl() noexcept
-    requires __needs_clear_padding<_Tp>::value
-      : __a_value() {
-    if (!__builtin_is_constant_evaluated()) {
-      __builtin_clear_padding(__a_value);
-    }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
+    std::__clear_padding_if_needed(__a_value);
   }
-#  endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
 
-#else
-  __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
-  }
-#endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
-#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
     std::__clear_padding_if_needed(__a_value);
-#endif
   }
+
   _Atomic(_Tp) __a_value;
 };
 
diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 44f1229f859b3..0a6e3d54b5911 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -9,8 +9,8 @@
 #ifndef _LIBCPP___ATOMIC_SUPPORT_GCC_H
 #define _LIBCPP___ATOMIC_SUPPORT_GCC_H
 
+#include <__atomic/clear_padding.h>
 #include <__atomic/memory_order.h>
-#include <__atomic/support/common.h>
 #include <__atomic/to_gcc_order.h>
 #include <__config>
 #include <__memory/addressof.h>
@@ -46,23 +46,9 @@ _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp volatile& __a_value,
 
 template <typename _Tp>
 struct __cxx_atomic_base_impl {
+  _LIBCPP_HIDE_FROM_ABI __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { std::__clear_padding_if_needed(__a_value); }
+
   _LIBCPP_HIDE_FROM_ABI
-#ifndef _LIBCPP_CXX03_LANG
-  __cxx_atomic_base_impl() _NOEXCEPT = default;
-
-#  if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
-  __cxx_atomic_base_impl() noexcept
-    requires __needs_clear_padding<_Tp>::value
-      : __a_value() {
-    if (!__builtin_is_constant_evaluated()) {
-      __builtin_clear_padding(__a_value);
-    }
-  }
-#  endif // _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_clear_padding)
-#else
-  __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
-  }
-#endif // _LIBCPP_CXX03_LANG
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
     std::__clear_padding_if_needed(__a_value);
   }
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 3fcb803796f0e..49789849e30a0 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -885,6 +885,7 @@ module std {
       export std.atomic.atomic_base // most of std::atomic methods are defined there
     }
     module check_memory_order     { header "__atomic/check_memory_order.h" }
+    module clear_padding          { header "__atomic/clear_padding.h" }
     module contention_t           { header "__atomic/contention_t.h" }
     module fence                  { header "__atomic/fence.h" }
     module floating_point_helper  { header "__atomic/floating_point_helper.h" }
@@ -896,7 +897,6 @@ module std {
     module support {
       header "__atomic/support.h"
       textual header "__atomic/support/c11.h"
-      textual header "__atomic/support/common.h"
       textual header "__atomic/support/gcc.h"
     }
 
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 78674a3f85204..e422e1c7e3e83 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -5,7 +5,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: c++03
 
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
@@ -16,17 +16,14 @@
 
 #include <atomic>
 #include <cassert>
-#include <chrono>
 #include <cstring>
-#include <type_traits>
 
 struct Foo {
   int i;
   char c;
 };
 
-static_assert(!std::has_unique_object_representations_v<Foo>);
-static_assert(sizeof(Foo) > sizeof(int) + sizeof(char));
+static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
 
 Foo make_foo(int i, char c, unsigned char pad_byte) {
   Foo f;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index e5fa3b96fc1d0..c09745a3d149f 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -5,7 +5,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: c++03
 
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
@@ -24,8 +24,7 @@ struct Foo {
   char c;
 };
 
-static_assert(!std::has_unique_object_representations_v<Foo>);
-static_assert(sizeof(Foo) > sizeof(int) + sizeof(char));
+static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
 
 Foo make_foo(int i, char c, unsigned char pad_byte) {
   Foo f;

>From 1abdef2c08fdc3f1446cda02ecc531c90a7f79c2 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 10:06:00 +0100
Subject: [PATCH 10/36] CI

---
 libcxx/include/__atomic/clear_padding.h                  | 9 +++++++--
 .../std/atomics/atomics.types.generic/padding.pass.cpp   | 2 +-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index ac83939d6ec16..5bc77ff4401ab 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -36,12 +36,14 @@ struct __needs_clear_padding
            _Not<is_same<_Tp, double>>> {};
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __clear_padding_if_needed(_Tp& __obj) noexcept {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
   if constexpr (__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
     if (!__builtin_is_constant_evaluated()) {
       __builtin_clear_padding(std::addressof(__obj));
     }
   }
+  // return __obj as c++11 does not constexpr function to return void
+  return __obj;
 }
 
 template <class _Tp, class _Up, class _CasFunc>
@@ -64,7 +66,10 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up
 #else // __has_builtin(__builtin_clear_padding)
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __clear_padding_if_needed(_Tp&) _NOEXCEPT {}
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
+  // return __obj as c++11 does not constexpr function to return void
+  return __obj;
+}
 
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index c09745a3d149f..dbd93ea9f2cfb 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -196,7 +196,7 @@ int main(int, char**) {
 // TODO(LLVM-23): Switch to XFAIL: clang-22
 #if __has_builtin(__builtin_clear_padding)
   test();
-#endif // __has_builtin(__builtin_clear_padding)
+#endif
 
   return 0;
 }

>From ce496f1e1cd1897c64d6082be0ebfd308c8a82e4 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 16:44:53 +0100
Subject: [PATCH 11/36] review comment

---
 libcxx/include/__atomic/support/gcc.h         |   7 +-
 .../atomics.types.generic/padding.pass.cpp    | 112 ++++---
 .../atomics.types.generic/padding.pass.cpp    | 153 ++++++----
 .../atomics.types.generic/padding2.pass.cpp   | 276 ++++++++++++++++++
 4 files changed, 439 insertions(+), 109 deletions(-)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp

diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 0a6e3d54b5911..2f6e0d5dbd20a 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -46,10 +46,11 @@ _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp volatile& __a_value,
 
 template <typename _Tp>
 struct __cxx_atomic_base_impl {
-  _LIBCPP_HIDE_FROM_ABI __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { std::__clear_padding_if_needed(__a_value); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
+    std::__clear_padding_if_needed(__a_value);
+  }
 
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
     std::__clear_padding_if_needed(__a_value);
   }
   _Tp __a_value;
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index e422e1c7e3e83..c8176b1940843 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -18,94 +18,120 @@
 #include <cassert>
 #include <cstring>
 
-struct Foo {
+struct WithTailPadding {
   int i;
   char c;
 };
 
-static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
+static_assert(sizeof(WithTailPadding) > sizeof(int) + sizeof(char), "");
 
-Foo make_foo(int i, char c, unsigned char pad_byte) {
-  Foo f;
-  std::memset(&f, pad_byte, sizeof(Foo));
-  f.i = i;
-  f.c = c;
-  return f;
+struct WithInternalPadding {
+  char c;
+  int i;
+};
+
+static_assert(sizeof(WithInternalPadding) > sizeof(int) + sizeof(char), "");
+
+struct WithInternalAndTailPadding {
+  char c;
+  int i;
+  char c2;
+};
+
+static_assert(sizeof(WithInternalAndTailPadding) > sizeof(int) + 2 * sizeof(char), "");
+
+template <class T>
+T make(int i, char c, unsigned char pad_byte) {
+  T obj;
+  std::memset(&obj, pad_byte, sizeof(T));
+  obj.i = i;
+  obj.c = c;
+  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+    obj.c2 = c;
+  }
+  return obj;
 }
 
-void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
-  alignas(Foo) unsigned char buf[sizeof(Foo)];
-  std::memset(buf, pad_byte, sizeof(Foo));
-  Foo& reference = *reinterpret_cast<Foo*>(buf);
-  reference.i    = f.i;
-  reference.c    = f.c;
-  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
+template <class T>
+void assert_padding(const T& obj, unsigned char pad_byte) {
+  alignas(T) unsigned char buf[sizeof(T)];
+  std::memset(buf, pad_byte, sizeof(T));
+  T& reference = *reinterpret_cast<T*>(buf);
+  reference.i  = obj.i;
+  reference.c  = obj.c;
+  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+    reference.c2 = obj.c2;
+  }
+  assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
+template <class T>
 void test() {
   {
     // atomic();
-    std::atomic<Foo> a;
-    Foo loaded = a.load();
+    std::atomic<T> a;
+    T loaded = a.load();
     assert(loaded.i == 0);
     assert(loaded.c == '\0');
-    assert_foo_padding(loaded, 0);
+    assert_padding(loaded, 0);
   }
 
   {
     // atomic(T);
-    Foo init = make_foo(10, 'a', 0xBB);
-    assert_foo_padding(init, 0xBB);
-    std::atomic<Foo> a(init);
-    Foo loaded = a.load();
+    T init = make<T>(10, 'a', 0xBB);
+    assert_padding(init, 0xBB);
+    std::atomic<T> a(init);
+    T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
-    assert_foo_padding(loaded, 0);
+    assert_padding(loaded, 0);
   }
   {
     // atomic::store
-    std::atomic<Foo> a;
-    Foo value = make_foo(5, 'x', 0xAB);
-    assert_foo_padding(value, 0xAB);
+    std::atomic<T> a;
+    T value = make<T>(5, 'x', 0xAB);
+    assert_padding(value, 0xAB);
     a.store(value);
-    Foo loaded = a.load();
+    T loaded = a.load();
     assert(loaded.i == 5);
     assert(loaded.c == 'x');
-    assert_foo_padding(loaded, 0);
+    assert_padding(loaded, 0);
   }
   {
     // atomic::exchange
-    Foo initial = make_foo(1, 'a', 0x00);
-    assert_foo_padding(initial, 0x00);
-    std::atomic<Foo> a(initial);
-    Foo new_val = make_foo(2, 'b', 0xCD);
-    assert_foo_padding(new_val, 0xCD);
-    Foo old = a.exchange(new_val);
+    T initial = make<T>(1, 'a', 0x00);
+    assert_padding(initial, 0x00);
+    std::atomic<T> a(initial);
+    T new_val = make<T>(2, 'b', 0xCD);
+    assert_padding(new_val, 0xCD);
+    T old = a.exchange(new_val);
     assert(old.i == 1);
     assert(old.c == 'a');
-    assert_foo_padding(old, 0);
-    Foo loaded = a.load();
+    assert_padding(old, 0);
+    T loaded = a.load();
     assert(loaded.i == 2);
     assert(loaded.c == 'b');
-    assert_foo_padding(loaded, 0);
+    assert_padding(loaded, 0);
   }
   {
     // atomic_init
-    std::atomic<Foo> a;
-    Foo init = make_foo(7, 'z', 0xEF);
-    assert_foo_padding(init, 0xEF);
+    std::atomic<T> a;
+    T init = make<T>(7, 'z', 0xEF);
+    assert_padding(init, 0xEF);
     std::atomic_init(&a, init);
-    Foo loaded = a.load();
+    T loaded = a.load();
     assert(loaded.i == 7);
     assert(loaded.c == 'z');
-    assert_foo_padding(loaded, 0);
+    assert_padding(loaded, 0);
   }
 }
 
 int main(int, char**) {
 // TODO(LLVM-23): Switch to XFAIL: clang-22
 #if __has_builtin(__builtin_clear_padding)
-  test();
+  test<WithTailPadding>();
+  test<WithInternalPadding>();
+  test<WithInternalAndTailPadding>();
 #endif
   return 0;
 }
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index dbd93ea9f2cfb..d7889f2a1ed4d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -19,81 +19,106 @@
 #include <cstring>
 #include <type_traits>
 
-struct Foo {
+struct WithTailPadding {
   int i;
   char c;
 };
 
-static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
+static_assert(sizeof(WithTailPadding) > sizeof(int) + sizeof(char), "");
 
-Foo make_foo(int i, char c, unsigned char pad_byte) {
-  Foo f;
-  std::memset(&f, pad_byte, sizeof(Foo));
-  f.i = i;
-  f.c = c;
-  return f;
+struct WithInternalPadding {
+  char c;
+  int i;
+};
+
+static_assert(sizeof(WithInternalPadding) > sizeof(int) + sizeof(char), "");
+
+struct WithInternalAndTailPadding {
+  char c;
+  int i;
+  char c2;
+};
+
+static_assert(sizeof(WithInternalAndTailPadding) > sizeof(int) + 2 * sizeof(char), "");
+
+template <class T>
+T make(int i, char c, unsigned char pad_byte) {
+  T obj;
+  std::memset(&obj, pad_byte, sizeof(T));
+  obj.i = i;
+  obj.c = c;
+  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+    obj.c2 = c;
+  }
+  return obj;
 }
 
-void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
-  alignas(Foo) unsigned char buf[sizeof(Foo)];
-  std::memset(buf, pad_byte, sizeof(Foo));
-  Foo& reference = *reinterpret_cast<Foo*>(buf);
-  reference.i    = f.i;
-  reference.c    = f.c;
-  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
+template <class T>
+void assert_padding(const T& obj, unsigned char pad_byte) {
+  alignas(T) unsigned char buf[sizeof(T)];
+  std::memset(buf, pad_byte, sizeof(T));
+  T& reference = *reinterpret_cast<T*>(buf);
+  reference.i  = obj.i;
+  reference.c  = obj.c;
+  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+    reference.c2 = obj.c2;
+  }
+  assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
-void libcpp_assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+template <class T>
+void libcpp_assert_padding(const T& obj, unsigned char pad_byte) {
 #ifdef _LIBCPP_VERSION
-  assert_foo_padding(f, pad_byte);
+  assert_padding(obj, pad_byte);
 #else
   (void)f;
   (void)pad_byte;
 #endif
 }
 
+template <class T>
 void test() {
   {
     // compare_exchange_strong
     // CAS should succeed when only padding differs in expected; expected is unchanged.
-    std::atomic<Foo> a;
+    std::atomic<T> a;
 
-    Foo init = make_foo(10, 'a', 0xBB);
-    assert_foo_padding(init, 0xBB);
+    T init = make<T>(10, 'a', 0xBB);
+    assert_padding(init, 0xBB);
     a.store(init);
 
-    Foo expected = make_foo(10, 'a', 0xAA);
-    assert_foo_padding(expected, 0xAA);
+    T expected = make<T>(10, 'a', 0xAA);
+    assert_padding(expected, 0xAA);
 
-    Foo original_expected; // make a copy including padding bits
-    std::memcpy(&original_expected, &expected, sizeof(Foo));
+    T original_expected; // make a copy including padding bits
+    std::memcpy(&original_expected, &expected, sizeof(T));
 
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    assert_foo_padding(new_value, 0xCC);
+    T new_value = make<T>(42, 'b', 0xCC);
+    assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
 
     assert(r);
-    assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
-    Foo loaded = a.load();
+    assert(std::memcmp(&expected, &original_expected, sizeof(T)) == 0);
+    T loaded = a.load();
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
+    libcpp_assert_padding(loaded, 0);
   }
 
   {
     // compare_exchange_strong
     // atomic and expected values are different; failure
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    assert_foo_padding(stored, 0xBB);
+    std::atomic<T> a;
+    T stored = make<T>(10, 'a', 0xBB);
+    assert_padding(stored, 0xBB);
     a.store(stored);
 
-    Foo expected = make_foo(99, 'a', 0xAA);
-    assert_foo_padding(expected, 0xAA);
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    assert_foo_padding(new_value, 0xCC);
+    T expected = make<T>(99, 'a', 0xAA);
+    assert_padding(expected, 0xAA);
+    T new_value = make<T>(42, 'b', 0xCC);
+    assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
 
@@ -101,27 +126,27 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_foo_padding(expected, 0);
-    Foo loaded = a.load();
+    libcpp_assert_padding(expected, 0);
+    T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
+    libcpp_assert_padding(loaded, 0);
   }
 
   {
     // compare_exchange_weak
     // atomic and expected only differs in padding bits. It should either succeed or spuriously fail
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    assert_foo_padding(stored, 0xBB);
+    std::atomic<T> a;
+    T stored = make<T>(10, 'a', 0xBB);
+    assert_padding(stored, 0xBB);
     a.store(stored);
 
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    assert_foo_padding(new_value, 0xCC);
+    T new_value = make<T>(42, 'b', 0xCC);
+    assert_padding(new_value, 0xCC);
 
-    Foo original_expected = make_foo(10, 'a', 0xAA);
-    assert_foo_padding(original_expected, 0xAA);
+    T original_expected = make<T>(10, 'a', 0xAA);
+    assert_padding(original_expected, 0xAA);
 
     bool r                  = false;
     const auto max_attempts = 100;
@@ -129,39 +154,39 @@ void test() {
     while (!r) {
       ++current_attempt;
       assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
-      Foo expected = make_foo(10, 'a', 0xAA);
-      assert_foo_padding(expected, 0xAA);
+      T expected = make<T>(10, 'a', 0xAA);
+      assert_padding(expected, 0xAA);
       r = a.compare_exchange_weak(expected, new_value);
       if (r) {
-        assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+        assert(std::memcmp(&expected, &original_expected, sizeof(T)) == 0);
       } else {
         // Spurious failure: expected is updated to the current atomic value.
         assert(expected.i == 10);
         assert(expected.c == 'a');
         // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-        libcpp_assert_foo_padding(expected, 0);
+        libcpp_assert_padding(expected, 0);
       }
     }
 
-    Foo loaded = a.load();
+    T loaded = a.load();
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
+    libcpp_assert_padding(loaded, 0);
   }
 
   {
     // compare_exchange_strong
     // atomic and expected values are different; failure
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    assert_foo_padding(stored, 0xBB);
+    std::atomic<T> a;
+    T stored = make<T>(10, 'a', 0xBB);
+    assert_padding(stored, 0xBB);
     a.store(stored);
 
-    Foo expected = make_foo(99, 'a', 0xAA);
-    assert_foo_padding(expected, 0xAA);
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    assert_foo_padding(new_value, 0xCC);
+    T expected = make<T>(99, 'a', 0xAA);
+    assert_padding(expected, 0xAA);
+    T new_value = make<T>(42, 'b', 0xCC);
+    assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_weak(expected, new_value);
 
@@ -169,12 +194,12 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_foo_padding(expected, 0);
-    Foo loaded = a.load();
+    libcpp_assert_padding(expected, 0);
+    T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
+    libcpp_assert_padding(loaded, 0);
   }
 
   {
@@ -195,7 +220,9 @@ void test() {
 int main(int, char**) {
 // TODO(LLVM-23): Switch to XFAIL: clang-22
 #if __has_builtin(__builtin_clear_padding)
-  test();
+  test<WithTailPadding>();
+  test<WithInternalPadding>();
+  test<WithInternalAndTailPadding>();
 #endif
 
   return 0;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
new file mode 100644
index 0000000000000..4e17471a2461f
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
@@ -0,0 +1,276 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03
+// UNSUPPORTED: no-localization
+
+// atomic_init is deprecated
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// atomic<T>::compare_exchange_weak
+// atomic<T>::compare_exchange_strong
+// CAS should work on types with padding bits
+
+#include <atomic>
+#include <cassert>
+#include <cstring>
+#include <type_traits>
+#include <iostream>
+
+struct Foo {
+  int i;
+  char c;
+};
+
+static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
+
+Foo make_foo(int i, char c, unsigned char pad_byte) {
+  Foo f;
+  std::memset(&f, pad_byte, sizeof(Foo));
+  f.i = i;
+  f.c = c;
+  return f;
+}
+
+void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+  alignas(Foo) unsigned char buf[sizeof(Foo)];
+  std::memset(buf, pad_byte, sizeof(Foo));
+  Foo& reference = *reinterpret_cast<Foo*>(buf);
+  reference.i    = f.i;
+  reference.c    = f.c;
+  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
+}
+
+void libcpp_assert_foo_padding(const Foo& f, unsigned char pad_byte) {
+#ifdef _LIBCPP_VERSION
+  assert_foo_padding(f, pad_byte);
+#else
+  (void)f;
+  (void)pad_byte;
+#endif
+}
+
+void test() {
+  std::cerr << "test 1" << std::endl;
+  {
+    // compare_exchange_strong
+    // CAS should succeed when only padding differs in expected; expected is unchanged.
+    std::atomic<Foo> a;
+    std::cerr << "test 2" << std::endl;
+
+    Foo init = make_foo(10, 'a', 0xBB);
+    std::cerr << "test 3" << std::endl;
+    assert_foo_padding(init, 0xBB);
+    std::cerr << "test 4" << std::endl;
+    a.store(init);
+
+    Foo expected = make_foo(10, 'a', 0xAA);
+    std::cerr << "test 5" << std::endl;
+    assert_foo_padding(expected, 0xAA);
+    std::cerr << "test 6" << std::endl;
+
+    Foo original_expected; // make a copy including padding bits
+    std::memcpy(&original_expected, &expected, sizeof(Foo));
+
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    std::cerr << "test 7" << std::endl;
+    assert_foo_padding(new_value, 0xCC);
+    std::cerr << "test 8" << std::endl;
+
+    bool r = a.compare_exchange_strong(expected, new_value);
+
+    std::cerr << "test 9" << std::endl;
+    assert(r);
+    std::cerr << "test 10" << std::endl;
+    assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+    std::cerr << "test 11" << std::endl;
+    Foo loaded = a.load();
+    assert(loaded.i == 42);
+    std::cerr << "test 12" << std::endl;
+    assert(loaded.c == 'b');
+    std::cerr << "test 13" << std::endl;
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+    std::cerr << "test 14" << std::endl;
+  }
+
+  {
+    // compare_exchange_strong
+    // atomic and expected values are different; failure
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    std::cerr << "test 15" << std::endl;
+    assert_foo_padding(stored, 0xBB);
+    std::cerr << "test 16" << std::endl;
+    a.store(stored);
+
+    Foo expected = make_foo(99, 'a', 0xAA);
+    std::cerr << "test 17" << std::endl;
+    assert_foo_padding(expected, 0xAA);
+    std::cerr << "test 18" << std::endl;
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    std::cerr << "test 19" << std::endl;
+    assert_foo_padding(new_value, 0xCC);
+    std::cerr << "test 10" << std::endl;
+
+    bool r = a.compare_exchange_strong(expected, new_value);
+
+    std::cerr << "test 21" << std::endl;
+    assert(!r);
+    std::cerr << "test 22" << std::endl;
+    assert(expected.i == 10);
+    std::cerr << "test 23" << std::endl;
+    assert(expected.c == 'a');
+    std::cerr << "test 24" << std::endl;
+    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    libcpp_assert_foo_padding(expected, 0);
+    std::cerr << "test 25" << std::endl;
+    Foo loaded = a.load();
+    assert(loaded.i == 10);
+    std::cerr << "test 26" << std::endl;
+    assert(loaded.c == 'a');
+    std::cerr << "test 27" << std::endl;
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+    std::cerr << "test 28" << std::endl;
+  }
+
+  {
+    // compare_exchange_weak
+    // atomic and expected only differs in padding bits. It should either succeed or spuriously fail
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    std::cerr << "test 29" << std::endl;
+    assert_foo_padding(stored, 0xBB);
+    std::cerr << "test 30" << std::endl;
+    a.store(stored);
+
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    std::cerr << "test 31" << std::endl;
+    assert_foo_padding(new_value, 0xCC);
+    std::cerr << "test 32" << std::endl;
+
+    Foo original_expected = make_foo(10, 'a', 0xAA);
+    std::cerr << "test 33" << std::endl;
+    assert_foo_padding(original_expected, 0xAA);
+    std::cerr << "test 34" << std::endl;
+
+    bool r                  = false;
+    const auto max_attempts = 100;
+    auto current_attempt    = 0;
+    while (!r) {
+      ++current_attempt;
+      std::cerr << "test 35" << std::endl;
+      assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
+      std::cerr << "test 36" << std::endl;
+      Foo expected = make_foo(10, 'a', 0xAA);
+      assert_foo_padding(expected, 0xAA);
+      std::cerr << "test 37" << std::endl;
+      r = a.compare_exchange_weak(expected, new_value);
+      if (r) {
+        std::cerr << "test 38" << std::endl;
+        assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
+        std::cerr << "test 39" << std::endl;
+      } else {
+        // Spurious failure: expected is updated to the current atomic value.
+        std::cerr << "test 40" << std::endl;
+        assert(expected.i == 10);
+        std::cerr << "test 41" << std::endl;
+        assert(expected.c == 'a');
+        std::cerr << "test 45" << std::endl;
+        // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+        libcpp_assert_foo_padding(expected, 0);
+        std::cerr << "test 43" << std::endl;
+      }
+    }
+
+    Foo loaded = a.load();
+    std::cerr << "test 44" << std::endl;
+    assert(loaded.i == 42);
+    std::cerr << "test 45" << std::endl;
+    assert(loaded.c == 'b');
+    std::cerr << "test 46" << std::endl;
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+    std::cerr << "test 47" << std::endl;
+  }
+
+  {
+    // compare_exchange_strong
+    // atomic and expected values are different; failure
+    std::atomic<Foo> a;
+    Foo stored = make_foo(10, 'a', 0xBB);
+    std::cerr << "test 48" << std::endl;
+    assert_foo_padding(stored, 0xBB);
+    std::cerr << "test 49" << std::endl;
+    a.store(stored);
+
+    Foo expected = make_foo(99, 'a', 0xAA);
+    std::cerr << "test 50" << std::endl;
+    assert_foo_padding(expected, 0xAA);
+    std::cerr << "test 51" << std::endl;
+    Foo new_value = make_foo(42, 'b', 0xCC);
+    std::cerr << "test 52" << std::endl;
+    assert_foo_padding(new_value, 0xCC);
+    std::cerr << "test 53" << std::endl;
+
+    bool r = a.compare_exchange_weak(expected, new_value);
+
+    std::cerr << "test 54" << std::endl;
+    assert(!r);
+    std::cerr << "test 55" << std::endl;
+    assert(expected.i == 10);
+    std::cerr << "test 56" << std::endl;
+    assert(expected.c == 'a');
+    std::cerr << "test 57" << std::endl;
+    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    libcpp_assert_foo_padding(expected, 0);
+    std::cerr << "test 58" << std::endl;
+    Foo loaded = a.load();
+    std::cerr << "test 59" << std::endl;
+    assert(loaded.i == 10);
+    std::cerr << "test 60" << std::endl;
+    assert(loaded.c == 'a');
+    std::cerr << "test 61" << std::endl;
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_foo_padding(loaded, 0);
+    std::cerr << "test 62" << std::endl;
+  }
+
+  {
+    // Types with unique object representations skip the padding-clearing path.
+    std::atomic<int> a(1);
+    int expected = 1;
+    std::cerr << "test 63" << std::endl;
+    assert(a.compare_exchange_strong(expected, 2));
+    std::cerr << "test 64" << std::endl;
+    assert(expected == 1);
+    std::cerr << "test 65" << std::endl;
+    assert(a.load() == 2);
+    std::cerr << "test 66" << std::endl;
+
+    expected = 3;
+    assert(!a.compare_exchange_strong(expected, 4));
+    std::cerr << "test 67" << std::endl;
+    assert(expected == 2);
+    std::cerr << "test 68" << std::endl;
+    assert(a.load() == 2);
+    std::cerr << "test 69" << std::endl;
+  }
+}
+
+int main(int, char**) {
+  // TODO(LLVM-23): Switch to XFAIL: clang-22
+  std::cerr << "main 1" << std::endl;
+#if __has_builtin(__builtin_clear_padding)
+  std::cerr << "main 2" << std::endl;
+  test();
+  std::cerr << "main 3" << std::endl;
+#endif
+  std::cerr << "main 4" << std::endl;
+  return 0;
+}

>From 9aef7b1ed9f3ab24d02e50be15dac8ce646609a6 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 17:07:00 +0100
Subject: [PATCH 12/36] review

---
 .../atomics.types.generic/padding.pass.cpp    |  7 +++--
 .../atomics.types.generic/padding.pass.cpp    | 27 +++++++++++++++++++
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index c8176b1940843..afeafb022abc4 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -10,8 +10,11 @@
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
 
-// atomic<T>::compare_exchange_weak
-// atomic<T>::compare_exchange_strong
+// atomic<T>::atomic()
+// atomic<T>::atomic(T)
+// atomic<T>::store(T)
+// atomic<T>::exchange(T)
+// atomic_init(T)
 // libc++ maintains the invariant of the atomic to have zero for all padding bits
 
 #include <atomic>
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index d7889f2a1ed4d..0467fdd492d7b 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -133,6 +133,33 @@ void test() {
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
     libcpp_assert_padding(loaded, 0);
   }
+  {
+    // compare_exchange_strong
+    // atomic and expected are the same, including padding
+
+    T init = make<T>(10, 'a', 0x00);
+    assert_padding(init, 0x00);
+    a.store(init);
+
+    T expected = make<T>(10, 'a', 0x00);
+    assert_padding(expected, 0x00);
+
+    T original_expected; // make a copy including padding bits
+    std::memcpy(&original_expected, &expected, sizeof(T));
+
+    T new_value = make<T>(42, 'b', 0x42);
+    assert_padding(new_value, 0x42);
+
+    bool r = a.compare_exchange_strong(expected, new_value);
+
+    assert(r);
+    assert(std::memcmp(&expected, &original_expected, sizeof(T)) == 0);
+    T loaded = a.load();
+    assert(loaded.i == 42);
+    assert(loaded.c == 'b');
+    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    libcpp_assert_padding(loaded, 0);
+  }
 
   {
     // compare_exchange_weak

>From 1aae8c5569716168259ef4e9f26767dbeb22ebe4 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 17:08:04 +0100
Subject: [PATCH 13/36] 14

---
 libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 0467fdd492d7b..e4d83e638ca77 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -47,7 +47,7 @@ T make(int i, char c, unsigned char pad_byte) {
   std::memset(&obj, pad_byte, sizeof(T));
   obj.i = i;
   obj.c = c;
-  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+  if constexpr (std::is_same<T, WithInternalAndTailPadding>::value) {
     obj.c2 = c;
   }
   return obj;

>From 4e1087b00db723495c7111efe549d06eb77121cf Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 17:10:02 +0100
Subject: [PATCH 14/36] 14

---
 .../test/libcxx/atomics/atomics.types.generic/padding.pass.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index afeafb022abc4..bf594b45ed54f 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -20,6 +20,7 @@
 #include <atomic>
 #include <cassert>
 #include <cstring>
+#include <type_traits>
 
 struct WithTailPadding {
   int i;
@@ -49,7 +50,7 @@ T make(int i, char c, unsigned char pad_byte) {
   std::memset(&obj, pad_byte, sizeof(T));
   obj.i = i;
   obj.c = c;
-  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
+  if constexpr (std::is_same<T, WithInternalAndTailPadding>::value) {
     obj.c2 = c;
   }
   return obj;

>From b968b8803d7e8395027f9c3675235358ac284f89 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 20:42:14 +0100
Subject: [PATCH 15/36] ci

---
 libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index e4d83e638ca77..0bafdbb1d7ede 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -136,7 +136,7 @@ void test() {
   {
     // compare_exchange_strong
     // atomic and expected are the same, including padding
-
+    std::atomic<T> a;
     T init = make<T>(10, 'a', 0x00);
     assert_padding(init, 0x00);
     a.store(init);

>From 1b78bd4708c488c19559b79c9571237ae534ac68 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 8 Jul 2026 22:13:05 +0100
Subject: [PATCH 16/36] ci

---
 libcxx/include/__atomic/support/gcc.h         |  5 ++--
 .../atomics.types.generic/padding.pass.cpp    | 24 ++++++++++-------
 .../atomics.types.generic/padding.pass.cpp    | 27 ++++++++++---------
 .../atomics.types.generic/padding2.pass.cpp   |  3 ---
 4 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index 2f6e0d5dbd20a..b162e2c2a63f0 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -50,9 +50,8 @@ struct __cxx_atomic_base_impl {
     std::__clear_padding_if_needed(__a_value);
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
-    std::__clear_padding_if_needed(__a_value);
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT
+      : __a_value(std::__clear_padding_if_needed(__value)) {}
   _Tp __a_value;
 };
 
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index bf594b45ed54f..6f894fe6cb605 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -44,15 +44,23 @@ struct WithInternalAndTailPadding {
 
 static_assert(sizeof(WithInternalAndTailPadding) > sizeof(int) + 2 * sizeof(char), "");
 
+template <class T>
+void set(T& obj, int i, char c) {
+  obj.i = i;
+  obj.c = c;
+}
+
+void set(WithInternalAndTailPadding& obj, int i, char c) {
+  obj.i  = i;
+  obj.c  = c;
+  obj.c2 = c;
+}
+
 template <class T>
 T make(int i, char c, unsigned char pad_byte) {
   T obj;
   std::memset(&obj, pad_byte, sizeof(T));
-  obj.i = i;
-  obj.c = c;
-  if constexpr (std::is_same<T, WithInternalAndTailPadding>::value) {
-    obj.c2 = c;
-  }
+  set(obj, i, c);
   return obj;
 }
 
@@ -61,11 +69,7 @@ void assert_padding(const T& obj, unsigned char pad_byte) {
   alignas(T) unsigned char buf[sizeof(T)];
   std::memset(buf, pad_byte, sizeof(T));
   T& reference = *reinterpret_cast<T*>(buf);
-  reference.i  = obj.i;
-  reference.c  = obj.c;
-  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
-    reference.c2 = obj.c2;
-  }
+  set(reference, obj.i, obj.c);
   assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 0bafdbb1d7ede..344d08b493e60 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -7,9 +7,6 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
 
-// atomic_init is deprecated
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-
 // atomic<T>::compare_exchange_weak
 // atomic<T>::compare_exchange_strong
 // CAS should work on types with padding bits
@@ -41,15 +38,23 @@ struct WithInternalAndTailPadding {
 
 static_assert(sizeof(WithInternalAndTailPadding) > sizeof(int) + 2 * sizeof(char), "");
 
+template <class T>
+void set(T& obj, int i, char c) {
+  obj.i = i;
+  obj.c = c;
+}
+
+void set(WithInternalAndTailPadding& obj, int i, char c) {
+  obj.i  = i;
+  obj.c  = c;
+  obj.c2 = c;
+}
+
 template <class T>
 T make(int i, char c, unsigned char pad_byte) {
   T obj;
   std::memset(&obj, pad_byte, sizeof(T));
-  obj.i = i;
-  obj.c = c;
-  if constexpr (std::is_same<T, WithInternalAndTailPadding>::value) {
-    obj.c2 = c;
-  }
+  set(obj, i, c);
   return obj;
 }
 
@@ -58,11 +63,7 @@ void assert_padding(const T& obj, unsigned char pad_byte) {
   alignas(T) unsigned char buf[sizeof(T)];
   std::memset(buf, pad_byte, sizeof(T));
   T& reference = *reinterpret_cast<T*>(buf);
-  reference.i  = obj.i;
-  reference.c  = obj.c;
-  if constexpr (std::is_same_v<T, WithInternalAndTailPadding>) {
-    reference.c2 = obj.c2;
-  }
+  set(reference, obj.i, obj.c);
   assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
index 4e17471a2461f..1040f342b8206 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
@@ -8,9 +8,6 @@
 // UNSUPPORTED: c++03
 // UNSUPPORTED: no-localization
 
-// atomic_init is deprecated
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-
 // atomic<T>::compare_exchange_weak
 // atomic<T>::compare_exchange_strong
 // CAS should work on types with padding bits

>From 9bbf9288e7f9608489be9024e2457e0d805c25d3 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Fri, 10 Jul 2026 08:29:04 +0100
Subject: [PATCH 17/36] CI

---
 .../atomics.types.generic/padding.pass.cpp    |   2 +-
 .../atomics.types.generic/padding.pass.cpp    |   2 +-
 .../atomics.types.generic/padding2.pass.cpp   | 273 ------------------
 3 files changed, 2 insertions(+), 275 deletions(-)
 delete mode 100644 libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 6f894fe6cb605..388ab0867fe38 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -135,7 +135,7 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to XFAIL: clang-22
+// TODO(LLVM-23): Switch to X_F_A_I_L: clang-22
 #if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 344d08b493e60..f1a534a2916d6 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -246,7 +246,7 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to XFAIL: clang-22
+// TODO(LLVM-23): Switch to X_F_A_I_L: clang-22
 #if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
deleted file mode 100644
index 1040f342b8206..0000000000000
--- a/libcxx/test/std/atomics/atomics.types.generic/padding2.pass.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
-// UNSUPPORTED: no-localization
-
-// atomic<T>::compare_exchange_weak
-// atomic<T>::compare_exchange_strong
-// CAS should work on types with padding bits
-
-#include <atomic>
-#include <cassert>
-#include <cstring>
-#include <type_traits>
-#include <iostream>
-
-struct Foo {
-  int i;
-  char c;
-};
-
-static_assert(sizeof(Foo) > sizeof(int) + sizeof(char), "");
-
-Foo make_foo(int i, char c, unsigned char pad_byte) {
-  Foo f;
-  std::memset(&f, pad_byte, sizeof(Foo));
-  f.i = i;
-  f.c = c;
-  return f;
-}
-
-void assert_foo_padding(const Foo& f, unsigned char pad_byte) {
-  alignas(Foo) unsigned char buf[sizeof(Foo)];
-  std::memset(buf, pad_byte, sizeof(Foo));
-  Foo& reference = *reinterpret_cast<Foo*>(buf);
-  reference.i    = f.i;
-  reference.c    = f.c;
-  assert(std::memcmp(&f, &reference, sizeof(Foo)) == 0);
-}
-
-void libcpp_assert_foo_padding(const Foo& f, unsigned char pad_byte) {
-#ifdef _LIBCPP_VERSION
-  assert_foo_padding(f, pad_byte);
-#else
-  (void)f;
-  (void)pad_byte;
-#endif
-}
-
-void test() {
-  std::cerr << "test 1" << std::endl;
-  {
-    // compare_exchange_strong
-    // CAS should succeed when only padding differs in expected; expected is unchanged.
-    std::atomic<Foo> a;
-    std::cerr << "test 2" << std::endl;
-
-    Foo init = make_foo(10, 'a', 0xBB);
-    std::cerr << "test 3" << std::endl;
-    assert_foo_padding(init, 0xBB);
-    std::cerr << "test 4" << std::endl;
-    a.store(init);
-
-    Foo expected = make_foo(10, 'a', 0xAA);
-    std::cerr << "test 5" << std::endl;
-    assert_foo_padding(expected, 0xAA);
-    std::cerr << "test 6" << std::endl;
-
-    Foo original_expected; // make a copy including padding bits
-    std::memcpy(&original_expected, &expected, sizeof(Foo));
-
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    std::cerr << "test 7" << std::endl;
-    assert_foo_padding(new_value, 0xCC);
-    std::cerr << "test 8" << std::endl;
-
-    bool r = a.compare_exchange_strong(expected, new_value);
-
-    std::cerr << "test 9" << std::endl;
-    assert(r);
-    std::cerr << "test 10" << std::endl;
-    assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
-    std::cerr << "test 11" << std::endl;
-    Foo loaded = a.load();
-    assert(loaded.i == 42);
-    std::cerr << "test 12" << std::endl;
-    assert(loaded.c == 'b');
-    std::cerr << "test 13" << std::endl;
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
-    std::cerr << "test 14" << std::endl;
-  }
-
-  {
-    // compare_exchange_strong
-    // atomic and expected values are different; failure
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    std::cerr << "test 15" << std::endl;
-    assert_foo_padding(stored, 0xBB);
-    std::cerr << "test 16" << std::endl;
-    a.store(stored);
-
-    Foo expected = make_foo(99, 'a', 0xAA);
-    std::cerr << "test 17" << std::endl;
-    assert_foo_padding(expected, 0xAA);
-    std::cerr << "test 18" << std::endl;
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    std::cerr << "test 19" << std::endl;
-    assert_foo_padding(new_value, 0xCC);
-    std::cerr << "test 10" << std::endl;
-
-    bool r = a.compare_exchange_strong(expected, new_value);
-
-    std::cerr << "test 21" << std::endl;
-    assert(!r);
-    std::cerr << "test 22" << std::endl;
-    assert(expected.i == 10);
-    std::cerr << "test 23" << std::endl;
-    assert(expected.c == 'a');
-    std::cerr << "test 24" << std::endl;
-    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_foo_padding(expected, 0);
-    std::cerr << "test 25" << std::endl;
-    Foo loaded = a.load();
-    assert(loaded.i == 10);
-    std::cerr << "test 26" << std::endl;
-    assert(loaded.c == 'a');
-    std::cerr << "test 27" << std::endl;
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
-    std::cerr << "test 28" << std::endl;
-  }
-
-  {
-    // compare_exchange_weak
-    // atomic and expected only differs in padding bits. It should either succeed or spuriously fail
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    std::cerr << "test 29" << std::endl;
-    assert_foo_padding(stored, 0xBB);
-    std::cerr << "test 30" << std::endl;
-    a.store(stored);
-
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    std::cerr << "test 31" << std::endl;
-    assert_foo_padding(new_value, 0xCC);
-    std::cerr << "test 32" << std::endl;
-
-    Foo original_expected = make_foo(10, 'a', 0xAA);
-    std::cerr << "test 33" << std::endl;
-    assert_foo_padding(original_expected, 0xAA);
-    std::cerr << "test 34" << std::endl;
-
-    bool r                  = false;
-    const auto max_attempts = 100;
-    auto current_attempt    = 0;
-    while (!r) {
-      ++current_attempt;
-      std::cerr << "test 35" << std::endl;
-      assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
-      std::cerr << "test 36" << std::endl;
-      Foo expected = make_foo(10, 'a', 0xAA);
-      assert_foo_padding(expected, 0xAA);
-      std::cerr << "test 37" << std::endl;
-      r = a.compare_exchange_weak(expected, new_value);
-      if (r) {
-        std::cerr << "test 38" << std::endl;
-        assert(std::memcmp(&expected, &original_expected, sizeof(Foo)) == 0);
-        std::cerr << "test 39" << std::endl;
-      } else {
-        // Spurious failure: expected is updated to the current atomic value.
-        std::cerr << "test 40" << std::endl;
-        assert(expected.i == 10);
-        std::cerr << "test 41" << std::endl;
-        assert(expected.c == 'a');
-        std::cerr << "test 45" << std::endl;
-        // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-        libcpp_assert_foo_padding(expected, 0);
-        std::cerr << "test 43" << std::endl;
-      }
-    }
-
-    Foo loaded = a.load();
-    std::cerr << "test 44" << std::endl;
-    assert(loaded.i == 42);
-    std::cerr << "test 45" << std::endl;
-    assert(loaded.c == 'b');
-    std::cerr << "test 46" << std::endl;
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
-    std::cerr << "test 47" << std::endl;
-  }
-
-  {
-    // compare_exchange_strong
-    // atomic and expected values are different; failure
-    std::atomic<Foo> a;
-    Foo stored = make_foo(10, 'a', 0xBB);
-    std::cerr << "test 48" << std::endl;
-    assert_foo_padding(stored, 0xBB);
-    std::cerr << "test 49" << std::endl;
-    a.store(stored);
-
-    Foo expected = make_foo(99, 'a', 0xAA);
-    std::cerr << "test 50" << std::endl;
-    assert_foo_padding(expected, 0xAA);
-    std::cerr << "test 51" << std::endl;
-    Foo new_value = make_foo(42, 'b', 0xCC);
-    std::cerr << "test 52" << std::endl;
-    assert_foo_padding(new_value, 0xCC);
-    std::cerr << "test 53" << std::endl;
-
-    bool r = a.compare_exchange_weak(expected, new_value);
-
-    std::cerr << "test 54" << std::endl;
-    assert(!r);
-    std::cerr << "test 55" << std::endl;
-    assert(expected.i == 10);
-    std::cerr << "test 56" << std::endl;
-    assert(expected.c == 'a');
-    std::cerr << "test 57" << std::endl;
-    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_foo_padding(expected, 0);
-    std::cerr << "test 58" << std::endl;
-    Foo loaded = a.load();
-    std::cerr << "test 59" << std::endl;
-    assert(loaded.i == 10);
-    std::cerr << "test 60" << std::endl;
-    assert(loaded.c == 'a');
-    std::cerr << "test 61" << std::endl;
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_foo_padding(loaded, 0);
-    std::cerr << "test 62" << std::endl;
-  }
-
-  {
-    // Types with unique object representations skip the padding-clearing path.
-    std::atomic<int> a(1);
-    int expected = 1;
-    std::cerr << "test 63" << std::endl;
-    assert(a.compare_exchange_strong(expected, 2));
-    std::cerr << "test 64" << std::endl;
-    assert(expected == 1);
-    std::cerr << "test 65" << std::endl;
-    assert(a.load() == 2);
-    std::cerr << "test 66" << std::endl;
-
-    expected = 3;
-    assert(!a.compare_exchange_strong(expected, 4));
-    std::cerr << "test 67" << std::endl;
-    assert(expected == 2);
-    std::cerr << "test 68" << std::endl;
-    assert(a.load() == 2);
-    std::cerr << "test 69" << std::endl;
-  }
-}
-
-int main(int, char**) {
-  // TODO(LLVM-23): Switch to XFAIL: clang-22
-  std::cerr << "main 1" << std::endl;
-#if __has_builtin(__builtin_clear_padding)
-  std::cerr << "main 2" << std::endl;
-  test();
-  std::cerr << "main 3" << std::endl;
-#endif
-  std::cerr << "main 4" << std::endl;
-  return 0;
-}

>From e60f49c5cc56ff8ec1b5cb0e0fa84afa1044e8b7 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Fri, 10 Jul 2026 08:52:15 +0100
Subject: [PATCH 18/36] ci

---
 libcxx/include/__atomic/support/c11.h | 13 ++++++++-----
 libcxx/include/__atomic/support/gcc.h |  9 +++++++--
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index 05b22d04962fa..d43a2c67f950a 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -30,13 +30,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <typename _Tp>
 struct __cxx_atomic_base_impl {
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
-    std::__clear_padding_if_needed(__a_value);
+  _LIBCPP_HIDE_FROM_ABI
+#ifndef _LIBCPP_CXX03_LANG
+  __cxx_atomic_base_impl() _NOEXCEPT = default;
+#else
+  __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
+#endif // _LIBCPP_CXX03_LANG
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {
-    std::__clear_padding_if_needed(__a_value);
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT
+      : __a_value(std::__clear_padding_if_needed(__value)) {}
 
   _Atomic(_Tp) __a_value;
 };
diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index b162e2c2a63f0..d2d4919d54614 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -46,12 +46,17 @@ _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp volatile& __a_value,
 
 template <typename _Tp>
 struct __cxx_atomic_base_impl {
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
-    std::__clear_padding_if_needed(__a_value);
+  _LIBCPP_HIDE_FROM_ABI
+#ifndef _LIBCPP_CXX03_LANG
+  __cxx_atomic_base_impl() _NOEXCEPT = default;
+#else
+  __cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
   }
+#endif // _LIBCPP_CXX03_LANG
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT
       : __a_value(std::__clear_padding_if_needed(__value)) {}
+
   _Tp __a_value;
 };
 

>From 1132a74e39f869723a4f6482663e03b1da31d135 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 16:26:08 +0100
Subject: [PATCH 19/36] review

---
 libcxx/include/__atomic/clear_padding.h            | 14 ++++++--------
 .../atomics/atomics.types.generic/padding.pass.cpp |  2 +-
 .../atomics/atomics.types.generic/padding.pass.cpp |  2 +-
 3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index 5bc77ff4401ab..f920ef39977b7 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -35,17 +35,16 @@ struct __needs_clear_padding
            _Not<is_same<_Tp, float>>,
            _Not<is_same<_Tp, double>>> {};
 
-template <class _Tp>
+template <class _Tp, __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp>>::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
-  if constexpr (__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
-    if (!__builtin_is_constant_evaluated()) {
-      __builtin_clear_padding(std::addressof(__obj));
-    }
-  }
-  // return __obj as c++11 does not constexpr function to return void
   return __obj;
 }
 
+template <class _Tp, __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp>>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
+  return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
+}
+
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
   if constexpr (!__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
@@ -67,7 +66,6 @@ _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up
 
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
-  // return __obj as c++11 does not constexpr function to return void
   return __obj;
 }
 
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 388ab0867fe38..45fb083cccf3f 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -135,7 +135,7 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to X_F_A_I_L: clang-22
+// TODO(LLVM-23): Switch to XFAIL with clang-22
 #if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index f1a534a2916d6..5ffba6ca844c5 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -246,7 +246,7 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to X_F_A_I_L: clang-22
+// TODO(LLVM-23): Switch to XFAIL with clang-22
 #if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();

>From b402c49968083a151825442b6bc1b37c41e263da Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 16:33:16 +0100
Subject: [PATCH 20/36] release notes

---
 libcxx/docs/ReleaseNotes/24.rst    | 1 +
 libcxx/docs/Status/Cxx20Papers.csv | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index e20fa560865ad..5d6e1bf9afdd5 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -42,6 +42,7 @@ Implemented Papers
 - P0792R14: ``function_ref`` : a type-erased callable reference (`Github <https://llvm.org/PR105376>`__)
 - P3948R1: ``constant_wrapper`` is the only tool needed for passing constant expressions via function arguments (`Github <https://llvm.org/PR189604>`__)
 - P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)
+- P0528R3: The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange (`Github <https://llvm.org/PR76180>`__)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 5539767ab800b..8e394b4bc4b3a 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -31,7 +31,7 @@
 "`P0458R2 <https://wg21.link/P0458R2>`__","Checking for Existence of an Element in Associative Containers","2018-06 (Rapperswil)","|Complete|","13","`#104029 <https://github.com/llvm/llvm-project/issues/104029>`__",""
 "`P0475R1 <https://wg21.link/P0475R1>`__","LWG 2511: guaranteed copy elision for piecewise construction","2018-06 (Rapperswil)","|Complete|","","`#104031 <https://github.com/llvm/llvm-project/issues/104031>`__",""
 "`P0476R2 <https://wg21.link/P0476R2>`__","Bit-casting object representations","2018-06 (Rapperswil)","|Complete|","14","`#104087 <https://github.com/llvm/llvm-project/issues/104087>`__",""
-"`P0528R3 <https://wg21.link/P0528R3>`__","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","2018-06 (Rapperswil)","","","`#99984 <https://github.com/llvm/llvm-project/issues/99984>`__",""
+"`P0528R3 <https://wg21.link/P0528R3>`__","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","2018-06 (Rapperswil)","|Complete|","24","`#99984 <https://github.com/llvm/llvm-project/issues/99984>`__",""
 "`P0542R5 <https://wg21.link/P0542R5>`__","Support for contract based programming in C++","2018-06 (Rapperswil)","|Nothing To Do|","n/a","`#104089 <https://github.com/llvm/llvm-project/issues/104089>`__","Pulled at the 2019-07 meeting in Cologne"
 "`P0556R3 <https://wg21.link/P0556R3>`__","Integral power-of-2 operations","2018-06 (Rapperswil)","|Complete|","9","`#104090 <https://github.com/llvm/llvm-project/issues/104090>`__",""
 "`P0619R4 <https://wg21.link/P0619R4>`__","Reviewing Deprecated Facilities of C++17 for C++20","2018-06 (Rapperswil)","|Complete|","20","`#99985 <https://github.com/llvm/llvm-project/issues/99985>`__","Removed headers are still provided as an extension, but with deprecation warnings."

>From 3f6a4dd52e50b3a9b4b856b3cb1690dc0cdf4061 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 17:01:57 +0100
Subject: [PATCH 21/36] ci

---
 libcxx/include/__atomic/clear_padding.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index f920ef39977b7..3099faa8ca6d1 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -12,6 +12,7 @@
 #include <__config>
 #include <__memory/addressof.h>
 #include <__type_traits/conjunction.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/has_unique_object_representation.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_same.h>

>From 3f4712755756ad66e0f657112a4f3375eca34f94 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 19:03:39 +0100
Subject: [PATCH 22/36] ci

---
 .../atomics.types.generic/padding.pass.cpp    | 19 ++++---
 .../atomics.types.generic/padding.pass.cpp    | 52 ++++++++++++-------
 2 files changed, 44 insertions(+), 27 deletions(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 45fb083cccf3f..116a860b3192c 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -57,11 +57,9 @@ void set(WithInternalAndTailPadding& obj, int i, char c) {
 }
 
 template <class T>
-T make(int i, char c, unsigned char pad_byte) {
-  T obj;
+void initialize(T& obj, int i, char c, unsigned char pad_byte) {
   std::memset(&obj, pad_byte, sizeof(T));
   set(obj, i, c);
-  return obj;
 }
 
 template <class T>
@@ -86,7 +84,8 @@ void test() {
 
   {
     // atomic(T);
-    T init = make<T>(10, 'a', 0xBB);
+    T init;
+    initialize(init, 10, 'a', 0xBB);
     assert_padding(init, 0xBB);
     std::atomic<T> a(init);
     T loaded = a.load();
@@ -97,7 +96,8 @@ void test() {
   {
     // atomic::store
     std::atomic<T> a;
-    T value = make<T>(5, 'x', 0xAB);
+    T value;
+    initialize(value, 5, 'x', 0xAB);
     assert_padding(value, 0xAB);
     a.store(value);
     T loaded = a.load();
@@ -107,10 +107,12 @@ void test() {
   }
   {
     // atomic::exchange
-    T initial = make<T>(1, 'a', 0x00);
+    T initial;
+    initialize(initial, 1, 'a', 0x00);
     assert_padding(initial, 0x00);
     std::atomic<T> a(initial);
-    T new_val = make<T>(2, 'b', 0xCD);
+    T new_val;
+    initialize(new_val, 2, 'b', 0xCD);
     assert_padding(new_val, 0xCD);
     T old = a.exchange(new_val);
     assert(old.i == 1);
@@ -124,7 +126,8 @@ void test() {
   {
     // atomic_init
     std::atomic<T> a;
-    T init = make<T>(7, 'z', 0xEF);
+    T init;
+    initialize(init, 7, 'z', 0xEF);
     assert_padding(init, 0xEF);
     std::atomic_init(&a, init);
     T loaded = a.load();
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 5ffba6ca844c5..fe930f8b05b7d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -51,11 +51,9 @@ void set(WithInternalAndTailPadding& obj, int i, char c) {
 }
 
 template <class T>
-T make(int i, char c, unsigned char pad_byte) {
-  T obj;
+void initialize(T& obj, int i, char c, unsigned char pad_byte) {
   std::memset(&obj, pad_byte, sizeof(T));
   set(obj, i, c);
-  return obj;
 }
 
 template <class T>
@@ -84,17 +82,20 @@ void test() {
     // CAS should succeed when only padding differs in expected; expected is unchanged.
     std::atomic<T> a;
 
-    T init = make<T>(10, 'a', 0xBB);
+    T init;
+    initialize(init, 10, 'a', 0xBB);
     assert_padding(init, 0xBB);
     a.store(init);
 
-    T expected = make<T>(10, 'a', 0xAA);
+    T expected;
+    initialize(expected, 10, 'a', 0xAA);
     assert_padding(expected, 0xAA);
 
     T original_expected; // make a copy including padding bits
     std::memcpy(&original_expected, &expected, sizeof(T));
 
-    T new_value = make<T>(42, 'b', 0xCC);
+    T new_value;
+    initialize(new_value, 42, 'b', 0xCC);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -112,13 +113,16 @@ void test() {
     // compare_exchange_strong
     // atomic and expected values are different; failure
     std::atomic<T> a;
-    T stored = make<T>(10, 'a', 0xBB);
+    T stored;
+    initialize(stored, 10, 'a', 0xBB);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
-    T expected = make<T>(99, 'a', 0xAA);
+    T expected;
+    initialize(expected, 99, 'a', 0xAA);
     assert_padding(expected, 0xAA);
-    T new_value = make<T>(42, 'b', 0xCC);
+    T new_value;
+    initialize(new_value, 42, 'b', 0xCC);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -138,17 +142,20 @@ void test() {
     // compare_exchange_strong
     // atomic and expected are the same, including padding
     std::atomic<T> a;
-    T init = make<T>(10, 'a', 0x00);
+    T init;
+    initialize(init, 10, 'a', 0x00);
     assert_padding(init, 0x00);
     a.store(init);
 
-    T expected = make<T>(10, 'a', 0x00);
+    T expected;
+    initialize(expected, 10, 'a', 0x00);
     assert_padding(expected, 0x00);
 
     T original_expected; // make a copy including padding bits
     std::memcpy(&original_expected, &expected, sizeof(T));
 
-    T new_value = make<T>(42, 'b', 0x42);
+    T new_value;
+    initialize(new_value, 42, 'b', 0x42);
     assert_padding(new_value, 0x42);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -166,14 +173,17 @@ void test() {
     // compare_exchange_weak
     // atomic and expected only differs in padding bits. It should either succeed or spuriously fail
     std::atomic<T> a;
-    T stored = make<T>(10, 'a', 0xBB);
+    T stored;
+    initialize(stored, 10, 'a', 0xBB);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
-    T new_value = make<T>(42, 'b', 0xCC);
+    T new_value;
+    initialize(new_value, 42, 'b', 0xCC);
     assert_padding(new_value, 0xCC);
 
-    T original_expected = make<T>(10, 'a', 0xAA);
+    T original_expected;
+    initialize(original_expected, 10, 'a', 0xAA);
     assert_padding(original_expected, 0xAA);
 
     bool r                  = false;
@@ -182,7 +192,8 @@ void test() {
     while (!r) {
       ++current_attempt;
       assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
-      T expected = make<T>(10, 'a', 0xAA);
+      T expected;
+      initialize(expected, 10, 'a', 0xAA);
       assert_padding(expected, 0xAA);
       r = a.compare_exchange_weak(expected, new_value);
       if (r) {
@@ -207,13 +218,16 @@ void test() {
     // compare_exchange_strong
     // atomic and expected values are different; failure
     std::atomic<T> a;
-    T stored = make<T>(10, 'a', 0xBB);
+    T stored;
+    initialize(stored, 10, 'a', 0xBB);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
-    T expected = make<T>(99, 'a', 0xAA);
+    T expected;
+    initialize(expected, 99, 'a', 0xAA);
     assert_padding(expected, 0xAA);
-    T new_value = make<T>(42, 'b', 0xCC);
+    T new_value;
+    initialize(new_value, 42, 'b', 0xCC);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_weak(expected, new_value);

>From 3b83d61786cac9434eeb1f261575624ff31f5e85 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 20:07:26 +0100
Subject: [PATCH 23/36] debug

---
 .../atomics.types.generic/padding.pass.cpp    | 64 ++++++++++++++++++-
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index fe930f8b05b7d..3b7f13b366e96 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -15,6 +15,7 @@
 #include <cassert>
 #include <cstring>
 #include <type_traits>
+#include <iostream>
 
 struct WithTailPadding {
   int i;
@@ -70,11 +71,19 @@ void libcpp_assert_padding(const T& obj, unsigned char pad_byte) {
 #ifdef _LIBCPP_VERSION
   assert_padding(obj, pad_byte);
 #else
-  (void)f;
+  (void)obj;
   (void)pad_byte;
 #endif
 }
 
+template <class T>
+void print_memory(const T& obj) {
+  for (size_t i = 0; i < sizeof(T); ++i) {
+    std::cerr << std::hex << static_cast<int>(reinterpret_cast<const unsigned char*>(&obj)[i]) << " ";
+  }
+  std::cerr << std::endl;
+}
+
 template <class T>
 void test() {
   {
@@ -84,11 +93,15 @@ void test() {
 
     T init;
     initialize(init, 10, 'a', 0xBB);
+    std::cerr << "test1 init padding should be 0xBB: " << std::endl;
+    print_memory(init);
     assert_padding(init, 0xBB);
     a.store(init);
 
     T expected;
     initialize(expected, 10, 'a', 0xAA);
+    std::cerr << "test1 expected padding should be 0xAA: " << std::endl;
+    print_memory(expected);
     assert_padding(expected, 0xAA);
 
     T original_expected; // make a copy including padding bits
@@ -96,6 +109,8 @@ void test() {
 
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
+    std::cerr << "test1 new_value padding should be 0xCC: " << std::endl;
+    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -106,6 +121,8 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    std::cerr << "test1 loaded padding should be 0: " << std::endl;
+    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -115,14 +132,20 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
+    std::cerr << "test2 stored padding should be 0xBB: " << std::endl;
+    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T expected;
     initialize(expected, 99, 'a', 0xAA);
+    std::cerr << "test2 expected padding should be 0xAA: " << std::endl;
+    print_memory(expected);
     assert_padding(expected, 0xAA);
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
+    std::cerr << "test2 new_value padding should be 0xCC: " << std::endl;
+    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -131,11 +154,15 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    std::cerr << "test2 expected padding should be 0: " << std::endl;
+    print_memory(expected);
     libcpp_assert_padding(expected, 0);
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    std::cerr << "test2 loaded padding should be 0: " << std::endl;
+    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
   {
@@ -144,11 +171,15 @@ void test() {
     std::atomic<T> a;
     T init;
     initialize(init, 10, 'a', 0x00);
+    std::cerr << "test3 init padding should be 0x00: " << std::endl;
+    print_memory(init);
     assert_padding(init, 0x00);
     a.store(init);
 
     T expected;
     initialize(expected, 10, 'a', 0x00);
+    std::cerr << "test3 expected padding should be 0x00: " << std::endl;
+    print_memory(expected);
     assert_padding(expected, 0x00);
 
     T original_expected; // make a copy including padding bits
@@ -156,6 +187,8 @@ void test() {
 
     T new_value;
     initialize(new_value, 42, 'b', 0x42);
+    std::cerr << "test3 new_value padding should be 0x42: " << std::endl;
+    print_memory(new_value);
     assert_padding(new_value, 0x42);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -166,6 +199,8 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    std::cerr << "test3 loaded padding should be 0: " << std::endl;
+    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -175,15 +210,21 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
+    std::cerr << "test4 stored padding should be 0xBB: " << std::endl;
+    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
+    std::cerr << "test4 new_value padding should be 0xCC: " << std::endl;
+    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     T original_expected;
     initialize(original_expected, 10, 'a', 0xAA);
+    std::cerr << "test4 original_expected padding should be 0xAA: " << std::endl;
+    print_memory(original_expected);
     assert_padding(original_expected, 0xAA);
 
     bool r                  = false;
@@ -194,6 +235,8 @@ void test() {
       assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
       T expected;
       initialize(expected, 10, 'a', 0xAA);
+      std::cerr << "test4 expected padding should be 0xAA: " << std::endl;
+      print_memory(expected);
       assert_padding(expected, 0xAA);
       r = a.compare_exchange_weak(expected, new_value);
       if (r) {
@@ -203,6 +246,8 @@ void test() {
         assert(expected.i == 10);
         assert(expected.c == 'a');
         // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+        std::cerr << "test4 expected padding should be 0: " << std::endl;
+        print_memory(expected);
         libcpp_assert_padding(expected, 0);
       }
     }
@@ -211,6 +256,8 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    std::cerr << "test4 loaded padding should be 0: " << std::endl;
+    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -220,14 +267,20 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
+    std::cerr << "test5 stored padding should be 0xBB: " << std::endl;
+    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T expected;
     initialize(expected, 99, 'a', 0xAA);
+    std::cerr << "test5 expected padding should be 0xAA: " << std::endl;
+    print_memory(expected);
     assert_padding(expected, 0xAA);
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
+    std::cerr << "test5 new_value padding should be 0xCC: " << std::endl;
+    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_weak(expected, new_value);
@@ -236,11 +289,15 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+    std::cerr << "test5 expected padding should be 0: " << std::endl;
+    print_memory(expected);
     libcpp_assert_padding(expected, 0);
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
+    std::cerr << "test5 loaded padding should be 0: " << std::endl;
+    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -262,10 +319,13 @@ void test() {
 int main(int, char**) {
 // TODO(LLVM-23): Switch to XFAIL with clang-22
 #if __has_builtin(__builtin_clear_padding)
+  std::cerr << "\nWithTailPadding\n" << std::endl;
   test<WithTailPadding>();
+  std::cerr << "\nWithInternalPadding\n" << std::endl;
   test<WithInternalPadding>();
+  std::cerr << "\nWithInternalAndTailPadding\n" << std::endl;
   test<WithInternalAndTailPadding>();
 #endif
 
-  return 0;
+  return 1;
 }

>From 35138bddbb31a33312c6295ad8f75f08af259fee Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 20:38:19 +0100
Subject: [PATCH 24/36] Revert "debug"

This reverts commit 8be9a83ee040faff62f0756555890484bf502a31.
---
 .../atomics.types.generic/padding.pass.cpp    | 64 +------------------
 1 file changed, 2 insertions(+), 62 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 3b7f13b366e96..fe930f8b05b7d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -15,7 +15,6 @@
 #include <cassert>
 #include <cstring>
 #include <type_traits>
-#include <iostream>
 
 struct WithTailPadding {
   int i;
@@ -71,19 +70,11 @@ void libcpp_assert_padding(const T& obj, unsigned char pad_byte) {
 #ifdef _LIBCPP_VERSION
   assert_padding(obj, pad_byte);
 #else
-  (void)obj;
+  (void)f;
   (void)pad_byte;
 #endif
 }
 
-template <class T>
-void print_memory(const T& obj) {
-  for (size_t i = 0; i < sizeof(T); ++i) {
-    std::cerr << std::hex << static_cast<int>(reinterpret_cast<const unsigned char*>(&obj)[i]) << " ";
-  }
-  std::cerr << std::endl;
-}
-
 template <class T>
 void test() {
   {
@@ -93,15 +84,11 @@ void test() {
 
     T init;
     initialize(init, 10, 'a', 0xBB);
-    std::cerr << "test1 init padding should be 0xBB: " << std::endl;
-    print_memory(init);
     assert_padding(init, 0xBB);
     a.store(init);
 
     T expected;
     initialize(expected, 10, 'a', 0xAA);
-    std::cerr << "test1 expected padding should be 0xAA: " << std::endl;
-    print_memory(expected);
     assert_padding(expected, 0xAA);
 
     T original_expected; // make a copy including padding bits
@@ -109,8 +96,6 @@ void test() {
 
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
-    std::cerr << "test1 new_value padding should be 0xCC: " << std::endl;
-    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -121,8 +106,6 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    std::cerr << "test1 loaded padding should be 0: " << std::endl;
-    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -132,20 +115,14 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
-    std::cerr << "test2 stored padding should be 0xBB: " << std::endl;
-    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T expected;
     initialize(expected, 99, 'a', 0xAA);
-    std::cerr << "test2 expected padding should be 0xAA: " << std::endl;
-    print_memory(expected);
     assert_padding(expected, 0xAA);
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
-    std::cerr << "test2 new_value padding should be 0xCC: " << std::endl;
-    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -154,15 +131,11 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    std::cerr << "test2 expected padding should be 0: " << std::endl;
-    print_memory(expected);
     libcpp_assert_padding(expected, 0);
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    std::cerr << "test2 loaded padding should be 0: " << std::endl;
-    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
   {
@@ -171,15 +144,11 @@ void test() {
     std::atomic<T> a;
     T init;
     initialize(init, 10, 'a', 0x00);
-    std::cerr << "test3 init padding should be 0x00: " << std::endl;
-    print_memory(init);
     assert_padding(init, 0x00);
     a.store(init);
 
     T expected;
     initialize(expected, 10, 'a', 0x00);
-    std::cerr << "test3 expected padding should be 0x00: " << std::endl;
-    print_memory(expected);
     assert_padding(expected, 0x00);
 
     T original_expected; // make a copy including padding bits
@@ -187,8 +156,6 @@ void test() {
 
     T new_value;
     initialize(new_value, 42, 'b', 0x42);
-    std::cerr << "test3 new_value padding should be 0x42: " << std::endl;
-    print_memory(new_value);
     assert_padding(new_value, 0x42);
 
     bool r = a.compare_exchange_strong(expected, new_value);
@@ -199,8 +166,6 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    std::cerr << "test3 loaded padding should be 0: " << std::endl;
-    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -210,21 +175,15 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
-    std::cerr << "test4 stored padding should be 0xBB: " << std::endl;
-    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
-    std::cerr << "test4 new_value padding should be 0xCC: " << std::endl;
-    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     T original_expected;
     initialize(original_expected, 10, 'a', 0xAA);
-    std::cerr << "test4 original_expected padding should be 0xAA: " << std::endl;
-    print_memory(original_expected);
     assert_padding(original_expected, 0xAA);
 
     bool r                  = false;
@@ -235,8 +194,6 @@ void test() {
       assert(current_attempt < max_attempts && "compare_exchange_weak did not succeed within 3 seconds");
       T expected;
       initialize(expected, 10, 'a', 0xAA);
-      std::cerr << "test4 expected padding should be 0xAA: " << std::endl;
-      print_memory(expected);
       assert_padding(expected, 0xAA);
       r = a.compare_exchange_weak(expected, new_value);
       if (r) {
@@ -246,8 +203,6 @@ void test() {
         assert(expected.i == 10);
         assert(expected.c == 'a');
         // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-        std::cerr << "test4 expected padding should be 0: " << std::endl;
-        print_memory(expected);
         libcpp_assert_padding(expected, 0);
       }
     }
@@ -256,8 +211,6 @@ void test() {
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    std::cerr << "test4 loaded padding should be 0: " << std::endl;
-    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -267,20 +220,14 @@ void test() {
     std::atomic<T> a;
     T stored;
     initialize(stored, 10, 'a', 0xBB);
-    std::cerr << "test5 stored padding should be 0xBB: " << std::endl;
-    print_memory(stored);
     assert_padding(stored, 0xBB);
     a.store(stored);
 
     T expected;
     initialize(expected, 99, 'a', 0xAA);
-    std::cerr << "test5 expected padding should be 0xAA: " << std::endl;
-    print_memory(expected);
     assert_padding(expected, 0xAA);
     T new_value;
     initialize(new_value, 42, 'b', 0xCC);
-    std::cerr << "test5 new_value padding should be 0xCC: " << std::endl;
-    print_memory(new_value);
     assert_padding(new_value, 0xCC);
 
     bool r = a.compare_exchange_weak(expected, new_value);
@@ -289,15 +236,11 @@ void test() {
     assert(expected.i == 10);
     assert(expected.c == 'a');
     // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    std::cerr << "test5 expected padding should be 0: " << std::endl;
-    print_memory(expected);
     libcpp_assert_padding(expected, 0);
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
     // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    std::cerr << "test5 loaded padding should be 0: " << std::endl;
-    print_memory(loaded);
     libcpp_assert_padding(loaded, 0);
   }
 
@@ -319,13 +262,10 @@ void test() {
 int main(int, char**) {
 // TODO(LLVM-23): Switch to XFAIL with clang-22
 #if __has_builtin(__builtin_clear_padding)
-  std::cerr << "\nWithTailPadding\n" << std::endl;
   test<WithTailPadding>();
-  std::cerr << "\nWithInternalPadding\n" << std::endl;
   test<WithInternalPadding>();
-  std::cerr << "\nWithInternalAndTailPadding\n" << std::endl;
   test<WithInternalAndTailPadding>();
 #endif
 
-  return 1;
+  return 0;
 }

>From b670b21eea376b882119916551fe01d738efb3d2 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Mon, 20 Jul 2026 20:44:00 +0100
Subject: [PATCH 25/36] test ci

---
 .../atomics.types.generic/padding.pass.cpp    | 20 ++++++++++++++-----
 .../atomics.types.generic/padding.pass.cpp    | 12 +----------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 116a860b3192c..cd41f2893864c 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -71,6 +71,16 @@ void assert_padding(const T& obj, unsigned char pad_byte) {
   assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
+template <class T>
+void assert_padding(const std::atomic<T>& obj, unsigned char pad_byte) {
+  alignas(T) unsigned char buf[sizeof(T)];
+  std::memset(buf, pad_byte, sizeof(T));
+  T& reference = *reinterpret_cast<T*>(buf);
+  T loaded     = obj.load();
+  set(reference, loaded.i, loaded.c);
+  assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
+}
+
 template <class T>
 void test() {
   {
@@ -79,7 +89,7 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 0);
     assert(loaded.c == '\0');
-    assert_padding(loaded, 0);
+    assert_padding(a, 0);
   }
 
   {
@@ -91,7 +101,7 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
-    assert_padding(loaded, 0);
+    assert_padding(a, 0);
   }
   {
     // atomic::store
@@ -103,7 +113,7 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 5);
     assert(loaded.c == 'x');
-    assert_padding(loaded, 0);
+    assert_padding(a, 0);
   }
   {
     // atomic::exchange
@@ -121,7 +131,7 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 2);
     assert(loaded.c == 'b');
-    assert_padding(loaded, 0);
+    assert_padding(a, 0);
   }
   {
     // atomic_init
@@ -133,7 +143,7 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 7);
     assert(loaded.c == 'z');
-    assert_padding(loaded, 0);
+    assert_padding(a, 0);
   }
 }
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index fe930f8b05b7d..10c15523cd70b 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -70,7 +70,7 @@ void libcpp_assert_padding(const T& obj, unsigned char pad_byte) {
 #ifdef _LIBCPP_VERSION
   assert_padding(obj, pad_byte);
 #else
-  (void)f;
+  (void)obj;
   (void)pad_byte;
 #endif
 }
@@ -105,8 +105,6 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_padding(loaded, 0);
   }
 
   {
@@ -135,8 +133,6 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_padding(loaded, 0);
   }
   {
     // compare_exchange_strong
@@ -165,8 +161,6 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_padding(loaded, 0);
   }
 
   {
@@ -210,8 +204,6 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 42);
     assert(loaded.c == 'b');
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_padding(loaded, 0);
   }
 
   {
@@ -240,8 +232,6 @@ void test() {
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
-    // libc++ always maintains the invariant of the atomic to have zeros in the padding bits
-    libcpp_assert_padding(loaded, 0);
   }
 
   {

>From d41266c0023b2aff7968963f7f94b412745a275a Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 12:18:49 +0100
Subject: [PATCH 26/36] padding

---
 .../test/libcxx/atomics/atomics.types.generic/padding.pass.cpp   | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index cd41f2893864c..a178ce74578ec 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -127,7 +127,6 @@ void test() {
     T old = a.exchange(new_val);
     assert(old.i == 1);
     assert(old.c == 'a');
-    assert_padding(old, 0);
     T loaded = a.load();
     assert(loaded.i == 2);
     assert(loaded.c == 'b');

>From 6630067f0e5a0ff13ff92dc49f27b60db4b7d441 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 12:40:31 +0100
Subject: [PATCH 27/36] clang22

---
 .../libcxx/atomics/atomics.types.generic/padding.pass.cpp    | 5 ++---
 .../test/std/atomics/atomics.types.generic/padding.pass.cpp  | 4 +---
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index a178ce74578ec..48ae68a8e97ba 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
+// XFAIL: clang-21, apple-clang-21, clang-22
 
 // atomic_init is deprecated
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
@@ -147,11 +148,9 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to XFAIL with clang-22
-#if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();
   test<WithInternalAndTailPadding>();
-#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 10c15523cd70b..dc0afa439dc12 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
+// XFAIL: clang-21, apple-clang-21, clang-22
 
 // atomic<T>::compare_exchange_weak
 // atomic<T>::compare_exchange_strong
@@ -250,12 +251,9 @@ void test() {
 }
 
 int main(int, char**) {
-// TODO(LLVM-23): Switch to XFAIL with clang-22
-#if __has_builtin(__builtin_clear_padding)
   test<WithTailPadding>();
   test<WithInternalPadding>();
   test<WithInternalAndTailPadding>();
-#endif
 
   return 0;
 }

>From dd7378c9e9e5d34605a6150fe66040da269eb678 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 13:26:21 +0100
Subject: [PATCH 28/36] cxx 03

---
 libcxx/include/__atomic/clear_padding.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index 3099faa8ca6d1..dad48ed27e6a4 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -32,23 +32,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp>
 struct __needs_clear_padding
-    : _And<_Not<integral_constant<bool, __has_unique_object_representations(_Tp)>>,
-           _Not<is_same<_Tp, float>>,
-           _Not<is_same<_Tp, double>>> {};
+    : _And<_Not<integral_constant<bool, __has_unique_object_representations(_Tp)> >,
+           _Not<is_same<_Tp, float> >,
+           _Not<is_same<_Tp, double> > > {};
 
-template <class _Tp, __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp>>::value, int> = 0>
+template <class _Tp, __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
   return __obj;
 }
 
-template <class _Tp, __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp>>::value, int> = 0>
+template <class _Tp, __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
   return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
 }
 
 template <class _Tp, class _Up, class _CasFunc>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
-  if constexpr (!__needs_clear_padding<__remove_cvref_t<_Tp>>::value) {
+  if constexpr (!__needs_clear_padding<__remove_cvref_t<_Tp> >::value) {
     return __cas_func(__expected, __value);
   } else {
     std::__clear_padding_if_needed(__value);

>From 7e43a29ac7d66b2f54f6118d7917ab94bb6c4538 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 14:26:21 +0100
Subject: [PATCH 29/36] ci

---
 libcxx/include/__atomic/clear_padding.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index dad48ed27e6a4..1a4223fd97763 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -37,12 +37,12 @@ struct __needs_clear_padding
            _Not<is_same<_Tp, double> > > {};
 
 template <class _Tp, __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
   return __obj;
 }
 
 template <class _Tp, __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) noexcept {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
   return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
 }
 

>From 5f8e9cb7358e40e237a1b5e22ac1811b51931382 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 15:49:25 +0100
Subject: [PATCH 30/36] ci

---
 libcxx/include/__atomic/clear_padding.h | 31 +++++++++++++++----------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index 1a4223fd97763..be55837cd8ec8 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -46,20 +46,27 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __ob
   return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
 }
 
-template <class _Tp, class _Up, class _CasFunc>
+template <class _Tp,
+          class _Up,
+          class _CasFunc,
+          __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
+  return __cas_func(__expected, __value);
+}
+
+template <class _Tp,
+          class _Up,
+          class _CasFunc,
+          __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
-  if constexpr (!__needs_clear_padding<__remove_cvref_t<_Tp> >::value) {
-    return __cas_func(__expected, __value);
+  std::__clear_padding_if_needed(__value);
+  __remove_cvref_t<_Tp> __expected_copy = *__expected;
+  std::__clear_padding_if_needed(__expected_copy);
+  if (__cas_func(std::addressof(__expected_copy), __value)) {
+    return true;
   } else {
-    std::__clear_padding_if_needed(__value);
-    __remove_cvref_t<_Tp> __expected_copy = *__expected;
-    std::__clear_padding_if_needed(__expected_copy);
-    if (__cas_func(std::addressof(__expected_copy), __value)) {
-      return true;
-    } else {
-      std::memcpy(__expected, std::addressof(__expected_copy), sizeof(__remove_cvref_t<_Tp>));
-      return false;
-    }
+    std::memcpy(__expected, std::addressof(__expected_copy), sizeof(__remove_cvref_t<_Tp>));
+    return false;
   }
 }
 

>From 6bdbcdb91f2f4fef083a794c9d4197a5a4ac025d Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 17:01:17 +0100
Subject: [PATCH 31/36] ci

---
 .../libcxx/atomics/atomics.types.generic/padding.pass.cpp   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 48ae68a8e97ba..65b890b75d1de 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -23,6 +23,8 @@
 #include <cstring>
 #include <type_traits>
 
+#include "test_macros.h"
+
 struct WithTailPadding {
   int i;
   char c;
@@ -87,10 +89,12 @@ void test() {
   {
     // atomic();
     std::atomic<T> a;
+    assert_padding(a, 0);
+#if TEST_STD_VER >= 20
     T loaded = a.load();
     assert(loaded.i == 0);
     assert(loaded.c == '\0');
-    assert_padding(a, 0);
+#endif
   }
 
   {

>From d2c579c00cb9008281703a28752962e1541ab195 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Wed, 22 Jul 2026 18:38:43 +0100
Subject: [PATCH 32/36] ci

---
 .../test/libcxx/atomics/atomics.types.generic/padding.pass.cpp  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 65b890b75d1de..c9ed3bbcc5704 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -88,9 +88,9 @@ template <class T>
 void test() {
   {
     // atomic();
+#if TEST_STD_VER >= 20
     std::atomic<T> a;
     assert_padding(a, 0);
-#if TEST_STD_VER >= 20
     T loaded = a.load();
     assert(loaded.i == 0);
     assert(loaded.c == '\0');

>From 75e535ea12fc9d38bd8cb50a321349448813b530 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Fri, 24 Jul 2026 07:49:38 +0100
Subject: [PATCH 33/36] ci

---
 libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index dc0afa439dc12..f9008f29f14b4 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
+// XFAIL: !has-64-bit-atomics
 // XFAIL: clang-21, apple-clang-21, clang-22
 
 // atomic<T>::compare_exchange_weak

>From 062c15c012a5628de722e44a0896076ea5147ab2 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 25 Jul 2026 09:56:49 +0100
Subject: [PATCH 34/36] review

---
 libcxx/include/__atomic/support/c11.h         | 25 ++++---
 libcxx/include/__atomic/support/gcc.h         | 68 ++++++++++---------
 .../test/configs/llvm-libc++-llvm-libc.cfg.in |  2 +-
 .../atomics.types.generic/padding.pass.cpp    |  4 ++
 .../atomics.types.generic/padding.pass.cpp    | 30 ++++----
 5 files changed, 72 insertions(+), 57 deletions(-)

diff --git a/libcxx/include/__atomic/support/c11.h b/libcxx/include/__atomic/support/c11.h
index d43a2c67f950a..9176a74462a5a 100644
--- a/libcxx/include/__atomic/support/c11.h
+++ b/libcxx/include/__atomic/support/c11.h
@@ -137,13 +137,16 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
   return std::__atomic_cas_with_clear_padding(
-      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+      __expected,
+      __value,
+      // clang fails to inline the lambda when the memory order is a constant
+      [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
         return __c11_atomic_compare_exchange_strong(
             std::addressof(__a->__a_value),
             __expected_or_copy,
             __value_maybe_padding_cleared,
             static_cast<__memory_order_underlying_t>(__success),
-            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+            static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
       });
 }
 template <class _Tp>
@@ -151,13 +154,15 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
   return std::__atomic_cas_with_clear_padding(
-      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+      __expected,
+      __value,
+      [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
         return __c11_atomic_compare_exchange_strong(
             std::addressof(__a->__a_value),
             __expected_or_copy,
             __value_maybe_padding_cleared,
             static_cast<__memory_order_underlying_t>(__success),
-            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+            static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
       });
 }
 
@@ -169,13 +174,15 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     memory_order __success,
     memory_order __failure) _NOEXCEPT {
   return std::__atomic_cas_with_clear_padding(
-      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+      __expected,
+      __value,
+      [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
         return __c11_atomic_compare_exchange_weak(
             std::addressof(__a->__a_value),
             __expected_or_copy,
             __value_maybe_padding_cleared,
             static_cast<__memory_order_underlying_t>(__success),
-            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+            static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
       });
 }
 
@@ -184,13 +191,15 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
     __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
     _NOEXCEPT {
   return std::__atomic_cas_with_clear_padding(
-      __expected, __value, [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) {
+      __expected,
+      __value,
+      [__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
         return __c11_atomic_compare_exchange_weak(
             std::addressof(__a->__a_value),
             __expected_or_copy,
             __value_maybe_padding_cleared,
             static_cast<__memory_order_underlying_t>(__success),
-            static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
+            static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
       });
 }
 
diff --git a/libcxx/include/__atomic/support/gcc.h b/libcxx/include/__atomic/support/gcc.h
index d2d4919d54614..bbd193efad8be 100644
--- a/libcxx/include/__atomic/support/gcc.h
+++ b/libcxx/include/__atomic/support/gcc.h
@@ -73,49 +73,49 @@ _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _
 }
 
 _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) {
-  __atomic_thread_fence(__to_gcc_order(__order));
+  __atomic_thread_fence(std::__to_gcc_order(__order));
 }
 
 _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) {
-  __atomic_signal_fence(__to_gcc_order(__order));
+  __atomic_signal_fence(std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
   std::__clear_padding_if_needed(__val);
-  __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
+  __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
   std::__clear_padding_if_needed(__val);
-  __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order));
+  __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) {
   _Tp __ret;
-  __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order));
+  __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), std::__to_gcc_order(__order));
   return __ret;
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_load_inplace(const volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) {
-  __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order));
+  __atomic_load(std::addressof(__a->__a_value), __dst, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI void
 __cxx_atomic_load_inplace(const __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) {
-  __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order));
+  __atomic_load(std::addressof(__a->__a_value), __dst, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) {
   _Tp __ret;
-  __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order));
+  __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), std::__to_gcc_order(__order));
   return __ret;
 }
 
@@ -125,7 +125,7 @@ __cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, me
   _Tp __ret;
   std::__clear_padding_if_needed(__value);
   __atomic_exchange(
-      std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
+      std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), std::__to_gcc_order(__order));
   return __ret;
 }
 
@@ -134,7 +134,7 @@ _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a
   _Tp __ret;
   std::__clear_padding_if_needed(__value);
   __atomic_exchange(
-      std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order));
+      std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), std::__to_gcc_order(__order));
   return __ret;
 }
 
@@ -152,8 +152,8 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
             __expected_or_copy,
             std::addressof(__value_maybe_padding_cleared),
             false,
-            __to_gcc_order(__success),
-            __to_gcc_failure_order(__failure));
+            std::__to_gcc_order(__success),
+            std::__to_gcc_failure_order(__failure));
       });
 }
 
@@ -167,8 +167,8 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
             __expected_or_copy,
             std::addressof(__value_maybe_padding_cleared),
             false,
-            __to_gcc_order(__success),
-            __to_gcc_failure_order(__failure));
+            std::__to_gcc_order(__success),
+            std::__to_gcc_failure_order(__failure));
       });
 }
 
@@ -186,8 +186,8 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
             __expected_or_copy,
             std::addressof(__value_maybe_padding_cleared),
             true,
-            __to_gcc_order(__success),
-            __to_gcc_failure_order(__failure));
+            std::__to_gcc_order(__success),
+            std::__to_gcc_failure_order(__failure));
       });
 }
 
@@ -201,8 +201,8 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
             __expected_or_copy,
             std::addressof(__value_maybe_padding_cleared),
             true,
-            __to_gcc_order(__success),
-            __to_gcc_failure_order(__failure));
+            std::__to_gcc_order(__success),
+            std::__to_gcc_failure_order(__failure));
       });
 }
 
@@ -226,65 +226,69 @@ struct __skip_amt<_Tp[n]> {};
 template <typename _Tp, typename _Td>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
-  return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
+  return __atomic_fetch_add(
+      std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp, typename _Td>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
-  return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
+  return __atomic_fetch_add(
+      std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp, typename _Td>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
-  return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
+  return __atomic_fetch_sub(
+      std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp, typename _Td>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) {
-  return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order));
+  return __atomic_fetch_sub(
+      std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) {
-  return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order));
+  return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, std::__to_gcc_order(__order));
 }
 
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_max(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
 #if __has_builtin(__atomic_fetch_max)
-  return __atomic_fetch_max(std::addressof(__a->__a_value), __val, __to_gcc_order(__order));
+  return __atomic_fetch_max(std::addressof(__a->__a_value), __val, std::__to_gcc_order(__order));
 #else
   _Tp __ret = __cxx_atomic_load(__a, memory_order_relaxed);
   _Tp __value;
@@ -298,7 +302,7 @@ __cxx_atomic_fetch_max(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, mem
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_max(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
 #if __has_builtin(__atomic_fetch_max)
-  return __atomic_fetch_max(std::addressof(__a->__a_value), __val, __to_gcc_order(__order));
+  return __atomic_fetch_max(std::addressof(__a->__a_value), __val, std::__to_gcc_order(__order));
 #else
   _Tp __ret = __cxx_atomic_load(__a, memory_order_relaxed);
   _Tp __value;
@@ -313,7 +317,7 @@ template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp
 __cxx_atomic_fetch_min(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
 #if __has_builtin(__atomic_fetch_min)
-  return __atomic_fetch_min(std::addressof(__a->__a_value), __val, __to_gcc_order(__order));
+  return __atomic_fetch_min(std::addressof(__a->__a_value), __val, std::__to_gcc_order(__order));
 #else
   _Tp __ret = __cxx_atomic_load(__a, memory_order_relaxed);
   _Tp __value;
@@ -327,7 +331,7 @@ __cxx_atomic_fetch_min(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, mem
 template <typename _Tp>
 _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_min(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) {
 #if __has_builtin(__atomic_fetch_min)
-  return __atomic_fetch_min(std::addressof(__a->__a_value), __val, __to_gcc_order(__order));
+  return __atomic_fetch_min(std::addressof(__a->__a_value), __val, std::__to_gcc_order(__order));
 #else
   _Tp __ret = __cxx_atomic_load(__a, memory_order_relaxed);
   _Tp __value;
diff --git a/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in b/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
index 885715eb42dfc..9c462aa8dd49b 100644
--- a/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
+++ b/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
@@ -8,7 +8,7 @@ config.substitutions.append(('%{compile_flags}',
     '-nostdlibinc -I %{include-dir} -I %{target-include-dir} -isystem @CMAKE_BINARY_DIR@/libc/include -I %{libcxx-dir}/test/support -idirafter @LIBC_KERNEL_HEADERS@'
 ))
 config.substitutions.append(('%{link_flags}',
-    '-nodefaultlibs -nostartfiles -L %{lib-dir} -lc++ -lc++abi @CMAKE_BINARY_DIR@/libc/startup/linux/crt1.o -Wl,--start-group @CMAKE_BINARY_DIR@/libc/lib/libc.a @CMAKE_BINARY_DIR@/libc/lib/libm.a -static -fno-use-cxa-atexit @CMAKE_BINARY_DIR@/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a -Wl,--end-group -Wl,--defsym,__dso_handle=0'
+    '-nodefaultlibs -nostartfiles -L %{lib-dir} -lc++ -lc++abi @CMAKE_BINARY_DIR@/libc/startup/linux/crt1.o -Wl,--start-group @CMAKE_BINARY_DIR@/libc/lib/libc.a @CMAKE_BINARY_DIR@/libc/lib/libm.a -static -fno-use-cxa-atexit @CMAKE_BINARY_DIR@/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a -Wl,--end-group -Wl,--defsym,__dso_handle=0 -pthread'
 ))
 config.substitutions.append(('%{exec}',
     '%{executor} --execdir %{temp} -- '
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index c9ed3bbcc5704..1029ede2f7181 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
+
+// Older Clang doesn't implement __builtin_clear_padding
 // XFAIL: clang-21, apple-clang-21, clang-22
 
 // atomic_init is deprecated
@@ -88,6 +90,8 @@ template <class T>
 void test() {
   {
     // atomic();
+    // Prio to C++20, the default constructor leaves std::atomic unitialized,
+    // so padding bytes are not guaranteed zero
 #if TEST_STD_VER >= 20
     std::atomic<T> a;
     assert_padding(a, 0);
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index f9008f29f14b4..5721acf4a66fe 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
 // XFAIL: !has-64-bit-atomics
+
+// Older Clang doesn't implement __builtin_clear_padding
 // XFAIL: clang-21, apple-clang-21, clang-22
 
 // atomic<T>::compare_exchange_weak
@@ -67,16 +69,6 @@ void assert_padding(const T& obj, unsigned char pad_byte) {
   assert(std::memcmp(&obj, &reference, sizeof(T)) == 0);
 }
 
-template <class T>
-void libcpp_assert_padding(const T& obj, unsigned char pad_byte) {
-#ifdef _LIBCPP_VERSION
-  assert_padding(obj, pad_byte);
-#else
-  (void)obj;
-  (void)pad_byte;
-#endif
-}
-
 template <class T>
 void test() {
   {
@@ -130,8 +122,10 @@ void test() {
     assert(!r);
     assert(expected.i == 10);
     assert(expected.c == 'a');
-    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_padding(expected, 0);
+// expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+#ifdef _LIBCPP_VERSION
+    assert_padding(expected, 0);
+#endif
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');
@@ -198,8 +192,10 @@ void test() {
         // Spurious failure: expected is updated to the current atomic value.
         assert(expected.i == 10);
         assert(expected.c == 'a');
-        // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-        libcpp_assert_padding(expected, 0);
+// expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+#ifdef _LIBCPP_VERSION
+        assert_padding(expected, 0);
+#endif
       }
     }
 
@@ -229,8 +225,10 @@ void test() {
     assert(!r);
     assert(expected.i == 10);
     assert(expected.c == 'a');
-    // expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
-    libcpp_assert_padding(expected, 0);
+// expected is updated to contain atomic's value and in libc++, the paddings bits are always zero
+#ifdef _LIBCPP_VERSION
+    assert_padding(expected, 0);
+#endif
     T loaded = a.load();
     assert(loaded.i == 10);
     assert(loaded.c == 'a');

>From d6693408d56e7547391faec30aae13d42f290ab4 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 25 Jul 2026 17:59:09 +0100
Subject: [PATCH 35/36] inline

---
 libcxx/include/__atomic/clear_padding.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__atomic/clear_padding.h b/libcxx/include/__atomic/clear_padding.h
index be55837cd8ec8..366c7d50b3734 100644
--- a/libcxx/include/__atomic/clear_padding.h
+++ b/libcxx/include/__atomic/clear_padding.h
@@ -46,11 +46,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __ob
   return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
 }
 
+// clang fails to inline the function when the memory order is a constant
 template <class _Tp,
           class _Up,
           class _CasFunc,
           __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE bool
+__atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
   return __cas_func(__expected, __value);
 }
 
@@ -78,7 +80,8 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __ob
 }
 
 template <class _Tp, class _Up, class _CasFunc>
-_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE bool
+__atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
   return __cas_func(__expected, __value);
 }
 

>From 2c65fc7458412e4347b328150011e67d97318499 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sat, 25 Jul 2026 21:17:36 +0100
Subject: [PATCH 36/36] f

---
 .../test/configs/llvm-libc++-llvm-libc.cfg.in |  2 +-
 .../atomics.types.generic/padding.pass.cpp    |  1 +
 .../atomics.types.generic/padding.pass.cpp    |  2 +-
 libcxx/utils/libcxx/test/features/misc.py     | 37 +++++++------------
 4 files changed, 17 insertions(+), 25 deletions(-)

diff --git a/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in b/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
index 9c462aa8dd49b..885715eb42dfc 100644
--- a/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
+++ b/libcxx/test/configs/llvm-libc++-llvm-libc.cfg.in
@@ -8,7 +8,7 @@ config.substitutions.append(('%{compile_flags}',
     '-nostdlibinc -I %{include-dir} -I %{target-include-dir} -isystem @CMAKE_BINARY_DIR@/libc/include -I %{libcxx-dir}/test/support -idirafter @LIBC_KERNEL_HEADERS@'
 ))
 config.substitutions.append(('%{link_flags}',
-    '-nodefaultlibs -nostartfiles -L %{lib-dir} -lc++ -lc++abi @CMAKE_BINARY_DIR@/libc/startup/linux/crt1.o -Wl,--start-group @CMAKE_BINARY_DIR@/libc/lib/libc.a @CMAKE_BINARY_DIR@/libc/lib/libm.a -static -fno-use-cxa-atexit @CMAKE_BINARY_DIR@/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a -Wl,--end-group -Wl,--defsym,__dso_handle=0 -pthread'
+    '-nodefaultlibs -nostartfiles -L %{lib-dir} -lc++ -lc++abi @CMAKE_BINARY_DIR@/libc/startup/linux/crt1.o -Wl,--start-group @CMAKE_BINARY_DIR@/libc/lib/libc.a @CMAKE_BINARY_DIR@/libc/lib/libm.a -static -fno-use-cxa-atexit @CMAKE_BINARY_DIR@/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a -Wl,--end-group -Wl,--defsym,__dso_handle=0'
 ))
 config.substitutions.append(('%{exec}',
     '%{executor} --execdir %{temp} -- '
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
index 1029ede2f7181..a01720ab5f49b 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
+// XFAIL: !has-128-bit-atomics
 
 // Older Clang doesn't implement __builtin_clear_padding
 // XFAIL: clang-21, apple-clang-21, clang-22
diff --git a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
index 5721acf4a66fe..241815b5da90a 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03
-// XFAIL: !has-64-bit-atomics
+// XFAIL: !has-128-bit-atomics
 
 // Older Clang doesn't implement __builtin_clear_padding
 // XFAIL: clang-21, apple-clang-21, clang-22
diff --git a/libcxx/utils/libcxx/test/features/misc.py b/libcxx/utils/libcxx/test/features/misc.py
index 464d2aaaad79c..efc341257ad4a 100644
--- a/libcxx/utils/libcxx/test/features/misc.py
+++ b/libcxx/utils/libcxx/test/features/misc.py
@@ -91,29 +91,20 @@ def _mingwSupportsModules(cfg):
         ),
         actions=[AddLinkFlag("-latomic")],
     ),
-    Feature(
-        name="has-64-bit-atomics",
-        when=lambda cfg: sourceBuilds(
-            cfg,
-            """
-            #include <atomic>
-            struct Large { char storage[64/8]; };
-            std::atomic<Large> x;
-            int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
-          """,
-        ),
-    ),
-    Feature(
-        name="has-1024-bit-atomics",
-        when=lambda cfg: sourceBuilds(
-            cfg,
-            """
-            #include <atomic>
-            struct Large { char storage[1024/8]; };
-            std::atomic<Large> x;
-            int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
-          """,
-        ),
+    *(
+        Feature(
+            name=f"has-{x}-bit-atomics",
+            when=lambda cfg, x=x: sourceBuilds(
+                cfg,
+                f"""
+                #include <atomic>
+                struct Large {{ char storage[{x}/8]; }};
+                std::atomic<Large> x;
+                int main(int, char**) {{ (void)x.load(); (void)x.is_lock_free(); return 0; }}
+                """,
+            ),
+        )
+        for x in [64, 128, 1024]
     ),
     # Tests that require 64-bit architecture
     Feature(



More information about the libcxx-commits mailing list