clang for Windows problem in Boost.TypeTraits

In Boost.TypeTraits this header file line:

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

gets an error message from clang in Windows of:

..\..\..\boost/type_traits/detail/is_function_ptr_tester.hpp:52:36: error: variadic function cannot use fastcall calling convention

I could not find anything in the C++11 standard about variadic functions and calling conventions. Is this a "bug" with clang under Windows or should Boost.TypeTraits not try to allow __fastcall in this situation when compiling with clang under Windows ?

This occurs in this place in Boost.TypeTraits with clang in Windows because _MSC_VER is defined and the code is acceptable with VC++.

Edward Diener <eldlistmailingz@tropicsoft.com>
writes:

In Boost.TypeTraits this header file line:

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

gets an error message from clang in Windows of:

..\..\..\boost/type_traits/detail/is_function_ptr_tester.hpp:52:36:
error: variadic function cannot use fastcall calling convention

I could not find anything in the C++11 standard about variadic
functions and calling conventions. Is this a "bug" with clang under
Windows or should Boost.TypeTraits not try to allow __fastcall in this
situation when compiling with clang under Windows ?

This occurs in this place in Boost.TypeTraits with clang in Windows
because _MSC_VER is defined and the code is acceptable with VC++.

Some calling conventions are hardly usable with variable number of
arguments. __fastcall, for instance requires that the called function
clears the stack, which poses obvious difficulties. I doubt that VC++
supports the necessary wizardly for *helping* the *programmer* to
properly do that. (Actually, the user would need to implement its own
calling convention on top of __fastcall and then use some compiler
intrinsics for accessing the parameters and cleaning up the stack.)

OTOH it is possible that the the function is never called or even that
no such function exists at all (a device on template metaprogramming,
for instance.)

So, IMO, VC++ might be too lax here while Clang++ is too strict. If
Clang++ is rejecting code that just declares a __fastcall variadic
function and such declaration is useful, I'll file a bug report.

Edward Diener <eldlistmailingz@tropicsoft.com>
writes:

In Boost.TypeTraits this header file line:

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

gets an error message from clang in Windows of:

..\..\..\boost/type_traits/detail/is_function_ptr_tester.hpp:52:36:
error: variadic function cannot use fastcall calling convention

I could not find anything in the C++11 standard about variadic
functions and calling conventions. Is this a "bug" with clang under
Windows or should Boost.TypeTraits not try to allow __fastcall in this
situation when compiling with clang under Windows ?

This occurs in this place in Boost.TypeTraits with clang in Windows
because _MSC_VER is defined and the code is acceptable with VC++.

Some calling conventions are hardly usable with variable number of
arguments. __fastcall, for instance requires that the called function
clears the stack, which poses obvious difficulties. I doubt that VC++
supports the necessary wizardly for *helping* the *programmer* to
properly do that. (Actually, the user would need to implement its own
calling convention on top of __fastcall and then use some compiler
intrinsics for accessing the parameters and cleaning up the stack.)

OTOH it is possible that the the function is never called or even that
no such function exists at all (a device on template metaprogramming,
for instance.)

The declaration is being used in template metaprogramming so it is being invoked at compile time to test whether some compile-time expression is a function pointer. It is being implemented for clang, as well VC++ compatible compilers on Windows, because _MSC_EXTENSIONS is defined in the clang implementation for Windows.

So, IMO, VC++ might be too lax here while Clang++ is too strict. If
Clang++ is rejecting code that just declares a __fastcall variadic
function and such declaration is useful, I'll file a bug report.

I can file the bug report as long as it has been ascertained as a clang bug. OTOH if you're filing the bug report might have more weight in getting it fixed, please go ahead and do so.

I am working to get clang in Windows to be able to compile Boost headers using the Boost Build clang toolset. So you may be hearing from me on this mailing list with further issues.

Thanks for your help.

Edward Diener <eldlistmailingz@tropicsoft.com>
writes:

So, IMO, VC++ might be too lax here while Clang++ is too strict. If
Clang++ is rejecting code that just declares a __fastcall variadic
function and such declaration is useful, I'll file a bug report.

I can file the bug report as long as it has been ascertained as a
clang bug. OTOH if you're filing the bug report might have more weight
in getting it fixed, please go ahead and do so.

