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

            Bug ID: 91606
           Summary: [9 regression] Optimization leads to invalid code
           Product: gcc
           Version: 9.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: m.cencora at gmail dot com
  Target Milestone: ---

Following code is miscompiled in C++14 mode and -O2 optimization level.

This works fine when compiled:
 - in C++17 mode, or lower optimization level
 - on previous gcc version (8.3)
 - on clang

I've verified with sanitizers/valgrind that this code is correct and does not
contain undefined behavior.

#include <array>
#include <type_traits>

template <typename T1, typename T2>
struct variant
{
   constexpr variant(T1 arg)
     : f1(arg),
       index(0)
   {}

   constexpr variant(T2 arg)
     : f2(arg),
       index(1)
   {}

   union
   {
      T1 f1;
      T2 f2;
   };
   std::size_t index = 0;
};

template <typename T1, typename T2>
constexpr const T1* get_if(const variant<T1, T2>* v)
{
   if (v->index != 0)
   {
      return nullptr;
   }
   return &v->f1;
}

template <typename T2, typename T1>
constexpr const T2* get_if(const variant<T1, T2>* v)
{
   if (v->index != 1)
   {
      return nullptr;
   }
   return &v->f2;
}


template <typename T, size_t N>
struct my_array
{
   constexpr const T* begin() const
   {
      return data;
   }

   constexpr const T* end() const
   {
      return data + N;
   }

   T data[N];
};

template <typename ...Ts>
constexpr auto get_array_of_variants(Ts ...ptrs)
{
   return std::array<variant<std::decay_t<Ts>...>, sizeof...(Ts)>{ ptrs... };
}





template <typename T>
constexpr auto get_member_functions();

template <typename Member, typename Class>
constexpr int getFuncId(Member (Class::*memFuncPtr))
{
    int idx = 0u;
    for (auto &anyFunc : get_member_functions<Class>())
    {
       if (auto *specificFunc = get_if<Member (Class::*)>(&anyFunc))
       {
          if (*specificFunc == memFuncPtr)
          {
             return idx;
          }
       }
       ++idx;
    }
    std::abort();
}



struct MyStruct
{
   void fun1(int /*a*/) {}

   int fun2(char /*b*/, short /*c*/, bool /*d*/) { return 0; }

};



template <>
constexpr auto get_member_functions<MyStruct>()
{
   return get_array_of_variants(&MyStruct::fun1, &MyStruct::fun2);
}


int main()
{
//     static_assert(getFuncId(&foo::MyStruct::fun1) == 0, "");
    return getFuncId(&MyStruct::fun1);
}

Following code changes fixes it:
 - changing std::array to my_array
 - changing:
 for (auto &anyFunc : get_member_functions<Class>())
into
 for (auto anyFunc : get_member_functions<Class>())

Reply via email to