Skip to content

Commit b0668d8

Browse files
authored
[libc++] Make sure that __desugars_to isn't tripped up by reference_wrapper, const and ref qualifiers (#132092)
Previously, const and ref qualification on an operation would cause __desugars_to to report false, which would lead to unnecessary pessimizations. The same holds for reference_wrapper. In practice, const and ref qualifications on the operation itself are not relevant to determining whether an operation desugars to something else or not, so can be ignored. We are not stripping volatile qualifiers from operations in this patch because we feel that this requires additional discussion. Fixes #129312
1 parent 9243f99 commit b0668d8

File tree

6 files changed

+98
-6
lines changed

6 files changed

+98
-6
lines changed

libcxx/include/__algorithm/sort.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include <__type_traits/is_constant_evaluated.h>
3535
#include <__type_traits/is_same.h>
3636
#include <__type_traits/is_trivially_copyable.h>
37-
#include <__type_traits/remove_cvref.h>
3837
#include <__utility/move.h>
3938
#include <__utility/pair.h>
4039
#include <climits>
@@ -52,8 +51,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
5251
template <class _Compare, class _Iter, class _Tp = typename iterator_traits<_Iter>::value_type>
5352
inline const bool __use_branchless_sort =
5453
__libcpp_is_contiguous_iterator<_Iter>::value && __is_cheap_to_copy<_Tp> && is_arithmetic<_Tp>::value &&
55-
(__desugars_to_v<__less_tag, __remove_cvref_t<_Compare>, _Tp, _Tp> ||
56-
__desugars_to_v<__greater_tag, __remove_cvref_t<_Compare>, _Tp, _Tp>);
54+
(__desugars_to_v<__less_tag, _Compare, _Tp, _Tp> || __desugars_to_v<__greater_tag, _Compare, _Tp, _Tp>);
5755

5856
namespace __detail {
5957

libcxx/include/__algorithm/stable_sort.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include <__type_traits/is_integral.h>
3030
#include <__type_traits/is_same.h>
3131
#include <__type_traits/is_trivially_assignable.h>
32-
#include <__type_traits/remove_cvref.h>
3332
#include <__utility/move.h>
3433
#include <__utility/pair.h>
3534

@@ -246,8 +245,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
246245
}
247246

248247
#if _LIBCPP_STD_VER >= 17
249-
constexpr auto __default_comp =
250-
__desugars_to_v<__totally_ordered_less_tag, __remove_cvref_t<_Compare>, value_type, value_type >;
248+
constexpr auto __default_comp = __desugars_to_v<__totally_ordered_less_tag, _Compare, value_type, value_type >;
251249
constexpr auto __integral_value =
252250
is_integral_v<value_type > && is_same_v< value_type&, __iter_reference<_RandomAccessIterator>>;
253251
constexpr auto __allowed_radix_sort = __default_comp && __integral_value;

libcxx/include/__functional/reference_wrapper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <__config>
1616
#include <__functional/weak_result_type.h>
1717
#include <__memory/addressof.h>
18+
#include <__type_traits/desugars_to.h>
1819
#include <__type_traits/enable_if.h>
1920
#include <__type_traits/invoke.h>
2021
#include <__type_traits/is_const.h>
@@ -149,6 +150,11 @@ void ref(const _Tp&&) = delete;
149150
template <class _Tp>
150151
void cref(const _Tp&&) = delete;
151152

153+
// Let desugars-to pass through std::reference_wrapper
154+
template <class _CanonicalTag, class _Operation, class... _Args>
155+
inline const bool __desugars_to_v<_CanonicalTag, reference_wrapper<_Operation>, _Args...> =
156+
__desugars_to_v<_CanonicalTag, _Operation, _Args...>;
157+
152158
_LIBCPP_END_NAMESPACE_STD
153159

154160
#endif // _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H

libcxx/include/__type_traits/desugars_to.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ struct __totally_ordered_less_tag {};
5252
template <class _CanonicalTag, class _Operation, class... _Args>
5353
inline const bool __desugars_to_v = false;
5454

55+
// For the purpose of determining whether something desugars to something else,
56+
// we disregard const and ref qualifiers on the operation itself.
57+
template <class _CanonicalTag, class _Operation, class... _Args>
58+
inline const bool __desugars_to_v<_CanonicalTag, _Operation const, _Args...> =
59+
__desugars_to_v<_CanonicalTag, _Operation, _Args...>;
60+
template <class _CanonicalTag, class _Operation, class... _Args>
61+
inline const bool __desugars_to_v<_CanonicalTag, _Operation&, _Args...> =
62+
__desugars_to_v<_CanonicalTag, _Operation, _Args...>;
63+
template <class _CanonicalTag, class _Operation, class... _Args>
64+
inline const bool __desugars_to_v<_CanonicalTag, _Operation&&, _Args...> =
65+
__desugars_to_v<_CanonicalTag, _Operation, _Args...>;
66+
5567
_LIBCPP_END_NAMESPACE_STD
5668

5769
#endif // _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: FROZEN-CXX03-HEADERS-FIXME
10+
11+
// This test requires variable templates
12+
// UNSUPPORTED: gcc && c++11
13+
14+
#include <__type_traits/desugars_to.h>
15+
16+
struct Tag {};
17+
struct Operation {};
18+
19+
namespace std {
20+
template <>
21+
bool const __desugars_to_v<Tag, Operation> = true;
22+
}
23+
24+
void tests() {
25+
// Make sure that __desugars_to is false by default
26+
{
27+
struct Foo {};
28+
static_assert(!std::__desugars_to_v<Tag, Foo>, "");
29+
}
30+
31+
// Make sure that __desugars_to bypasses const and ref qualifiers on the operation
32+
{
33+
static_assert(std::__desugars_to_v<Tag, Operation>, ""); // no quals
34+
static_assert(std::__desugars_to_v<Tag, Operation const>, "");
35+
36+
static_assert(std::__desugars_to_v<Tag, Operation&>, "");
37+
static_assert(std::__desugars_to_v<Tag, Operation const&>, "");
38+
39+
static_assert(std::__desugars_to_v<Tag, Operation&&>, "");
40+
static_assert(std::__desugars_to_v<Tag, Operation const&&>, "");
41+
}
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: FROZEN-CXX03-HEADERS-FIXME
10+
11+
// This test requires variable templates
12+
// UNSUPPORTED: gcc && c++11
13+
14+
// <functional>
15+
16+
// reference_wrapper
17+
18+
// Ensure that std::reference_wrapper does not inhibit optimizations based on the
19+
// std::__desugars_to internal helper.
20+
21+
#include <functional>
22+
#include <__type_traits/desugars_to.h>
23+
24+
struct Operation {};
25+
struct Tag {};
26+
27+
namespace std {
28+
template <>
29+
bool const __desugars_to_v<Tag, Operation> = true;
30+
}
31+
32+
static_assert(std::__desugars_to_v<Tag, Operation>, "something is wrong with the test");
33+
34+
// make sure we pass through reference_wrapper
35+
static_assert(std::__desugars_to_v<Tag, std::reference_wrapper<Operation> >, "");
36+
static_assert(std::__desugars_to_v<Tag, std::reference_wrapper<Operation const> >, "");

0 commit comments

Comments
 (0)