Nobody will slap you in the wrist for filing a bug report that ends
closed as INVALID :slight_smile: Right now, possibly you are the individual with
more knowledge about this issue on the whole Clang community, so you
will need to explain how and where this issue was discovered, and why
changing Clang handling of that code would be helpful for the Boost
library writers. With all that information the developers will judge if
a change makes sense and is feasible. So please go ahead and file the
bug report if you wish to see the problem fixed.

I am working to get clang in Windows to be able to compile Boost
headers using the Boost Build clang toolset. So you may be hearing
from me on this mailing list with further issues.

Good. And please don't hesitate about filing bugs when you think that
doing so *might* be appropiate. No need to be 100% sure.

And please note that suggesting improvements is another use of the bug
database.

Thanks for your help.

You're welcome.

I think it's a defect in both. Boost should drop the overloaded vararg is_function_ptr_tester specializations with non-standard calling conventions as they are never used. When MSVC encounters a vararg function with stdcall/fastcall it silently converts it to cdecl. Though for compatibility with (broken) MSVC code Clang should match that behavior if desired.

-Nico

I could not find anything in the C++11 standard about variadic functions
and calling conventions. Is this a "bug" with clang under Windows or
should Boost.TypeTraits not try to allow __fastcall in this situation
when compiling with clang under Windows ?

I think it's a defect in both. Boost should drop the overloaded vararg
is_function_ptr_tester specializations with non-standard calling
conventions as they are never used. When MSVC encounters a vararg
function with stdcall/fastcall it silently converts it to cdecl.

is there a way to test that this is what it actually does ?

Though
for compatibility with (broken) MSVC code Clang should match that
behavior if desired.

The issue is that MSVC will accept the declaration without a compiler error as part of its extensions no matter what it may silently do. So if clang in Windows also defines the _MSC_EXTENSIONS macro it should ideally emulate MSVC in that regard.

I will however mention in the Boost developers forum that it might be good to drop the overloaded vararg specializations with non-standard calling conventions for MSVC. Or Boost could decide to test for clang and not allow it when using clang.

I could not find anything in the C++11 standard about variadic functions
and calling conventions. Is this a "bug" with clang under Windows or
should Boost.TypeTraits not try to allow __fastcall in this situation
when compiling with clang under Windows ?

I think it's a defect in both. Boost should drop the overloaded vararg
is_function_ptr_tester specializations with non-standard calling
conventions as they are never used. When MSVC encounters a vararg
function with stdcall/fastcall it silently converts it to cdecl.

is there a way to test that this is what it actually does ?

First, compiling the code "void __fastcall foo() { }" produces the
symbol ?foo@@YAXZZ which demangles to 'void __cdecl foo(...)'.

Second, you can call it and verify that the assembly is adhering to the
usual C calling convention.

Though

for compatibility with (broken) MSVC code Clang should match that
behavior if desired.

The issue is that MSVC will accept the declaration without a compiler
error as part of its extensions no matter what it may silently do. So if
clang in Windows also defines the _MSC_EXTENSIONS macro it should ideally
emulate MSVC in that regard.

I agree, this is a reasonable expectation, but I would classify this bug as
low priority, since variadic fastcall doesn't make sense.

I will however mention in the Boost developers forum that it might be good
to drop the overloaded vararg specializations with non-standard calling
conventions for MSVC. Or Boost could decide to test for clang and not allow
it when using clang.

Boost probably should drop this specialization. It's actually declaring
the __cdecl specialization after the implicit adjustment. When I attempt
to define a specialization for both 'R (__fastcall *)(...)' and 'R (__cdecl
*)(...)' in the same TU, I get a compiler error from MSVC:
t.cpp(7) : error C2995: 'void is_function_template(R (__cdecl *)(...))' :
function template has already been defined
        t.cpp(5) : see declaration of 'is_function_template'

extern "C" int printf(const char *fmt, ...);
template <typename T>
void is_function_template(T t) { printf("no\n"); }
template <typename R>
void is_function_template(R (__cdecl *fptr)(...)) { printf("cdecl\n"); }
template <typename R>
void is_function_template(R (__fastcall *fptr)(...)) {
printf("fastcall\n"); }

            I could not find anything in the C++11 standard about
            variadic functions
            and calling conventions. Is this a "bug" with clang under
            Windows or
            should Boost.TypeTraits not try to allow __fastcall in this
            situation
            when compiling with clang under Windows ?

        I think it's a defect in both. Boost should drop the overloaded
        vararg
        is_function_ptr_tester specializations with non-standard calling
        conventions as they are never used. When MSVC encounters a vararg
        function with stdcall/fastcall it silently converts it to cdecl.

    is there a way to test that this is what it actually does ?

