Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Implement LWG-3843 and LWG-3940 #475

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,72 @@ __host__ __device__ constexpr bool test() {
return true;
}

__host__ __device__ void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS

// int
{
const cuda::std::expected<int, int> e(cuda::std::unexpect, 5);
enum constructor_used : unsigned int {
default_constructed = 1 << 0,
lvalue_constructed = 1 << 1,
const_lvalue_constructed = 1 << 2,
rvalue_constructed = 1 << 3,
const_rvalue_constructed = 1 << 4,
};

struct track_construction {
track_construction() = default;
track_construction& operator=(const track_construction&) = default;
track_construction& operator=(track_construction&&) = default;

__host__ __device__ track_construction(track_construction& other) noexcept
: val_(other.val_ | lvalue_constructed) {}
__host__ __device__ track_construction(const track_construction& other) noexcept
: val_(other.val_ | const_lvalue_constructed) {}
__host__ __device__ track_construction(track_construction&& other) noexcept
: val_(other.val_ | rvalue_constructed) {}
__host__ __device__ track_construction(const track_construction&& other) noexcept
: val_(other.val_ | const_rvalue_constructed) {}

unsigned int val_ = default_constructed;
};

__host__ __device__ void testException() {
{ // &
try {
cuda::std::expected<int, track_construction> e(cuda::std::unexpect);
(void) e.value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error() == 5);
// We need to pass the error via `as_const`
assert(ex.error().val_ == const_lvalue_constructed | rvalue_constructed);
}
}

{ // const &
try {
cuda::std::expected<int, track_construction> e(cuda::std::unexpect);
(void) cuda::std::as_const(e).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error().val_ == const_lvalue_constructed | rvalue_constructed);
}
}

{ // &&
try {
cuda::std::expected<int, track_construction> e(cuda::std::unexpect);
(void) cuda::std::move(e).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error().val_ == rvalue_constructed);
}
}

{ // const &&
try {
cuda::std::expected<int, track_construction> e(cuda::std::unexpect);
(void) cuda::std::move(cuda::std::as_const(e)).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error().val_ == const_rvalue_constructed | rvalue_constructed);
}
}

Expand All @@ -87,15 +142,16 @@ __host__ __device__ void testException() {
assert(ex.error() == 5);
}
}

#endif // TEST_HAS_NO_EXCEPTIONS
}
#endif // TEST_HAS_NO_EXCEPTIONS

int main(int, char**) {
test();
#if TEST_STD_VER > 17 && defined(_LIBCUDACXX_ADDRESSOF)
static_assert(test(), "");
#endif // TEST_STD_VER > 17 && defined(_LIBCUDACXX_ADDRESSOF)
#ifndef TEST_HAS_NO_EXCEPTIONS
testException();
#endif // TEST_HAS_NO_EXCEPTIONS
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,95 @@ __host__ __device__ constexpr bool test() {

return true;
}
#ifndef TEST_HAS_NO_EXCEPTIONS

enum constructor_used : unsigned int {
default_constructed = 1 << 0,
lvalue_constructed = 1 << 1,
const_lvalue_constructed = 1 << 2,
rvalue_constructed = 1 << 3,
const_rvalue_constructed = 1 << 4,
};

struct track_construction {
track_construction() = default;
track_construction& operator=(const track_construction&) = default;
track_construction& operator=(track_construction&&) = default;

__host__ __device__ track_construction(track_construction& other) noexcept
: val_(other.val_ | lvalue_constructed) {}
__host__ __device__ track_construction(const track_construction& other) noexcept
: val_(other.val_ | const_lvalue_constructed) {}
__host__ __device__ track_construction(track_construction&& other) noexcept
: val_(other.val_ | rvalue_constructed) {}
__host__ __device__ track_construction(const track_construction&& other) noexcept
: val_(other.val_ | const_rvalue_constructed) {}

unsigned int val_ = default_constructed;
};

__host__ __device__ void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
{ // &
try {
cuda::std::expected<void, track_construction> e(cuda::std::unexpect);
(void) e.value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
// We bind against the `const &` overload
assert(ex.error().val_ == const_lvalue_constructed | rvalue_constructed);
}
}

// int
{
const cuda::std::expected<void, int> e(cuda::std::unexpect, 5);
{ // const &
try {
e.value();
cuda::std::expected<void, track_construction> e(cuda::std::unexpect);
(void) cuda::std::as_const(e).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error() == 5);
assert(ex.error().val_ == const_lvalue_constructed | rvalue_constructed);
}
}

{ // &&
try {
cuda::std::expected<void, track_construction> e(cuda::std::unexpect);
(void) cuda::std::move(e).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
assert(ex.error().val_ == rvalue_constructed);
}
}

{ // const &&
try {
cuda::std::expected<void, track_construction> e(cuda::std::unexpect);
(void) cuda::std::move(cuda::std::as_const(e)).value();
assert(false);
} catch (const cuda::std::bad_expected_access<int>& ex) {
// We bind against the const& overload
assert(ex.error().val_ == const_lvalue_constructed | rvalue_constructed);
}
}

// MoveOnly
{
cuda::std::expected<void, MoveOnly> e(cuda::std::unexpect, 5);
try {
cuda::std::move(e).value();
(void) cuda::std::move(e).value();
assert(false);
} catch (const cuda::std::bad_expected_access<MoveOnly>& ex) {
assert(ex.error() == 5);
}
}

#endif // TEST_HAS_NO_EXCEPTIONS
}
#endif // TEST_HAS_NO_EXCEPTIONS

