-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[libcxx] implement LWG4148: unique_ptr::operator* should not allow dangling references #128213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libcxx Author: None (elhewaty) ChangesFixes: #118362 Full diff: https://github.com/llvm/llvm-project/pull/128213.diff 2 Files Affected:
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index e8ef386f7f9fc..5e8335e971f6d 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -261,7 +261,10 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const
- _NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) {
+ _NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>()))
+ // TODO: use reference_converts_from_temporary_v once implemented.
+ requires(!__reference_converts_from_temporary(__add_lvalue_reference_t<_Tp>, decltype(*declval<pointer>())))
+ {
return *__ptr_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_; }
diff --git a/libcxx/test/libcxx/memory/unique_ptr.compile.fail.cpp b/libcxx/test/libcxx/memory/unique_ptr.compile.fail.cpp
new file mode 100644
index 0000000000000..633247da3a5a4
--- /dev/null
+++ b/libcxx/test/libcxx/memory/unique_ptr.compile.fail.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
+//
+//===----------------------------------------------------------------------===//
+
+// <memory>
+
+#include <iostream>
+#include <memory>
+
+using namespace std;
+
+struct deleter {
+ using pointer = long*;
+ void operator()(pointer) const {}
+};
+
+int main(int argc, char const *argv[]) {
+ long l = 0;
+ std::unique_ptr<const int, deleter> p(&l);
+ // Error: indirection requires pointer operand ('std::unique_ptr<const int, deleter>' invalid)
+ int i = *p;
+ cout << i << endl;
+ return 0;
+}
\ No newline at end of file
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this!
libcxx/include/__memory/unique_ptr.h
Outdated
// TODO: use reference_converts_from_temporary_v once implemented. | ||
requires(!__reference_converts_from_temporary(__add_lvalue_reference_t<_Tp>, decltype(*declval<pointer>()))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is implemented as a constraint. That has several issues:
- it's only available in C++20 and newer, this code should work in C++11
- this is not always a mandates, a
static_assert
is the way to do this. Please add a useful message in thestatic_assert
.
@@ -261,7 +261,10 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr { | |||
} | |||
|
|||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const | |||
_NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) { | |||
_NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) | |||
// TODO: use reference_converts_from_temporary_v once implemented. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a C++23 type trait? Can we use it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not implemented yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But reference_converts_from_temporary_v
shouldn't be available before C++23. If you decide to add the static_assert
in old modes, it may be more consistent (and less verbose) to solely use the intrinsic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general we tend to add our own private declaration instead of directly using an intrinsic. This private declaration can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elhewaty #128649 has been merged. The private __reference_converts_from_temporary_v
has been removed as per the code review but you can restore it and use it.
a1e77d2#diff-cfa44dc4db9caf101a253c6f6db926764176ac7ff62744a7776949b83c1ad26dL24
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@H-G-Hristov If we remove the private should we use the libcxx public one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of the private variable was requested during the review because it wasn't used. If you decide to use it, you can just copy the implementation from my branch (if it is still available) and reintroduce it. Please note that Apple Clang doesn't support the intrinsic yet, which complicates things a bit. Please check the tests about which platforms in the current CI don't have proper support yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elhewaty Please check: a1e77d2#diff-cfa44dc4db9caf101a253c6f6db926764176ac7ff62744a7776949b83c1ad26dL24 You can revert the revert in this commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please not that __has_builtin(__reference_converts_from_temporary)
does not return correct value in clang 19.0 and 19.1.0, which also affect Clang 20.0 on Android (Clang on Android doesn't match official Clang releases) in NDK r29. Also AppleClang 17 (released in XCode 16.3, which also doesn't match to any official Clang release) doesn't support the intrinsic.
# if __has_builtin(__reference_converts_from_temporary) || \
(defined(_LIBCPP_CLANG_VER) && \
((!defined(__ANDROID__) && _LIBCPP_CLANG_VER >= 1901) || (defined(__ANDROID__) && _LIBCPP_CLANG_VER >= 2000)))
0553825
to
21bcffd
Compare
21bcffd
to
ebdf97e
Compare
@mordante The crash in the CI is the same as the one I mentioned on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you add a release note for implementing this paper?
https://github.com/llvm/llvm-project/blob/main/libcxx/docs/ReleaseNotes/21.rst
We don't do that for LWG issues. |
@mordante can you take a look? |
long l = 0; | ||
std::unique_ptr<const int, deleter> p(&l); | ||
int i = | ||
*p; // expect-error {{static assertion failed due to requirement '!__reference_converts_from_temporary(const int &, long &)': Reference type _Tp must not convert from a temporary object}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*p; // expect-error {{static assertion failed due to requirement '!__reference_converts_from_temporary(const int &, long &)': Reference type _Tp must not convert from a temporary object}} | |
*p; // expected-error@*:* {{static assertion failed due to requirement '!__reference_converts_from_temporary(const int &, long &)': Reference type _Tp must not convert from a temporary object}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mordante Why it crashes during the build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elhewaty Can you apply my suggestion, that should fix some of your CI issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elhewaty are you still interested in pursuing this patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mordante, I am sorry for being late, I had a ton of things to take care of in the past few weeks, I couldn't even open my pc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am some how confused, was the builtin reference_converts_from_temporary_v
fully removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elhewaty Please check my answer above. No it wasn't just the private variable.
ebdf97e
to
d8f59f3
Compare
…ngling references
d8f59f3
to
b031f46
Compare
Fixes: #118362