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