217 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11// template<class U = T>12// constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);13//14// Constraints:15// - is_same_v<remove_cvref_t<U>, in_place_t> is false; and16// - is_same_v<expected, remove_cvref_t<U>> is false; and17// - is_same_v<remove_cvref_t<U>, unexpect_t> is false; and18// - remove_cvref_t<U> is not a specialization of unexpected; and19// - is_constructible_v<T, U> is true.20//21// Effects: Direct-non-list-initializes val with std::forward<U>(v).22//23// Postconditions: has_value() is true.24//25// Throws: Any exception thrown by the initialization of val.26 27#include <cassert>28#include <expected>29#include <type_traits>30#include <utility>31 32#include "MoveOnly.h"33#include "test_macros.h"34#include "../../types.h"35 36// Test Constraints:37static_assert(std::is_constructible_v<std::expected<int, int>, int>);38 39// is_same_v<remove_cvref_t<U>, in_place_t>40struct FromJustInplace {41 FromJustInplace(std::in_place_t);42};43static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t>);44static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t const&>);45 46// is_same_v<expected, remove_cvref_t<U>>47// Note that result is true because it is covered by the constructors that take expected48static_assert(std::is_constructible_v<std::expected<int, int>, std::expected<int, int>&>);49 50struct T {51 explicit T(auto) {}52};53struct E {54 E(int) {}55};56 57// is_same_v<remove_cvref_t<U>, unexpect_t> is false;58static_assert(!std::is_constructible_v<std::expected<T, E>, std::unexpect_t>);59 60// remove_cvref_t<U> is a specialization of unexpected61// Note that result is true because it is covered by the constructors that take unexpected62static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpected<int>&>);63 64// !is_constructible_v<T, U>65struct foo {};66static_assert(!std::is_constructible_v<std::expected<int, int>, foo>);67 68// test explicit(!is_convertible_v<U, T>)69struct NotConvertible {70 explicit NotConvertible(int);71};72static_assert(std::is_convertible_v<int, std::expected<int, int>>);73static_assert(!std::is_convertible_v<int, std::expected<NotConvertible, int>>);74 75struct CopyOnly {76 int i;77 constexpr CopyOnly(int ii) : i(ii) {}78 CopyOnly(const CopyOnly&) = default;79 CopyOnly(CopyOnly&&) = delete;80 friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }81};82 83struct MoveOnly2 {84 int j;85 bool used_move1 = false;86 bool used_move2 = false;87 88 constexpr explicit MoveOnly2(int jj) : j(jj) {}89 constexpr MoveOnly2(const MoveOnly2&) = delete;90 constexpr MoveOnly2(MoveOnly2&& m) : j(m.j), used_move1(true) {}91 constexpr MoveOnly2(const MoveOnly2&& m) : j(m.j), used_move2(true) {}92};93 94struct BaseError {};95struct DerivedError : BaseError {};96 97template <class T, class E = int>98constexpr void testInt() {99 std::expected<T, E> e(5);100 assert(e.has_value());101 assert(e.value() == 5);102}103 104template <class T, class E = int>105constexpr void testLValue() {106 T t(5);107 std::expected<T, E> e(t);108 assert(e.has_value());109 assert(e.value() == 5);110}111 112template <class T, class E = int>113constexpr void testRValue() {114 std::expected<T, E> e(T(5));115 assert(e.has_value());116 assert(e.value() == 5);117}118 119constexpr bool test() {120 testInt<int>();121 testInt<CopyOnly>();122 testInt<MoveOnly>();123 testInt<TailClobberer<0>, bool>();124 testLValue<int>();125 testLValue<CopyOnly>();126 testLValue<TailClobberer<0>, bool>();127 testRValue<int>();128 testRValue<MoveOnly>();129 testRValue<TailClobberer<0>, bool>();130 131 // Test default template argument.132 // Without it, the template parameter cannot be deduced from an initializer list133 {134 struct Bar {135 int i;136 int j;137 constexpr Bar(int ii, int jj) : i(ii), j(jj) {}138 };139 140 std::expected<Bar, int> e({5, 6});141 assert(e.value().i == 5);142 assert(e.value().j == 6);143 }144 145 // https://cplusplus.github.io/LWG/issue3836146 147 // Test &148 {149 std::expected<bool, DerivedError> e1(false);150 std::expected<bool, BaseError> e2(e1);151 assert(e2.has_value());152 assert(!e2.value()); // yes, e2 holds "false" since LWG3836153 }154 155 // Test &&156 {157 std::expected<bool, DerivedError> e1(false);158 std::expected<bool, BaseError> e2(std::move(e1));159 assert(e2.has_value());160 assert(!e2.value()); // yes, e2 holds "false" since LWG3836161 }162 163 // Test const&164 {165 const std::expected<bool, DerivedError> e1(false);166 std::expected<bool, BaseError> e2(e1);167 assert(e2.has_value());168 assert(!e2.value()); // yes, e2 holds "false" since LWG3836169 }170 171 // Test const&&172 {173 const std::expected<bool, DerivedError> e1(false);174 std::expected<bool, BaseError> e2(std::move(e1));175 assert(e2.has_value());176 assert(!e2.value()); // yes, e2 holds "false" since LWG3836177 }178 179 // Check move constructor selection180 {181 MoveOnly2 t{1};182 std::expected<MoveOnly2, BaseError> e1(std::move(t));183 assert(e1.has_value());184 assert(e1.value().used_move1 == true);185 assert(e1.value().j == 1);186 }187 {188 const MoveOnly2 t2{2};189 std::expected<MoveOnly2, BaseError> e1(std::move(t2));190 assert(e1.has_value());191 assert(e1.value().used_move2 == true);192 assert(e1.value().j == 2);193 }194 return true;195}196 197void testException() {198#ifndef TEST_HAS_NO_EXCEPTIONS199 struct Throwing {200 Throwing(int) { throw Except{}; };201 };202 203 try {204 std::expected<Throwing, int> u(5);205 assert(false);206 } catch (Except) {207 }208#endif // TEST_HAS_NO_EXCEPTIONS209}210 211int main(int, char**) {212 test();213 static_assert(test());214 testException();215 return 0;216}217