241 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// <expected>12 13// template<class F> constexpr auto or_else(F&& f) &;14// template<class F> constexpr auto or_else(F&& f) const &;15// template<class F> constexpr auto or_else(F&& f) &&;16// template<class F> constexpr auto or_else(F&& f) const &&;17 18#include <cassert>19#include <concepts>20#include <expected>21#include <memory>22#include <type_traits>23#include <utility>24 25#include "../../types.h"26 27struct LVal {28 constexpr std::expected<int, int> operator()(int&) { return 1; }29 std::expected<int, int> operator()(const int&) = delete;30 std::expected<int, int> operator()(int&&) = delete;31 std::expected<int, int> operator()(const int&&) = delete;32};33 34struct CLVal {35 std::expected<int, int> operator()(int&) = delete;36 constexpr std::expected<int, int> operator()(const int&) { return 1; }37 std::expected<int, int> operator()(int&&) = delete;38 std::expected<int, int> operator()(const int&&) = delete;39};40 41struct RVal {42 std::expected<int, int> operator()(int&) = delete;43 std::expected<int, int> operator()(const int&) = delete;44 constexpr std::expected<int, int> operator()(int&&) { return 1; }45 std::expected<int, int> operator()(const int&&) = delete;46};47 48struct CRVal {49 std::expected<int, int> operator()(int&) = delete;50 std::expected<int, int> operator()(const int&) = delete;51 std::expected<int, int> operator()(int&&) = delete;52 constexpr std::expected<int, int> operator()(const int&&) { return 1; }53};54 55struct RefQual {56 constexpr std::expected<int, int> operator()(int) & { return 1; }57 std::expected<int, int> operator()(int) const& = delete;58 std::expected<int, int> operator()(int) && = delete;59 std::expected<int, int> operator()(int) const&& = delete;60};61 62struct CRefQual {63 std::expected<int, int> operator()(int) & = delete;64 constexpr std::expected<int, int> operator()(int) const& { return 1; }65 std::expected<int, int> operator()(int) && = delete;66 std::expected<int, int> operator()(int) const&& = delete;67};68 69struct RVRefQual {70 std::expected<int, int> operator()(int) & = delete;71 std::expected<int, int> operator()(int) const& = delete;72 constexpr std::expected<int, int> operator()(int) && { return 1; }73 std::expected<int, int> operator()(int) const&& = delete;74};75 76struct RVCRefQual {77 std::expected<int, int> operator()(int) & = delete;78 std::expected<int, int> operator()(int) const& = delete;79 std::expected<int, int> operator()(int) && = delete;80 constexpr std::expected<int, int> operator()(int) const&& { return 1; }81};82 83template <class E, class F>84concept has_or_else =85 requires(E&& e, F&& f) {86 { std::forward<E>(e).or_else(std::forward<F>(f)) };87 };88// clang-format off89// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.90static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&, int()>);91static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&&, int()>);92 93// [LWG 3983] https://cplusplus.github.io/LWG/issue3938, check std::expected monadic ops well-formed with move-only error_type.94static_assert(has_or_else<std::expected<int, MoveOnlyErrorType>&, std::expected<int, int>(MoveOnlyErrorType &)>);95static_assert(has_or_else<const std::expected<int, MoveOnlyErrorType>&, std::expected<int, int>(const MoveOnlyErrorType &)>);96static_assert(has_or_else<std::expected<int, MoveOnlyErrorType>&&, std::expected<int, int>(MoveOnlyErrorType&&)>);97static_assert(has_or_else<const std::expected<int, MoveOnlyErrorType>&&, std::expected<int, int>(const MoveOnlyErrorType&&)>);98 99constexpr void test_val_types() {100 // Test & overload101 {102 // Without & qualifier on F's operator()103 {104 std::expected<int, int> e(std::unexpected<int>(0));105 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(LVal{});106 assert(val == 1);107 }108 109 // With & qualifier on F's operator110 {111 std::expected<int, int> e(std::unexpected<int>(0));112 RefQual l{};113 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);114 assert(val == 1);115 }116 }117 118 // Test const& overload119 {120 // Without const& qualifier on F's operator()121 {122 const std::expected<int, int> e(std::unexpected<int>(0));123 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(CLVal{});124 assert(val == 1);125 }126 127 // With const& qualifier on F's operator()128 {129 const std::expected<int, int> e(std::unexpected<int>(0));130 const CRefQual l{};131 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);132 assert(val == 1);133 }134 }135 136 // Test && overload137 {138 // Without && qualifier on F's operator()139 {140 std::expected<int, int> e(std::unexpected<int>(0));141 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVal{});142 assert(val == 1);143 }144 145 // With && qualifier on F's operator()146 {147 std::expected<int, int> e(std::unexpected<int>(0));148 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVRefQual{});149 assert(val == 1);150 }151 }152 153 // Test const&& overload154 {155 // Without const&& qualifier on F's operator()156 {157 const std::expected<int, int> e(std::unexpected<int>(0));158 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(CRVal{});159 assert(val == 1);160 }161 162 // With const&& qualifier on F's operator()163 {164 const std::expected<int, int> e(std::unexpected<int>(0));165 const RVCRefQual l{};166 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(std::move(l));167 assert(val == 1);168 }169 }170}171// clang-format on172 173struct NonConst {174 std::expected<int, int> non_const() { return std::expected<int, int>(std::unexpect, 1); }175};176 177// check that the lambda body is not instantiated during overload resolution178constexpr void test_sfinae() {179 std::expected<int, NonConst> e{1};180 auto l = [](auto&& x) { return x.non_const(); };181 (void)e.or_else(l);182 (void)std::move(e).or_else(l);183}184 185constexpr void test_move_only_error_type() {186 // Test &187 {188 std::expected<int, MoveOnlyErrorType> e;189 auto l = [](MoveOnlyErrorType&) { return std::expected<int, int>{}; };190 (void)e.or_else(l);191 }192 193 // Test const&194 {195 const std::expected<int, MoveOnlyErrorType> e;196 auto l = [](const MoveOnlyErrorType&) { return std::expected<int, int>{}; };197 (void)e.or_else(l);198 }199 200 // Test &&201 {202 std::expected<int, MoveOnlyErrorType> e;203 auto l = [](MoveOnlyErrorType&&) { return std::expected<int, int>{}; };204 (void)std::move(e).or_else(l);205 }206 207 // Test const&&208 {209 const std::expected<int, MoveOnlyErrorType> e;210 auto l = [](const MoveOnlyErrorType&&) { return std::expected<int, int>{}; };211 (void)std::move(e).or_else(l);212 }213}214 215constexpr bool test() {216 test_sfinae();217 test_val_types();218 test_move_only_error_type();219 220 std::expected<int, int> e(1);221 const auto& ce = e;222 223 const auto never_called = [](int) {224 assert(false);225 return std::expected<int, int>();226 };227 228 (void)e.or_else(never_called);229 (void)std::move(e).or_else(never_called);230 (void)ce.or_else(never_called);231 (void)std::move(ce).or_else(never_called);232 return true;233}234 235int main(int, char**) {236 test();237 static_assert(test());238 239 return 0;240}241