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
-------------------------------------------------
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);
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