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

            Bug ID: 95222
           Summary: GCC 10.1 x86 issue with function pointers with calling
                    convention attribute and template specialization
           Product: gcc
           Version: 10.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: raptorfactor at raptorfactor dot com
  Target Milestone: ---

The following code (which is a simplified repro from a much larger function
introspection library) used to work with GCC 9.x, but does not with the update
to 10.1. Is this a compiler/toolchain bug or is there something incorrect about
the code that I'm missing (obviously it's non-standard and relying on the
behavior of vendor extensions)?

>>>>>>>>>>>>>>>

#if defined(_MSC_VER)
#define CC_FASTCALL __fastcall
#define CC_STDCALL __stdcall
#else
#define CC_FASTCALL __attribute__((fastcall))
#define CC_STDCALL __attribute__((stdcall))
#endif

template <typename FuncT>
struct FuncResult;

template <typename R, typename... Args>
struct FuncResult<R(*)(Args...)>
{
    using type = R;
};

template <typename R, typename... Args>
struct FuncResult<R(CC_FASTCALL*)(Args...)>
{
    using type = R;
};

template <typename R, typename... Args>
struct FuncResult<R(CC_STDCALL*)(Args...)>
{
    using type = R;
};

template <typename FuncT>
auto wrap(FuncT f) -> typename FuncResult<FuncT>::type
{
    return f(1, 2, 3);
}

int CC_FASTCALL func1(int x, int y, int z)
{
    return x + y + z;
}

int CC_STDCALL func2(int x, int y, int z)
{
    return x + y + z;
}

int main()
{
    return wrap(&func1) + wrap(&func2);
}

>>>>>>>>>>>>>>>

With the calling convention specific specialization:

>>>>>>>>>>>>>>>

main.cpp:19:8: error: redefinition of 'struct FuncResult<R (*)(Args ...)>'
   19 | struct FuncResult<R(CC_FASTCALL*)(Args...)>
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:13:8: note: previous definition of 'struct FuncResult<R (*)(Args
...)>'
   13 | struct FuncResult<R(*)(Args...)>
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~

>>>>>>>>>>>>>>>

Without the calling convention specific specialization:

>>>>>>>>>>>>>>>

main.cpp:50:23: error: no matching function for call to 'wrap(int
(__attribute__((fastcall)) *)(int, int, int))'
   50 |     return wrap(&func1) + wrap(&func2);
      |                       ^
main.cpp:33:6: note: candidate: 'template<class FuncT> typename
FuncResult<FuncT>::type wrap(FuncT)'
   33 | auto wrap(FuncT f) -> typename FuncResult<FuncT>::type
      |      ^~~~
main.cpp:33:6: note:   template argument deduction/substitution failed:
main.cpp: In substitution of 'template<class FuncT> typename
FuncResult<FuncT>::type wrap(FuncT) [with FuncT = int
(__attribute__((fastcall)) *)(int, int, int)]':
main.cpp:50:23:   required from here
main.cpp:33:6: error: invalid use of incomplete type 'struct FuncResult<int
(__attribute__((fastcall)) *)(int, int, int)>'
main.cpp:10:8: note: declaration of 'struct FuncResult<int
(__attribute__((fastcall)) *)(int, int, int)>'
   10 | struct FuncResult;
      |        ^~~~~~~~~~

>>>>>>>>>>>>>>>

Damned if you do, damned if you don't. Is anyone aware of a workaround for
this? It's blocking my build and I can't figure out an easy workaround.

Thanks.

Reply via email to