[libcxx-commits] [libcxx] 277a9f6 - [libc++] Add [[clang::lifetimebound]] attribute to std::forward and friends

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jan 13 17:54:39 PST 2023


Author: Nikolas Klauser
Date: 2023-01-14T02:54:33+01:00
New Revision: 277a9f6e5f85bfa1c58ca21c26a5a74326f002ff

URL: https://github.com/llvm/llvm-project/commit/277a9f6e5f85bfa1c58ca21c26a5a74326f002ff
DIFF: https://github.com/llvm/llvm-project/commit/277a9f6e5f85bfa1c58ca21c26a5a74326f002ff.diff

LOG: [libc++] Add [[clang::lifetimebound]] attribute to std::forward and friends

This allows clang to catch lifetime bugs through these functions.
As a drive-by, replace `_LIBCPP_INLINE_VISIBILITY` with `_LIBCPP_HIDE_FROM_ABI`.
Fixes #59900

Reviewed By: ldionne, #libc

Spies: rsmith, rnk, aaron.ballman, libcxx-commits

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

Added: 
    libcxx/test/libcxx/utilities/utility/forward/lifetimebound.verify.cpp

Modified: 
    libcxx/include/__config
    libcxx/include/__utility/forward.h
    libcxx/include/__utility/forward_like.h
    libcxx/include/__utility/move.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__config b/libcxx/include/__config
index 505ccf95de724..a5d54d4e1872c 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1055,6 +1055,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
 #    define _LIBCPP_FALLTHROUGH() ((void)0)
 #  endif
 
+#  if __has_cpp_attribute(_Clang::__lifetimebound__)
+#    define _LIBCPP_LIFETIMEBOUND [[_Clang::__lifetimebound__]]
+#  else
+#    define _LIBCPP_LIFETIMEBOUND
+#  endif
+
 #  if __has_attribute(__nodebug__)
 #    define _LIBCPP_NODEBUG __attribute__((__nodebug__))
 #  else

diff  --git a/libcxx/include/__utility/forward.h b/libcxx/include/__utility/forward.h
index 4e254e0fa0e87..010f2362bdcee 100644
--- a/libcxx/include/__utility/forward.h
+++ b/libcxx/include/__utility/forward.h
@@ -21,14 +21,14 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp>
-_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR _Tp&&
-forward(__libcpp_remove_reference_t<_Tp>& __t) _NOEXCEPT {
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp&&
+forward(_LIBCPP_LIFETIMEBOUND __libcpp_remove_reference_t<_Tp>& __t) _NOEXCEPT {
   return static_cast<_Tp&&>(__t);
 }
 
 template <class _Tp>
-_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR _Tp&&
-forward(__libcpp_remove_reference_t<_Tp>&& __t) _NOEXCEPT {
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp&&
+forward(_LIBCPP_LIFETIMEBOUND __libcpp_remove_reference_t<_Tp>&& __t) _NOEXCEPT {
   static_assert(!is_lvalue_reference<_Tp>::value, "cannot forward an rvalue as an lvalue");
   return static_cast<_Tp&&>(__t);
 }

diff  --git a/libcxx/include/__utility/forward_like.h b/libcxx/include/__utility/forward_like.h
index 1446964da5428..7bb0d7d2033c3 100644
--- a/libcxx/include/__utility/forward_like.h
+++ b/libcxx/include/__utility/forward_like.h
@@ -34,7 +34,8 @@ template <class _Ap, class _Bp>
 using _ForwardLike = _OverrideRef<_Ap&&, _CopyConst<remove_reference_t<_Ap>, remove_reference_t<_Bp>>>;
 
 template <class _Tp, class _Up>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto forward_like(_Up&& __ux) noexcept -> _ForwardLike<_Tp, _Up> {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto forward_like(_LIBCPP_LIFETIMEBOUND _Up&& __ux) noexcept
+    -> _ForwardLike<_Tp, _Up> {
   return static_cast<_ForwardLike<_Tp, _Up>>(__ux);
 }
 

diff  --git a/libcxx/include/__utility/move.h b/libcxx/include/__utility/move.h
index 2ffcba29876af..4859c39e8bd5d 100644
--- a/libcxx/include/__utility/move.h
+++ b/libcxx/include/__utility/move.h
@@ -23,8 +23,8 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp>
-_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_remove_reference_t<_Tp>&&
-move(_Tp&& __t) _NOEXCEPT {
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __libcpp_remove_reference_t<_Tp>&&
+move(_LIBCPP_LIFETIMEBOUND _Tp&& __t) _NOEXCEPT {
   typedef _LIBCPP_NODEBUG __libcpp_remove_reference_t<_Tp> _Up;
   return static_cast<_Up&&>(__t);
 }
@@ -34,9 +34,9 @@ using __move_if_noexcept_result_t =
     __conditional_t<!is_nothrow_move_constructible<_Tp>::value && is_copy_constructible<_Tp>::value, const _Tp&, _Tp&&>;
 
 template <class _Tp>
-_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 __move_if_noexcept_result_t<_Tp>
-move_if_noexcept(_Tp& __x) _NOEXCEPT {
-  return _VSTD::move(__x);
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __move_if_noexcept_result_t<_Tp>
+move_if_noexcept(_LIBCPP_LIFETIMEBOUND _Tp& __x) _NOEXCEPT {
+  return std::move(__x);
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/libcxx/utilities/utility/forward/lifetimebound.verify.cpp b/libcxx/test/libcxx/utilities/utility/forward/lifetimebound.verify.cpp
new file mode 100644
index 0000000000000..4381c3af756b6
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/forward/lifetimebound.verify.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <utility>
+
+#include "test_macros.h"
+
+struct S {
+  const int& func() [[clang::lifetimebound]];
+};
+
+void func() {
+  auto&& v1 = std::move(int{});                              // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
+  auto&& v2 = std::forward<int&&>(int{});                    // expected-warning {{temporary bound to local reference 'v2' will be destroyed at the end of the full-expression}}
+  auto&& v3 = std::forward<const int&>(S{}.func());          // expected-warning {{temporary bound to local reference 'v3' will be destroyed at the end of the full-expression}}
+  auto&& v4 = std::move_if_noexcept<const int&>(S{}.func()); // expected-warning {{temporary bound to local reference 'v4' will be destroyed at the end of the full-expression}}
+#if TEST_STD_VER >= 23
+  auto&& v5 = std::forward_like<int&&>(int{});               // expected-warning {{temporary bound to local reference 'v5' will be destroyed at the end of the full-expression}}
+#endif
+}


        


More information about the libcxx-commits mailing list