https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87205

--- Comment #9 from Peter Dimov <pdimov at gmail dot com> ---
For more context, see https://godbolt.org/z/SzfpKr

```
#include <type_traits>

template<class... T> struct variant
{
    std::aligned_union_t<0, T...> storage_;
    unsigned index_;
};

template<class T0, class T1, class T2, class T3, class T4, class T5, class F>
auto visit( variant<T0, T1, T2, T3, T4, T5>& v, F f )
{
    switch( v.index_ )
    {
        case 0: return f( (T0&)v.storage_ );
        case 1: return f( (T1&)v.storage_ );
        case 2: return f( (T2&)v.storage_ );
        case 3: return f( (T3&)v.storage_ );
        case 4: return f( (T4&)v.storage_ );
        case 5: return f( (T5&)v.storage_ );
        default: __builtin_unreachable();
    }
}

struct X
{
    int v;
};

template<int I> struct Y: X
{
};

using V = variant<Y<0>, Y<1>, Y<2>, Y<3>, Y<4>, Y<5>>;

void f( X& );
int g( int );

int h1( V& v )
{
    return visit( v, [](X const& x){ return x.v; } );
}

int h2( V& v )
{
    return visit( v, [](auto&& x){ return x.v; } );
}

void h3( V& v )
{
    return visit( v, [](auto&& x){ f(x); } );
}

int h4( V& v )
{
    return visit( v, [](auto&& x){ return g(x.v); } );
}
```

This generates

```
h1(variant<Y<0>, Y<1>, Y<2>, Y<3>, Y<4>, Y<5> >&):
  mov eax, DWORD PTR [rdi]
  ret
h2(variant<Y<0>, Y<1>, Y<2>, Y<3>, Y<4>, Y<5> >&):
  mov eax, DWORD PTR [rdi]
  ret
h3(variant<Y<0>, Y<1>, Y<2>, Y<3>, Y<4>, Y<5> >&):
  cmp DWORD PTR [rdi+4], 5
  jbe .L15
.L15:
  jmp f(X&)
h4(variant<Y<0>, Y<1>, Y<2>, Y<3>, Y<4>, Y<5> >&):
  cmp DWORD PTR [rdi+4], 5
  jbe .L19
.L19:
  mov edi, DWORD PTR [rdi]
  jmp g(int)
```

so the member access is folded in both cases (which is good!), even though the
first occurs through X& and the second through Y<I>&.

I've been unable to determine what makes the optimizations misfire. This code
should in principle be the same as the simplified one, but it isn't.

Reply via email to