mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 13:46:37 +00:00
[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
This commit is contained in:
parent
dc9c41125c
commit
277a9f6e5f
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user