| 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 |
| 10 | |
| 11 | // <tuple> |
| 12 | |
| 13 | // See https://llvm.org/PR20855. |
| 14 | |
| 15 | #include <functional> |
| 16 | #include <tuple> |
| 17 | #include <string> |
| 18 | #include <cassert> |
| 19 | #include "test_macros.h" |
| 20 | |
| 21 | #if TEST_HAS_BUILTIN(__reference_constructs_from_temporary) |
| 22 | # define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(__reference_constructs_from_temporary(__VA_ARGS__), "") |
| 23 | # define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...) \ |
| 24 | static_assert(!__reference_constructs_from_temporary(__VA_ARGS__), "") |
| 25 | #else |
| 26 | // TODO(LLVM 22): Remove this as all support compilers should have __reference_constructs_from_temporary implemented. |
| 27 | # define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(__reference_binds_to_temporary(__VA_ARGS__), "") |
| 28 | # define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...) static_assert(!__reference_binds_to_temporary(__VA_ARGS__), "") |
| 29 | #endif |
| 30 | |
| 31 | template <class Tp> |
| 32 | struct ConvertsTo { |
| 33 | using RawTp = typename std::remove_cv< typename std::remove_reference<Tp>::type>::type; |
| 34 | |
| 35 | operator Tp() const { |
| 36 | return static_cast<Tp>(value); |
| 37 | } |
| 38 | |
| 39 | mutable RawTp value; |
| 40 | }; |
| 41 | |
| 42 | struct Base {}; |
| 43 | struct Derived : Base {}; |
| 44 | |
| 45 | |
| 46 | static_assert(std::is_same<decltype("abc" ), decltype(("abc" ))>::value, "" ); |
| 47 | ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, decltype("abc" )); |
| 48 | ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, decltype(("abc" ))); |
| 49 | ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, const char*&&); |
| 50 | |
| 51 | ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(int&, const ConvertsTo<int&>&); |
| 52 | ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(const int&, ConvertsTo<int&>&); |
| 53 | ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(Base&, Derived&); |
| 54 | |
| 55 | |
| 56 | static_assert(std::is_constructible<int&, std::reference_wrapper<int>>::value, "" ); |
| 57 | static_assert(std::is_constructible<int const&, std::reference_wrapper<int>>::value, "" ); |
| 58 | |
| 59 | template <class T> struct CannotDeduce { |
| 60 | using type = T; |
| 61 | }; |
| 62 | |
| 63 | template <class ...Args> |
| 64 | void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {} |
| 65 | |
| 66 | void compile_tests() { |
| 67 | { |
| 68 | F<int, int const&>(std::make_tuple(args: 42, args: 42)); |
| 69 | } |
| 70 | { |
| 71 | F<int, int const&>(std::make_tuple<const int&, const int&>(args: 42, args: 42)); |
| 72 | std::tuple<int, int const&> t(std::make_tuple<const int&, const int&>(args: 42, args: 42)); |
| 73 | } |
| 74 | { |
| 75 | auto fn = &F<int, std::string const&>; |
| 76 | fn(std::tuple<int, std::string const&>(42, std::string("a" ))); |
| 77 | fn(std::make_tuple(args: 42, args: std::string("a" ))); |
| 78 | } |
| 79 | { |
| 80 | Derived d; |
| 81 | std::tuple<Base&, Base const&> t(d, d); |
| 82 | } |
| 83 | { |
| 84 | ConvertsTo<int&> ct; |
| 85 | std::tuple<int, int&> t(42, ct); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | void allocator_tests() { |
| 90 | std::allocator<int> alloc; |
| 91 | int x = 42; |
| 92 | { |
| 93 | std::tuple<int&> t(std::ref(t&: x)); |
| 94 | assert(&std::get<0>(t) == &x); |
| 95 | std::tuple<int&> t1(std::allocator_arg, alloc, std::ref(t&: x)); |
| 96 | assert(&std::get<0>(t1) == &x); |
| 97 | } |
| 98 | { |
| 99 | auto r = std::ref(t&: x); |
| 100 | auto const& cr = r; |
| 101 | std::tuple<int&> t(r); |
| 102 | assert(&std::get<0>(t) == &x); |
| 103 | std::tuple<int&> t1(cr); |
| 104 | assert(&std::get<0>(t1) == &x); |
| 105 | std::tuple<int&> t2(std::allocator_arg, alloc, r); |
| 106 | assert(&std::get<0>(t2) == &x); |
| 107 | std::tuple<int&> t3(std::allocator_arg, alloc, cr); |
| 108 | assert(&std::get<0>(t3) == &x); |
| 109 | } |
| 110 | { |
| 111 | std::tuple<int const&> t(std::ref(t&: x)); |
| 112 | assert(&std::get<0>(t) == &x); |
| 113 | std::tuple<int const&> t2(std::cref(t: x)); |
| 114 | assert(&std::get<0>(t2) == &x); |
| 115 | std::tuple<int const&> t3(std::allocator_arg, alloc, std::ref(t&: x)); |
| 116 | assert(&std::get<0>(t3) == &x); |
| 117 | std::tuple<int const&> t4(std::allocator_arg, alloc, std::cref(t: x)); |
| 118 | assert(&std::get<0>(t4) == &x); |
| 119 | } |
| 120 | { |
| 121 | auto r = std::ref(t&: x); |
| 122 | auto cr = std::cref(t: x); |
| 123 | std::tuple<int const&> t(r); |
| 124 | assert(&std::get<0>(t) == &x); |
| 125 | std::tuple<int const&> t2(cr); |
| 126 | assert(&std::get<0>(t2) == &x); |
| 127 | std::tuple<int const&> t3(std::allocator_arg, alloc, r); |
| 128 | assert(&std::get<0>(t3) == &x); |
| 129 | std::tuple<int const&> t4(std::allocator_arg, alloc, cr); |
| 130 | assert(&std::get<0>(t4) == &x); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | |
| 135 | int main(int, char**) { |
| 136 | compile_tests(); |
| 137 | allocator_tests(); |
| 138 | |
| 139 | return 0; |
| 140 | } |
| 141 | |