Boost logo

Boost :

Subject: Re: [boost] [type_traits] Variadic function pointer with __fastcall calling convention
From: Edward Diener (eldiener_at_[hidden])
Date: 2013-10-05 10:22:36


On 10/2/2013 2:28 PM, Stephan T. Lavavej wrote:
> [Edward Diener]
>> Nonetheless VC++ ( 8, 9, 10, and 11 ) does not produce a compiler error
>> when a __stdcall or __fastcall calling convention is used in a pointer
>> to function taking old-style varags. Do you see this as an ongoing bug
>> in VC++ ?
>
> According to my understanding, it's a "feature", not a bug (but also not a feature).

The problem from clang's perspective is that they must emulate this
"feature" <g> to compile Boost type_traits. Their developers feel that
Boost type_traits should not depend on this feature, ie. should not
specify any VC++ calling conventions for varargs function or function
template declarations.

>
> This is vaguely similar to how C++ immediately rewrites array parameters in functions to pointer parameters (and function parameters to function pointer parameters, and drops const on value parameters as far as outside callers are concerned). Different syntax results in the same type being emitted.
>
>> If so Boost type_traits should not support it AFAICS.
>
> There is nothing to support, because the types are identical as far as templates are concerned:

What I mean is that in VC++ the declarations are redundant, being the
same template redeclared. In type_traits is_function_ptr_tester.hpp the
lines:

  template <class R >
  yes_type is_function_ptr_tester(R (__stdcall*)( ...));

  template <class R >
  yes_type is_function_ptr_tester(R (__fastcall*)( ...));

  template <class R >
  yes_type is_function_ptr_tester(R (__cdecl*)( ...));

are just redeclaring the same function template, whereas

  template <class R >
  yes_type is_function_ptr_tester(R (__stdcall*)());

  template <class R >
  yes_type is_function_ptr_tester(R (__fastcall*)());

  template <class R >
  yes_type is_function_ptr_tester(R (__cdecl*)());

are different function templates.

>
> C:\Temp>type meow.cpp
> #include <iostream>
> #include <type_traits>
> using namespace std;
>
> int main() {
> cout << boolalpha;
> cout << is_same<void (*)(int, ...), void (*)(int, ...)>::value << endl;
> cout << is_same<void (*)(int, ...), void (__cdecl *)(int, ...)>::value << endl;
> cout << is_same<void (*)(int, ...), void (__stdcall *)(int, ...)>::value << endl;
> cout << is_same<void (*)(int, ...), void (__fastcall *)(int, ...)>::value << endl;
> }
>
> C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
> meow.cpp
>
> C:\Temp>meow
> true
> true
> true
> true
>
>> The list is appreciated. But were old-style varargs included in your tests ?
>
> Yes. As I noted, they are an exception - when I specialize our type traits for old-style varargs, I don't apply any explicit calling convention, because I was unable to find anything that made the types physically different.

Understood.

>
>> I have not tried VC in VS2013, but the matter should be cleared up so
>> that VC++ at least does not at accept the __fastcall calling convention
>> with old-style varags if what you say in the first line of your reply is
>> true.
>
> This is not the only place where VC looks at a calling convention and decides to silently rewrite it. As I recall, VC does this for non-vararg functions on x64 too (I would have to dig up my notes to find the exact examples).
>
> From a library author perspective, this rewriting doesn't matter. You just want to be able to provide a set of specializations such that users (potentially saying calling conventions that get rewritten) always activate one of your specializations.
>
> I believe I have achieved this in VC 2013 - std::is_function and std::is_member_function_pointer should always return true regardless of the user-written calling convention (with the exception of __vectorcall; I have fixed that for post-2013-RTM). Boost can achieve the exact same thing.

Thanks for the information. Boost is more complicated than just VC++. It
has to support other compilers, even with VC++ calling conventions.

In this case clang either has to change to be like VC++ and treat all
calling conventions with varargs functions and function templates as if
no calling convention existed or Boost type_traits should change and
eliminate the redundant function templates in is_function_ptr_tester.hpp
when varargs declarations are specified.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk