[type_traits] Variadic function pointer with __fastcall calling convention
In type_traits/detail/is_function_ptr_tester.hpp there are pointer to function signatures being tested which have the __fastcall calling convention and variadic functions. While MSVC accepts this code clang in Windows, which defines _MSC_VER and _MSC_EXTENSIONS, currently gives an error. The justification for giving an error is that __fastcall is a callee stack cleanup calling convention, so it cannot be used for variadic functions. There is a bug report regarding this in the Bugzilla for llvm at http://llvm.org/bugs/show_bug.cgi?id=12535. Comments have been made to me in e-mail and the clang developer's mailing list that it is a type_traits error to allow this, even for MSVC-emulation code. Of course we can temporarily fix this for clang on Windows, possibly with a BOOST_WORKAROUND solution for clang and see if/how clang eventually addresses the bug report. But I would like some sort of resolution so that clang on Windows can compile type_traits in the current Boost trunk.
I audited VC's
On 10/1/2013 9:40 PM, Stephan T. Lavavej wrote:
I audited VC's
for calling convention madness, and I do not believe that custom calling conventions can be applied to old-style varargs.
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++ ? If so Boost type_traits should not support it AFAICS.
It's been a few months since I looked at this, but VC sometimes looks at a calling convention that shouldn't be there (this is especially true for x64/ARM) and simply pretends that it's an acceptable calling convention.
Understood.
To figure out all of the criteria for calling conventions, I wrote a templated struct, then attempted to specialize it for all known calling conventions, then removed the ones that triggered errors (due to immediate rejections) or duplicates (due to silent rewrites).
Here is my Matrix Of Doom, transcribed as (mostly) English instead of code:
__cdecl - Always. __clrcall - _M_CEE defined. __fastcall - _M_IX86 defined and _M_CEE not defined. __stdcall - _M_IX86 defined. __thiscall - _M_IX86 defined. Member functions only. __vectorcall - VC 2013 or newer. _M_CEE must not be defined. Available for _M_X64. Available for _M_IX86 when _M_IX86_FP is at least 2.
The list is appreciated. But were old-style varargs included in your tests ?
To be resistant to the calling convention switches (/Gd, /Gr, /Gz, /Gv) I always mark specializations for free/member function pointers with a calling convention (__cdecl is always present, at a minimum). The only exception is the old-style variadics, which I do not mark with any explicit calling convention.
It is (quite) possible that there is a bug in my machinery, but so far it seems to be well-behaved in VC 2013 (the only deficiency is that I need to apply it throughout the STL).
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.
STL
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Edward Diener Sent: Tuesday, October 01, 2013 6:09 PM To: boost@lists.boost.org Subject: [boost] [type_traits] Variadic function pointer with __fastcall calling convention
In type_traits/detail/is_function_ptr_tester.hpp there are pointer to function signatures being tested which have the __fastcall calling convention and variadic functions. While MSVC accepts this code clang in Windows, which defines _MSC_VER and _MSC_EXTENSIONS, currently gives an error. The justification for giving an error is that __fastcall is a callee stack cleanup calling convention, so it cannot be used for variadic functions.
There is a bug report regarding this in the Bugzilla for llvm at http://llvm.org/bugs/show_bug.cgi?id=12535.
Comments have been made to me in e-mail and the clang developer's mailing list that it is a type_traits error to allow this, even for MSVC-emulation code. Of course we can temporarily fix this for clang on Windows, possibly with a BOOST_WORKAROUND solution for clang and see if/how clang eventually addresses the bug report. But I would like some sort of resolution so that clang on Windows can compile type_traits in the current Boost trunk.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[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). 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:
C:\Temp>type meow.cpp
#include <iostream>
#include
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.
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. STL
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
using namespace std; int main() { cout << boolalpha; cout << is_same
::value << endl; cout << is_same ::value << endl; cout << is_same ::value << endl; cout << is_same ::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.
[Edward Diener]
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.
I agree with clang's devs (because that's what VC's
What I mean is that in VC++ the declarations are redundant, being the same template redeclared.
Right. So if you want to absorb all old-style varargs, you need only one overload/specialization.
In this case clang either has to change to be like VC++
Oh, I thought clang was attempting to be VC-compatible here (like our copy of EDG for Intellisense does).
If clang is supposed to be VC-compatible, then they should treat varargs with calling conventions like VC does, and Boost should do what VC
On 10/5/2013 4:02 PM, Stephan T. Lavavej wrote:
[Edward Diener]
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.
I agree with clang's devs (because that's what VC's
does).
Thanks for the encouragement. I will quote you when I propose to John Maddock, the main Boost type_traits implementor, that Boost should so the same.
What I mean is that in VC++ the declarations are redundant, being the same template redeclared.
Right. So if you want to absorb all old-style varargs, you need only one overload/specialization.
It looks as if the overload specialization for C++ should specify __cdecl. If this is left out of a function specification, is not the default calling convention user-specified, with __cdecl being the default ? So if the end-user changes the default to something other than __cdecl is that considered the end-user's fault with VC++ ?
In this case clang either has to change to be like VC++
Oh, I thought clang was attempting to be VC-compatible here (like our copy of EDG for Intellisense does).
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible. Of course it is a bit of a tightrope act because 3rd party libraries for Windows which test for VC++ using _MSC_VER and other VC++ macros which clang on Windows supports, may want to be able to use clang to compile the code also.
If clang is supposed to be VC-compatible, then they should treat varargs with calling conventions like VC does, and Boost should do what VC
does (i.e. one overload/specialization with no calling convention - or __cdecl would work, I think).
It seems as if __cdecl is better than no calling convention, because the end-user has the ability to change the default calling convention on VC++.
If clang wants to be different from VC, then Boost should do something different for clang and VC.
I do not work developing clang but I am just trying to compile Boost code with the clang toolset.
If this is left out of a function specification, is not the default calling convention user-specified, with __cdecl being the default ?
Yes for ordinary functions (non-varargs, non-member). Member functions (non-varargs) always default to __thiscall.
So if the end-user changes the default to something other than __cdecl is that considered the end-user's fault with VC++ ?
Our goal for VC's STL is to be immune to all of the calling-convention switches (/Gd, /Gr, /Gz, /Gv). I believe that 2013's
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible.
Well, calling conventions are non-Standard. STL -----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Edward Diener Sent: Sunday, October 06, 2013 4:02 PM To: boost@lists.boost.org Subject: Re: [boost] [type_traits] Variadic function pointer with __fastcall calling convention On 10/5/2013 4:02 PM, Stephan T. Lavavej wrote:
[Edward Diener]
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.
I agree with clang's devs (because that's what VC's
does).
Thanks for the encouragement. I will quote you when I propose to John Maddock, the main Boost type_traits implementor, that Boost should so the same.
What I mean is that in VC++ the declarations are redundant, being the same template redeclared.
Right. So if you want to absorb all old-style varargs, you need only one overload/specialization.
It looks as if the overload specialization for C++ should specify __cdecl. If this is left out of a function specification, is not the default calling convention user-specified, with __cdecl being the default ? So if the end-user changes the default to something other than __cdecl is that considered the end-user's fault with VC++ ?
In this case clang either has to change to be like VC++
Oh, I thought clang was attempting to be VC-compatible here (like our copy of EDG for Intellisense does).
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible. Of course it is a bit of a tightrope act because 3rd party libraries for Windows which test for VC++ using _MSC_VER and other VC++ macros which clang on Windows supports, may want to be able to use clang to compile the code also.
If clang is supposed to be VC-compatible, then they should treat varargs with calling conventions like VC does, and Boost should do what VC
does (i.e. one overload/specialization with no calling convention - or __cdecl would work, I think).
It seems as if __cdecl is better than no calling convention, because the end-user has the ability to change the default calling convention on VC++.
If clang wants to be different from VC, then Boost should do something different for clang and VC.
I do not work developing clang but I am just trying to compile Boost code with the clang toolset. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 10/7/2013 2:05 PM, Stephan T. Lavavej wrote:
If this is left out of a function specification, is not the default calling convention user-specified, with __cdecl being the default ?
Yes for ordinary functions (non-varargs, non-member). Member functions (non-varargs) always default to __thiscall.
So if the end-user changes the default to something other than __cdecl is that considered the end-user's fault with VC++ ?
Our goal for VC's STL is to be immune to all of the calling-convention switches (/Gd, /Gr, /Gz, /Gv). I believe that 2013's
has achieved this (except for /Gv, which we've fixed post-2013-RTM), although I am aware of bugs elsewhere (mostly in <functional>). Because varargs functions (member and non-member) are always __cdecl, regardless of the calling-convention switches, it doesn't matter if you mark them as such, or leave them unmarked.
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible.
Well, calling conventions are non-Standard.
Agreed ! What I think clang should do, when emulating VC++ under Windows, is to do what VC++ does. In the area of calling conventions with varargs clang should accept anything the user specifies and silently treat the calling convention as __cdecl. As I understand your explanation that is what VC++ does. OTOH, when dealing with VC++ and other compilers emulating VC++ by defining _MSC_VER, I am going to suggest that Boost type_traits only present vararg overloads with no calling convention, as there is no need to specify vararg overloads with any calling convention because they all become __cdecl anyway. Thanks very much for your comments and help with how VC++ treats this topic.
STL
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Edward Diener Sent: Sunday, October 06, 2013 4:02 PM To: boost@lists.boost.org Subject: Re: [boost] [type_traits] Variadic function pointer with __fastcall calling convention
On 10/5/2013 4:02 PM, Stephan T. Lavavej wrote:
[Edward Diener]
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.
I agree with clang's devs (because that's what VC's
does). Thanks for the encouragement. I will quote you when I propose to John Maddock, the main Boost type_traits implementor, that Boost should so the same.
What I mean is that in VC++ the declarations are redundant, being the same template redeclared.
Right. So if you want to absorb all old-style varargs, you need only one overload/specialization.
It looks as if the overload specialization for C++ should specify __cdecl. If this is left out of a function specification, is not the default calling convention user-specified, with __cdecl being the default ? So if the end-user changes the default to something other than __cdecl is that considered the end-user's fault with VC++ ?
In this case clang either has to change to be like VC++
Oh, I thought clang was attempting to be VC-compatible here (like our copy of EDG for Intellisense does).
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible. Of course it is a bit of a tightrope act because 3rd party libraries for Windows which test for VC++ using _MSC_VER and other VC++ macros which clang on Windows supports, may want to be able to use clang to compile the code also.
If clang is supposed to be VC-compatible, then they should treat varargs with calling conventions like VC does, and Boost should do what VC
does (i.e. one overload/specialization with no calling convention - or __cdecl would work, I think). It seems as if __cdecl is better than no calling convention, because the end-user has the ability to change the default calling convention on VC++.
If clang wants to be different from VC, then Boost should do something different for clang and VC.
I do not work developing clang but I am just trying to compile Boost code with the clang toolset.
On Mon, 7 Oct 2013, Stephan T. Lavavej wrote:
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible.
Well, calling conventions are non-Standard.
extern "C" is, among other things, a calling convention, so treating other calling conventions the same way could arguably be called "the standard way". Now there are several defects about the handling of extern "C", so it may not be that helpful... -- Marc Glisse
On 10/8/2013 3:59 AM, Marc Glisse wrote:
On Mon, 7 Oct 2013, Stephan T. Lavavej wrote:
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible.
Well, calling conventions are non-Standard.
extern "C" is, among other things, a calling convention, so treating other calling conventions the same way could arguably be called "the standard way". Now there are several defects about the handling of extern "C", so it may not be that helpful...
There is no mention of calling conventions in the C++ standard so specifying extern "C" as one seems a bit of a stretch. Anyway the header files in type_traits/detail which had vararg arguments and VC++ calling conventions do not have to worry about this AFAICS.
On Wed, 9 Oct 2013, Edward Diener wrote:
On 10/8/2013 3:59 AM, Marc Glisse wrote:
On Mon, 7 Oct 2013, Stephan T. Lavavej wrote:
I believe that clang wants to be compatible enough to VC++ on Windows to be able to compile Windows header files, but still wants to follow the C++ standard as closely as possible.
Well, calling conventions are non-Standard.
extern "C" is, among other things, a calling convention, so treating other calling conventions the same way could arguably be called "the standard way". Now there are several defects about the handling of extern "C", so it may not be that helpful...
There is no mention of calling conventions in the C++ standard so specifying extern "C" as one seems a bit of a stretch.
You didn't look closely enough. Language linkage was made part of a function's type precisely to support a different calling convention. [expr.call] Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined (7.5). [dcl.link] Some of the properties associated with an entity with language linkage are specific to each implementation and are not described here. For example, a particular language linkage may be associated with a particular form of representing names of objects and functions with external linkage, or with a particular calling convention, etc. -- Marc Glisse
participants (3)
-
Edward Diener
-
Marc Glisse
-
Stephan T. Lavavej