From 46b2538ecbd3f51c599f18c6f465bebecc8a3c04 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 29 Jan 2025 10:11:51 +0100 Subject: [PATCH] Suppress execution checks for `expected` --- .../include/cuda/std/__expected/expected.h | 20 ++ .../cuda/std/__expected/expected_base.h | 18 ++ .../include/cuda/std/__expected/unexpected.h | 7 + .../expected/device_only_types.pass.cpp | 218 +++++++++++++++++ .../expected/host_only_types.pass.cpp | 220 ++++++++++++++++++ .../unexpected/device_only_types.pass.cpp | 115 +++++++++ .../unexpected/host_only_types.pass.cpp | 118 ++++++++++ 7 files changed, 716 insertions(+) create mode 100644 libcudacxx/test/libcudacxx/cuda/utilities/expected/device_only_types.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/cuda/utilities/expected/host_only_types.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/cuda/utilities/unexpected/device_only_types.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/cuda/utilities/unexpected/host_only_types.pass.cpp diff --git a/libcudacxx/include/cuda/std/__expected/expected.h b/libcudacxx/include/cuda/std/__expected/expected.h index cc5ddfc03f0..f618ff57c92 100644 --- a/libcudacxx/include/cuda/std/__expected/expected.h +++ b/libcudacxx/include/cuda/std/__expected/expected.h @@ -1070,6 +1070,7 @@ class expected : private __expected_move_assign<_Tp, _Err> } // [expected.object.eq], equality operators + _CCCL_EXEC_CHECK_DISABLE friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const expected& __y) { if (__x.__has_val_ != __y.has_value()) @@ -1090,12 +1091,14 @@ class expected : private __expected_move_assign<_Tp, _Err> } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const expected& __y) { return !(__x == __y); } # endif // _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2, class _E2) _CCCL_REQUIRES((!_CCCL_TRAIT(is_void, _T2))) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) @@ -1118,6 +1121,7 @@ class expected : private __expected_move_assign<_Tp, _Err> } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2, class _E2) _CCCL_REQUIRES((!_CCCL_TRAIT(is_void, _T2))) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const expected<_T2, _E2>& __y) @@ -1126,6 +1130,7 @@ class expected : private __expected_move_assign<_Tp, _Err> } # endif // _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2) _CCCL_REQUIRES((!__expected::__is_expected_nonvoid<_T2>) ) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const _T2& __v) @@ -1133,18 +1138,21 @@ class expected : private __expected_move_assign<_Tp, _Err> return __x.__has_val_ && static_cast(__x.__union_.__val_ == __v); } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2) _CCCL_REQUIRES((!__expected::__is_expected_nonvoid<_T2>) ) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const _T2& __v, const expected& __x) { return __x.__has_val_ && static_cast(__x.__union_.__val_ == __v); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2) _CCCL_REQUIRES((!__expected::__is_expected_nonvoid<_T2>) ) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const _T2& __v) { return !__x.__has_val_ || static_cast(__x.__union_.__val_ != __v); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T2) _CCCL_REQUIRES((!__expected::__is_expected_nonvoid<_T2>) ) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const _T2& __v, const expected& __x) @@ -1153,22 +1161,26 @@ class expected : private __expected_move_assign<_Tp, _Err> } # endif // _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { return !__x.__has_val_ && static_cast(__x.__union_.__unex_ == __e.error()); } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const unexpected<_E2>& __e, const expected& __x) { return !__x.__has_val_ && static_cast(__x.__union_.__unex_ == __e.error()); } + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const unexpected<_E2>& __e) { return __x.__has_val_ || static_cast(__x.__union_.__unex_ != __e.error()); } + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const unexpected<_E2>& __e, const expected& __x) { @@ -1906,6 +1918,7 @@ class expected : private __expected_move_assign } // [expected.void.eq], equality operators + _CCCL_EXEC_CHECK_DISABLE friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const expected& __y) noexcept { if (__x.__has_val_ != __y.has_value()) @@ -1918,12 +1931,14 @@ class expected : private __expected_move_assign } } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const expected& __y) noexcept { return !(__x == __y); } # endif + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const expected& __y) noexcept @@ -1938,6 +1953,7 @@ class expected : private __expected_move_assign } } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const expected& __x, const expected& __y) noexcept @@ -1946,22 +1962,26 @@ class expected : private __expected_move_assign } # endif + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) noexcept { return !__x.__has_val_ && static_cast(__x.__union_.__unex_ == __y.error()); } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE template friend _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const unexpected<_E2>& __y, const expected& __x) noexcept { return !__x.__has_val_ && static_cast(__x.__union_.__unex_ == __y.error()); } + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI friend constexpr bool operator!=(const expected& __x, const unexpected<_E2>& __y) noexcept { return __x.__has_val_ || static_cast(__x.__union_.__unex_ != __y.error()); } + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI friend constexpr bool operator!=(const unexpected<_E2>& __y, const expected& __x) noexcept { diff --git a/libcudacxx/include/cuda/std/__expected/expected_base.h b/libcudacxx/include/cuda/std/__expected/expected_base.h index 31de97e3f50..0de6cc29158 100644 --- a/libcudacxx/include/cuda/std/__expected/expected_base.h +++ b/libcudacxx/include/cuda/std/__expected/expected_base.h @@ -71,30 +71,35 @@ union __expected_union_t struct __empty_t {}; + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Tp2 = _Tp) _CCCL_REQUIRES(_CCCL_TRAIT(is_default_constructible, _Tp2)) _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t() noexcept(_CCCL_TRAIT(is_nothrow_default_constructible, _Tp2)) : __val_() {} + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Tp2 = _Tp) _CCCL_REQUIRES((!_CCCL_TRAIT(is_default_constructible, _Tp2))) _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t() noexcept : __empty_() {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t(in_place_t, _Args&&... __args) noexcept( _CCCL_TRAIT(is_nothrow_constructible, _Tp, _Args...)) : __val_(_CUDA_VSTD::forward<_Args>(__args)...) {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t(unexpect_t, _Args&&... __args) noexcept( _CCCL_TRAIT(is_nothrow_constructible, _Err, _Args...)) : __unex_(_CUDA_VSTD::forward<_Args>(__args)...) {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t( __expected_construct_from_invoke_tag, @@ -104,6 +109,7 @@ union __expected_union_t : __val_(_CUDA_VSTD::invoke(_CUDA_VSTD::forward<_Fun>(__fun), _CUDA_VSTD::forward<_Args>(__args)...)) {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t( __expected_construct_from_invoke_tag, @@ -128,18 +134,21 @@ union __expected_union_t<_Tp, _Err, true> struct __empty_t {}; + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Tp2 = _Tp) _CCCL_REQUIRES(_CCCL_TRAIT(is_default_constructible, _Tp2)) _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t() noexcept(_CCCL_TRAIT(is_nothrow_default_constructible, _Tp2)) : __val_() {} + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Tp2 = _Tp) _CCCL_REQUIRES((!_CCCL_TRAIT(is_default_constructible, _Tp2))) _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t() noexcept : __empty_() {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t(in_place_t, _Args&&... __args) noexcept( _CCCL_TRAIT(is_nothrow_constructible, _Tp, _Args...)) @@ -152,6 +161,7 @@ union __expected_union_t<_Tp, _Err, true> : __unex_(_CUDA_VSTD::forward<_Args>(__args)...) {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t( __expected_construct_from_invoke_tag, @@ -161,6 +171,7 @@ union __expected_union_t<_Tp, _Err, true> : __val_(_CUDA_VSTD::invoke(_CUDA_VSTD::forward<_Fun>(__fun), _CUDA_VSTD::forward<_Args>(__args)...)) {} + _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_HIDE_FROM_ABI constexpr __expected_union_t( __expected_construct_from_invoke_tag, @@ -436,6 +447,7 @@ struct __expected_storage : __expected_destruct<_Tp, _Err> { _LIBCUDACXX_DELEGATE_CONSTRUCTORS(__expected_storage, __expected_destruct, _Tp, _Err); + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T1, class _T2, class... _Args) _CCCL_REQUIRES(_CCCL_TRAIT(is_nothrow_constructible, _T1, _Args...)) static _LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX20 void @@ -445,6 +457,7 @@ struct __expected_storage : __expected_destruct<_Tp, _Err> _LIBCUDACXX_CONSTRUCT_AT(__newval, _CUDA_VSTD::forward<_Args>(__args)...); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T1, class _T2, class... _Args) _CCCL_REQUIRES( (!_CCCL_TRAIT(is_nothrow_constructible, _T1, _Args...)) _CCCL_AND _CCCL_TRAIT(is_nothrow_move_constructible, _T1)) @@ -456,6 +469,7 @@ struct __expected_storage : __expected_destruct<_Tp, _Err> _LIBCUDACXX_CONSTRUCT_AT(__newval, _CUDA_VSTD::move(__tmp)); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _T1, class _T2, class... _Args) _CCCL_REQUIRES( (!_CCCL_TRAIT(is_nothrow_constructible, _T1, _Args...)) _CCCL_AND(!_CCCL_TRAIT(is_nothrow_move_constructible, _T1))) @@ -475,6 +489,7 @@ struct __expected_storage : __expected_destruct<_Tp, _Err> __trans.__complete(); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Err2 = _Err) _CCCL_REQUIRES(_CCCL_TRAIT(is_nothrow_move_constructible, _Err2)) static _LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX20 void @@ -493,6 +508,7 @@ struct __expected_storage : __expected_destruct<_Tp, _Err> __with_err.__has_val_ = true; } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Err2 = _Err) _CCCL_REQUIRES((!_CCCL_TRAIT(is_nothrow_move_constructible, _Err2))) static _LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX20 void @@ -653,6 +669,7 @@ struct __expected_copy_assign<_Tp, _Err, __smf_availability::__available> : __ex _CCCL_HIDE_FROM_ABI __expected_copy_assign(const __expected_copy_assign&) = default; _CCCL_HIDE_FROM_ABI __expected_copy_assign(__expected_copy_assign&&) = default; + _CCCL_EXEC_CHECK_DISABLE _LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX20 __expected_copy_assign& operator=(const __expected_copy_assign& __other) noexcept( _CCCL_TRAIT(is_nothrow_copy_assignable, _Tp) && _CCCL_TRAIT(is_nothrow_copy_constructible, _Tp) @@ -917,6 +934,7 @@ struct __expected_storage : __expected_destruct { _LIBCUDACXX_DELEGATE_CONSTRUCTORS(__expected_storage, __expected_destruct, void, _Err); + _CCCL_EXEC_CHECK_DISABLE static _LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX20 void __swap_val_unex_impl( __expected_storage& __with_val, __expected_storage& __with_err) noexcept(_CCCL_TRAIT(is_nothrow_move_constructible, _Err)) diff --git a/libcudacxx/include/cuda/std/__expected/unexpected.h b/libcudacxx/include/cuda/std/__expected/unexpected.h index 0f8f3784374..0da94402a85 100644 --- a/libcudacxx/include/cuda/std/__expected/unexpected.h +++ b/libcudacxx/include/cuda/std/__expected/unexpected.h @@ -73,6 +73,7 @@ class unexpected _CCCL_HIDE_FROM_ABI unexpected(const unexpected&) = default; _CCCL_HIDE_FROM_ABI unexpected(unexpected&&) = default; + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Error = _Err) _CCCL_REQUIRES((!_CCCL_TRAIT(is_same, remove_cvref_t<_Error>, unexpected) && !_CCCL_TRAIT(is_same, remove_cvref_t<_Error>, in_place_t) @@ -82,6 +83,7 @@ class unexpected : __unex_(_CUDA_VSTD::forward<_Error>(__error)) {} + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class... _Args) _CCCL_REQUIRES(_CCCL_TRAIT(is_constructible, _Err, _Args...)) _LIBCUDACXX_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, _Args&&... __args) noexcept( @@ -89,6 +91,7 @@ class unexpected : __unex_(_CUDA_VSTD::forward<_Args>(__args)...) {} + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Up, class... _Args) _CCCL_REQUIRES(_CCCL_TRAIT(is_constructible, _Err, initializer_list<_Up>&, _Args...)) _LIBCUDACXX_HIDE_FROM_ABI constexpr explicit unexpected( @@ -123,6 +126,7 @@ class unexpected } // [expected.un.swap] + _CCCL_EXEC_CHECK_DISABLE _LIBCUDACXX_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(_CCCL_TRAIT(is_nothrow_swappable, _Err)) { static_assert(_CCCL_TRAIT(is_swappable, _Err), "E must be swappable"); @@ -130,6 +134,7 @@ class unexpected swap(__unex_, __other.__unex_); } + _CCCL_EXEC_CHECK_DISABLE _CCCL_TEMPLATE(class _Err2 = _Err) _CCCL_REQUIRES(_CCCL_TRAIT(is_swappable, _Err2)) friend _LIBCUDACXX_HIDE_FROM_ABI constexpr void @@ -140,6 +145,7 @@ class unexpected } // [expected.un.eq] + _CCCL_EXEC_CHECK_DISABLE template _CCCL_NODISCARD_FRIEND _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator==(const unexpected& __lhs, @@ -148,6 +154,7 @@ class unexpected return __lhs.error() == __rhs.error(); } # if _CCCL_STD_VER < 2020 + _CCCL_EXEC_CHECK_DISABLE template _CCCL_NODISCARD_FRIEND _LIBCUDACXX_HIDE_FROM_ABI constexpr bool operator!=(const unexpected& __lhs, diff --git a/libcudacxx/test/libcudacxx/cuda/utilities/expected/device_only_types.pass.cpp b/libcudacxx/test/libcudacxx/cuda/utilities/expected/device_only_types.pass.cpp new file mode 100644 index 00000000000..2ca4c902fa5 --- /dev/null +++ b/libcudacxx/test/libcudacxx/cuda/utilities/expected/device_only_types.pass.cpp @@ -0,0 +1,218 @@ +//===----------------------------------------------------------------------===// +// +// Part of the libcu++ 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 +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. +// +//===----------------------------------------------------------------------===// + +// We cannot suppress execution checks in cuda::std::construct_at +// XFAIL: c++20 + +#include +#include +#include + +#include "test_macros.h" + +struct device_only_type +{ + int val_; + + __device__ device_only_type(const int val = 0) noexcept + : val_(val) + {} + __device__ device_only_type(cuda::std::initializer_list, const int val) noexcept + : val_(val) + {} + + __device__ device_only_type(const device_only_type& other) noexcept + : val_(other.val_) + {} + __device__ device_only_type(device_only_type&& other) noexcept + : val_(cuda::std::exchange(other.val_, -1)) + {} + + __device__ device_only_type& operator=(const device_only_type& other) noexcept + { + val_ = other.val_; + return *this; + } + + __device__ device_only_type& operator=(device_only_type&& other) noexcept + + { + val_ = cuda::std::exchange(other.val_, -1); + return *this; + } + + __device__ ~device_only_type() noexcept {} + + __device__ friend bool operator==(const device_only_type& lhs, const device_only_type& rhs) noexcept + { + return lhs.val_ == rhs.val_; + } + __device__ friend bool operator!=(const device_only_type& lhs, const device_only_type& rhs) noexcept + { + return lhs.val_ != rhs.val_; + } +}; + +__device__ void test() +{ + using expected = cuda::std::expected; + { // default construction + expected default_constructed{}; + assert(default_constructed.has_value()); + assert(*default_constructed == 0); + } + + { // in_place zero initialization + expected in_place_zero_initialization{cuda::std::in_place}; + assert(in_place_zero_initialization.has_value()); + assert(*in_place_zero_initialization == 0); + } + + { // in_place initialization + expected in_place_initialization{cuda::std::in_place, 42}; + assert(in_place_initialization.has_value()); + assert(*in_place_initialization == 42); + } + + { // initializer_list initialization + expected init_list_initialization{cuda::std::in_place, cuda::std::initializer_list{}, 42}; + assert(init_list_initialization.has_value()); + assert(*init_list_initialization == 42); + } + + { // unexpect zero initialization + expected in_place_zero_initialization{cuda::std::unexpect}; + assert(!in_place_zero_initialization.has_value()); + assert(in_place_zero_initialization.error() == 0); + } + + { // unexpect initialization + expected in_place_initialization{cuda::std::unexpect, 42}; + assert(!in_place_initialization.has_value()); + assert(in_place_initialization.error() == 42); + } + + { // initializer_list initialization + expected init_list_initialization{cuda::std::unexpect, cuda::std::initializer_list{}, 42}; + assert(!init_list_initialization.has_value()); + assert(init_list_initialization.error() == 42); + } + + { // value initialization + expected value_initialization{42}; + assert(value_initialization.has_value()); + assert(*value_initialization == 42); + } + + { // copy construction + expected input{42}; + expected dest{input}; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // move construction + expected input{42}; + expected dest{cuda::std::move(input)}; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, value to value + expected input{42}; + expected dest{1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, value to empty + expected input{42}; + expected dest{}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, empty to value + expected input{}; + expected dest{1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 0); + } + + { // assignment, empty to empty + expected input{}; + expected dest{}; + dest = input; + assert(dest.has_value()); + assert(*dest == 0); + } + + { // assignment, error to value + expected input{cuda::std::unexpect, 42}; + expected dest{1337}; + dest = input; + assert(!dest.has_value()); + assert(dest.error() == 42); + } + + { // assignment, value to error + expected input{42}; + expected dest{cuda::std::unexpect, 1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, error to error + expected input{cuda::std::unexpect, 42}; + expected dest{cuda::std::unexpect, 1337}; + dest = input; + assert(!dest.has_value()); + assert(dest.error() == 42); + } + + { // comparison with expected with value + expected lhs{42}; + expected rhs{1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } + + { // comparison with expected with error + expected lhs{cuda::std::unexpect, 42}; + expected rhs{cuda::std::unexpect, 1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } + + { // comparison with type and value + expected expect{42}; + assert(expect == device_only_type{42}); + assert(device_only_type{42} == expect); + assert(expect != device_only_type{1337}); + assert(device_only_type{1337} != expect); + } + + { // comparison with type and error + expected expect{cuda::std::unexpect, 42}; + assert(expect == cuda::std::unexpected{42}); + assert(cuda::std::unexpected{42} == expect); + assert(expect != cuda::std::unexpected{1337}); + assert(cuda::std::unexpected{1337} != expect); + } +} + +int main(int arg, char** argv) +{ + NV_IF_TARGET(NV_IS_DEVICE, (test();)) + return 0; +} diff --git a/libcudacxx/test/libcudacxx/cuda/utilities/expected/host_only_types.pass.cpp b/libcudacxx/test/libcudacxx/cuda/utilities/expected/host_only_types.pass.cpp new file mode 100644 index 00000000000..cee912e566b --- /dev/null +++ b/libcudacxx/test/libcudacxx/cuda/utilities/expected/host_only_types.pass.cpp @@ -0,0 +1,220 @@ +//===----------------------------------------------------------------------===// +// +// Part of the libcu++ 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 +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: nvrtc + +// We cannot suppress execution checks in cuda::std::construct_at +// XFAIL: c++20 + +#include +#include +#include + +#include "test_macros.h" + +struct host_only_type +{ + int val_; + + host_only_type(const int val = 0) noexcept + : val_(val) + {} + host_only_type(cuda::std::initializer_list, const int val) noexcept + : val_(val) + {} + + host_only_type(const host_only_type& other) noexcept + : val_(other.val_) + {} + host_only_type(host_only_type&& other) noexcept + : val_(cuda::std::exchange(other.val_, -1)) + {} + + host_only_type& operator=(const host_only_type& other) noexcept + { + val_ = other.val_; + return *this; + } + + host_only_type& operator=(host_only_type&& other) noexcept + + { + val_ = cuda::std::exchange(other.val_, -1); + return *this; + } + + ~host_only_type() noexcept {} + + friend bool operator==(const host_only_type& lhs, const host_only_type& rhs) noexcept + { + return lhs.val_ == rhs.val_; + } + friend bool operator!=(const host_only_type& lhs, const host_only_type& rhs) noexcept + { + return lhs.val_ != rhs.val_; + } +}; + +void test() +{ + using expected = cuda::std::expected; + { // default construction + expected default_constructed{}; + assert(default_constructed.has_value()); + assert(*default_constructed == 0); + } + + { // in_place zero initialization + expected in_place_zero_initialization{cuda::std::in_place}; + assert(in_place_zero_initialization.has_value()); + assert(*in_place_zero_initialization == 0); + } + + { // in_place initialization + expected in_place_initialization{cuda::std::in_place, 42}; + assert(in_place_initialization.has_value()); + assert(*in_place_initialization == 42); + } + + { // initializer_list initialization + expected init_list_initialization{cuda::std::in_place, cuda::std::initializer_list{}, 42}; + assert(init_list_initialization.has_value()); + assert(*init_list_initialization == 42); + } + + { // unexpect zero initialization + expected in_place_zero_initialization{cuda::std::unexpect}; + assert(!in_place_zero_initialization.has_value()); + assert(in_place_zero_initialization.error() == 0); + } + + { // unexpect initialization + expected in_place_initialization{cuda::std::unexpect, 42}; + assert(!in_place_initialization.has_value()); + assert(in_place_initialization.error() == 42); + } + + { // initializer_list initialization + expected init_list_initialization{cuda::std::unexpect, cuda::std::initializer_list{}, 42}; + assert(!init_list_initialization.has_value()); + assert(init_list_initialization.error() == 42); + } + + { // value initialization + expected value_initialization{42}; + assert(value_initialization.has_value()); + assert(*value_initialization == 42); + } + + { // copy construction + expected input{42}; + expected dest{input}; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // move construction + expected input{42}; + expected dest{cuda::std::move(input)}; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, value to value + expected input{42}; + expected dest{1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, value to empty + expected input{42}; + expected dest{}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, empty to value + expected input{}; + expected dest{1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 0); + } + + { // assignment, empty to empty + expected input{}; + expected dest{}; + dest = input; + assert(dest.has_value()); + assert(*dest == 0); + } + + { // assignment, error to value + expected input{cuda::std::unexpect, 42}; + expected dest{1337}; + dest = input; + assert(!dest.has_value()); + assert(dest.error() == 42); + } + + { // assignment, value to error + expected input{42}; + expected dest{cuda::std::unexpect, 1337}; + dest = input; + assert(dest.has_value()); + assert(*dest == 42); + } + + { // assignment, error to error + expected input{cuda::std::unexpect, 42}; + expected dest{cuda::std::unexpect, 1337}; + dest = input; + assert(!dest.has_value()); + assert(dest.error() == 42); + } + + { // comparison with expected with value + expected lhs{42}; + expected rhs{1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } + + { // comparison with expected with error + expected lhs{cuda::std::unexpect, 42}; + expected rhs{cuda::std::unexpect, 1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } + + { // comparison with type and value + expected expect{42}; + assert(expect == host_only_type{42}); + assert(host_only_type{42} == expect); + assert(expect != host_only_type{1337}); + assert(host_only_type{1337} != expect); + } + + { // comparison with type and error + expected expect{cuda::std::unexpect, 42}; + assert(expect == cuda::std::unexpected{42}); + assert(cuda::std::unexpected{42} == expect); + assert(expect != cuda::std::unexpected{1337}); + assert(cuda::std::unexpected{1337} != expect); + } +} + +int main(int arg, char** argv) +{ + NV_IF_TARGET(NV_IS_HOST, (test();)) + return 0; +} diff --git a/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/device_only_types.pass.cpp b/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/device_only_types.pass.cpp new file mode 100644 index 00000000000..aa6882d4901 --- /dev/null +++ b/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/device_only_types.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// Part of the libcu++ 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 +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. +// +//===----------------------------------------------------------------------===// + +// We cannot suppress execution checks in cuda::std::construct_at +// XFAIL: c++20 + +#include +#include + +#include "test_macros.h" + +struct device_only_type +{ + int val_; + + __device__ device_only_type(const int val = 0) noexcept + : val_(val) + {} + __device__ device_only_type(cuda::std::initializer_list, const int val) noexcept + : val_(val) + {} + + __device__ device_only_type(const device_only_type& other) noexcept + : val_(other.val_) + {} + __device__ device_only_type(device_only_type&& other) noexcept + : val_(cuda::std::exchange(other.val_, -1)) + {} + + __device__ device_only_type& operator=(const device_only_type& other) noexcept + { + val_ = other.val_; + return *this; + } + + __device__ device_only_type& operator=(device_only_type&& other) noexcept + + { + val_ = cuda::std::exchange(other.val_, -1); + return *this; + } + + __device__ ~device_only_type() noexcept {} + + __device__ friend bool operator==(const device_only_type& lhs, const device_only_type& rhs) noexcept + { + return lhs.val_ == rhs.val_; + } + __device__ friend bool operator!=(const device_only_type& lhs, const device_only_type& rhs) noexcept + { + return lhs.val_ != rhs.val_; + } +}; + +__device__ void test() +{ + using unexpected = cuda::std::unexpected; + { // in_place zero initialization + unexpected in_place_zero_initialization{cuda::std::in_place}; + assert(in_place_zero_initialization.error() == 0); + } + + { // in_place initialization + unexpected in_place_initialization{cuda::std::in_place, 42}; + assert(in_place_initialization.error() == 42); + } + + { // value initialization + unexpected value_initialization{42}; + assert(value_initialization.error() == 42); + } + + { // initializer_list initialization + unexpected init_list_initialization{cuda::std::in_place, cuda::std::initializer_list{}, 42}; + assert(init_list_initialization.error() == 42); + } + + { // copy construction + unexpected input{42}; + unexpected dest{input}; + assert(dest.error() == 42); + } + + { // move construction + unexpected input{42}; + unexpected dest{cuda::std::move(input)}; + assert(dest.error() == 42); + } + + { // assignment + unexpected input{42}; + unexpected dest{1337}; + dest = input; + assert(dest.error() == 42); + } + + { // comparison with unexpected + unexpected lhs{42}; + unexpected rhs{1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } +} + +int main(int arg, char** argv) +{ + NV_IF_TARGET(NV_IS_DEVICE, (test();)) + return 0; +} diff --git a/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/host_only_types.pass.cpp b/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/host_only_types.pass.cpp new file mode 100644 index 00000000000..77e81df722c --- /dev/null +++ b/libcudacxx/test/libcudacxx/cuda/utilities/unexpected/host_only_types.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the libcu++ 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 +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: nvrtc + +// We cannot suppress execution checks in cuda::std::construct_at +// XFAIL: c++20 + +#include +#include +#include + +#include "test_macros.h" + +struct host_only_type +{ + int val_; + + host_only_type(const int val = 0) noexcept + : val_(val) + {} + host_only_type(cuda::std::initializer_list, const int val) noexcept + : val_(val) + {} + + host_only_type(const host_only_type& other) noexcept + : val_(other.val_) + {} + host_only_type(host_only_type&& other) noexcept + : val_(cuda::std::exchange(other.val_, -1)) + {} + + host_only_type& operator=(const host_only_type& other) noexcept + { + val_ = other.val_; + return *this; + } + + host_only_type& operator=(host_only_type&& other) noexcept + + { + val_ = cuda::std::exchange(other.val_, -1); + return *this; + } + + ~host_only_type() noexcept {} + + friend bool operator==(const host_only_type& lhs, const host_only_type& rhs) noexcept + { + return lhs.val_ == rhs.val_; + } + friend bool operator!=(const host_only_type& lhs, const host_only_type& rhs) noexcept + { + return lhs.val_ != rhs.val_; + } +}; + +void test() +{ + using unexpected = cuda::std::unexpected; + { // in_place zero initialization + unexpected in_place_zero_initialization{cuda::std::in_place}; + assert(in_place_zero_initialization.error() == 0); + } + + { // in_place initialization + unexpected in_place_initialization{cuda::std::in_place, 42}; + assert(in_place_initialization.error() == 42); + } + + { // value initialization + unexpected value_initialization{42}; + assert(value_initialization.error() == 42); + } + + { // initializer_list initialization + unexpected init_list_initialization{cuda::std::in_place, cuda::std::initializer_list{}, 42}; + assert(init_list_initialization.error() == 42); + } + + { // copy construction + unexpected input{42}; + unexpected dest{input}; + assert(dest.error() == 42); + } + + { // move construction + unexpected input{42}; + unexpected dest{cuda::std::move(input)}; + assert(dest.error() == 42); + } + + { // assignment + unexpected input{42}; + unexpected dest{1337}; + dest = input; + assert(dest.error() == 42); + } + + { // comparison with unexpected + unexpected lhs{42}; + unexpected rhs{1337}; + assert(!(lhs == rhs)); + assert(lhs != rhs); + } +} + +int main(int arg, char** argv) +{ + NV_IF_TARGET(NV_IS_HOST, (test();)) + return 0; +}