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

Alexander Shaposhnikov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 13 17:50:34 PST 2023


alexander-shaposhnikov created this revision.
alexander-shaposhnikov added reviewers: rsmith, aaron.ballman, dblaikie.
alexander-shaposhnikov created this object with visibility "All Users".
Herald added a project: All.
alexander-shaposhnikov requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add lifetimebound attribute to std::move/std::forward.
This diff addresses https://github.com/llvm/llvm-project/issues/59900

Test plan: ninja  check-clang check-clang-tools check-llvm


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D141744

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/attr-lifetimebound.cpp
  clang/test/SemaCXX/builtin-std-move.cpp


Index: clang/test/SemaCXX/builtin-std-move.cpp
===================================================================
--- clang/test/SemaCXX/builtin-std-move.cpp
+++ clang/test/SemaCXX/builtin-std-move.cpp
@@ -85,7 +85,7 @@
 
 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 {};
Index: clang/test/SemaCXX/attr-lifetimebound.cpp
===================================================================
--- clang/test/SemaCXX/attr-lifetimebound.cpp
+++ clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -113,3 +113,55 @@
   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);
+}
+
+} // inline namespace foo
+} // namespace std
+
+namespace move_forward_as_const_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());
+} // namespace move_forward_as_const_examples
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -16180,6 +16180,21 @@
     default:
       break;
     }
+
+    // Add lifetime attribute to std::move, std::fowrard et al.
+    switch (BuiltinID) {
+    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);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D141744.489171.patch
Type: text/x-patch
Size: 3928 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230114/ce435556/attachment.bin>


More information about the cfe-commits mailing list