diff --git a/libcxx/include/__algorithm/max.h b/libcxx/include/__algorithm/max.h --- a/libcxx/include/__algorithm/max.h +++ b/libcxx/include/__algorithm/max.h @@ -28,7 +28,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& -max(const _Tp& __a, const _Tp& __b, _Compare __comp) +max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { return __comp(__a, __b) ? __b : __a; } @@ -37,7 +37,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& -max(const _Tp& __a, const _Tp& __b) +max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { return _VSTD::max(__a, __b, __less<_Tp>()); } diff --git a/libcxx/include/__algorithm/min.h b/libcxx/include/__algorithm/min.h --- a/libcxx/include/__algorithm/min.h +++ b/libcxx/include/__algorithm/min.h @@ -28,7 +28,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& -min(const _Tp& __a, const _Tp& __b, _Compare __comp) +min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { return __comp(__b, __a) ? __b : __a; } @@ -37,7 +37,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& -min(const _Tp& __a, const _Tp& __b) +min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { return _VSTD::min(__a, __b, __less<_Tp>()); } diff --git a/libcxx/include/__algorithm/minmax.h b/libcxx/include/__algorithm/minmax.h --- a/libcxx/include/__algorithm/minmax.h +++ b/libcxx/include/__algorithm/minmax.h @@ -27,7 +27,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 pair -minmax(const _Tp& __a, const _Tp& __b, _Compare __comp) +minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { return __comp(__b, __a) ? pair(__b, __a) : pair(__a, __b); @@ -37,7 +37,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 pair -minmax(const _Tp& __a, const _Tp& __b) +minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { return std::minmax(__a, __b, __less<_Tp>()); } diff --git a/libcxx/include/__algorithm/ranges_max.h b/libcxx/include/__algorithm/ranges_max.h --- a/libcxx/include/__algorithm/ranges_max.h +++ b/libcxx/include/__algorithm/ranges_max.h @@ -40,7 +40,10 @@ template > _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr - const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const { + const _Tp& operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a, + _LIBCPP_LIFETIMEBOUND const _Tp& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { return std::invoke(__comp, std::invoke(__proj, __a), std::invoke(__proj, __b)) ? __b : __a; } diff --git a/libcxx/include/__algorithm/ranges_min.h b/libcxx/include/__algorithm/ranges_min.h --- a/libcxx/include/__algorithm/ranges_min.h +++ b/libcxx/include/__algorithm/ranges_min.h @@ -39,7 +39,10 @@ template > _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr - const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const { + const _Tp& operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a, + _LIBCPP_LIFETIMEBOUND const _Tp& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { return std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a)) ? __b : __a; } diff --git a/libcxx/include/__algorithm/ranges_minmax.h b/libcxx/include/__algorithm/ranges_minmax.h --- a/libcxx/include/__algorithm/ranges_minmax.h +++ b/libcxx/include/__algorithm/ranges_minmax.h @@ -46,7 +46,10 @@ template > _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result - operator()(const _Type& __a, const _Type& __b, _Comp __comp = {}, _Proj __proj = {}) const { + operator()(_LIBCPP_LIFETIMEBOUND const _Type& __a, + _LIBCPP_LIFETIMEBOUND const _Type& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { if (std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a))) return {__b, __a}; return {__a, __b}; diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -298,7 +298,10 @@ module min { private header "__algorithm/min.h" } module min_element { private header "__algorithm/min_element.h" } module min_max_result { private header "__algorithm/min_max_result.h" } - module minmax { private header "__algorithm/minmax.h" } + module minmax { + private header "__algorithm/minmax.h" + export * + } module minmax_element { private header "__algorithm/minmax_element.h" } module mismatch { private header "__algorithm/mismatch.h" } module move { private header "__algorithm/move.h" } diff --git a/libcxx/test/libcxx/algorithms/lifetimebound.verify.cpp b/libcxx/test/libcxx/algorithms/lifetimebound.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/lifetimebound.verify.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 +// ADDITIONAL_COMPILE_FLAGS: -Wno-pessimizing-move -Wno-unused-variable + +#include + +#include "test_macros.h" + +struct Comp { + template + bool operator()(T, U) { + return false; + } +}; + +void func() { + int i = 0; + { + auto&& v1 = std::min(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}} + auto&& v2 = std::min(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}} + 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}} + 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}} + } + { + auto&& v1 = std::max(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}} + auto&& v2 = std::max(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}} + 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}} + 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}} + } + { + auto&& v1 = std::minmax(0, i); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}} + auto&& v2 = std::minmax(i, 0); // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}} + 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}} + 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}} + 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}} + 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}} + 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}} + 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}} + } +#if TEST_STD_VER >= 20 + { + 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}} + 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}} + 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}} + 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}} + } + { + 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}} + 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}} + 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}} + 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}} + } + { + 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}} + 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}} + 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}} + 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}} + 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}} + 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}} + 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}} + 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}} + } +#endif // TEST_STD_VER >= 20 +}