[clang] 31b0be4 - [Clang] Add lifetimebound attribute to std::move/std::forward

Alexander Shaposhnikov via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 19 13:07:58 PST 2023


Author: Alexander Shaposhnikov
Date: 2023-01-19T20:57:24Z
New Revision: 31b0be4eba9e8e9244799f0ebcb18175faff69ab

URL: https://github.com/llvm/llvm-project/commit/31b0be4eba9e8e9244799f0ebcb18175faff69ab
DIFF: https://github.com/llvm/llvm-project/commit/31b0be4eba9e8e9244799f0ebcb18175faff69ab.diff

LOG: [Clang] Add lifetimebound attribute to std::move/std::forward

Clang now automatically adds [[clang::lifetimebound]] to the parameters of
std::move, std::forward et al, this enables Clang to diagnose more cases
where the returned reference outlives the object.
Associated GitHub issue: https://github.com/llvm/llvm-project/issues/60020

Test plan: ninja check-clang check-all

Differential revision: https://reviews.llvm.org/D141744

Added: 
    

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaDecl.cpp
    clang/test/SemaCXX/attr-lifetimebound.cpp
    clang/test/SemaCXX/builtin-std-move.cpp
    clang/test/SemaCXX/builtins.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index dbec1cd7c196..2e99a6072a94 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2933,7 +2933,8 @@ implementation details of ``__sync_lock_test_and_set()``.  The
 ``__builtin_addressof`` performs the functionality of the built-in ``&``
 operator, ignoring any ``operator&`` overload.  This is useful in constant
 expressions in C++11, where there is no other way to take the address of an
-object that overloads ``operator&``.
+object that overloads ``operator&``. Clang automatically adds
+``[[clang::lifetimebound]]`` to the parameter of ``__builtin_addressof``.
 
 **Example of use**:
 

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 97ce8866d3cc..541f8e1eb671 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -458,6 +458,9 @@ Improvements to Clang's diagnostics
   only when ``x`` is a string literal.
 - Clang will now reject the GNU extension address of label in coroutines explicitly.
   This fixes `Issue 56436 <https://github.com/llvm/llvm-project/issues/56436>`_.
+- Clang now automatically adds ``[[clang::lifetimebound]]`` to the parameters of
+  ``std::move, std::forward`` et al, this enables Clang to diagnose more cases
+  where the returned reference outlives the object.
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index faa75f671fde..3ae3e33a6704 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16182,6 +16182,24 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
     default:
       break;
     }
+
+    // Add lifetime attribute to std::move, std::fowrard et al.
+    switch (BuiltinID) {
+    case Builtin::BIaddressof:
+    case Builtin::BI__addressof:
+    case Builtin::BI__builtin_addressof:
+    case Builtin::BIas_const:
+    case Builtin::BIforward:
+    case Builtin::BImove:
+    case Builtin::BImove_if_noexcept:
+      if (ParmVarDecl *P = FD->getParamDecl(0u);
+          !P->hasAttr<LifetimeBoundAttr>())
+        P->addAttr(
+            LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+      break;
+    default:
+      break;
+    }
   }
 
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);

diff  --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 90124c323d02..22cf5d0ab001 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -113,3 +113,77 @@ namespace p0936r0_examples {
   std::map<std::string, std::string> m;
   const std::string &v = findOrDefault(m, "foo"s, "bar"s); // expected-warning {{temporary bound to local reference 'v'}}
 }
+
+// definitions for std::move, std::forward et al.
+namespace std {
+inline namespace foo {
+
+template <class T> struct remove_reference {
+    typedef T type;
+};
+template <class T> struct remove_reference<T &> {
+    typedef T type;
+};
+template <class T> struct remove_reference<T &&> {
+    typedef T type;
+};
+
+template <class T> constexpr typename remove_reference<T>::type &&move(T &&t) {
+    return static_cast<typename remove_reference<T>::type>(t);
+}
+
+template <class T>
+constexpr T &&forward(typename remove_reference<T>::type &t) {
+    return static_cast<T &&>(t);
+}
+
+template <class T>
+constexpr T &&forward(typename remove_reference<T>::type &&t) {
+    return static_cast<T &&>(t);
+}
+
+template <class T> constexpr const T &as_const(T &x) { return x; }
+
+template <class T, bool RValueRef> struct PickRef {
+    using type = typename remove_reference<T>::type &;
+};
+template <class T> struct PickRef<T, true> {
+    using type = typename remove_reference<T>::type &&;
+};
+
+template <class T>
+auto move_if_noexcept(T &t) ->
+    typename PickRef<T, noexcept(T(static_cast<T &&>(t)))>::type {
+    return static_cast<
+        typename PickRef<T, noexcept(T(static_cast<T &&>(t)))>::type>(t);
+}
+
+template <class T> T *addressof(T &arg) {
+    return reinterpret_cast<T *>(
+        &const_cast<char &>(reinterpret_cast<const volatile char &>(arg)));
+}
+
+} // namespace foo
+} // namespace std
+
+namespace move_forward_et_al_examples {
+  struct S {
+    S &self() [[clang::lifetimebound]] { return *this; }
+  };
+
+  S &&Move = std::move(S{}); // expected-warning {{temporary bound to local reference 'Move' will be destroyed at the end of the full-expression}}
+  S MoveOk = std::move(S{});
+
+  S &&Forward = std::forward<S &&>(S{}); // expected-warning {{temporary bound to local reference 'Forward' will be destroyed at the end of the full-expression}}
+  S ForwardOk = std::forward<S &&>(S{});
+
+  const S &Const = std::as_const(S{}.self()); // expected-warning {{temporary bound to local reference 'Const' will be destroyed at the end of the full-expression}}
+  const S ConstOk = std::as_const(S{}.self());
+
+  S &&MoveIfNoExcept = std::move_if_noexcept(S{}.self()); // expected-warning {{temporary bound to local reference 'MoveIfNoExcept' will be destroyed at the end of the full-expression}}
+  S MoveIfNoExceptOk = std::move_if_noexcept(S{}.self());
+
+  S *AddressOf = std::addressof(S{}.self()); // expected-warning {{temporary whose address is used as value of local variable 'AddressOf' will be destroyed at the end of the full-expression}}
+  S X;
+  S *AddressOfOk = std::addressof(X);
+} // namespace move_forward_et_al_examples

diff  --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index eb2b85e8e7c7..8e4928da4edb 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -85,7 +85,7 @@ static_assert(f({}), "should be constexpr");
 
 A &forward_rval_as_lval() {
   std::forward<A&&>(A()); // expected-warning {{const attribute}}
-  return std::forward<A&>(A()); // expected-note {{instantiation of}}
+  return std::forward<A&>(A()); // expected-note {{instantiation of}} expected-warning {{returning reference}}
 }
 
 struct B {};

diff  --git a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp
index 3687acdeed69..82d1820bf9f3 100644
--- a/clang/test/SemaCXX/builtins.cpp
+++ b/clang/test/SemaCXX/builtins.cpp
@@ -40,7 +40,7 @@ namespace addressof {
   struct U { int n : 5; } u;
   int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}}
 
-  S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}}
+  S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} expected-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}}
 }
 
 namespace function_start {


        


More information about the cfe-commits mailing list