[libcxx-commits] [libcxx] [libc++][NFC] Simplify some `optional.observe` tests (PR #175682)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 19 13:58:56 PST 2026


================
@@ -10,94 +10,126 @@
 // <optional>
 
 // constexpr T& optional<T>::operator*() &;
+// constexpr const T& optional<T>::operator*() const&;
+// constexpr T&& optional<T>::operator*() &&;
+// constexpr const T&& optional<T>::operator*() const&&;
+// constexpr T& optional<T&>::operator*() const;
 
 #include <cassert>
 #include <memory>
 #include <optional>
+#include <utility>
 
 #include "test_macros.h"
 #if TEST_STD_VER >= 26
 #  include "copy_move_types.h"
 #endif
 
-using std::optional;
-
-struct X
-{
-    constexpr int test() const& {return 3;}
-    int test() & {return 4;}
-    constexpr int test() const&& {return 5;}
-    int test() && {return 6;}
+struct X {
+  constexpr int test() const& { return 3; }
+  constexpr int test() & { return 4; }
+  constexpr int test() const&& { return 5; }
+  constexpr int test() && { return 6; }
 };
 
-struct Y
-{
-    constexpr int test() {return 7;}
-};
+template <typename T>
+constexpr void test_contract() {
+  std::optional<T> opt(T{});
+
+  ASSERT_SAME_TYPE(decltype(*opt), T&);
+  ASSERT_SAME_TYPE(decltype(*std::move(opt)), T&&);
+  ASSERT_SAME_TYPE(decltype(*std::as_const(opt)), const T&);
+  ASSERT_SAME_TYPE(decltype(*std::move(std::as_const(opt))), const T&&);
 
-constexpr int
-test()
-{
-    optional<Y> opt{Y{}};
-    return (*opt).test();
+  ASSERT_NOEXCEPT(*opt);
+  ASSERT_NOEXCEPT(*std::move(opt));
+  ASSERT_NOEXCEPT(*std::as_const(opt));
+  ASSERT_NOEXCEPT(*std::move(std::as_const(opt)));
 }
 
 #if TEST_STD_VER >= 26
-constexpr bool test_ref() {
+template <typename T>
+constexpr void test_ref_contract() {
+  std::optional<T&> opt;
+  ASSERT_SAME_TYPE(decltype(*opt), T&);
+  ASSERT_SAME_TYPE(decltype(*std::move(opt)), T&);
+  ASSERT_SAME_TYPE(decltype(*std::as_const(opt)), T&);
+  ASSERT_SAME_TYPE(decltype(*std::move(std::as_const(opt))), T&);
+
+  ASSERT_NOEXCEPT(*opt);
+  ASSERT_NOEXCEPT(*std::move(opt));
+  ASSERT_NOEXCEPT(*std::as_const(opt));
+  ASSERT_NOEXCEPT(*std::move(std::as_const(opt)));
+}
+#endif
+
+constexpr bool test() {
+  test_contract<int>();
+  test_contract<float>();
+  test_contract<double>();
+  test_contract<X>();
+  test_contract<const int>();
+  test_contract<const float>();
+  test_contract<const double>();
+  test_contract<const X>();
+
+  std::optional<X> opt{X{}};
+  {
+    assert((*std::as_const(opt)).test() == 3);
+    assert((*opt).test() == 4);
+    assert((*std::move(std::as_const(opt))).test() == 5);
+    assert((*std::move(opt)).test() == 6);
+  }
----------------
ldionne wrote:

For the non-reference optional, we don't test anywhere that we return a stable reference to the contained object. I'd add:

```c++
// Test that optional::operator* returns a stable reference to the contained value
{
  std::optional<X> opt{X{}};
  X& value = *opt;
  assert(&value == &*opt);
}
```

https://github.com/llvm/llvm-project/pull/175682


More information about the libcxx-commits mailing list