[libcxx-commits] [PATCH] D128214: [libc++] Makes `unique_ptr operator*() noexcept.

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Wed Nov 8 13:37:39 PST 2023


ldionne added inline comments.


================
Comment at: libcxx/include/__memory/unique_ptr.h:288
+#ifndef _LIBCPP_CXX03_LANG
+      noexcept(__is_noexcept_deref_or_void<pointer>::value)
+#endif
----------------
Can we use `_NOEXCEPT_(...)` instead?


================
Comment at: libcxx/include/__memory/unique_ptr.h:272-286
+  _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const
+#if _LIBCPP_STD_VER >= 20
+      noexcept([] {
+        if constexpr (is_void_v<remove_pointer_t<pointer>>)
+          return true;
+        else
+          // This avoids evaluating noexcept(*declval<pointer>() when pointer == void*.
----------------
Mordante wrote:
> ldionne wrote:
> > I think I understand the issue now. So what's going on is that the contents of `noexcept` are not SFINAE-d on, and so this becomes a hard error. A test case we should add (in all standard modes) is this (https://godbolt.org/z/Teforbb6j):
> > 
> > ```
> > #include <type_traits>
> > #include <memory>
> > 
> > 
> > template <class T, class = void>
> > struct has_dereference : std::false_type { };
> > 
> > template <class T>
> > struct has_dereference<T, decltype((void)*std::declval<T>())> : std::true_type { };
> > 
> > // test the test
> > static_assert( has_dereference<int*>::value, "");
> > static_assert(!has_dereference<int>::value, "");
> > static_assert(!has_dereference<void*>::value, "");
> > 
> > // make sure std::unique_ptr<void>::operator* is SFINAE-friendly
> > static_assert(has_dereference<std::unique_ptr<void>>::value, "");
> > static_assert(noexcept(*std::declval<std::unique_ptr<void>>()), "");
> > ```
> > 
> > And then the implementation should handle `void` in all standard modes, because the problem is detectable with SFINAE in all modes:
> > 
> > ```
> > #ifndef _LIBCPP_CXX03_LANG
> > template <class _Ptr>
> > struct __is_noexcept_deref_or_void {
> >   static constexpr bool value = noexcept(*std::declval<_Ptr>());
> > };
> > 
> > template <>
> > struct __is_noexcept_deref_or_void<void*> : true_type {};
> > #endif
> > 
> > LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const
> >   _NOEXCEPT(__is_noexcept_deref_or_void<pointer>::value)
> > {...}
> > ```
> Since we can't use `has_dereference` in the `noexcept` I wonder why we need these tests. It was useful during the discussion, but only adding the second code block seems sufficient to me.
Can we add these tests though?

```
// make sure std::unique_ptr<void>::operator* is SFINAE-friendly
static_assert(has_dereference<std::unique_ptr<void>>::value, "");
static_assert(noexcept(*std::declval<std::unique_ptr<void>>()), "");
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128214/new/

https://reviews.llvm.org/D128214



More information about the libcxx-commits mailing list