| 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 | // <utility> |
| 12 | |
| 13 | // template <class T1, class T2> struct pair |
| 14 | |
| 15 | // template <class U, class V> |
| 16 | // constexpr explicit(see below) pair(pair<U, V>&& p); |
| 17 | |
| 18 | #include <utility> |
| 19 | #include <memory> |
| 20 | #include <cassert> |
| 21 | |
| 22 | #include "archetypes.h" |
| 23 | #include "test_convertible.h" |
| 24 | |
| 25 | #include "test_macros.h" |
| 26 | using namespace ImplicitTypes; // Get implicitly archetypes |
| 27 | |
| 28 | template <class T1, class U1, |
| 29 | bool CanCopy = true, bool CanConvert = CanCopy> |
| 30 | void test_pair_rv() |
| 31 | { |
| 32 | using P1 = std::pair<T1, int>; |
| 33 | using P2 = std::pair<int, T1>; |
| 34 | using UP1 = std::pair<U1, int>&&; |
| 35 | using UP2 = std::pair<int, U1>&&; |
| 36 | static_assert(std::is_constructible<P1, UP1>::value == CanCopy, "" ); |
| 37 | static_assert(test_convertible<P1, UP1>() == CanConvert, "" ); |
| 38 | static_assert(std::is_constructible<P2, UP2>::value == CanCopy, "" ); |
| 39 | static_assert(test_convertible<P2, UP2>() == CanConvert, "" ); |
| 40 | } |
| 41 | |
| 42 | struct Base |
| 43 | { |
| 44 | virtual ~Base() {} |
| 45 | }; |
| 46 | |
| 47 | struct Derived |
| 48 | : public Base |
| 49 | { |
| 50 | }; |
| 51 | |
| 52 | |
| 53 | template <class T, class U> |
| 54 | struct DPair : public std::pair<T, U> { |
| 55 | using Base = std::pair<T, U>; |
| 56 | using Base::Base; |
| 57 | }; |
| 58 | |
| 59 | struct ExplicitT { |
| 60 | constexpr explicit ExplicitT(int x) : value(x) {} |
| 61 | int value; |
| 62 | }; |
| 63 | |
| 64 | struct ImplicitT { |
| 65 | constexpr ImplicitT(int x) : value(x) {} |
| 66 | int value; |
| 67 | }; |
| 68 | |
| 69 | struct NotCopyOrMoveConstructible { |
| 70 | NotCopyOrMoveConstructible() = default; |
| 71 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible const&) = delete; |
| 72 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible&&) = delete; |
| 73 | }; |
| 74 | |
| 75 | struct NonCopyConstructible { |
| 76 | NonCopyConstructible(NonCopyConstructible const&) = delete; |
| 77 | NonCopyConstructible(NonCopyConstructible&&) = default; |
| 78 | }; |
| 79 | |
| 80 | int main(int, char**) |
| 81 | { |
| 82 | { |
| 83 | typedef std::pair<std::unique_ptr<Derived>, int> P1; |
| 84 | typedef std::pair<std::unique_ptr<Base>, long> P2; |
| 85 | P1 p1(std::unique_ptr<Derived>(), 4); |
| 86 | P2 p2 = std::move(p1); |
| 87 | assert(p2.first == nullptr); |
| 88 | assert(p2.second == 4); |
| 89 | } |
| 90 | { |
| 91 | // We allow derived types to use this constructor |
| 92 | using P1 = DPair<long, long>; |
| 93 | using P2 = std::pair<int, int>; |
| 94 | P1 p1(42, 101); |
| 95 | P2 p2(std::move(p1)); |
| 96 | assert(p2.first == 42); |
| 97 | assert(p2.second == 101); |
| 98 | } |
| 99 | { |
| 100 | test_pair_rv<AllCtors, AllCtors>(); |
| 101 | test_pair_rv<AllCtors, AllCtors&>(); |
| 102 | test_pair_rv<AllCtors, AllCtors&&>(); |
| 103 | test_pair_rv<AllCtors, const AllCtors&>(); |
| 104 | test_pair_rv<AllCtors, const AllCtors&&>(); |
| 105 | |
| 106 | test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors>(); |
| 107 | test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors&, true, false>(); |
| 108 | test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors&&, true, false>(); |
| 109 | test_pair_rv<ExplicitTypes::AllCtors, const ExplicitTypes::AllCtors&, true, false>(); |
| 110 | test_pair_rv<ExplicitTypes::AllCtors, const ExplicitTypes::AllCtors&&, true, false>(); |
| 111 | |
| 112 | test_pair_rv<MoveOnly, MoveOnly>(); |
| 113 | test_pair_rv<MoveOnly, MoveOnly&, false>(); |
| 114 | test_pair_rv<MoveOnly, MoveOnly&&>(); |
| 115 | |
| 116 | test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly>(); // copy construction |
| 117 | test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly&, false>(); |
| 118 | test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly&&, true, false>(); |
| 119 | |
| 120 | test_pair_rv<CopyOnly, CopyOnly>(); |
| 121 | test_pair_rv<CopyOnly, CopyOnly&>(); |
| 122 | test_pair_rv<CopyOnly, CopyOnly&&>(); |
| 123 | |
| 124 | /* For ExplicitTypes::CopyOnly, two of the viable candidates for initializing from a non-const xvalue are: |
| 125 | * pair(const pair&); // (defaulted copy constructor) |
| 126 | * template<class U1, class U2> explicit pair(const pair<U1, U2>&&); [U1 = ExplicitTypes::CopyOnly, U2 = int] |
| 127 | * |
| 128 | * This results in diverging behavior for test_convertible which uses copy-list-initialization. |
| 129 | * Prior to CWG2137, this would have selected the first (non-explicit) ctor as explicit ctors |
| 130 | * would not be considered. Afterwards, it should select the second since it is a better match, |
| 131 | * and then failed because it is explicit. |
| 132 | * |
| 133 | * This may change with future defect reports, and some compilers only have partial support |
| 134 | * for CWG2137, so use std::is_convertible directly to avoid a copy-list-initialization |
| 135 | */ |
| 136 | { |
| 137 | using P1 = std::pair<ExplicitTypes::CopyOnly, int>; |
| 138 | using P2 = std::pair<int, ExplicitTypes::CopyOnly>; |
| 139 | using UP1 = std::pair<ExplicitTypes::CopyOnly, int>&&; |
| 140 | using UP2 = std::pair<int, ExplicitTypes::CopyOnly>&&; |
| 141 | static_assert(std::is_constructible<P1, UP1>::value, "" ); |
| 142 | static_assert(std::is_convertible<P1, UP1>::value, "" ); |
| 143 | static_assert(std::is_constructible<P2, UP2>::value, "" ); |
| 144 | static_assert(std::is_convertible<P2, UP2>::value, "" ); |
| 145 | } |
| 146 | test_pair_rv<ExplicitTypes::CopyOnly, ExplicitTypes::CopyOnly&, true, false>(); |
| 147 | test_pair_rv<ExplicitTypes::CopyOnly, ExplicitTypes::CopyOnly&&, true, false>(); |
| 148 | |
| 149 | test_pair_rv<NonCopyable, NonCopyable, false>(); |
| 150 | test_pair_rv<NonCopyable, NonCopyable&, false>(); |
| 151 | test_pair_rv<NonCopyable, NonCopyable&&, false>(); |
| 152 | test_pair_rv<NonCopyable, const NonCopyable&, false>(); |
| 153 | test_pair_rv<NonCopyable, const NonCopyable&&, false>(); |
| 154 | } |
| 155 | { // Test construction of references |
| 156 | test_pair_rv<NonCopyable&, NonCopyable&>(); |
| 157 | test_pair_rv<NonCopyable&, NonCopyable&&>(); |
| 158 | test_pair_rv<NonCopyable&, NonCopyable const&, false>(); |
| 159 | test_pair_rv<NonCopyable const&, NonCopyable&&>(); |
| 160 | test_pair_rv<NonCopyable&&, NonCopyable&&>(); |
| 161 | |
| 162 | test_pair_rv<ConvertingType&, int, false>(); |
| 163 | test_pair_rv<ExplicitTypes::ConvertingType&, int, false>(); |
| 164 | // Unfortunately the below conversions are allowed and create dangling |
| 165 | // references. |
| 166 | //test_pair_rv<ConvertingType&&, int>(); |
| 167 | //test_pair_rv<ConvertingType const&, int>(); |
| 168 | //test_pair_rv<ConvertingType const&&, int>(); |
| 169 | // But these are not because the converting constructor is explicit. |
| 170 | test_pair_rv<ExplicitTypes::ConvertingType&&, int, false>(); |
| 171 | test_pair_rv<ExplicitTypes::ConvertingType const&, int, false>(); |
| 172 | test_pair_rv<ExplicitTypes::ConvertingType const&&, int, false>(); |
| 173 | } |
| 174 | { |
| 175 | test_pair_rv<AllCtors, int, false>(); |
| 176 | test_pair_rv<ExplicitTypes::AllCtors, int, false>(); |
| 177 | test_pair_rv<ConvertingType, int>(); |
| 178 | test_pair_rv<ExplicitTypes::ConvertingType, int, true, false>(); |
| 179 | |
| 180 | test_pair_rv<ConvertingType, int>(); |
| 181 | test_pair_rv<ConvertingType, ConvertingType>(); |
| 182 | test_pair_rv<ConvertingType, ConvertingType const&>(); |
| 183 | test_pair_rv<ConvertingType, ConvertingType&>(); |
| 184 | test_pair_rv<ConvertingType, ConvertingType&&>(); |
| 185 | |
| 186 | test_pair_rv<ExplicitTypes::ConvertingType, int, true, false>(); |
| 187 | test_pair_rv<ExplicitTypes::ConvertingType, int&, true, false>(); |
| 188 | test_pair_rv<ExplicitTypes::ConvertingType, const int&, true, false>(); |
| 189 | test_pair_rv<ExplicitTypes::ConvertingType, int&&, true, false>(); |
| 190 | test_pair_rv<ExplicitTypes::ConvertingType, const int&&, true, false>(); |
| 191 | |
| 192 | test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType>(); |
| 193 | test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType const&, true, false>(); |
| 194 | test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType&, true, false>(); |
| 195 | test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType&&, true, false>(); |
| 196 | } |
| 197 | { |
| 198 | // When constructing a pair containing a reference, we only bind the |
| 199 | // reference, so it doesn't matter whether the type is or isn't |
| 200 | // copy/move constructible. |
| 201 | { |
| 202 | using P1 = std::pair<NotCopyOrMoveConstructible&, long>; |
| 203 | using P2 = std::pair<NotCopyOrMoveConstructible&, int>; |
| 204 | static_assert(std::is_constructible<P1, P2&&>::value, "" ); |
| 205 | |
| 206 | NotCopyOrMoveConstructible obj; |
| 207 | P2 p2{obj, 3}; |
| 208 | P1 p1(std::move(p2)); |
| 209 | assert(&p1.first == &obj); |
| 210 | assert(&p2.first == &obj); |
| 211 | } |
| 212 | { |
| 213 | using P1 = std::pair<NotCopyOrMoveConstructible&&, long>; |
| 214 | using P2 = std::pair<NotCopyOrMoveConstructible&&, int>; |
| 215 | static_assert(std::is_constructible<P1, P2&&>::value, "" ); |
| 216 | |
| 217 | NotCopyOrMoveConstructible obj; |
| 218 | P2 p2{std::move(obj), 3}; |
| 219 | P1 p1(std::move(p2)); |
| 220 | assert(&p1.first == &obj); |
| 221 | assert(&p2.first == &obj); |
| 222 | } |
| 223 | } |
| 224 | { |
| 225 | // Make sure we can't move-construct from a pair containing a reference |
| 226 | // if that type isn't copy-constructible (since otherwise we'd be stealing |
| 227 | // the object through the reference). |
| 228 | using P1 = std::pair<NonCopyConstructible, long>; |
| 229 | using P2 = std::pair<NonCopyConstructible&, int>; |
| 230 | static_assert(!std::is_constructible<P1, P2&&>::value, "" ); |
| 231 | } |
| 232 | #if TEST_STD_VER > 11 |
| 233 | { // explicit constexpr test |
| 234 | constexpr std::pair<int, int> p1(42, 43); |
| 235 | constexpr std::pair<ExplicitT, ExplicitT> p2(std::move(p1)); |
| 236 | static_assert(p2.first.value == 42, "" ); |
| 237 | static_assert(p2.second.value == 43, "" ); |
| 238 | } |
| 239 | { // implicit constexpr test |
| 240 | constexpr std::pair<int, int> p1(42, 43); |
| 241 | constexpr std::pair<ImplicitT, ImplicitT> p2 = std::move(p1); |
| 242 | static_assert(p2.first.value == 42, "" ); |
| 243 | static_assert(p2.second.value == 43, "" ); |
| 244 | } |
| 245 | #endif |
| 246 | |
| 247 | return 0; |
| 248 | } |
| 249 | |