769c42f4a552a75c8c38870ddc1b50d2ea874e4e.patch (3927B)
1 From 769c42f4a552a75c8c38870ddc1b50d2ea874e4e Mon Sep 17 00:00:00 2001 2 From: "A. Jiang" <de34@live.cn> 3 Date: Tue, 3 Jun 2025 23:54:49 +0800 4 Subject: [PATCH] [libc++] Fix padding calculation for function reference types 5 (#142125) 6 7 #109028 caused `sizeof` to be sometimes applied to function reference 8 types, which makes a program ill-formed. This PR handles reference types 9 by specializations to prevent such bogus `sizeof` expression to be 10 instantiated. 11 12 Fixes #142118. 13 --- 14 libcxx/include/__memory/compressed_pair.h | 15 +++++++++++---- 15 .../unique.ptr.ctor/pointer_deleter.pass.cpp | 19 +++++++++++++++++++ 16 2 files changed, 30 insertions(+), 4 deletions(-) 17 18 diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h 19 index 38798a21fa3c9..fb7b7b7afcc8c 100644 20 --- a/libcxx/include/__memory/compressed_pair.h 21 +++ b/libcxx/include/__memory/compressed_pair.h 22 @@ -15,7 +15,6 @@ 23 #include <__type_traits/datasizeof.h> 24 #include <__type_traits/is_empty.h> 25 #include <__type_traits/is_final.h> 26 -#include <__type_traits/is_reference.h> 27 28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 29 # pragma GCC system_header 30 @@ -63,9 +62,17 @@ inline const size_t __compressed_pair_alignment = _LIBCPP_ALIGNOF(_Tp); 31 template <class _Tp> 32 inline const size_t __compressed_pair_alignment<_Tp&> = _LIBCPP_ALIGNOF(void*); 33 34 -template <class _ToPad, 35 - bool _Empty = ((is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || 36 - is_reference<_ToPad>::value || sizeof(_ToPad) == __datasizeof_v<_ToPad>)> 37 +template <class _ToPad> 38 +inline const bool __is_reference_or_unpadded_object = 39 + (is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || sizeof(_ToPad) == __datasizeof_v<_ToPad>; 40 + 41 +template <class _Tp> 42 +inline const bool __is_reference_or_unpadded_object<_Tp&> = true; 43 + 44 +template <class _Tp> 45 +inline const bool __is_reference_or_unpadded_object<_Tp&&> = true; 46 + 47 +template <class _ToPad, bool _Empty = __is_reference_or_unpadded_object<_ToPad> > 48 class __compressed_pair_padding { 49 char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {}; 50 }; 51 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 52 index a91abc856fb19..a438bfb58ce44 100644 53 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp 54 +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp 55 @@ -32,6 +32,8 @@ bool my_free_called = false; 56 57 void my_free(void*) { my_free_called = true; } 58 59 +TEST_CONSTEXPR_CXX23 void deleter_function(A*) {} 60 + 61 #if TEST_STD_VER >= 11 62 struct DeleterBase { 63 TEST_CONSTEXPR_CXX23 void operator()(void*) const {} 64 @@ -325,6 +327,21 @@ TEST_CONSTEXPR_CXX23 void test_nullptr() { 65 #endif 66 } 67 68 +template <bool IsArray> 69 +TEST_CONSTEXPR_CXX23 void test_function_reference() { 70 + typedef typename std::conditional<!IsArray, A, A[]>::type VT; 71 + { 72 + std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function); 73 + assert(u.get() == nullptr); 74 + assert(u.get_deleter() == deleter_function); 75 + } 76 + { 77 + std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function); 78 + assert(u.get() == nullptr); 79 + assert(u.get_deleter() == deleter_function); 80 + } 81 +} 82 + 83 TEST_CONSTEXPR_CXX23 bool test() { 84 { 85 test_basic</*IsArray*/ false>(); 86 @@ -332,6 +349,7 @@ TEST_CONSTEXPR_CXX23 bool test() { 87 test_basic_single(); 88 test_sfinae<false>(); 89 test_noexcept<false>(); 90 + test_function_reference<false>(); 91 } 92 { 93 test_basic</*IsArray*/ true>(); 94 @@ -339,6 +357,7 @@ TEST_CONSTEXPR_CXX23 bool test() { 95 test_sfinae<true>(); 96 test_sfinae_runtime(); 97 test_noexcept<true>(); 98 + test_function_reference<true>(); 99 } 100 101 return true;