First, compiling the code "void __fastcall foo() { }" produces the
symbol ?foo@@YAXZZ which demangles to 'void __cdecl foo(...)'.

Second, you can call it and verify that the assembly is adhering to the
usual C calling convention.

Understood.

        Though
        for compatibility with (broken) MSVC code Clang should match that
        behavior if desired.

    The issue is that MSVC will accept the declaration without a
    compiler error as part of its extensions no matter what it may
    silently do. So if clang in Windows also defines the _MSC_EXTENSIONS
    macro it should ideally emulate MSVC in that regard.

I agree, this is a reasonable expectation, but I would classify this bug
as low priority, since variadic fastcall doesn't make sense.

I have brought this last point up in the Boost developers forum.

    I will however mention in the Boost developers forum that it might
    be good to drop the overloaded vararg specializations with
    non-standard calling conventions for MSVC. Or Boost could decide to
    test for clang and not allow it when using clang.

Boost probably should drop this specialization. It's actually declaring
the __cdecl specialization after the implicit adjustment. When I
attempt to define a specialization for both 'R (__fastcall *)(...)' and
'R (__cdecl *)(...)' in the same TU, I get a compiler error from MSVC:
t.cpp(7) : error C2995: 'void is_function_template(R (__cdecl *)(...))'
: function template has already been defined
         t.cpp(5) : see declaration of 'is_function_template'

extern "C" int printf(const char *fmt, ...);
template <typename T>
void is_function_template(T t) { printf("no\n"); }
template <typename R>
void is_function_template(R (__cdecl *fptr)(...)) { printf("cdecl\n"); }
template <typename R>
void is_function_template(R (__fastcall *fptr)(...)) {
printf("fastcall\n"); }

Yet just the declarations in the Boost header file does not give an MSVC compiler error:

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

in the same TU. But I will bring up in the Boost forum that actually trying to define separate implementations in the same TU with those signatures does generate an MSVC error.

I did some research on pointers to __fastcall variadic functions. Type
declaration of such pointer is accepted by MSVS, but it means a pointer to
__cdecl function.

In other words:
void (*fp)(...)
is the same as
void (__fastcall*fp)(...)
and
void (__stdcall*fp)(...)

You can even write:

void __stdcall test(...) {}typedef void (__fastcall*fp)(...);fp f = &test;

One more proof:

void (__fastcall*f)(...) = 1;

produces error: cannot convert from 'int' to 'void (__cdecl *)(...)'.

I believe this template specialization really make no sense.

As far as clang is considered, it does not accept pointers to __fastcall
variadic function but accepts pointers for __stdcall variadic function.
Such template specialization exists in the same Boost file.

I've filed http://llvm.org/bugs/show_bug.cgi?id=17464 to track this.

- Hans

Wait a minute, this header is included only if
BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION macro is defined. It is probably
some old lack of template specialization workaround. It does not compile in
VS either.

For the record, Microsoft documents this behavior.

__vectorcall, __thiscall,__stdcall all degrade to __cdecl. See:
http://msdn.microsoft.com/en-us/library/zxk0tw93(v=vs.120).aspx
http://msdn.microsoft.com/en-us/library/ek8tkfbw(v=vs.120).aspx
http://msdn.microsoft.com/en-us/library/dn375768(v=vs.120).aspx

    In Boost.TypeTraits this header file line:

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

    gets an error message from clang in Windows of:

    ..\..\..\boost/type_traits/__detail/is_function_ptr_tester.__hpp:52:36:
    error: variadic function cannot use fastcall calling convention

Wait a minute, this header is included only if
BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION macro is defined.

That is incorrect. It is included by is_function.hpp whenever _MSC_EXTENSIONS is defined, as it is for clang under Windows.

It is
probably some old lack of template specialization workaround. It does
not compile in VS either.

It compiles fine under VC++ when I run 'bjam toolset=msvc-11.0' in the type_traits test directory. There are some errors, because of warnings, but they have nothing to do with the above situation.

I've filed http://llvm.org/bugs/show_bug.cgi?id=17464 to track this.

Someone else had already files http://llvm.org/bugs/show_bug.cgi?id=12535 .