William Tran-Viet cad1721781
[libc++][NFC] Simplify some optional.observe tests (#175682)
- Collapse the different ref/const-qualifier `operator*`, `operator->`
  and `value()` tests since they were all very similar to each other
- Refactor them to be inline with the current testing style
2026-01-23 17:28:59 -05:00

147 lines
4.1 KiB
C++

//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// <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
struct X {
constexpr int test() const& { return 3; }
constexpr int test() & { return 4; }
constexpr int test() const&& { return 5; }
constexpr int test() && { return 6; }
};
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&&);
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
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);
// Test that operator* returns a stable reference
X& x = *opt;
assert(&x == &(*opt));
const X& x2 = *std::as_const(opt);
assert(&x2 == &(*opt));
}
#if TEST_STD_VER >= 26
test_ref_contract<int>();
test_ref_contract<float>();
test_ref_contract<double>();
test_ref_contract<X>();
test_ref_contract<const int>();
test_ref_contract<const float>();
test_ref_contract<const double>();
test_ref_contract<const X>();
{
TracedCopyMove x{};
std::optional<TracedCopyMove&> o1(x);
assert(std::addressof(*o1) == std::addressof(x));
assert(std::addressof(*std::move(o1)) == std::addressof(x));
assert(std::addressof(*std::as_const(o1)) == std::addressof(x));
assert(std::addressof(*std::move(std::as_const(o1))) == std::addressof(x));
assert(x.constMove == 0);
assert(x.nonConstMove == 0);
assert(x.constCopy == 0);
assert(x.nonConstCopy == 0);
}
{
TracedCopyMove x{};
std::optional<const TracedCopyMove&> o2(x);
assert(std::addressof(*o2) == std::addressof(x));
assert(std::addressof(*std::move(o2)) == std::addressof(x));
assert(std::addressof(*std::as_const(o2)) == std::addressof(x));
assert(std::addressof(*std::move(std::as_const(o2))) == std::addressof(x));
assert(x.constMove == 0);
assert(x.nonConstMove == 0);
assert(x.constCopy == 0);
assert(x.nonConstCopy == 0);
}
{
// Verify that optional<T&>::operator* always returns a T&
X x{};
std::optional<X&> o3(x);
assert((*o3).test() == 4);
assert((*std::as_const(o3)).test() == 4);
assert((*std::move(o3)).test() == 4);
assert((*std::move(std::as_const(o3))).test() == 4);
}
#endif
return true;
}
int main(int, char**) {
assert(test());
static_assert(test());
return 0;
}