[libcxx-commits] [libcxx] 934650b - [libc++] Add [[clang::lifetimebound]] to min/max algorithms

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 30 09:01:53 PST 2023


Author: Nikolas Klauser
Date: 2023-01-30T18:01:46+01:00
New Revision: 934650b24fbfea88c34f735b9cfd0d86e0f608d9

URL: https://github.com/llvm/llvm-project/commit/934650b24fbfea88c34f735b9cfd0d86e0f608d9
DIFF: https://github.com/llvm/llvm-project/commit/934650b24fbfea88c34f735b9cfd0d86e0f608d9.diff

LOG: [libc++] Add [[clang::lifetimebound]] to min/max algorithms

Reviewed By: Mordante, #libc

Spies: libcxx-commits

Differential Revision: https://reviews.llvm.org/D142608

Added: 
    libcxx/test/libcxx/algorithms/lifetimebound.verify.cpp

Modified: 
    libcxx/include/__algorithm/max.h
    libcxx/include/__algorithm/min.h
    libcxx/include/__algorithm/minmax.h
    libcxx/include/__algorithm/ranges_max.h
    libcxx/include/__algorithm/ranges_min.h
    libcxx/include/__algorithm/ranges_minmax.h
    libcxx/include/module.modulemap.in

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__algorithm/max.h b/libcxx/include/__algorithm/max.h
index a08a3fc59bdad..97f61f2aad6b9 100644
--- a/libcxx/include/__algorithm/max.h
+++ b/libcxx/include/__algorithm/max.h
@@ -28,7 +28,7 @@ template <class _Tp, class _Compare>
 _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 @@ template <class _Tp>
 _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
index 2882485ad76f9..d073a16533e4d 100644
--- a/libcxx/include/__algorithm/min.h
+++ b/libcxx/include/__algorithm/min.h
@@ -28,7 +28,7 @@ template <class _Tp, class _Compare>
 _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 @@ template <class _Tp>
 _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
index 6ef0a777083f9..f486de2efd75b 100644
--- a/libcxx/include/__algorithm/minmax.h
+++ b/libcxx/include/__algorithm/minmax.h
@@ -27,7 +27,7 @@ template<class _Tp, class _Compare>
 _LIBCPP_NODISCARD_EXT inline
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
 pair<const _Tp&, const _Tp&>
-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<const _Tp&, const _Tp&>(__b, __a) :
                               pair<const _Tp&, const _Tp&>(__a, __b);
@@ -37,7 +37,7 @@ template<class _Tp>
 _LIBCPP_NODISCARD_EXT inline
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
 pair<const _Tp&, const _Tp&>
-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
index 55aef997698c6..2a16159cc1ef3 100644
--- a/libcxx/include/__algorithm/ranges_max.h
+++ b/libcxx/include/__algorithm/ranges_max.h
@@ -40,7 +40,10 @@ struct __fn {
   template <class _Tp, class _Proj = identity,
             indirect_strict_weak_order<projected<const _Tp*, _Proj>> _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
index 0e31f57fb8dde..d7a0227045223 100644
--- a/libcxx/include/__algorithm/ranges_min.h
+++ b/libcxx/include/__algorithm/ranges_min.h
@@ -39,7 +39,10 @@ struct __fn {
   template <class _Tp, class _Proj = identity,
             indirect_strict_weak_order<projected<const _Tp*, _Proj>> _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
index f82e00551e47b..ea6e54ce016a0 100644
--- a/libcxx/include/__algorithm/ranges_minmax.h
+++ b/libcxx/include/__algorithm/ranges_minmax.h
@@ -46,7 +46,10 @@ struct __fn {
   template <class _Type, class _Proj = identity,
             indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less>
   _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<const _Type&>
-  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
index a12848335ca58..cd860065d41f5 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -298,7 +298,10 @@ module std [system] {
       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
index 0000000000000..b16ecfbdeb544
--- /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 <algorithm>
+
+#include "test_macros.h"
+
+struct Comp {
+  template <class T, class U>
+  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
+}


        


More information about the libcxx-commits mailing list