Skip to content

Commit 934650b

Browse files
committed
[libc++] Add [[clang::lifetimebound]] to min/max algorithms
Reviewed By: Mordante, #libc Spies: libcxx-commits Differential Revision: https://reviews.llvm.org/D142608
1 parent 23872aa commit 934650b

File tree

8 files changed

+93
-10
lines changed

8 files changed

+93
-10
lines changed

libcxx/include/__algorithm/max.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ template <class _Tp, class _Compare>
2828
_LIBCPP_NODISCARD_EXT inline
2929
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
3030
const _Tp&
31-
max(const _Tp& __a, const _Tp& __b, _Compare __comp)
31+
max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp)
3232
{
3333
return __comp(__a, __b) ? __b : __a;
3434
}
@@ -37,7 +37,7 @@ template <class _Tp>
3737
_LIBCPP_NODISCARD_EXT inline
3838
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
3939
const _Tp&
40-
max(const _Tp& __a, const _Tp& __b)
40+
max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
4141
{
4242
return _VSTD::max(__a, __b, __less<_Tp>());
4343
}

libcxx/include/__algorithm/min.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ template <class _Tp, class _Compare>
2828
_LIBCPP_NODISCARD_EXT inline
2929
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
3030
const _Tp&
31-
min(const _Tp& __a, const _Tp& __b, _Compare __comp)
31+
min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp)
3232
{
3333
return __comp(__b, __a) ? __b : __a;
3434
}
@@ -37,7 +37,7 @@ template <class _Tp>
3737
_LIBCPP_NODISCARD_EXT inline
3838
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
3939
const _Tp&
40-
min(const _Tp& __a, const _Tp& __b)
40+
min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
4141
{
4242
return _VSTD::min(__a, __b, __less<_Tp>());
4343
}

