Clang++ fails to compile Wine's include/winnt.h. This is caused by Wine defining some function inline, while the compiler provides an intrinsic version. This is fine with a C compilation, but fails in a C++ compilation.
This serie fixes the compilation by better detecting the various cases and giving favor to intrinsic when defined (on clang/clang++).
From: Eric Pouech epouech@codeweavers.com
clang++ generates an error when an intrinsic function is redefined as inline. Now clang provides intrinsic variant of Interlocked*64 family on i386 machine.
So, we use intrinsic variant for clang whenever __has_builtin() reports its presence.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- include/winnt.h | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 22 deletions(-)
diff --git a/include/winnt.h b/include/winnt.h index 20db9a8aabd..fd7b37cb1c0 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6745,6 +6745,12 @@ typedef enum _FIRMWARE_TYPE FirmwareTypeMax } FIRMWARE_TYPE, *PFIRMWARE_TYPE;
+#if (defined(__clang__) || defined(__GNUC__)) && defined(__has_builtin) +# define WINE__HAS_BUILTIN(x) __has_builtin(x) +#else +# define WINE__HAS_BUILTIN(x) 0 +#endif + /* Intrinsic functions */
#define BitScanForward _BitScanForward @@ -6809,63 +6815,73 @@ long _InterlockedOr(long volatile *,long); long _InterlockedXor(long volatile *,long); DECLSPEC_NORETURN void __fastfail(unsigned int);
-#ifndef __i386__ - +#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedAnd64) #pragma intrinsic(_InterlockedAnd64) -#pragma intrinsic(_InterlockedDecrement64) -#pragma intrinsic(_InterlockedExchangeAdd64) -#pragma intrinsic(_InterlockedIncrement64) -#pragma intrinsic(_InterlockedOr64) -#pragma intrinsic(_InterlockedXor64) - __int64 _InterlockedAnd64(__int64 volatile *, __int64); -__int64 _InterlockedDecrement64(__int64 volatile *); -__int64 _InterlockedExchangeAdd64(__int64 volatile *, __int64); -__int64 _InterlockedIncrement64(__int64 volatile *); -__int64 _InterlockedOr64(__int64 volatile *, __int64); -__int64 _InterlockedXor64(__int64 volatile *, __int64); - #else - static FORCEINLINE __int64 InterlockedAnd64( __int64 volatile *dest, __int64 val ) { __int64 prev; do prev = *dest; while (InterlockedCompareExchange64( dest, prev & val, prev ) != prev); return prev; } +#endif + +#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedDecrement64) +#pragma intrinsic(_InterlockedDecrement64) +__int64 _InterlockedDecrement64(__int64 volatile *); +#else +static FORCEINLINE __int64 InterlockedDecrement64( __int64 volatile *dest ) +{ + return InterlockedExchangeAdd64( dest, -1 ) - 1; +} +#endif
+#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchangeAdd64) +__int64 _InterlockedExchangeAdd64(__int64 volatile *, __int64); +#else static FORCEINLINE __int64 InterlockedExchangeAdd64( __int64 volatile *dest, __int64 val ) { __int64 prev; do prev = *dest; while (InterlockedCompareExchange64( dest, prev + val, prev ) != prev); return prev; } +#endif
+#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedIncrement64) +#pragma intrinsic(_InterlockedIncrement64) +__int64 _InterlockedIncrement64(__int64 volatile *); +#else static FORCEINLINE __int64 InterlockedIncrement64( __int64 volatile *dest ) { return InterlockedExchangeAdd64( dest, 1 ) + 1; } +#endif
-static FORCEINLINE __int64 InterlockedDecrement64( __int64 volatile *dest ) -{ - return InterlockedExchangeAdd64( dest, -1 ) - 1; -} - +#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedOr64) +#pragma intrinsic(_InterlockedOr64) +__int64 _InterlockedOr64(__int64 volatile *, __int64); +#else static FORCEINLINE __int64 InterlockedOr64( __int64 volatile *dest, __int64 val ) { __int64 prev; do prev = *dest; while (InterlockedCompareExchange64( dest, prev | val, prev ) != prev); return prev; } +#endif
+#if !defined(__i386__) || WINE__HAS_BUILTIN(_InterlockedXor64) +#pragma intrinsic(_InterlockedXor64) +__int64 _InterlockedXor64(__int64 volatile *, __int64); +#else static FORCEINLINE __int64 InterlockedXor64( __int64 volatile *dest, __int64 val ) { __int64 prev; do prev = *dest; while (InterlockedCompareExchange64( dest, prev ^ val, prev ) != prev); return prev; } - -#endif /* __i386__ */ +#endif
static FORCEINLINE long InterlockedAdd( long volatile *dest, long val ) {
From: Eric Pouech epouech@codeweavers.com
clang++ generates an error when an intrinsic function is redefined as an inline function. Note the _InterlockedCompareExchange128 for a x86_64 machine is only defined as intrinsic when -mcx16 option is enabled. But we use always use the intrinsic definition on x86_64 so that compilation done without the -mcx16 could be detected (on C++ only). And the intrinsic has been added recently to aarch64 machine for clang. So, it's detected thanks to __has_builtin() macro.
(thanks to Jacek for some insights on clang)
Signed-off-by: Eric Pouech epouech@codeweavers.com --- include/winnt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/winnt.h b/include/winnt.h index fd7b37cb1c0..041aa4a36be 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -7186,7 +7186,7 @@ static FORCEINLINE DECLSPEC_NORETURN void __fastfail(unsigned int code)
#define InterlockedCompareExchange128 _InterlockedCompareExchange128
-#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_MSC_VER) && (!defined(__clang__) || !defined(__aarch64__) || WINE__HAS_BUILTIN(_InterlockedCompareExchange128))
#pragma intrinsic(_InterlockedCompareExchange128) unsigned char _InterlockedCompareExchange128(volatile __int64 *, __int64, __int64, __int64 *);
Jacek Caban (@jacek) commented about include/winnt.h:
FirmwareTypeMax
} FIRMWARE_TYPE, *PFIRMWARE_TYPE;
+#if (defined(__clang__) || defined(__GNUC__)) && defined(__has_builtin) +# define WINE__HAS_BUILTIN(x) __has_builtin(x) +#else +# define WINE__HAS_BUILTIN(x) 0 +#endif
I think you could just ensure that `__has_builtin` always defined (like we do for `__has_attribute`).