blob: 4ddfb463385c700eb77b227fda6b995580b82d0a [file] [log] [blame]
Eric Fiselierd5019332016-04-15 18:05:59 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// UNSUPPORTED: c++98, c++03
11
12// <tuple>
13
14// template <class... Types> class tuple;
15
16// template <class TupleLike>
17// tuple(TupleLike&&);
18// template <class Alloc, class TupleLike>
19// tuple(std::allocator_arg_t, Alloc const&, TupleLike&&);
20
21// Check that the tuple-like ctors are properly disabled when the UTypes...
22// constructor should be selected. See PR22806.
23
24#include <tuple>
25#include <memory>
26#include <cassert>
27
28template <class Tp>
29using uncvref_t = typename std::remove_cv<typename std::remove_reference<Tp>::type>::type;
30
31template <class Tuple, class = uncvref_t<Tuple>>
32struct IsTuple : std::false_type {};
33
34template <class Tuple, class ...Args>
35struct IsTuple<Tuple, std::tuple<Args...>> : std::true_type {};
36
37struct ConstructibleFromTupleAndInt {
38 enum State { FromTuple, FromInt, Copied, Moved };
39 State state;
40
41 ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt const&) : state(Copied) {}
42 ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt &&) : state(Moved) {}
43
44 template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
45 explicit ConstructibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
46
47 explicit ConstructibleFromTupleAndInt(int) : state(FromInt) {}
48};
49
50struct ConvertibleFromTupleAndInt {
51 enum State { FromTuple, FromInt, Copied, Moved };
52 State state;
53
54 ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt const&) : state(Copied) {}
55 ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt &&) : state(Moved) {}
56
57 template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
58 ConvertibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
59
60 ConvertibleFromTupleAndInt(int) : state(FromInt) {}
61};
62
63struct ConstructibleFromInt {
64 enum State { FromInt, Copied, Moved };
65 State state;
66
67 ConstructibleFromInt(ConstructibleFromInt const&) : state(Copied) {}
68 ConstructibleFromInt(ConstructibleFromInt &&) : state(Moved) {}
69
70 explicit ConstructibleFromInt(int) : state(FromInt) {}
71};
72
73struct ConvertibleFromInt {
74 enum State { FromInt, Copied, Moved };
75 State state;
76
77 ConvertibleFromInt(ConvertibleFromInt const&) : state(Copied) {}
78 ConvertibleFromInt(ConvertibleFromInt &&) : state(Moved) {}
79 ConvertibleFromInt(int) : state(FromInt) {}
80};
81
82int main()
83{
84 // Test for the creation of dangling references when a tuple is used to
85 // store a reference to another tuple as its only element.
86 // Ex std::tuple<std::tuple<int>&&>.
87 // In this case the constructors 1) 'tuple(UTypes&&...)'
88 // and 2) 'tuple(TupleLike&&)' need to be manually disambiguated because
89 // when both #1 and #2 participate in partial ordering #2 will always
90 // be chosen over #1.
91 // See PR22806 and LWG issue #2549 for more information.
92 // (https://llvm.org/bugs/show_bug.cgi?id=22806)
93 using T = std::tuple<int>;
94 std::allocator<int> A;
95 { // rvalue reference
96 T t1(42);
97 std::tuple< T&& > t2(std::move(t1));
98 assert(&std::get<0>(t2) == &t1);
99 }
100 { // const lvalue reference
101 T t1(42);
102
103 std::tuple< T const & > t2(t1);
104 assert(&std::get<0>(t2) == &t1);
105
106 std::tuple< T const & > t3(static_cast<T const&>(t1));
107 assert(&std::get<0>(t3) == &t1);
108 }
109 { // lvalue reference
110 T t1(42);
111
112 std::tuple< T & > t2(t1);
113 assert(&std::get<0>(t2) == &t1);
114 }
115 { // const rvalue reference
116 T t1(42);
117
118 std::tuple< T const && > t2(std::move(t1));
119 assert(&std::get<0>(t2) == &t1);
120 }
121 { // rvalue reference via uses-allocator
122 T t1(42);
123 std::tuple< T&& > t2(std::allocator_arg, A, std::move(t1));
124 assert(&std::get<0>(t2) == &t1);
125 }
126 { // const lvalue reference via uses-allocator
127 T t1(42);
128
129 std::tuple< T const & > t2(std::allocator_arg, A, t1);
130 assert(&std::get<0>(t2) == &t1);
131
132 std::tuple< T const & > t3(std::allocator_arg, A, static_cast<T const&>(t1));
133 assert(&std::get<0>(t3) == &t1);
134 }
135 { // lvalue reference via uses-allocator
136 T t1(42);
137
138 std::tuple< T & > t2(std::allocator_arg, A, t1);
139 assert(&std::get<0>(t2) == &t1);
140 }
141 { // const rvalue reference via uses-allocator
142 T const t1(42);
143 std::tuple< T const && > t2(std::allocator_arg, A, std::move(t1));
144 assert(&std::get<0>(t2) == &t1);
145 }
146 // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
147 // 'tuple<T>' where UDT *can* be constructed from 'tuple<T>' In this case
148 // the 'tuple(UTypes...)' ctor should be choosen and 'UDT' constructed frow
149 // 'tuple<T>'.
150 {
151 using VT = ConstructibleFromTupleAndInt;
152 std::tuple<int> t1(42);
153 std::tuple<VT> t2(t1);
154 assert(std::get<0>(t2).state == VT::FromTuple);
155 }
156 {
157 using VT = ConvertibleFromTupleAndInt;
158 std::tuple<int> t1(42);
159 std::tuple<VT> t2 = {t1};
160 assert(std::get<0>(t2).state == VT::FromTuple);
161 }
162 // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
163 // 'tuple<T>' where UDT cannot be constructed from 'tuple<T>' but can
164 // be constructed from 'T'. In this case the tuple-like ctor should be
165 // chosen and 'UDT' constructed from 'T'
166 {
167 using VT = ConstructibleFromInt;
168 std::tuple<int> t1(42);
169 std::tuple<VT> t2(t1);
170 assert(std::get<0>(t2).state == VT::FromInt);
171 }
172 {
173 using VT = ConvertibleFromInt;
174 std::tuple<int> t1(42);
175 std::tuple<VT> t2 = {t1};
176 assert(std::get<0>(t2).state == VT::FromInt);
177 }
178}