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
10 
11 // type_traits
12 // common_reference
13 
14 #include <tuple>
15 #include <type_traits>
16 #include <utility>
17 
18 #include "test_macros.h"
19 
20 template <class T>
21 constexpr bool has_type = requires {
22   typename T::type;
23 };
24 
25 // A slightly simplified variation of std::tuple
26 template <class...>
27 struct UserTuple {};
28 
29 template <class, class, class>
30 struct Tuple_helper {};
31 template <class... Ts, class... Us>
32 struct Tuple_helper<std::void_t<std::common_reference_t<Ts, Us>...>, UserTuple<Ts...>, UserTuple<Us...> > {
33   using type = UserTuple<std::common_reference_t<Ts, Us>...>;
34 };
35 
36 template <class... Ts, class... Us, template <class> class TQual, template <class> class UQual>
37 struct std::basic_common_reference< ::UserTuple<Ts...>, ::UserTuple<Us...>, TQual, UQual>
38     : ::Tuple_helper<void, UserTuple<TQual<Ts>...>, UserTuple<UQual<Us>...> > {};
39 
40 struct X2 {};
41 struct Y2 {};
42 struct Z2 {};
43 
44 template <>
45 struct std::common_type<X2, Y2> {
46   using type = Z2;
47 };
48 template <>
49 struct std::common_type<Y2, X2> {
50   using type = Z2;
51 };
52 
53 // (6.1)
54 //  -- If sizeof...(T) is zero, there shall be no member type.
55 static_assert(!has_type<std::common_reference<> >);
56 
57 // (6.2)
58 //  -- Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
59 //     pack T. The member typedef type shall denote the same type as T0.
60 static_assert(std::is_same_v<std::common_reference_t<void>, void>);
61 static_assert(std::is_same_v<std::common_reference_t<int>, int>);
62 static_assert(std::is_same_v<std::common_reference_t<int&>, int&>);
63 static_assert(std::is_same_v<std::common_reference_t<int&&>, int&&>);
64 static_assert(std::is_same_v<std::common_reference_t<int const>, int const>);
65 static_assert(std::is_same_v<std::common_reference_t<int const&>, int const&>);
66 static_assert(std::is_same_v<std::common_reference_t<int const&&>, int const&&>);
67 static_assert(std::is_same_v<std::common_reference_t<int volatile[]>, int volatile[]>);
68 static_assert(std::is_same_v<std::common_reference_t<int volatile (&)[]>, int volatile (&)[]>);
69 static_assert(std::is_same_v<std::common_reference_t<int volatile (&&)[]>, int volatile (&&)[]>);
70 static_assert(std::is_same_v<std::common_reference_t<void (&)()>, void (&)()>);
71 static_assert(std::is_same_v<std::common_reference_t<void (&&)()>, void (&&)()>);
72 
73 // (6.3)
74 //  -- Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
75 //     the pack T. Then
76 // (6.3.1)
77 //    -- If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed,
78 //       then the member typedef type denotes that type.
79 struct B {};
80 struct D : B {};
81 static_assert(std::is_same_v<std::common_reference_t<B&, D&>, B&>);
82 static_assert(std::is_same_v<std::common_reference_t<B const&, D&>, B const&>);
83 static_assert(std::is_same_v<std::common_reference_t<B&, D const&>, B const&>);
84 static_assert(std::is_same_v<std::common_reference_t<B&, D const&, D&>, B const&>);
85 static_assert(std::is_same_v<std::common_reference_t<B&, D&, B&, D&>, B&>);
86 
87 static_assert(std::is_same_v<std::common_reference_t<B&&, D&&>, B&&>);
88 static_assert(std::is_same_v<std::common_reference_t<B const&&, D&&>, B const&&>);
89 static_assert(std::is_same_v<std::common_reference_t<B&&, D const&&>, B const&&>);
90 static_assert(std::is_same_v<std::common_reference_t<B&, D&&>, B const&>);
91 static_assert(std::is_same_v<std::common_reference_t<B&, D const&&>, B const&>);
92 static_assert(std::is_same_v<std::common_reference_t<B const&, D&&>, B const&>);
93 
94 static_assert(std::is_same_v<std::common_reference_t<B&&, D&>, B const&>);
95 static_assert(std::is_same_v<std::common_reference_t<B&&, D const&>, B const&>);
96 static_assert(std::is_same_v<std::common_reference_t<B const&&, D&>, B const&>);
97 
98 static_assert(std::is_same_v<std::common_reference_t<int const&, int volatile&>, int const volatile&>);
99 static_assert(std::is_same_v<std::common_reference_t<int const volatile&&, int volatile&&>, int const volatile&&>);
100 
101 static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&&)[10]>, int const (&)[10]>);
102 static_assert(std::is_same_v<std::common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile (&)[10]>);
103 
104 // (6.3.2)
105 //    -- Otherwise, if basic_common_reference<remove_cvref_t<T1>,
106 //       remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, then the
107 //       member typedef type denotes that type.
108 static_assert(std::is_same_v<std::common_reference_t<const UserTuple<int, short>&, UserTuple<int&, short volatile&>>,
109                              UserTuple<const int&, const volatile short&>>);
110 
111 static_assert(std::is_same_v<std::common_reference_t<volatile UserTuple<int, short>&, const UserTuple<int, short>&>,
112                              const volatile UserTuple<int, short>&>);
113 
114 // (6.3.3)
115 //    -- Otherwise, if COND_RES(T1, T2) is well-formed, then the member typedef
116 //       type denotes that type.
117 static_assert(std::is_same_v<std::common_reference_t<void, void>, void>);
118 static_assert(std::is_same_v<std::common_reference_t<int, short>, int>);
119 static_assert(std::is_same_v<std::common_reference_t<int, short&>, int>);
120 static_assert(std::is_same_v<std::common_reference_t<int&, short&>, int>);
121 static_assert(std::is_same_v<std::common_reference_t<int&, short>, int>);
122 
123 // tricky volatile reference case
124 static_assert(std::is_same_v<std::common_reference_t<int&&, int volatile&>, int>);
125 static_assert(std::is_same_v<std::common_reference_t<int volatile&, int&&>, int>);
126 
127 static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&)[11]>, int*>);
128 
129 // https://github.com/ericniebler/stl2/issues/338
130 struct MyIntRef {
131   MyIntRef(int&);
132 };
133 static_assert(std::is_same_v<std::common_reference_t<int&, MyIntRef>, MyIntRef>);
134 
135 // (6.3.4)
136 //    -- Otherwise, if common_type_t<T1, T2> is well-formed, then the member
137 //       typedef type denotes that type.
138 struct moveonly {
139   moveonly() = default;
140   moveonly(moveonly&&) = default;
141   moveonly& operator=(moveonly&&) = default;
142 };
143 struct moveonly2 : moveonly {};
144 
145 static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly>, moveonly>);
146 static_assert(std::is_same_v<std::common_reference_t<moveonly2 const&, moveonly>, moveonly>);
147 static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly2>, moveonly>);
148 
149 static_assert(std::is_same_v<std::common_reference_t<X2&, Y2 const&>, Z2>);
150 
151 // (6.3.5)
152 //    -- Otherwise, there shall be no member type.
153 static_assert(!has_type<std::common_reference<volatile UserTuple<short>&, const UserTuple<int, short>&> >);
154 
155 // (6.4)
156 //  -- Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest,
157 //     respectively, denote the first, second, and (pack of) remaining types
158 //     comprising T. Let C be the type common_reference_t<T1, T2>. Then:
159 // (6.4.1)
160 //    -- If there is such a type C, the member typedef type shall denote the
161 //       same type, if any, as common_reference_t<C, Rest...>.
162 static_assert(std::is_same_v<std::common_reference_t<int, int, int>, int>);
163 static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, int volatile&>, int const volatile&>);
164 static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, float&>, float>);
165 
166 // (6.4.2)
167 //    -- Otherwise, there shall be no member type.
168 static_assert(!has_type<std::common_reference<int, short, int, char*> >);
169 
170 #if TEST_STD_VER > 20
171 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, int>>, std::tuple<int, int>>);
172 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, long>, std::tuple<long, int>>, std::tuple<long, long>>);
173 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const int&>, std::tuple<const int&, int>>,
174                              std::tuple<const int&, int>>);
175 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, volatile int&>, std::tuple<volatile int&, int>>,
176                              std::tuple<volatile int&, int>>);
177 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const volatile int&>, std::tuple<const volatile int&, int>>,
178                              std::tuple<const volatile int&, int>>);
179 static_assert(!has_type<std::common_reference_t<std::tuple<const int&, volatile int&>, std::tuple<volatile int&, const int&>>>);
180 
181 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>);
182 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>);
183 static_assert(!has_type<std::common_reference<std::tuple<int, const X2>, std::tuple<float, const Z2>>>);
184 static_assert(!has_type<std::common_reference<std::tuple<int, X2>, std::tuple<float, Z2>>>);
185 static_assert(!has_type<std::common_reference<std::tuple<int, X2>, int, X2>>);
186 
187 struct A {};
188 template <template<class> class TQual, template<class> class UQual>
189 struct std::basic_common_reference<A, std::tuple<B>, TQual, UQual> {
190   using type = tuple<UQual<B>>;
191 };
192 
193 static_assert(std::is_same_v<std::common_reference_t<A, std::tuple<B>, std::tuple<D>>, std::tuple<B>>);
194 
195 
196 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, int>>,
197                              std::pair<int, int>>);
198 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, long>, std::pair<long, int>>,
199                              std::pair<long, long>>);
200 static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const int&>, std::pair<const int&, int>>,
201                              std::pair<const int&, int>>);
202 static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, volatile int&>, std::pair<volatile int&, int>>,
203                              std::pair<volatile int&, int>>);
204 static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const volatile int&>, std::pair<const volatile int&, int>>,
205                              std::pair<const volatile int&, int>>);
206 static_assert(!has_type<std::common_reference_t<std::pair<const int&, volatile int&>,
207                         std::pair<volatile int&, const int&>>>);
208 
209 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>);
210 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>);
211 static_assert(!has_type<std::common_reference<std::pair<int, const X2>, std::pair<float, const Z2>>>);
212 static_assert(!has_type<std::common_reference<std::pair<int, X2>, std::pair<float, Z2>>>);
213 static_assert(!has_type<std::common_reference<std::pair<int, X2>, int, X2>>);
214 #endif
215