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

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 3 10:54:32 PDT 2023


ldionne accepted this revision.
ldionne added a comment.
This revision is now accepted and ready to land.

LGTM once the comments have been addressed.



================
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*.
----------------
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)
{...}
```


================
Comment at: libcxx/include/memory:452-454
     // observers
-    typename constexpr add_lvalue_reference<T>::type operator*() const;               // constexpr since C++23
+    typename constexpr
+    add_lvalue_reference<T>::type operator*() const noexcept(see below);              // constexpr since C++23
----------------
We can probably drop the `typename` from the synopsis?


================
Comment at: libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.single.pass.cpp:21
+#if TEST_STD_VER >= 11
+struct ThrowDereference {
+  TEST_CONSTEXPR_CXX23 ThrowDereference& operator*() noexcept(false);
----------------
As you mentioned, you could also add a few more test cases with user-defined pointer types. For example a `noexcept(true)` user-defined type.

Also with builtin types, e.g. `noexcept(*declval<unique_ptr<int>>())`.


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