libcxx/include/__algorithm/minmax.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ template<class _Tp, class _Compare>
2727
_LIBCPP_NODISCARD_EXT inline
2828
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
2929
pair<const _Tp&, const _Tp&>
30-
minmax(const _Tp& __a, const _Tp& __b, _Compare __comp)
30+
minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp)
3131
{
3232
return __comp(__b, __a) ? pair<const _Tp&, const _Tp&>(__b, __a) :
3333
pair<const _Tp&, const _Tp&>(__a, __b);
@@ -37,7 +37,7 @@ template<class _Tp>
3737
_LIBCPP_NODISCARD_EXT inline
3838
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
3939
pair<const _Tp&, const _Tp&>
40-
minmax(const _Tp& __a, const _Tp& __b)
40+
minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
4141
{
4242
return std::minmax(__a, __b, __less<_Tp>());
4343
}

libcxx/include/__algorithm/ranges_max.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ struct __fn {
4040
template <class _Tp, class _Proj = identity,
4141
indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less>
4242
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
43-
const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const {
43+
const _Tp& operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a,
44+
_LIBCPP_LIFETIMEBOUND const _Tp& __b,
45+
_Comp __comp = {},
46+
_Proj __proj = {}) const {
4447
return std::invoke(__comp, std::invoke(__proj, __a), std::invoke(__proj, __b)) ? __b : __a;
4548
}
4649

libcxx/include/__algorithm/ranges_min.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ struct __fn {
3939
template <class _Tp, class _Proj = identity,
4040
indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less>
4141
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
42-
const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const {
42+
const _Tp& operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a,
43+
_LIBCPP_LIFETIMEBOUND const _Tp& __b,
44+
_Comp __comp = {},
45+
_Proj __proj = {}) const {
4346
return std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a)) ? __b : __a;
4447
}
4548

libcxx/include/__algorithm/ranges_minmax.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ struct __fn {
4646
template <class _Type, class _Proj = identity,
4747
indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less>
4848
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<const _Type&>
49-
operator()(const _Type& __a, const _Type& __b, _Comp __comp = {}, _Proj __proj = {}) const {
49+
operator()(_LIBCPP_LIFETIMEBOUND const _Type& __a,
50+
_LIBCPP_LIFETIMEBOUND const _Type& __b,
51+
_Comp __comp = {},
52+
_Proj __proj = {}) const {
5053
if (std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a)))
5154
return {__b, __a};
5255
return {__a, __b};

libcxx/include/module.modulemap.in

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,10 @@ module std [system] {
298298
module min { private header "__algorithm/min.h" }
299299
module min_element { private header "__algorithm/min_element.h" }
300300
module min_max_result { private header "__algorithm/min_max_result.h" }
301-
module minmax { private header "__algorithm/minmax.h" }
301+
module minmax {
302+
private header "__algorithm/minmax.h"
303+
export *
304+
}
302305
module minmax_element { private header "__algorithm/minmax_element.h" }
303306
module mismatch { private header "__algorithm/mismatch.h" }
304307
module move { private header "__algorithm/move.h" }
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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: c++03
10+
// ADDITIONAL_COMPILE_FLAGS: -Wno-pessimizing-move -Wno-unused-variable
11+
12+
#include <algorithm>
13+
14+
#include "test_macros.h"
15+
16+
struct Comp {
17+
template <class T, class U>
18+
bool operator()(T, U) {
19+
return false;
20+
}
21+
};
22+
23+
void func() {
24+
int i = 0;
25+
{
26+
auto&& v1 = std::min(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
27+
auto&& v2 = std::min(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
28+
auto&& v3 = std::min(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
29+
auto&& v4 = std::min(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
30+
}
31+
{
32+
auto&& v1 = std::max(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
33+
auto&& v2 = std::max(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
34+
auto&& v3 = std::max(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
35+
auto&& v4 = std::max(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
36+
}
37+
{
38+
auto&& v1 = std::minmax(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
39+
auto&& v2 = std::minmax(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
40+
auto&& v3 = std::minmax(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
41+
auto&& v4 = std::minmax(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
42+
auto v5 = std::minmax(0, i); // expected-warning {{temporary whose address is used as value of local variable 'v5' will be destroyed at the end of the full-expression}}
43+
auto v6 = std::minmax(i, 0); // expected-warning {{temporary whose address is used as value of local variable 'v6' will be destroyed at the end of the full-expression}}
44+
auto v7 = std::minmax(0, i, Comp{}); // expected-warning {{temporary whose address is used as value of local variable 'v7' will be destroyed at the end of the full-expression}}
45+
auto v8 = std::minmax(i, 0, Comp{}); // expected-warning {{temporary whose address is used as value of local variable 'v8' will be destroyed at the end of the full-expression}}
46+
}
47+
#if TEST_STD_VER >= 20
48+
{
49+
auto&& v1 = std::ranges::min(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
50+
auto&& v2 = std::ranges::min(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
51+
auto&& v3 = std::ranges::min(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
52+
auto&& v4 = std::ranges::min(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
53+
}
54+
{
55+
auto&& v1 = std::ranges::max(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
56+
auto&& v2 = std::ranges::max(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
57+
auto&& v3 = std::ranges::max(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
58+
auto&& v4 = std::ranges::max(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
59+
}
60+
{
61+
auto&& v1 = std::ranges::minmax(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
62+
auto&& v2 = std::ranges::minmax(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
63+
auto&& v3 = std::ranges::minmax(0, i, Comp{}); // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
64+
auto&& v4 = std::ranges::minmax(i, 0, Comp{}); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
65+
auto v5 = std::ranges::minmax(0, i); // expected-warning {{temporary whose address is used as value of local variable 'v5' will be destroyed at the end of the full-expression}}
66+
auto v6 = std::ranges::minmax(i, 0); // expected-warning {{temporary whose address is used as value of local variable 'v6' will be destroyed at the end of the full-expression}}
67+
auto v7 = std::ranges::minmax(0, i, Comp{}); // expected-warning {{temporary whose address is used as value of local variable 'v7' will be destroyed at the end of the full-expression}}
68+
auto v8 = std::ranges::minmax(i, 0, Comp{}); // expected-warning {{temporary whose address is used as value of local variable 'v8' will be destroyed at the end of the full-expression}}
69+
}
70+
#endif // TEST_STD_VER >= 20
71+
}

0 commit comments

Comments
 (0)