[libcxx-commits] [libcxx] [libc++] Fix padding calculation for function reference types (PR #142125)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Fri May 30 04:21:33 PDT 2025


https://github.com/frederick-vs-ja created https://github.com/llvm/llvm-project/pull/142125

#109028 caused `sizeof` to be sometimes applied to function reference types, which makes a program ill-formed. This PR handles reference types by specializations to prevent such bogus `sizeof` expression to be instantiated.

Fixes #142118.

>From e41699f73cee80536401bbe87d1f907e26a1facf Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Fri, 30 May 2025 19:17:52 +0800
Subject: [PATCH] [libc++] Fix padding calculation for function reference types

---
 libcxx/include/__memory/compressed_pair.h     | 15 +++++++++++----
 .../unique.ptr.ctor/pointer_deleter.pass.cpp  | 19 +++++++++++++++++++
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h
index 38798a21fa3c9..fb7b7b7afcc8c 100644
--- a/libcxx/include/__memory/compressed_pair.h
+++ b/libcxx/include/__memory/compressed_pair.h
@@ -15,7 +15,6 @@
 #include <__type_traits/datasizeof.h>
 #include <__type_traits/is_empty.h>
 #include <__type_traits/is_final.h>
-#include <__type_traits/is_reference.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -63,9 +62,17 @@ inline const size_t __compressed_pair_alignment = _LIBCPP_ALIGNOF(_Tp);
 template <class _Tp>
 inline const size_t __compressed_pair_alignment<_Tp&> = _LIBCPP_ALIGNOF(void*);
 
-template <class _ToPad,
-          bool _Empty = ((is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) ||
-                         is_reference<_ToPad>::value || sizeof(_ToPad) == __datasizeof_v<_ToPad>)>
+template <class _ToPad>
+inline const bool __is_reference_or_unpadded_object =
+    (is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || sizeof(_ToPad) == __datasizeof_v<_ToPad>;
+
+template <class _Tp>
+inline const bool __is_reference_or_unpadded_object<_Tp&> = true;
+
+template <class _Tp>
+inline const bool __is_reference_or_unpadded_object<_Tp&&> = true;
+
+template <class _ToPad, bool _Empty = __is_reference_or_unpadded_object<_ToPad> >
 class __compressed_pair_padding {
   char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {};
 };
diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp
index a91abc856fb19..a438bfb58ce44 100644
--- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp
@@ -32,6 +32,8 @@ bool my_free_called = false;
 
 void my_free(void*) { my_free_called = true; }
 
+TEST_CONSTEXPR_CXX23 void deleter_function(A*) {}
+
 #if TEST_STD_VER >= 11
 struct DeleterBase {
   TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
@@ -325,6 +327,21 @@ TEST_CONSTEXPR_CXX23 void test_nullptr() {
 #endif
 }
 
+template <bool IsArray>
+TEST_CONSTEXPR_CXX23 void test_function_reference() {
+  typedef typename std::conditional<!IsArray, A, A[]>::type VT;
+  {
+    std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function);
+    assert(u.get() == nullptr);
+    assert(u.get_deleter() == deleter_function);
+  }
+  {
+    std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function);
+    assert(u.get() == nullptr);
+    assert(u.get_deleter() == deleter_function);
+  }
+}
+
 TEST_CONSTEXPR_CXX23 bool test() {
   {
     test_basic</*IsArray*/ false>();
@@ -332,6 +349,7 @@ TEST_CONSTEXPR_CXX23 bool test() {
     test_basic_single();
     test_sfinae<false>();
     test_noexcept<false>();
+    test_function_reference<false>();
   }
   {
     test_basic</*IsArray*/ true>();
@@ -339,6 +357,7 @@ TEST_CONSTEXPR_CXX23 bool test() {
     test_sfinae<true>();
     test_sfinae_runtime();
     test_noexcept<true>();
+    test_function_reference<true>();
   }
 
   return true;



More information about the libcxx-commits mailing list