1 // This test comes from upstream bug
2 // https://sourceware.org/bugzilla/show_bug.cgi?id=21296
3 //
4 // It has to be compiled once with clang++ and once with g++, like
5 // this:
6 //
7 // clang++ -std=c++14 -o test40-PR21296-libclang.so -shared -fPIC test40-PR21296-clanggcc.cc -g
8 //
9 // g++ -o test40-PR21296-libgcc.so -shared -fPIC test40-PR21296-clanggcc.cc -g
10 //
11 extern "C" void free(void*) throw ();
12 extern "C" char* strdup(const char*);
13
14 struct STR {
STRSTR15 STR(const char* S): C(strdup(S)) {}
~STRSTR16 ~STR() { free(C); }
STRSTR17 STR(STR&& O): C(O.C) { O.C = 0; }
18 char* C;
19 };
20
21 extern "C" int printf(const char*,...);
22
23 namespace std
24 {
25
26 typedef unsigned long size_t;
27
28 struct true_type { static constexpr bool value = true; };
29 struct false_type { static constexpr bool value = false; };
30
31 // Reference transformations.
32
33 /// remove_reference
34 template<typename _Tp>
35 struct remove_reference
36 { typedef _Tp type; };
37
38 template<typename _Tp>
39 struct remove_reference<_Tp&>
40 { typedef _Tp type; };
41
42 template<typename _Tp>
43 struct remove_reference<_Tp&&>
44 { typedef _Tp type; };
45
46
47 /**
48 * @brief Forward an lvalue.
49 * @return The parameter cast to the specified type.
50 *
51 * This function is used to implement "perfect forwarding".
52 */
53 template<typename _Tp>
54 constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type & __t)55 forward(typename std::remove_reference<_Tp>::type& __t) noexcept
56 { return static_cast<_Tp&&>(__t); }
57
58 /**
59 * @brief Forward an rvalue.
60 * @return The parameter cast to the specified type.
61 *
62 * This function is used to implement "perfect forwarding".
63 */
64 template<typename _Tp>
65 constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type && __t)66 forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
67 {
68 return static_cast<_Tp&&>(__t);
69 }
70
71 /**
72 * @brief Convert a value to an rvalue.
73 * @param __t A thing of arbitrary type.
74 * @return The parameter cast to an rvalue-reference to allow moving it.
75 */
76 template<typename _Tp>
77 constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp && __t)78 move(_Tp&& __t) noexcept
79 { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
80
81
82 // Adds a const reference to a non-reference type.
83 template<typename _Tp>
84 struct __add_c_ref
85 { typedef const _Tp& type; };
86
87 template<typename _Tp>
88 struct __add_c_ref<_Tp&>
89 { typedef _Tp& type; };
90
91 template<std::size_t _Idx, typename _Head, bool _IsEmptyNotFinal>
92 struct _Head_base;
93
94
95 template<std::size_t _Idx, typename _Head>
96 struct _Head_base<_Idx, _Head, false>
97 {
_Head_basestd::_Head_base98 constexpr _Head_base()
99 : _M_head_impl() { }
100
_Head_basestd::_Head_base101 constexpr _Head_base(const _Head& __h)
102 : _M_head_impl(__h) { }
103
104 template<typename _UHead, typename = true_type>
_Head_basestd::_Head_base105 constexpr _Head_base(_UHead&& __h)
106 : _M_head_impl(std::forward<_UHead>(__h)) { }
107
108 static constexpr const _Head&
_M_headstd::_Head_base109 _M_head(const _Head_base& __b) noexcept { return __b._M_head_impl; }
110
111 _Head _M_head_impl;
112 };
113
114 template<std::size_t _Idx, typename... _Elements>
115 struct _Tuple_impl;
116
117 template<std::size_t _Idx>
118 struct _Tuple_impl<_Idx>
119 {
120 template<std::size_t, typename...> friend class _Tuple_impl;
121
122 _Tuple_impl() = default;
123 };
124
125 template<typename... _Elements>
126 class tuple;
127
128 template<std::size_t _Idx, typename _Head, typename... _Tail>
129 struct _Tuple_impl<_Idx, _Head, _Tail...>
130 : public _Tuple_impl<_Idx + 1, _Tail...>,
131 private _Head_base<_Idx, _Head, /*__empty_not_final<_Head>::value*/
132 0>
133 {
134 template<std::size_t, typename...> friend class _Tuple_impl;
135
136 typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited;
137 typedef _Head_base<_Idx, _Head, /*__empty_not_final<_Head>::value*/ 0> _Base;
138
139 static constexpr const _Head&
_M_headstd::_Tuple_impl140 _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); }
141
142 static constexpr const _Inherited&
_M_tailstd::_Tuple_impl143 _M_tail(const _Tuple_impl& __t) noexcept { return __t; }
144
145 template<typename _UHead, typename... _UTail, typename = false_type>
146 explicit
_Tuple_implstd::_Tuple_impl147 constexpr _Tuple_impl(_UHead&& __head, _UTail&&... __tail)
148 : _Inherited(std::forward<_UTail>(__tail)...),
149 _Base(std::forward<_UHead>(__head)) { }
150
151 constexpr
_Tuple_implstd::_Tuple_impl152 _Tuple_impl(_Tuple_impl&& __in)
153 noexcept(false)
154 : _Inherited(std::move(_M_tail(__in))),
155 _Base(std::forward<_Head>(_M_head(__in))) { }
156
157 };
158
159 /// Primary class template, tuple
160 template<typename... _Elements>
161 class tuple : public _Tuple_impl<0, _Elements...>
162 {
163 typedef _Tuple_impl<0, _Elements...> _Inherited;
164
165 public:
166 template<typename... _UElements, typename = true_type>
167 explicit
tuple(_UElements &&...__elements)168 constexpr tuple(_UElements&&... __elements)
169 : _Inherited(std::forward<_UElements>(__elements)...) { }
170 };
171
172
173 /// Gives the type of the ith element of a given tuple type.
174 template<std::size_t __i, typename _Tp>
175 struct tuple_element;
176
177 /**
178 * Recursive case for tuple_element: strip off the first element in
179 * the tuple and retrieve the (i-1)th element of the remaining tuple.
180 */
181 template<std::size_t __i, typename _Head, typename... _Tail>
182 struct tuple_element<__i, tuple<_Head, _Tail...> >
183 : tuple_element<__i - 1, tuple<_Tail...> > { };
184
185 /**
186 * Basis case for tuple_element: The first element is the one we're seeking.
187 */
188 template<typename _Head, typename... _Tail>
189 struct tuple_element<0, tuple<_Head, _Tail...> >
190 {
191 typedef _Head type;
192 };
193
194 template<std::size_t __i, typename _Tp>
195 struct tuple_element<__i, const _Tp>
196 {
197 typedef const typename tuple_element<__i, _Tp>::type type;
198 };
199
200
201 template<std::size_t __i, typename _Head, typename... _Tail>
202 constexpr typename __add_c_ref<_Head>::type
__get_helper(const _Tuple_impl<__i,_Head,_Tail...> & __t)203 __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
204 { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); }
205
206 // Return a reference (const reference, rvalue reference) to the ith element
207 // of a tuple. Any const or non-const ref elements are returned with their
208 // original type.
209 template<std::size_t __i, typename... _Elements>
210 constexpr typename __add_c_ref<
211 typename tuple_element<__i, tuple<_Elements...>>::type
212 >::type
get(const tuple<_Elements...> & __t)213 get(const tuple<_Elements...>& __t) noexcept
214 { return __get_helper<__i>(__t); }
215
216
217 template<typename... _Elements>
218 tuple<_Elements&&...>
forward_as_tuple(_Elements &&...__args)219 forward_as_tuple(_Elements&&... __args) noexcept
220 { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
221
222 } // namespace std
223
224
225 using namespace std;
226
227 template <class T>
tpl(T x)228 void tpl(T x) {
229 printf("tpl: &C=%p\n", get<0>(x).C);
230 printf("tpl: C=%s\n", get<0>(x).C);
231 };
232
233 template<typename... _Elements>
234 tuple<_Elements&&...>
my_forward_as_tuple(_Elements &&...__args)235 my_forward_as_tuple(_Elements&&... __args) noexcept
236 { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
237
238
239 namespace {
call(const char * pass,STR && __k)240 void call(const char* pass, STR&& __k) {
241 printf("%s: &rval=%p\n", pass, &__k);
242 printf("%s: &C=%p\n", pass, __k.C);
243 tpl(my_forward_as_tuple(std::move(__k)));
244 }
245 }
246
clang()247 void clang() {
248 call("clang", "a");
249 }
250