SDL: Fixing compilation errors for VS2019 Clang toolset (fixes #4702)

From 6b66542e7be0861d5dd7c763ab4aae91eddd1268 Mon Sep 17 00:00:00 2001
From: hgs3 <[EMAIL REDACTED]>
Date: Wed, 17 Nov 2021 17:04:34 -0600
Subject: [PATCH] Fixing compilation errors for VS2019 Clang toolset (fixes
 #4702)

---
 .github/workflows/main.yml | 16 +++++++++-------
 CMakeLists.txt             | 16 ++++++++++++----
 include/SDL_endian.h       |  8 ++++----
 3 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 914e24e28c..4c1850fc0e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,13 +15,15 @@ jobs:
       fail-fast: false
       matrix:
         platform:
-        - { name: Windows (x64),     os: windows-latest, shell: pwsh, flags: -A x64 }
-        - { name: Windows (x86),     os: windows-latest, shell: pwsh, flags: -A Win32 }
-        - { name: Windows (ARM64),   os: windows-latest, shell: pwsh, flags: -A ARM64 }
-        - { name: Windows (mingw32), os: windows-latest, shell: 'msys2 {0}', msystem: mingw32, msys-env: mingw-w64-i686 }
-        - { name: Windows (mingw64), os: windows-latest, shell: 'msys2 {0}', msystem: mingw64, msys-env: mingw-w64-x86_64 }
-        - { name: Linux,             os: ubuntu-20.04,   shell: sh,   flags: -GNinja }
-        - { name: MacOS,             os: macos-latest,   shell: sh }
+        - { name: Windows (x64),          os: windows-latest, shell: pwsh, flags: -A x64 }
+        - { name: Windows (x86),          os: windows-latest, shell: pwsh, flags: -A Win32 }
+        - { name: Windows (clang-cl x64), os: windows-latest, shell: pwsh, flags: -T ClangCL -A x64 }
+        - { name: Windows (clang-cl x86), os: windows-latest, shell: pwsh, flags: -T ClangCL -A Win32 }
+        - { name: Windows (ARM64),        os: windows-latest, shell: pwsh, flags: -A ARM64 }
+        - { name: Windows (mingw32),      os: windows-latest, shell: 'msys2 {0}', msystem: mingw32, msys-env: mingw-w64-i686 }
+        - { name: Windows (mingw64),      os: windows-latest, shell: 'msys2 {0}', msystem: mingw64, msys-env: mingw-w64-x86_64 }
+        - { name: Linux,                  os: ubuntu-20.04,   shell: sh,   flags: -GNinja }
+        - { name: MacOS,                  os: macos-latest,   shell: sh }
 
     steps:
     - name: Set up MSYS2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cd8599f7a2..e3d3b149dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -199,6 +199,11 @@ endif()
 if(CMAKE_C_COMPILER_ID MATCHES "Clang")
   set(USE_CLANG TRUE)
   set(OPT_DEF_ASM TRUE)
+  # Visual Studio 2019 v16.2 added support for Clang/LLVM.
+  # Check if a Visual Studio project is being generated with the Clang toolset.
+  if(MSVC)
+    set(MSVC_CLANG TRUE)
+  endif()
 elseif(CMAKE_COMPILER_IS_GNUCC)
   set(USE_GCC TRUE)
   set(OPT_DEF_ASM TRUE)
@@ -214,7 +219,7 @@ if(USE_GCC OR USE_CLANG)
 endif()
 
 # Default option knobs
-if(APPLE OR ARCH_64)
+if(APPLE OR ARCH_64 OR MSVC_CLANG)
   if(NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "arm")
     set(OPT_DEF_SSEMATH ON)
   endif()
@@ -288,7 +293,8 @@ endif()
 target_compile_definitions(sdl-build-options INTERFACE "-DUSING_GENERATED_CONFIG_H")
 target_include_directories(sdl-build-options BEFORE INTERFACE "${SDL2_BINARY_DIR}/include")
 target_include_directories(sdl-build-options INTERFACE "${SDL2_SOURCE_DIR}/include")
-if(USE_GCC OR USE_CLANG)
+# Note: The clang toolset for Visual Studio does not support the '-idirafter' option.
+if(USE_GCC OR (USE_CLANG AND NOT MSVC_CLANG))
   # !!! FIXME: do we _need_ to mess with CMAKE_C_FLAGS here?
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -idirafter \"${SDL2_SOURCE_DIR}/src/video/khronos\"")
 else()
@@ -2667,7 +2673,8 @@ if(SDL_SHARED)
       SOVERSION ${LT_REVISION}
       OUTPUT_NAME "SDL2")
   endif()
-  if(MSVC AND NOT SDL_LIBC)
+  # Note: The clang toolset for Visual Studio does not support /NODEFAULTLIB.
+  if(MSVC AND NOT SDL_LIBC AND NOT MSVC_CLANG)
     # Don't try to link with the default set of libraries.
     if(NOT WINDOWS_STORE)
       set_target_properties(SDL2 PROPERTIES LINK_FLAGS_RELEASE "/NODEFAULTLIB")
@@ -2699,7 +2706,8 @@ if(SDL_STATIC)
     # clobbered, when the suffix is realized via subsequent rename.
   endif()
   set_target_properties(SDL2-static PROPERTIES POSITION_INDEPENDENT_CODE ${SDL_STATIC_PIC})
-  if(MSVC AND NOT SDL_LIBC)
+  # Note: The clang toolset for Visual Studio does not support /NODEFAULTLIB.
+  if(MSVC AND NOT SDL_LIBC AND NOT MSVC_CLANG)
     set_target_properties(SDL2-static PROPERTIES LINK_FLAGS_RELEASE "/NODEFAULTLIB")
     set_target_properties(SDL2-static PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB")
     set_target_properties(SDL2-static PROPERTIES STATIC_LIBRARY_FLAGS "/NODEFAULTLIB")
diff --git a/include/SDL_endian.h b/include/SDL_endian.h
index 62505e4aa5..41c37cd294 100644
--- a/include/SDL_endian.h
+++ b/include/SDL_endian.h
@@ -90,7 +90,7 @@ extern "C" {
  */
 
 /* various modern compilers may have builtin swap */
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 #   define HAS_BUILTIN_BSWAP16 (_SDL_HAS_BUILTIN(__builtin_bswap16)) || \
         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
 #   define HAS_BUILTIN_BSWAP32 (_SDL_HAS_BUILTIN(__builtin_bswap32)) || \
@@ -109,7 +109,7 @@ extern "C" {
 
 #if HAS_BUILTIN_BSWAP16
 #define SDL_Swap16(x) __builtin_bswap16(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
 #pragma intrinsic(_byteswap_ushort)
 #define SDL_Swap16(x) _byteswap_ushort(x)
 #elif defined(__i386__) && !HAS_BROKEN_BSWAP
@@ -165,7 +165,7 @@ SDL_Swap16(Uint16 x)
 
 #if HAS_BUILTIN_BSWAP32
 #define SDL_Swap32(x) __builtin_bswap32(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
 #pragma intrinsic(_byteswap_ulong)
 #define SDL_Swap32(x) _byteswap_ulong(x)
 #elif defined(__i386__) && !HAS_BROKEN_BSWAP
@@ -224,7 +224,7 @@ SDL_Swap32(Uint32 x)
 
 #if HAS_BUILTIN_BSWAP64
 #define SDL_Swap64(x) __builtin_bswap64(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
 #pragma intrinsic(_byteswap_uint64)
 #define SDL_Swap64(x) _byteswap_uint64(x)
 #elif defined(__i386__) && !HAS_BROKEN_BSWAP