[libc++] Fix padding calculation for function reference types (#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.
This commit is contained in:
A. Jiang
2025-06-03 23:54:49 +08:00
committed by GitHub
parent 6ca59aae8e
commit 769c42f4a5
2 changed files with 30 additions and 4 deletions

View File

@@ -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>] = {};
};

View File

@@ -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;