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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10 11 // constexpr bool has_value() const noexcept; 12 13 #include <cassert> 14 #include <concepts> 15 #include <expected> 16 #include <optional> 17 #include <type_traits> 18 #include <utility> 19 20 #include "test_macros.h" 21 #include "../../types.h" 22 23 // Test noexcept 24 template <class T> 25 concept HasValueNoexcept = 26 requires(T t) { 27 { t.has_value() } noexcept; 28 }; 29 30 struct Foo {}; 31 static_assert(!HasValueNoexcept<Foo>); 32 33 static_assert(HasValueNoexcept<std::expected<int, int>>); 34 static_assert(HasValueNoexcept<const std::expected<int, int>>); 35 36 constexpr bool test() { 37 // has_value 38 { 39 const std::expected<int, int> e(5); 40 assert(e.has_value()); 41 } 42 43 // !has_value 44 { 45 const std::expected<int, int> e(std::unexpect, 5); 46 assert(!e.has_value()); 47 } 48 49 // The following tests check that the "has_value" flag is not overwritten 50 // by the constructor of the value. This could happen because the flag is 51 // stored in the tail padding of the value. 52 // 53 // The first test is a simplified version of the real code where this was 54 // first observed. 55 // 56 // The other tests use a synthetic struct that clobbers its tail padding 57 // on construction, making the issue easier to reproduce. 58 // 59 // See https://github.com/llvm/llvm-project/issues/68552 and the linked PR. 60 { 61 auto f1 = []() -> std::expected<std::optional<int>, long> { return 0; }; 62 63 auto f2 = [&f1]() -> std::expected<std::optional<int>, int> { 64 return f1().transform_error([](auto) { return 0; }); 65 }; 66 67 auto e = f2(); 68 assert(e.has_value()); 69 } 70 { 71 const std::expected<TailClobberer<0>, bool> e = {}; 72 // clang-cl does not support [[no_unique_address]] yet. 73 #if !(defined(TEST_COMPILER_CLANG) && defined(_MSC_VER)) 74 LIBCPP_STATIC_ASSERT(sizeof(TailClobberer<0>) == sizeof(e)); 75 #endif 76 assert(e.has_value()); 77 } 78 79 return true; 80 } 81 82 int main(int, char**) { 83 test(); 84 static_assert(test()); 85 return 0; 86 } 87