1 /* { dg-do compile } */
2 /* { dg-options "-O2 -std=gnu++14 -fdump-tree-sra" } */
3 
4 #include <utility>
5 
6 #define EGGS_CXX11_CONSTEXPR constexpr
7 #define EGGS_CXX11_STATIC_CONSTEXPR static constexpr
8 #define EGGS_CXX14_CONSTEXPR constexpr
9 #define EGGS_CXX11_NOEXCEPT noexcept
10 
11 namespace eggs { namespace variants { namespace detail
12 {
13     struct empty
14     {
15         EGGS_CXX11_CONSTEXPR bool operator==(empty) const { return true; }
16         EGGS_CXX11_CONSTEXPR bool operator<(empty) const { return false; }
17     };
18 
19     template <typename T>
20     struct identity
21     {
22         using type = T;
23     };
24 
25     template <std::size_t I>
26     struct index
27     {
28         EGGS_CXX11_STATIC_CONSTEXPR std::size_t value = I;
29     };
30 
31     template <typename ...Ts>
32     struct pack
33     {
34         using type = pack;
35         EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Ts);
36     };
37 
38     template <typename T, T ...Vs>
39     struct pack_c
40     {
41         using type = pack_c;
42         EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Vs);
43     };
44 
45     ///////////////////////////////////////////////////////////////////////////
46     template <typename Is, bool Odd>
47     struct _make_index_pack_twice;
48 
49     template <std::size_t ...Is>
50     struct _make_index_pack_twice<
51         pack_c<std::size_t, Is...>
52       , false
53     > : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)...>
54     {};
55 
56     template <std::size_t ...Is>
57     struct _make_index_pack_twice<
58         pack_c<std::size_t, Is...>
59       , true
60     > : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)..., sizeof...(Is) * 2>
61     {};
62 
63     template <std::size_t N>
64     struct _make_index_pack
65       : _make_index_pack_twice<
66             typename _make_index_pack<N / 2>::type
67           , N % 2 != 0
68         >
69     {};
70 
71     template <>
72     struct _make_index_pack<1>
73       : pack_c<std::size_t, 0>
74     {};
75 
76     template <>
77     struct _make_index_pack<0>
78       : pack_c<std::size_t>
79     {};
80 
81     template <std::size_t N>
82     using make_index_pack = typename _make_index_pack<N>::type;
83 
84     template <typename Ts>
85     struct _index_pack;
86 
87     template <typename ...Ts>
88     struct _index_pack<pack<Ts...>>
89       : _make_index_pack<sizeof...(Ts)>
90     {};
91 
92     template <typename Ts>
93     using index_pack = typename _index_pack<Ts>::type;
94 
95     ///////////////////////////////////////////////////////////////////////////
96     template <typename Vs>
97     struct all_of;
98 
99     template <bool ...Vs>
100     struct all_of<pack_c<bool, Vs...>>
101       : std::integral_constant<
102             bool
103           , std::is_same<
104                 pack_c<bool, Vs...>
105               , pack_c<bool, (Vs || true)...> // true...
106             >::value
107         >
108     {};
109 
110     template <typename ...Ts>
111     struct all_of<pack<Ts...>>
112       : all_of<pack_c<bool, (Ts::value)...>>
113     {};
114 
115     template <typename ...Vs>
116     struct any_of;
117 
118     template <bool ...Vs>
119     struct any_of<pack_c<bool, Vs...>>
120       : std::integral_constant<
121             bool
122           , !all_of<pack_c<bool, !Vs...>>::value
123         >
124     {};
125 
126     template <typename ...Ts>
127     struct any_of<pack<Ts...>>
128       : any_of<pack_c<bool, (Ts::value)...>>
129     {};
130 
131     ///////////////////////////////////////////////////////////////////////////
132     template <std::size_t I, typename T>
133     struct _indexed {};
134 
135     template <typename Ts, typename Is = index_pack<Ts>>
136     struct _indexer;
137 
138     template <typename ...Ts, std::size_t ...Is>
139     struct _indexer<pack<Ts...>, pack_c<std::size_t, Is...>>
140       : _indexed<Is, Ts>...
141     {};
142 
143     empty _at_index(...);
144 
145     template <std::size_t I, typename T>
146     identity<T> _at_index(_indexed<I, T> const&);
147 
148     template <std::size_t I, typename Ts>
149     struct at_index
150       : decltype(_at_index<I>(_indexer<Ts>{}))
151     {};
152 
153     empty _index_of(...);
154 
155     template <typename T, std::size_t I>
156     index<I> _index_of(_indexed<I, T> const&);
157 
158     template <typename T, typename Ts>
159     struct index_of
160       : decltype(_index_of<T>(_indexer<Ts>{}))
161     {};
162 }}}
163 
164 namespace eggs { namespace variants { namespace detail
165 {
166     template <typename Ts, bool IsTriviallyDestructible>
167     struct _union;
168 
169     ///////////////////////////////////////////////////////////////////////////
170     template <bool IsTriviallyDestructible>
171     struct _union<pack<>, IsTriviallyDestructible>
172     {};
173 
174     template <typename T, typename ...Ts>
175     struct _union<pack<T, Ts...>, true>
176     {
177         EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = 1 + sizeof...(Ts);
178 
179         template <typename ...Args>
180         EGGS_CXX11_CONSTEXPR _union(index<0>, Args&&... args)
181           : _head(std::forward<Args>(args)...)
182         {}
183 
184         template <std::size_t I, typename ...Args>
185         EGGS_CXX11_CONSTEXPR _union(index<I>, Args&&... args)
186           : _tail(index<I - 1>{}, std::forward<Args>(args)...)
187         {}
188 
189         EGGS_CXX14_CONSTEXPR void* target() EGGS_CXX11_NOEXCEPT
190         {
191             return &_target;
192         }
193 
194         EGGS_CXX11_CONSTEXPR void const* target() const EGGS_CXX11_NOEXCEPT
195         {
196             return &_target;
197         }
198 
199         EGGS_CXX14_CONSTEXPR T& get(index<0>) EGGS_CXX11_NOEXCEPT
200         {
201             return this->_head;
202         }
203 
204         EGGS_CXX11_CONSTEXPR T const& get(index<0>) const EGGS_CXX11_NOEXCEPT
205         {
206             return this->_head;
207         }
208 
209         template <
210             std::size_t I
211           , typename U = typename at_index<I, pack<T, Ts...>>::type
212         >
213         EGGS_CXX14_CONSTEXPR U& get(index<I>) EGGS_CXX11_NOEXCEPT
214         {
215             return this->_tail.get(index<I - 1>{});
216         }
217 
218         template <
219             std::size_t I
220           , typename U = typename at_index<I, pack<T, Ts...>>::type
221         >
222         EGGS_CXX11_CONSTEXPR U const& get(index<I>) const EGGS_CXX11_NOEXCEPT
223         {
224             return this->_tail.get(index<I - 1>{});
225         }
226 
227     private:
228         union
229         {
230             char _target;
231             T _head;
232             _union<pack<Ts...>, true> _tail;
233         };
234     };
235 
236     ///////////////////////////////////////////////////////////////////////////
237     template <typename Ts, bool TriviallyCopyable, bool TriviallyDestructible>
238     struct _storage;
239 
240     template <typename ...Ts>
241     struct _storage<pack<Ts...>, true, true>
242       : _union<
243             pack<Ts...>
244           , all_of<pack<std::is_trivially_destructible<Ts>...>>::value
245         >
246     {
247         using base_type = _union<
248             pack<Ts...>
249           , all_of<pack<std::is_trivially_destructible<Ts>...>>::value
250         >;
251 
252         EGGS_CXX11_CONSTEXPR _storage() EGGS_CXX11_NOEXCEPT
253           : base_type{index<0>{}}
254           , _which{0}
255         {}
256 
257         _storage(_storage const& rhs) = default;
258         _storage(_storage&& rhs) = default;
259 
260         template <std::size_t I, typename ...Args>
261         EGGS_CXX11_CONSTEXPR _storage(index<I> which, Args&&... args)
262           : base_type{which, std::forward<Args>(args)...}
263           , _which{I}
264         {}
265 
266         _storage& operator=(_storage const& rhs) = default;
267         _storage& operator=(_storage&& rhs) = default;
268 
269         EGGS_CXX11_CONSTEXPR std::size_t which() const
270         {
271             return _which;
272         }
273 
274         using base_type::target;
275         using base_type::get;
276 
277     protected:
278         std::size_t _which;
279     };
280 
281     template <typename ...Ts>
282     using storage = _storage<
283         pack<empty, Ts...>
284       , all_of<pack<std::is_trivially_copyable<Ts>...>>::value
285       , all_of<pack<std::is_trivially_destructible<Ts>...>>::value
286     >;
287 }}}
288 
289 namespace eggs { namespace variants
290 {
291     template <typename ...Ts>
292     class variant;
293 
294     namespace detail
295     {
296         ///////////////////////////////////////////////////////////////////////
297         namespace _best_match
298         {
299             template <typename Ts, std::size_t I = 0>
300             struct overloads
301             {};
302 
303             template <typename T, typename ...Ts, std::size_t I>
304             struct overloads<pack<T, Ts...>, I>
305               : overloads<pack<Ts...>, I + 1>
306             {
307                 using fun_ptr = index<I>(*)(T);
308                 operator fun_ptr();
309             };
310 
311             template <typename F, typename T>
312             auto _invoke(F&&, T&&)
313              -> decltype(std::declval<F>()(std::declval<T>()));
314 
315             struct _fallback {};
316 
317             _fallback _invoke(...);
318 
319             template <
320                 typename T, typename U
321               , typename R = decltype(_best_match::_invoke(
322                     std::declval<T>(), std::declval<U>()))
323             >
324             struct result_of : R
325             {};
326 
327             template <typename T, typename U>
328             struct result_of<T, U, _fallback>
329             {};
330         }
331 
332         template <typename U, typename ...Ts>
333         struct index_of_best_match
334           : _best_match::result_of<_best_match::overloads<Ts...>, U>
335         {};
336 
337     }
338 
339     template <typename ...Ts>
340     class variant
341     {
342 
343     public:
344         EGGS_CXX11_CONSTEXPR variant() EGGS_CXX11_NOEXCEPT = delete;
345 
346         variant(variant const& rhs) = default;
347 
348         variant(variant&& rhs) = default;
349 
350         template <
351             typename U
352           , typename Enable = typename std::enable_if<!std::is_same<
353                 typename std::decay<U>::type, variant
354             >::value>::type
355           , std::size_t I = detail::index_of_best_match<
356                 U&&, detail::pack<Ts...>>::value
357           , typename T = typename detail::at_index<
358                 I, detail::pack<Ts...>>::type
359         >
360         EGGS_CXX11_CONSTEXPR variant(U&& v)
361             noexcept(
362                 std::is_nothrow_constructible<T, U&&>::value)
363           : _storage{detail::index<I + 1>{}, std::forward<U>(v)}
364         {}
365 
366         ~variant() = default;
367         variant& operator=(variant const& rhs) = delete;
368 
369     private:
370         detail::storage<Ts...> _storage;
371     };
372 }}
373 
374 template <class T, class Base>
375 struct ref_proxy : Base
376 {
377     using Base::Base;
378 
379     ref_proxy()
380         : Base()
381     {
382     }
383 
384     ref_proxy(Base ptr)
385         : Base(std::move(ptr))
386     {
387     }
388 };
389 
390 template <class T>
391 struct inplace_ref
392 {
393     explicit inplace_ref(T inner)
394         : inner_(inner)
395     {
396     }
397 
398     T inner_;
399 };
400 
401 template <class ...Variants>
402 struct variant_ref
403 {
404     variant_ref() = delete;
405 
406     explicit variant_ref(eggs::variants::variant<Variants...> t)
407         : inner_storage_(t)
408     {
409     }
410 
411     template <class Source>
412     variant_ref(ref_proxy<Source, variant_ref> ptr)
413         : inner_storage_(ptr.inner_storage_)
414     {}
415 
416 private:
417     eggs::variants::variant<Variants...> inner_storage_;
418 };
419 
420 struct option_1
421 {
422     void *a, *b, *c, *d, *e;
423 };
424 
425 struct option_2
426 {
427 };
428 
429 using option_ref = variant_ref<option_1, option_2>;
430 
431 
432 struct qual_option
433 {
434     qual_option(ref_proxy<void, option_ref > type, int quals)
435         : type_(type)
436         , quals_(quals)
437     {
438     }
439 
440     explicit qual_option(ref_proxy<void, option_ref > type)
441         : qual_option(type, 0)
442     {
443     }
444 
445     ref_proxy<void, option_ref > type_;
446     int quals_;
447 };
448 
449 inline ref_proxy<option_2, option_ref > make_object_1()
450 {
451     return ref_proxy<option_2, option_ref >(option_2());
452 }
453 
454 inline ref_proxy<option_2, option_ref > make_object_2()
455 {
456     return make_object_1();
457 }
458 
459 inline inplace_ref<qual_option> make_object_3(ref_proxy<option_2, option_ref>&& a0)
460 {
461     return inplace_ref<qual_option>(qual_option(a0));
462 }
463 
464 inline ref_proxy<qual_option, inplace_ref<qual_option> > make_object_4(ref_proxy<option_2, option_ref>&& a0)
465 {
466     return make_object_3(std::move(a0));
467 }
468 
469 
470 ref_proxy<qual_option, inplace_ref<qual_option> > f() __attribute__((noinline));
471 
472 ref_proxy<qual_option, inplace_ref<qual_option> > f()
473 {
474     return make_object_4(make_object_2());
475 }
476 
477 int main(int argc, char* argv[])
478 {
479     for (;;)
480         f();
481 }
482 
483 /* { dg-final { scan-tree-dump "Removing load:.*ptr;" "sra" } } */
484