int main(int, char**) {
test();
static_assert(test(), "");
#ifndef TEST_HAS_NO_EXCEPTIONS
testException();
#endif // TEST_HAS_NO_EXCEPTIONS

return 0;
}
18 changes: 16 additions & 2 deletions include/cuda/std/detail/libcxx/include/__expected/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "../__type_traits/negation.h"
#include "../__type_traits/remove_cv.h"
#include "../__type_traits/remove_cvref.h"
#include "../__utility/as_const.h"
#include "../__utility/exception_guard.h"
#include "../__utility/forward.h"
#include "../__utility/in_place.h"
Expand Down Expand Up @@ -509,7 +510,8 @@ class expected : private __expected_move_assign<_Tp, _Err>

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr bool has_value() const noexcept { return this->__has_val_; }

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr const _Tp& value() const& {
_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr
const _Tp& value() const& {
if (!this->__has_val_) {
__expected::__throw_bad_expected_access<_Err>(this->__union_.__unex_);
}
Expand All @@ -519,13 +521,17 @@ class expected : private __expected_move_assign<_Tp, _Err>
_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr
_Tp& value() & {
if (!this->__has_val_) {
__expected::__throw_bad_expected_access<_Err>(this->__union_.__unex_);
__expected::__throw_bad_expected_access<_Err>(_CUDA_VSTD::as_const(this->__union_.__unex_));
}
return this->__union_.__val_;
}

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr
const _Tp&& value() const&& {
static_assert(_LIBCUDACXX_TRAIT(is_copy_constructible, _Err),
"expected::value() const&& requires is_copy_constructible_v<E>");
static_assert(_LIBCUDACXX_TRAIT(is_constructible, _Err, const _Err&&),
"expected::value() const&& requires is_constructible_v<E, const E&&>");
if (!this->__has_val_) {
__expected::__throw_bad_expected_access<_Err>(_CUDA_VSTD::move(this->__union_.__unex_));
}
Expand All @@ -534,6 +540,10 @@ class expected : private __expected_move_assign<_Tp, _Err>

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr
_Tp&& value() && {
static_assert(_LIBCUDACXX_TRAIT(is_copy_constructible, _Err),
"expected::value() && requires is_copy_constructible_v<E>");
static_assert(_LIBCUDACXX_TRAIT(is_move_constructible, _Err),
"expected::value() && requires is_move_constructible<E>");
if (!this->__has_val_) {
__expected::__throw_bad_expected_access<_Err>(_CUDA_VSTD::move(this->__union_.__unex_));
}
Expand Down Expand Up @@ -1324,6 +1334,10 @@ class expected<void, _Err> : private __expected_move_assign<void, _Err>

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY
constexpr void value() && {
static_assert(_LIBCUDACXX_TRAIT(is_copy_constructible, _Err),
"expected::value() && requires is_copy_constructible_v<E>");
static_assert(_LIBCUDACXX_TRAIT(is_move_constructible, _Err),
"expected::value() && requires is_move_constructible_v<E>");
if (!this->__has_val_) {
__expected::__throw_bad_expected_access<_Err>(_CUDA_VSTD::move(this->__union_.__unex_));
}
Expand Down