Skip to content

Commit 769c42f

Browse files
[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.
1 parent 6ca59aa commit 769c42f

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

libcxx/include/__memory/compressed_pair.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include <__type_traits/datasizeof.h>
1616
#include <__type_traits/is_empty.h>
1717
#include <__type_traits/is_final.h>
18-
#include <__type_traits/is_reference.h>
1918

2019
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2120
# pragma GCC system_header
@@ -63,9 +62,17 @@ inline const size_t __compressed_pair_alignment = _LIBCPP_ALIGNOF(_Tp);
6362
template <class _Tp>
6463
inline const size_t __compressed_pair_alignment<_Tp&> = _LIBCPP_ALIGNOF(void*);
6564

66-
template <class _ToPad,
67-
bool _Empty = ((is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) ||
68-
is_reference<_ToPad>::value || sizeof(_ToPad) == __datasizeof_v<_ToPad>)>
65+
template <class _ToPad>
66+
inline const bool __is_reference_or_unpadded_object =
67+
(is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || sizeof(_ToPad) == __datasizeof_v<_ToPad>;
68+
69+
template <class _Tp>
70+
inline const bool __is_reference_or_unpadded_object<_Tp&> = true;
71+
72+
template <class _Tp>
73+
inline const bool __is_reference_or_unpadded_object<_Tp&&> = true;
74+
75+
template <class _ToPad, bool _Empty = __is_reference_or_unpadded_object<_ToPad> >
6976
class __compressed_pair_padding {
7077
char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {};
7178
};

libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ bool my_free_called = false;
3232

3333
void my_free(void*) { my_free_called = true; }
3434

35+
TEST_CONSTEXPR_CXX23 void deleter_function(A*) {}
36+
3537
#if TEST_STD_VER >= 11
3638
struct DeleterBase {
3739
TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
@@ -325,20 +327,37 @@ TEST_CONSTEXPR_CXX23 void test_nullptr() {
325327
#endif
326328
}
327329

330+
template <bool IsArray>
331+
TEST_CONSTEXPR_CXX23 void test_function_reference() {
332+
typedef typename std::conditional<!IsArray, A, A[]>::type VT;
333+
{
334+
std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function);
335+
assert(u.get() == nullptr);
336+
assert(u.get_deleter() == deleter_function);
337+
}
338+
{
339+
std::unique_ptr<VT, void (&)(A*)> u(nullptr, deleter_function);
340+
assert(u.get() == nullptr);
341+
assert(u.get_deleter() == deleter_function);
342+
}
343+
}
344+
328345
TEST_CONSTEXPR_CXX23 bool test() {
329346
{
330347
test_basic</*IsArray*/ false>();
331348
test_nullptr<false>();
332349
test_basic_single();
333350
test_sfinae<false>();
334351
test_noexcept<false>();
352+
test_function_reference<false>();
335353
}
336354
{
337355
test_basic</*IsArray*/ true>();
338356
test_nullptr<true>();
339357
test_sfinae<true>();
340358
test_sfinae_runtime();
341359
test_noexcept<true>();
360+
test_function_reference<true>();
342361
}
343362

344363
return true;

0 commit comments

Comments
 (0)