[winapi] Problem with the latest clang on Windows
Updates to clang on Windows have broken the use of clang with the [winapi] library. I do not know if this has occurred in the past but it seems to have occurred recently when I build the latest clang from source and use it on Windows to compile build Boost libraries which use the internal winapi library. Preprocessing clang and gcc output for a given call in the Boost winapi library and in the corresponding mingw windows.h shows that both compilers view the same source but treat them differently. As an example let's look at the GetSystemTimeAsFileTime call. The preprocessed source for both clang and gcc shows: In the Boost winapi it is: __attribute__((dllimport)) void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(FILETIME_* lpFileTime); In the mingw/gcc windows.h it is: void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(LPFILETIME); where the FILETIME_ and LPFILETIME are the same. When gcc sees these two declarations in the two different headers it says everything is OK. When clang sees these two declarations in the two different headers it gives an error: In file included from test_winapi.cpp:9: In file included from /mingw/include\windows.h:62: /mingw/include\winbase.h:1397:24: error: conflicting types for 'GetSystemTimeAsFileTime' WINBASEAPI void WINAPI GetSystemTimeAsFileTime(LPFILETIME); ^ ..\..\..\boost/detail/winapi/time.hpp:70:9: note: previous declaration is here GetSystemTimeAsFileTime(FILETIME_* lpFileTime); ^ For this line in boost/detail/winapi/time.hpp __declspec(dllimport) void WINAPI GetSystemTimeAsFileTime(FILETIME_* lpFileTime); It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
On 31 May 2015 at 20:07, Edward Diener wrote:
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
Oddly enough this topic came up at C++ Now when I was chatting with Chandler. They are immovable on clang being standards conformant in mingw mode. That means API declarations must match. Else it's a bug, and it will be errored out. Just because MSVC uses sloppy declspec doesn't mean it's valid C++. They will not back down, or change their mind on this, period. Switching clang into msvc mode makes everything just work. For reference. Boost.Thread no longer compiles at all on clang in mingw mode for the same reason, but nearly gets there with clang in msvc mode. I suspect plenty more libraries are similar. At some point we'll need to go fix up all our code. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 5/31/2015 8:44 PM, Niall Douglas wrote:
On 31 May 2015 at 20:07, Edward Diener wrote:
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
Oddly enough this topic came up at C++ Now when I was chatting with Chandler.
They are immovable on clang being standards conformant in mingw mode. That means API declarations must match. Else it's a bug, and it will be errored out. Just because MSVC uses sloppy declspec doesn't mean it's valid C++. They will not back down, or change their mind on this, period.
Evidently from my OP it is gcc being sloppy.
Switching clang into msvc mode makes everything just work.
Clang in MSVC mode means you're dealing with a compiler trying to emulate a broken preprocessor. No thanks ! I already had this discussion on the clang mailing lists and since they are adamant that they must attempt to emulate the VC++ preprocessor bugs in all situations I will not use that mode. I suggested to them a system by which they could emulate the broken VC++ preprocessor for VC++ headers which need it and otherwise support a C++ standard compliant preprocessor everywhere else, but they did not want to consider it. So it doesn't make everything just work. In fact it may break any Boost library which uses Boost PP. And that's not a problem which Boost PP is going to try to solve. Boost build also doesn't have built-in support for clang in VC++ mode on Windows but works fine with clang in gcc mode on Windows.
For reference. Boost.Thread no longer compiles at all on clang in mingw mode for the same reason, but nearly gets there with clang in msvc mode. I suspect plenty more libraries are similar. At some point we'll need to go fix up all our code.
If we fix up Boost win32 we might be OK. That was the gist of my OP.
On 5/31/2015 6:31 PM, Edward Diener wrote:
On 5/31/2015 8:44 PM, Niall Douglas wrote:
On 31 May 2015 at 20:07, Edward Diener wrote:
Switching clang into msvc mode makes everything just work.
Clang in MSVC mode means you're dealing with a compiler trying to emulate a broken preprocessor. No thanks ! I already had this discussion on the clang mailing lists and since they are adamant that they must attempt to emulate the VC++ preprocessor bugs in all situations I will not use that mode. I suggested to them a system by which they could emulate the broken VC++ preprocessor for VC++ headers which need it and otherwise support a C++ standard compliant preprocessor everywhere else, but they did not want to consider it.
So it doesn't make everything just work. In fact it may break any Boost library which uses Boost PP. And that's not a problem which Boost PP is going to try to solve.
Boost build also doesn't have built-in support for clang in VC++ mode on Windows but works fine with clang in gcc mode on Windows.
Agreed. Clang in MSVC mode is junk. Regards, Paul Mensonides
On Sunday 31 May 2015 20:07:43 Edward Diener wrote:
Updates to clang on Windows have broken the use of clang with the [winapi] library. I do not know if this has occurred in the past but it seems to have occurred recently when I build the latest clang from source and use it on Windows to compile build Boost libraries which use the internal winapi library.
Preprocessing clang and gcc output for a given call in the Boost winapi library and in the corresponding mingw windows.h shows that both compilers view the same source but treat them differently.
As an example let's look at the GetSystemTimeAsFileTime call. The preprocessed source for both clang and gcc shows:
In the Boost winapi it is:
__attribute__((dllimport)) void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
In the mingw/gcc windows.h it is:
void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(LPFILETIME);
where the FILETIME_ and LPFILETIME are the same.
When gcc sees these two declarations in the two different headers it says everything is OK.
When clang sees these two declarations in the two different headers it gives an error:
In file included from test_winapi.cpp:9: In file included from /mingw/include\windows.h:62: /mingw/include\winbase.h:1397:24: error: conflicting types for 'GetSystemTimeAsFileTime' WINBASEAPI void WINAPI GetSystemTimeAsFileTime(LPFILETIME); ^ ..\..\..\boost/detail/winapi/time.hpp:70:9: note: previous declaration is here GetSystemTimeAsFileTime(FILETIME_* lpFileTime); ^
For this line in boost/detail/winapi/time.hpp
__declspec(dllimport) void WINAPI GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
There's this possibly related ticket: https://svn.boost.org/trac/boost/ticket/11338 I'm puzzled how the function can be not dllimport as it is implemented in kernel32.dll. MS Windows SDK defines WINBASEAPI to be __declspec(dllimport) and so is MinGW64 (see winbase.h and winnt.h). Does clang use its own SDK? Also, is it known for sure that the attribute is what's causing the faulre? Because formally, the winapi declaration also involves structures different from those in windows.h and I don't see an easy way around this.
On 6/1/2015 4:02 AM, Andrey Semashev wrote:
On Sunday 31 May 2015 20:07:43 Edward Diener wrote:
Updates to clang on Windows have broken the use of clang with the [winapi] library. I do not know if this has occurred in the past but it seems to have occurred recently when I build the latest clang from source and use it on Windows to compile build Boost libraries which use the internal winapi library.
Preprocessing clang and gcc output for a given call in the Boost winapi library and in the corresponding mingw windows.h shows that both compilers view the same source but treat them differently.
As an example let's look at the GetSystemTimeAsFileTime call. The preprocessed source for both clang and gcc shows:
In the Boost winapi it is:
__attribute__((dllimport)) void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
In the mingw/gcc windows.h it is:
void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(LPFILETIME);
where the FILETIME_ and LPFILETIME are the same.
When gcc sees these two declarations in the two different headers it says everything is OK.
When clang sees these two declarations in the two different headers it gives an error:
In file included from test_winapi.cpp:9: In file included from /mingw/include\windows.h:62: /mingw/include\winbase.h:1397:24: error: conflicting types for 'GetSystemTimeAsFileTime' WINBASEAPI void WINAPI GetSystemTimeAsFileTime(LPFILETIME); ^ ..\..\..\boost/detail/winapi/time.hpp:70:9: note: previous declaration is here GetSystemTimeAsFileTime(FILETIME_* lpFileTime); ^
For this line in boost/detail/winapi/time.hpp
__declspec(dllimport) void WINAPI GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
There's this possibly related ticket:
https://svn.boost.org/trac/boost/ticket/11338
I'm puzzled how the function can be not dllimport as it is implemented in kernel32.dll. MS Windows SDK defines WINBASEAPI to be __declspec(dllimport) and so is MinGW64 (see winbase.h and winnt.h). Does clang use its own SDK?
gcc and clang on Windows can use the win32 implementation provided by mingw. Evidently the mingw header files translates WINBASEAPI to be empty. I will try gcc with mingw64 to see if it is different. Unfortunately I have had problems building/using clang with mingw64 and clang even acknowledges that it only supports mingw and not mingw64 on Windows. The suggested a way to get clang working with mingw64 but I have not been able to make that work. I have been asked by clang to file a bug report regarding this situation, and wil do that.
Also, is it known for sure that the attribute is what's causing the faulre? Because formally, the winapi declaration also involves structures different from those in windows.h and I don't see an easy way around this.
Is the FILETIME struct in winapi different than that in windows.h ? If it is it means that you can never include Boost's winapi and the equivalent windows.h struct in the same TU without having a compile error. I don't think that Boost's winapi could have been designed that way.
On 6/1/2015 10:07 AM, Edward Diener wrote:
On 6/1/2015 4:02 AM, Andrey Semashev wrote:
On Sunday 31 May 2015 20:07:43 Edward Diener wrote:
Updates to clang on Windows have broken the use of clang with the [winapi] library. I do not know if this has occurred in the past but it seems to have occurred recently when I build the latest clang from source and use it on Windows to compile build Boost libraries which use the internal winapi library.
Preprocessing clang and gcc output for a given call in the Boost winapi library and in the corresponding mingw windows.h shows that both compilers view the same source but treat them differently.
As an example let's look at the GetSystemTimeAsFileTime call. The preprocessed source for both clang and gcc shows:
In the Boost winapi it is:
__attribute__((dllimport)) void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
In the mingw/gcc windows.h it is:
void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(LPFILETIME);
where the FILETIME_ and LPFILETIME are the same.
When gcc sees these two declarations in the two different headers it says everything is OK.
When clang sees these two declarations in the two different headers it gives an error:
In file included from test_winapi.cpp:9: In file included from /mingw/include\windows.h:62: /mingw/include\winbase.h:1397:24: error: conflicting types for 'GetSystemTimeAsFileTime' WINBASEAPI void WINAPI GetSystemTimeAsFileTime(LPFILETIME); ^ ..\..\..\boost/detail/winapi/time.hpp:70:9: note: previous declaration is here GetSystemTimeAsFileTime(FILETIME_* lpFileTime); ^
For this line in boost/detail/winapi/time.hpp
__declspec(dllimport) void WINAPI GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR.
There's this possibly related ticket:
https://svn.boost.org/trac/boost/ticket/11338
I'm puzzled how the function can be not dllimport as it is implemented in kernel32.dll. MS Windows SDK defines WINBASEAPI to be __declspec(dllimport) and so is MinGW64 (see winbase.h and winnt.h). Does clang use its own SDK?
gcc and clang on Windows can use the win32 implementation provided by mingw. Evidently the mingw header files translates WINBASEAPI to be empty.
I will try gcc with mingw64 to see if it is different. Unfortunately I have had problems building/using clang with mingw64 and clang even acknowledges that it only supports mingw and not mingw64 on Windows. The suggested a way to get clang working with mingw64 but I have not been able to make that work.
With mingw64 WINBASEAPI is __attribute__((dllimport)). I will ask on the mingw mailing list why WINBASEAPI is empty in mingw as opposed to mingw64.
I have been asked by clang to file a bug report regarding this situation, and wil do that.
Also, is it known for sure that the attribute is what's causing the faulre? Because formally, the winapi declaration also involves structures different from those in windows.h and I don't see an easy way around this.
Is the FILETIME struct in winapi different than that in windows.h ? If it is it means that you can never include Boost's winapi and the equivalent windows.h struct in the same TU without having a compile error. I don't think that Boost's winapi could have been designed that way.
On Monday 01 June 2015 10:07:56 Edward Diener wrote:
On 6/1/2015 4:02 AM, Andrey Semashev wrote:
I'm puzzled how the function can be not dllimport as it is implemented in kernel32.dll. MS Windows SDK defines WINBASEAPI to be __declspec(dllimport) and so is MinGW64 (see winbase.h and winnt.h). Does clang use its own SDK?
gcc and clang on Windows can use the win32 implementation provided by mingw. Evidently the mingw header files translates WINBASEAPI to be empty.
I will try gcc with mingw64 to see if it is different. Unfortunately I have had problems building/using clang with mingw64 and clang even acknowledges that it only supports mingw and not mingw64 on Windows. The suggested a way to get clang working with mingw64 but I have not been able to make that work.
My understanding is that MinGW (http://mingw.org/) was discontinued in favor of MinGW64 (http://mingw-w64.org/). Not sure if we should support it. Anyway, if it turns out that there is no dllimport just in the MinGW SDK then I'm inclined to think it's a bug in the SDK. If we decide so, we could add a workaround if it is possible to detect that particular SDK.
I have been asked by clang to file a bug report regarding this situation, and wil do that.
Thanks. Could you post the link to the bug report?
Also, is it known for sure that the attribute is what's causing the faulre? Because formally, the winapi declaration also involves structures different from those in windows.h and I don't see an easy way around this.
Is the FILETIME struct in winapi different than that in windows.h ? If it is it means that you can never include Boost's winapi and the equivalent windows.h struct in the same TU without having a compile error. I don't think that Boost's winapi could have been designed that way.
The structure itself is binary compatible with that defined in Windows SDK. But it has a different name and is declared in the boost::detail::winapi namespace, so from the language standpoint it is a distinct type. The WinAPI functions have extern "C" linkage, which makes them have the same mangled name as the real ones in Windows SDK. If the compiler checks that C++ declarations of the similarly named extern "C" functions have the same argument types then this is a showstopper and I don't think we can do anything except to always include and use windows.h on that compiler.
Andrey Semashev wrote:
If the compiler checks that C++ declarations of the similarly named extern "C" functions have the same argument types then this is a showstopper and I don't think we can do anything except to always include and use windows.h on that compiler.
Maybe we can, but I'm not sure if it's worth it. // at global scope struct FILETIME; extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(FILETIME*); namespace winapi { struct FILETIME { ... }; inline void GetSystemTimeAsFileTime( FILETIME * p ) { ::GetSystemTimeAsFileTime( (::FILETIME*)p ); } }
On Monday 01 June 2015 18:01:48 Peter Dimov wrote:
Andrey Semashev wrote:
If the compiler checks that C++ declarations of the similarly named extern "C" functions have the same argument types then this is a showstopper and I don't think we can do anything except to always include and use windows.h on that compiler.
Maybe we can, but I'm not sure if it's worth it.
// at global scope struct FILETIME; extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(FILETIME*);
namespace winapi { struct FILETIME { ... };
inline void GetSystemTimeAsFileTime( FILETIME * p ) { ::GetSystemTimeAsFileTime( (::FILETIME*)p ); } }
Interesting idea, I haven't though about it.
On 6/1/2015 10:48 AM, Andrey Semashev wrote:
On Monday 01 June 2015 10:07:56 Edward Diener wrote:
On 6/1/2015 4:02 AM, Andrey Semashev wrote:
I'm puzzled how the function can be not dllimport as it is implemented in kernel32.dll. MS Windows SDK defines WINBASEAPI to be __declspec(dllimport) and so is MinGW64 (see winbase.h and winnt.h). Does clang use its own SDK?
gcc and clang on Windows can use the win32 implementation provided by mingw. Evidently the mingw header files translates WINBASEAPI to be empty.
I will try gcc with mingw64 to see if it is different. Unfortunately I have had problems building/using clang with mingw64 and clang even acknowledges that it only supports mingw and not mingw64 on Windows. The suggested a way to get clang working with mingw64 but I have not been able to make that work.
My understanding is that MinGW (http://mingw.org/) was discontinued in favor of MinGW64 (http://mingw-w64.org/). Not sure if we should support it.
What do you mean by "discontinued" ? MingW is still around. A clang build targeting gcc on Windows works out of the box with MingW and not with MingW64. I have already discussed this on the clang developer's mailing list and the last response was: "You're completely right that supporting mingw64 is better than supporting than mingw.org. With open source projects, someone needs to push http://reviews.llvm.org/D5268 through the process until commit. This takes time... I hope to get to this someday."
Anyway, if it turns out that there is no dllimport just in the MinGW SDK then I'm inclined to think it's a bug in the SDK. If we decide so, we could add a workaround if it is possible to detect that particular SDK.
I have been asked by clang to file a bug report regarding this situation, and wil do that.
Thanks. Could you post the link to the bug report?
I have not done it yet but when I do I will provide the link.
Also, is it known for sure that the attribute is what's causing the faulre? Because formally, the winapi declaration also involves structures different from those in windows.h and I don't see an easy way around this.
Is the FILETIME struct in winapi different than that in windows.h ? If it is it means that you can never include Boost's winapi and the equivalent windows.h struct in the same TU without having a compile error. I don't think that Boost's winapi could have been designed that way.
The structure itself is binary compatible with that defined in Windows SDK. But it has a different name and is declared in the boost::detail::winapi namespace, so from the language standpoint it is a distinct type. The WinAPI functions have extern "C" linkage, which makes them have the same mangled name as the real ones in Windows SDK. If the compiler checks that C++ declarations of the similarly named extern "C" functions have the same argument types then this is a showstopper and I don't think we can do anything except to always include and use windows.h on that compiler.
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
On 6/1/2015 10:48 AM, Andrey Semashev wrote:
My understanding is that MinGW (http://mingw.org/) was discontinued in favor of MinGW64 (http://mingw-w64.org/). Not sure if we should support it.
What do you mean by "discontinued" ?
I mean it's not being released for quite some time. The last stable compiler release I can see was in 2013. Mailing lists[1][2] activity is rather low. Combined with the fact that the compiler still doesn't support 64-bit targets, this is a strong indication to me that the project is pretty much dead.
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6: ...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.... It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition. [1] http://dir.gmane.org/gmane.comp.gnu.mingw.devel [2] http://dir.gmane.org/gmane.comp.gnu.mingw.user
On 6/1/2015 3:12 PM, Andrey Semashev wrote:
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
On 6/1/2015 10:48 AM, Andrey Semashev wrote:
My understanding is that MinGW (http://mingw.org/) was discontinued in favor of MinGW64 (http://mingw-w64.org/). Not sure if we should support it.
What do you mean by "discontinued" ?
I mean it's not being released for quite some time. The last stable compiler release I can see was in 2013. Mailing lists[1][2] activity is rather low. Combined with the fact that the compiler still doesn't support 64-bit targets, this is a strong indication to me that the project is pretty much dead.
There is still activity on those mailing lists and I have seen nothing on the mingw site that suggests they have come to an end. If clang builds supported mingw64 then I agree that I would not bother with setting up mingw, but since clang/mingw64 is hardly a viable option I still maintain mingw for testing. I quoted you with what one of the clang developers said about clang/mingw64. I have not made a further issue with him or anyone else on the clang mailing list about it.
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6:
...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function....
It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition.
OK, so just declaring a function with the same name but different signature doesn't mean a compiler error. But when we invoke the function with a signature that matches one of the declarations does the C++ standard say it is an error because another declaration with the same name but a different signature exists ? Evidently clang thinks it is an error but gcc does not.
[1] http://dir.gmane.org/gmane.comp.gnu.mingw.devel [2] http://dir.gmane.org/gmane.comp.gnu.mingw.user
On Monday 01 June 2015 17:56:59 Edward Diener wrote:
On 6/1/2015 3:12 PM, Andrey Semashev wrote:
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6: ...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function....
It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition.
OK, so just declaring a function with the same name but different signature doesn't mean a compiler error. But when we invoke the function with a signature that matches one of the declarations does the C++ standard say it is an error because another declaration with the same name but a different signature exists ? Evidently clang thinks it is an error but gcc does not.
I didn't find any specifics on this (but I could be missing something). The extern "C" linkage affects overload resolution (13.3.2/3), so that if there are two viable extern "C" function declarations that are in different namespaces are visible at the call site, the two declarations do not conflict as they are considered to declare the one and only extern "C" function. But then again, the example does not consider the case when the two declarations differ in arguments. The standard also mentions that language-specific linkage may have other effects, such as special name mangling or calling conventions (7.5/1), but naturally, it doesn't go into specifics of these effects. Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it. If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
On 2 Jun 2015 at 1:57, Andrey Semashev wrote:
Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it.
If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
Obviously declspec anything is non-standard. I believe the reason clang is insisting on this behaviour is because declspec is part of the type definition. You can see this in how pointers to functions retain their declspec attributes in the pointer type. Therefore not always specifying them consistently is an ODR violation, and therefore clang is being right here. GCC matches MSVC's incorrectness here for ease of life. As does clang when in MSVC mode. Regarding mingw's broken headers which don't specify dllimport correctly for kernel32 imports, yeah that's one of a long litany of problems in mingw's headers. I in fact gave up on mingw support in AFIO in the v1.3 release, it was becoming too painful to keep working around their severe quality problems. AFIO now only supports mingw-w64. Mingw-w64 have done an excellent job, and are light years ahead of mingw in quality control and stability. They also support the C++ 11 <thread> header, which mingw does not. Regarding why clang is not on mingw-w64 yet, apparently it may be political. See http://sourceforge.net/p/mingw-w64/mailman/mingw-w64-public/thread/873 8aihlgy.fsf@wanadoo.es/. I agree with the assessment that mingw support is not a priority for the clang devs compared to MSVC support, but I am not aware of any active campaign against mingw-w64 support. It's more no one could be bothered relative to other things to do I think. Anyway, from my own perspective whilst it would be nice if mingw-clang was working, it's no showstopper for me personally. MinGW users are a tiny proportion of the user base, sufficiently tiny that GCC is good enough for now. I see mingw-w64 is very shortly going to release a GCC 5.1 build, it's hardly like MinGW users are suffering from ancient GCC tooling or something. winclang is a whole different beast though. That's an enormous threat to MSVC in the medium term. Microsoft may, of course, just go ahead and bundle a winclang toolset in future Visual Studios as an equally supported alternative to MSVC. That would be *enormous* for anyone trying to do modern C++ on Windows, though MSVC is coming along hugely of late and it's still vastly faster to compile than clang, and I suspect always will be. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 6/1/2015 9:11 PM, Niall Douglas wrote:
On 2 Jun 2015 at 1:57, Andrey Semashev wrote:
Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it.
If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
Obviously declspec anything is non-standard.
I believe the reason clang is insisting on this behaviour is because declspec is part of the type definition. You can see this in how pointers to functions retain their declspec attributes in the pointer type.
Therefore not always specifying them consistently is an ODR violation, and therefore clang is being right here. GCC matches MSVC's incorrectness here for ease of life. As does clang when in MSVC mode.
Regarding mingw's broken headers which don't specify dllimport correctly for kernel32 imports, yeah that's one of a long litany of problems in mingw's headers. I in fact gave up on mingw support in AFIO in the v1.3 release, it was becoming too painful to keep working around their severe quality problems. AFIO now only supports mingw-w64.
Mingw-w64 have done an excellent job, and are light years ahead of mingw in quality control and stability. They also support the C++ 11 <thread> header, which mingw does not.
I agree that mingw64 is much better but clang can only target gcc from mingw, and not mingw64, without alot of hacking I am not in the mood to try. In order to run clang on Windows using bjam to test Boost library code I have to build clang targeting mingw/gcc. There is no other choice unless clang provides mingw64/gcc as a possible target.
Regarding why clang is not on mingw-w64 yet, apparently it may be political. See http://sourceforge.net/p/mingw-w64/mailman/mingw-w64-public/thread/873 8aihlgy.fsf@wanadoo.es/.
That does not appear to be apropos the issue of building clang with mingw64/gcc. Instead it appears to be about using clang to create mingw64 builds. Did I miss something in that discussion ?
I agree with the assessment that mingw support is not a priority for the clang devs compared to MSVC support, but I am not aware of any active campaign against mingw-w64 support. It's more no one could be bothered relative to other things to do I think.
As explained before the current MSVC build of clang is absolutely useless for testing Boost, unless you are not using Boost PP at all. Which is fine but many libraries are for a good reason.
Anyway, from my own perspective whilst it would be nice if mingw-clang was working, it's no showstopper for me personally. MinGW users are a tiny proportion of the user base, sufficiently tiny that GCC is good enough for now. I see mingw-w64 is very shortly going to release a GCC 5.1 build, it's hardly like MinGW users are suffering from ancient GCC tooling or something.
I also test gcc on Windows using mingw64. It works very nicely. But it is good to try clang also with Boost libraries. Despite what you may believe both gcc and clang are better C++ standard conformant compilers than even the most recent VC++13 version. That's not to say I haven't used VC++ extensively in corporate consulting jobs. I have and it has done the job for the type of programming corporations desire. But if you are talking about adherence to the C++ standard VC++ has always been behind, never mind the broken preprocessor.
winclang is a whole different beast though. That's an enormous threat to MSVC in the medium term. Microsoft may, of course, just go ahead and bundle a winclang toolset in future Visual Studios as an equally supported alternative to MSVC. That would be *enormous* for anyone trying to do modern C++ on Windows, though MSVC is coming along hugely of late and it's still vastly faster to compile than clang, and I suspect always will be.
The slow compilation speed of clang has been also discussed on their developers mailing list. But that's not a showstopper.
Niall
On 6/1/2015 6:57 PM, Andrey Semashev wrote:
On Monday 01 June 2015 17:56:59 Edward Diener wrote:
On 6/1/2015 3:12 PM, Andrey Semashev wrote:
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6: ...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function....
It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition.
OK, so just declaring a function with the same name but different signature doesn't mean a compiler error. But when we invoke the function with a signature that matches one of the declarations does the C++ standard say it is an error because another declaration with the same name but a different signature exists ? Evidently clang thinks it is an error but gcc does not.
I didn't find any specifics on this (but I could be missing something). The extern "C" linkage affects overload resolution (13.3.2/3), so that if there are two viable extern "C" function declarations that are in different namespaces are visible at the call site, the two declarations do not conflict as they are considered to declare the one and only extern "C" function. But then again, the example does not consider the case when the two declarations differ in arguments. The standard also mentions that language-specific linkage may have other effects, such as special name mangling or calling conventions (7.5/1), but naturally, it doesn't go into specifics of these effects.
Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it.
If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
Clang bug report at: https://llvm.org/bugs/show_bug.cgi?id=23722 You can view their response if/when it comes.
On 6/1/2015 6:57 PM, Andrey Semashev wrote:
On Monday 01 June 2015 17:56:59 Edward Diener wrote:
On 6/1/2015 3:12 PM, Andrey Semashev wrote:
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6: ...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function....
It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition.
OK, so just declaring a function with the same name but different signature doesn't mean a compiler error. But when we invoke the function with a signature that matches one of the declarations does the C++ standard say it is an error because another declaration with the same name but a different signature exists ? Evidently clang thinks it is an error but gcc does not.
I didn't find any specifics on this (but I could be missing something). The extern "C" linkage affects overload resolution (13.3.2/3), so that if there are two viable extern "C" function declarations that are in different namespaces are visible at the call site, the two declarations do not conflict as they are considered to declare the one and only extern "C" function. But then again, the example does not consider the case when the two declarations differ in arguments. The standard also mentions that language-specific linkage may have other effects, such as special name mangling or calling conventions (7.5/1), but naturally, it doesn't go into specifics of these effects.
Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it.
If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
The reply from clang was quick on the bug report: "The problem is that the two function declarations have different parameter types. The windows.h version takes ::_FILETIME*, whereas the boost version takes boost::detail::winapi::_FILETIME*. Because they're 'extern "C"' functions, they are redeclarations of the same function, and are ill-formed because they have different types." I have asked for the appropriate place in the C++ standard which justifies the error.
On 2/06/2015 18:34, Edward Diener wrote:
The reply from clang was quick on the bug report:
"The problem is that the two function declarations have different parameter types. The windows.h version takes ::_FILETIME*, whereas the boost version takes boost::detail::winapi::_FILETIME*. Because they're 'extern "C"' functions, they are redeclarations of the same function, and are ill-formed because they have different types."
I have asked for the appropriate place in the C++ standard which justifies the error.
Standard or no, it does make sense that this should at least be a warning, if not an error, unless the compiler can prove that the two types really are binary compatible (and even that is still dubious because it *can't* prove that they're semantically compatible). Accidental parameter incompatibilities in C functions is the source of many hard-to-locate bugs. What is the reason that Boost WinAPI redeclares the structure? Can it be changed to just use the one from the Windows headers (perhaps via typedef, if the internal typename is needed for compatibility)? (After writing the above, a cursory glance at the code suggests that it does do that if BOOST_USE_WINDOWS_H is defined. So that changes the question: under what conditions is that not defined?)
On Friday 05 June 2015 19:04:51 Gavin Lambert wrote:
What is the reason that Boost WinAPI redeclares the structure? Can it be changed to just use the one from the Windows headers (perhaps via typedef, if the internal typename is needed for compatibility)?
(After writing the above, a cursory glance at the code suggests that it does do that if BOOST_USE_WINDOWS_H is defined. So that changes the question: under what conditions is that not defined?)
The reason of Boost.WinAPI existence is that people don't want to include windows.h, especially in public headers. It is a heavy header that brings in most of SDK. It depends on predefined macros, so including it once defines the API users will be able to use; this is inconvenient for both Boost and its users. Also, windows.h defines a few offending macros, like min/max. In order to provide Windows API Boost.WinAPI has to redefine functions and structures from Windows SDK in a binary compatible way but in the way it doesn't conflict with windows.h. That's the current implementation. BOOST_USE_WINDOWS_H is a macro that can be defined by the user if he wants Boost to include windows.h. There's not much practical point in this except to solve compatibility problems like in the original post.
On 5/06/2015 20:31, Andrey Semashev wrote:
On Friday 05 June 2015 19:04:51 Gavin Lambert wrote:
What is the reason that Boost WinAPI redeclares the structure? Can it be changed to just use the one from the Windows headers (perhaps via typedef, if the internal typename is needed for compatibility)?
(After writing the above, a cursory glance at the code suggests that it does do that if BOOST_USE_WINDOWS_H is defined. So that changes the question: under what conditions is that not defined?)
The reason of Boost.WinAPI existence is that people don't want to include windows.h, especially in public headers. It is a heavy header that brings in most of SDK. It depends on predefined macros, so including it once defines the API users will be able to use; this is inconvenient for both Boost and its users. Also, windows.h defines a few offending macros, like min/max.
I'm not sure why this is a desirable goal. Any user application is
almost guaranteed to #include
Gavin Lambert wrote:
Any user application is almost guaranteed to #include
at some point...
Not in every .cpp file. Any portable application isolates its
On Monday 08 June 2015 11:12:19 Gavin Lambert wrote:
On 5/06/2015 20:31, Andrey Semashev wrote:
The reason of Boost.WinAPI existence is that people don't want to include windows.h, especially in public headers. It is a heavy header that brings in most of SDK. It depends on predefined macros, so including it once defines the API users will be able to use; this is inconvenient for both Boost and its users. Also, windows.h defines a few offending macros, like min/max.
I'm not sure why this is a desirable goal. Any user application is almost guaranteed to #include
at some point -- it's the platform header, you can't really accomplish anything of value without doing so at some point, except in very trivial cases. (Just like any non-trivial Linux app is likely to include one of the sys/ headers at some point.)
By not including windows.h in Boost we let the user decide what features of windows.h he wants to use and not depend on his choice. This is much less of a problem with POSIX headers because they are more fine grained and do not depend on predefined macros so much.
On 6/1/2015 6:57 PM, Andrey Semashev wrote:
On Monday 01 June 2015 17:56:59 Edward Diener wrote:
On 6/1/2015 3:12 PM, Andrey Semashev wrote:
On Monday 01 June 2015 11:23:36 Edward Diener wrote:
What does the C++ standard say about the extern "C" declarations duplicating the same name as regular declarations but different types. Is it an ODR violation ? Maybe that is what the clang problem is about although gcc does not feel it is a problem seeing the exact same preprocessed output.
I could only find 7.5/6: ...Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function....
It doesn't say anything about argument types. ODR also doesn't apply here since we're talking about the function declaration, not its definition.
OK, so just declaring a function with the same name but different signature doesn't mean a compiler error. But when we invoke the function with a signature that matches one of the declarations does the C++ standard say it is an error because another declaration with the same name but a different signature exists ? Evidently clang thinks it is an error but gcc does not.
I didn't find any specifics on this (but I could be missing something). The extern "C" linkage affects overload resolution (13.3.2/3), so that if there are two viable extern "C" function declarations that are in different namespaces are visible at the call site, the two declarations do not conflict as they are considered to declare the one and only extern "C" function. But then again, the example does not consider the case when the two declarations differ in arguments. The standard also mentions that language-specific linkage may have other effects, such as special name mangling or calling conventions (7.5/1), but naturally, it doesn't go into specifics of these effects.
Since other than the above there are no special treatment of extern "C" function calls from the language perspective, I would assume that as long as the call in unambiguous by the C++ overload resolution rules, the language should allow it.
If clang folks say this should not compile then perhaps they could point to the relevant part of the standard.
The clang explanation, when asked to point to the C++ standard, is: "[dcl.link]/6: "At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function." [basic.link]/10: "the types specified by all declarations referring to a given variable or function shall be identical" So the program is ill-formed because the same function is declared with two different types."
On Friday 05 June 2015 05:45:18 Edward Diener wrote:
The clang explanation, when asked to point to the C++ standard, is:
"[dcl.link]/6: "At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function."
[basic.link]/10: "the types specified by all declarations referring to a given variable or function shall be identical"
So the program is ill-formed because the same function is declared with two different types."
Ok, I'll modify Boost.WinAPI according to Peter's suggestion in a few days. I intend to keep dllimport attributes on the functions though. If that still breaks clang then I believe clang ticket should be reopened (or a MinGW ticket should be filed). Thanks Edward for communicating this through.
On 6/5/2015 6:21 AM, Andrey Semashev wrote:
On Friday 05 June 2015 05:45:18 Edward Diener wrote:
The clang explanation, when asked to point to the C++ standard, is:
"[dcl.link]/6: "At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function."
[basic.link]/10: "the types specified by all declarations referring to a given variable or function shall be identical"
So the program is ill-formed because the same function is declared with two different types."
Ok, I'll modify Boost.WinAPI according to Peter's suggestion in a few days. I intend to keep dllimport attributes on the functions though.
That's fine. Just for you interest I asked on the mingw mailing list why their implementation did not have dllimport while mingw64 does have dllimport, and their response was: "AFAIK, the dllimport attribute is not needed with C functions, but it might be needed with variables and C++ classes. See the GCC manual for the details." From the GCC docs: "For Microsoft Windows targets the use of the dllimport attribute on functions is not necessary, but provides a small performance benefit by eliminating a thunk in the DLL." I quoted this in my reply to their reply but that was not going to change their mind evidently as they did not respond further. BTW maybe you can coordinate things so that fixing ticket https://svn.boost.org/trac/boost/ticket/11338 is not going to be duplicated effort.
If that still breaks clang then I believe clang ticket should be reopened (or a MinGW ticket should be filed).
No problem. I can do that if necessary.
Thanks Edward for communicating this through.
Clang, for all its pickiness, problems, and slow compiler speed, is still a great compiler to use to check code so I do have an interest in seeing that it works whenever possible with the Boost code I write or test.
Le 01/06/15 10:02, Andrey Semashev a écrit :
On Sunday 31 May 2015 20:07:43 Edward Diener wrote:
Updates to clang on Windows have broken the use of clang with the [winapi] library. I do not know if this has occurred in the past but it seems to have occurred recently when I build the latest clang from source and use it on Windows to compile build Boost libraries which use the internal winapi library.
Preprocessing clang and gcc output for a given call in the Boost winapi library and in the corresponding mingw windows.h shows that both compilers view the same source but treat them differently.
As an example let's look at the GetSystemTimeAsFileTime call. The preprocessed source for both clang and gcc shows:
In the Boost winapi it is:
__attribute__((dllimport)) void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
In the mingw/gcc windows.h it is:
void __attribute__((__stdcall__)) GetSystemTimeAsFileTime(LPFILETIME);
where the FILETIME_ and LPFILETIME are the same.
When gcc sees these two declarations in the two different headers it says everything is OK.
When clang sees these two declarations in the two different headers it gives an error:
In file included from test_winapi.cpp:9: In file included from /mingw/include\windows.h:62: /mingw/include\winbase.h:1397:24: error: conflicting types for 'GetSystemTimeAsFileTime' WINBASEAPI void WINAPI GetSystemTimeAsFileTime(LPFILETIME); ^ ..\..\..\boost/detail/winapi/time.hpp:70:9: note: previous declaration is here GetSystemTimeAsFileTime(FILETIME_* lpFileTime); ^
For this line in boost/detail/winapi/time.hpp
__declspec(dllimport) void WINAPI GetSystemTimeAsFileTime(FILETIME_* lpFileTime);
It seems like the fix for clang is to leave out the __declspec(dllimport) portion of all these Boost winapi calls while leaving it in for everybody else. I am discussing this on the clang developers mailing list but it seems like they are pretty adamant that if they see __attribute__((dllimport)) in from of a function declaration and do not see it in front of another function declaration, despite the rest of the signatire being the same, the two declarations are not the same function being declared and therefore an error because of ODR. There's this possibly related ticket:
I have no access to a windows environment. I could create a branch and do my best to port to Boost.WinAPI if someone is ready to test it. I would also accept any working patch. Best, Vicente
On Monday 01 June 2015 19:13:58 Vicente J. Botet Escriba wrote:
Le 01/06/15 10:02, Andrey Semashev a écrit :
There's this possibly related ticket:
I have no access to a windows environment.
I could create a branch and do my best to port to Boost.WinAPI if someone is ready to test it.
I would also accept any working patch.
Unfortunately, I don't have much time lately to prepare a patch. I could test the branch on the local VM, though. We also have quite a few Windows testers.
participants (7)
-
Andrey Semashev
-
Edward Diener
-
Gavin Lambert
-
Niall Douglas
-
Paul Mensonides
-
Peter Dimov
-
Vicente J. Botet Escriba