From 7185e96da1fa243edd5b295ff8664e00cdd4cfa1 Mon Sep 17 00:00:00 2001 From: Michael Winterberg Date: Tue, 5 Jan 2016 16:03:06 -0800 Subject: [PATCH] Fixed issues with MSVC emulations of clz and clzll. Both clang-cl and Clang/C2 #define _MSC_VER but also have support for __builtin_clz and __builtin_clzll, leading to duplicate macro definition warnings. Emulation of clz using _BitScanReverse is suppressed if the builtins are already available. Additionally, the value of the output parameter of _BitScanReverse is undefined if the input value is 0, which is avoided by construction, so the code analysis warning for using uninitialized data is now suppressed. --- format.h | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/format.h b/format.h index 345877a7..52a567f1 100644 --- a/format.h +++ b/format.h @@ -75,7 +75,7 @@ typedef __int64 intmax_t; # define FMT_API #endif -#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_MSC_VER) # include // _BitScanReverse, _BitScanReverse64 namespace fmt { @@ -84,9 +84,14 @@ namespace internal { inline uint32_t clz(uint32_t x) { unsigned long r = 0; _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +#pragma warning(suppress: 6102) return 31 - r; } -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) # ifdef _WIN64 # pragma intrinsic(_BitScanReverse64) @@ -104,9 +109,14 @@ inline uint32_t clzll(uint64_t x) { // Scan the low 32 bits. _BitScanReverse(&r, static_cast(x)); # endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +#pragma warning(suppress: 6102) return 63 - r; } -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) } } #endif @@ -801,6 +811,23 @@ typedef BasicData<> Data; # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif +#if defined(_MSC_VER) + +// Some compilers masquerade as both MSVC and GCC-likes or +// otherwise support __builtin_clz and __builtin_clzll, so +// only define FMT_BUILTIN_CLZ using the MSVC intrinsics +// if the clz and clzll builtins are not available. +#if !defined(FMT_BUILTIN_CLZ) +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) +#endif + +#if !defined(FMT_BUILTIN_CLZLL) +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +#endif + +#endif + + #ifdef FMT_BUILTIN_CLZLL // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1.