From 1baf122cd41d6500139649661052236b8e684565 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 19 Apr 2019 11:11:53 -0400
Subject: MSVC: Do not add /W3 to CMAKE_<LANG>_FLAGS by default

We do not add default warning flags on other compilers, and having
a warning flag in the default flags makes it hard for projects to
customize the warning level.  They need to use string processing
to remove `/W3` from `CMAKE_{C,CXX}_FLAGS`.  Therefore we should
drop it.

However, projects may be using string processing to replace `/W3`
with another flag, so we cannot simply drop it.  Add a policy to
drop it in a compatible way.

Fixes: #18317
---
 Help/manual/cmake-policies.7.rst                   |  1 +
 Help/policy/CMP0092.rst                            | 38 ++++++++++++++++++++++
 Help/release/dev/msvc-warning-flags.rst            |  6 ++++
 Modules/Platform/Windows-Intel-Fortran.cmake       |  9 ++++-
 Modules/Platform/Windows-MSVC.cmake                | 17 ++++++++--
 Modules/Platform/Windows-NVIDIA-CUDA.cmake         | 11 ++++++-
 Source/cmPolicies.h                                |  5 ++-
 Tests/RunCMake/CMakeLists.txt                      |  1 +
 Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake  |  2 ++
 Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake  |  2 ++
 Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake |  2 ++
 .../RunCMake/MSVCWarningFlags/CMP0092-common.cmake | 12 +++++++
 Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt     |  3 ++
 Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake |  5 +++
 14 files changed, 109 insertions(+), 5 deletions(-)
 create mode 100644 Help/policy/CMP0092.rst
 create mode 100644 Help/release/dev/msvc-warning-flags.rst
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt
 create mode 100644 Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake

diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 043fb5c..8fcd386 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.15
 .. toctree::
    :maxdepth: 1
 
+   CMP0092: MSVC warning flags are not in CMAKE_{C,CXX}_FLAGS by default. </policy/CMP0092>
    CMP0091: MSVC runtime library flags are selected by an abstraction. </policy/CMP0091>
    CMP0090: export(PACKAGE) does not populate package registry by default. </policy/CMP0090>
    CMP0089: Compiler id for IBM Clang-based XL compilers is now XLClang. </policy/CMP0089>
diff --git a/Help/policy/CMP0092.rst b/Help/policy/CMP0092.rst
new file mode 100644
index 0000000..8d3a288
--- /dev/null
+++ b/Help/policy/CMP0092.rst
@@ -0,0 +1,38 @@
+CMP0092
+-------
+
+MSVC warning flags are not in :variable:`CMAKE_<LANG>_FLAGS` by default.
+
+When using MSVC-like compilers in CMake 3.14 and below, warning flags
+like ``/W3`` are added to :variable:`CMAKE_<LANG>_FLAGS` by default.
+This is problematic for projects that want to choose a different warning
+level programmatically.  In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave out warning flags from the value of
+:variable:`CMAKE_<LANG>_FLAGS` by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of warning flags.  The policy setting takes effect as of
+the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_<LANG>_FLAGS` for a given lanuage ``<LANG>``.
+
+.. note::
+
+  Once the policy has taken effect at the top of a project for a given
+  language, that choice must be used throughout the tree for that language.
+  In projects that have nested projects in subdirectories, be sure to
+  convert everything together.
+
+The ``OLD`` behavior for this policy is to place MSVC warning flags in the
+default :variable:`CMAKE_<LANG>_FLAGS` cache entries.  The ``NEW`` behavior
+for this policy is to *not* place MSVC warning flags in the default cache
+entries.
+
+This policy was introduced in CMake version 3.15.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/msvc-warning-flags.rst b/Help/release/dev/msvc-warning-flags.rst
new file mode 100644
index 0000000..b89d6fa
--- /dev/null
+++ b/Help/release/dev/msvc-warning-flags.rst
@@ -0,0 +1,6 @@
+msvc-warning-flags
+------------------
+
+* With MSVC-like compilers the value of :variable:`CMAKE_<LANG>_FLAGS`
+  no longer contains warning flags like ``/W3`` by default.
+  See policy :policy:`CMP0092`.
diff --git a/Modules/Platform/Windows-Intel-Fortran.cmake b/Modules/Platform/Windows-Intel-Fortran.cmake
index f00a8e4..e3804fb 100644
--- a/Modules/Platform/Windows-Intel-Fortran.cmake
+++ b/Modules/Platform/Windows-Intel-Fortran.cmake
@@ -13,7 +13,14 @@ else()
   set(_DBGLIBS " /dbglibs")
   set(_THREADS " /threads")
 endif()
-string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1 /nologo /fpp${_LIBSDLL}${_THREADS}")
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(NOT _cmp0092 STREQUAL "NEW")
+  string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_Fortran_FLAGS_INIT " /nologo /fpp${_LIBSDLL}${_THREADS}")
 string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full${_DBGLIBS}")
 string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " /O1 /DNDEBUG")
 string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " /O2 /DNDEBUG")
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index 4279a74..ed0e7fb 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -366,21 +366,34 @@ macro(__windows_compiler_msvc lang)
       set(_MDd " /MDd")
       set(_MD " /MD")
     endif()
+
+    cmake_policy(GET CMP0092 _cmp0092)
+    if(_cmp0092 STREQUAL "NEW")
+      set(_W3 "")
+      set(_Wall "")
+    else()
+      set(_W3 " /W3")
+      set(_Wall " -Wall")
+    endif()
+    unset(_cmp0092)
+
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       # note: MSVC 14 2015 Update 1 sets -fno-ms-compatibility by default, but this does not allow one to compile many projects
       # that include MS's own headers. CMake itself is affected project too.
-      string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS -Wall${_FLAGS_${lang}}")
+      string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS${_Wall}${_FLAGS_${lang}}")
       string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} -gline-tables-only -fno-inline -O0 ${_RTC1}")
       string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} -O2 -DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} -gline-tables-only -O2 -fno-inline -DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
     else()
-      string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS /W3${_FLAGS_${lang}}")
+      string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS${_W3}${_FLAGS_${lang}}")
       string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} /Zi /Ob0 /Od ${_RTC1}")
       string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} /Zi /O2 /Ob1 /DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
     endif()
+    unset(_Wall)
+    unset(_W3)
     unset(_MDd)
     unset(_MD)
 
diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
index 6a2667a..f160c7b 100644
--- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
@@ -60,11 +60,20 @@ unset(__IMPLICT_DLINK_FLAGS)
 
 string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")
 
-string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"/W3${_FLAGS_CXX}\"")
+cmake_policy(GET CMP0092 _cmp0092)
+if(_cmp0092 STREQUAL "NEW")
+  set(_W3 "")
+else()
+  set(_W3 "/W3")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
 string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"-MDd -Zi -Ob0 -Od ${_RTC1}\"")
 string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"-MD -O2 -Ob2\" -DNDEBUG")
 string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"-MD -Zi -O2 -Ob1\" -DNDEBUG")
 string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"-MD -O1 -Ob1\" -DNDEBUG")
+unset(_W3)
 
 set(CMAKE_CUDA_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
 
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 113dd35..0e42295 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -270,7 +270,10 @@ class cmMakefile;
          15, 0, cmPolicies::WARN)                                             \
   SELECT(POLICY, CMP0091,                                                     \
          "MSVC runtime library flags are selected by an abstraction.", 3, 15, \
-         0, cmPolicies::WARN)
+         0, cmPolicies::WARN)                                                 \
+  SELECT(POLICY, CMP0092,                                                     \
+         "MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.", 3,   \
+         15, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index a8dcb4b..4973e55 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -197,6 +197,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
 endif()
 if(MSVC)
   add_RunCMake_test(MSVCRuntimeLibrary)
+  add_RunCMake_test(MSVCWarningFlags)
 endif()
 add_RunCMake_test(ObjectLibrary)
 add_RunCMake_test(ParseImplicitIncludeInfo)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake
new file mode 100644
index 0000000..15c52d2
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0092 NEW)
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake
new file mode 100644
index 0000000..ea75445
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0092 OLD)
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake
new file mode 100644
index 0000000..45e183f
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake
new file mode 100644
index 0000000..87d7f67
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+cmake_policy(GET CMP0092 cmp0092)
+if(cmp0092 STREQUAL "NEW")
+  if("${CMAKE_C_FLAGS}" MATCHES "([/-]W[0-9])")
+    message(SEND_ERROR "CMAKE_C_FLAGS has '${CMAKE_MATCH_1}' under NEW behavior")
+  endif()
+else()
+  if(NOT " ${CMAKE_C_FLAGS} " MATCHES " /W3 ")
+    message(SEND_ERROR "CMAKE_C_FLAGS does not have '/W3' under OLD behavior")
+  endif()
+endif()
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt b/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt
new file mode 100644
index 0000000..3e470a2
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake b/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake
new file mode 100644
index 0000000..7ce448d
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0092-WARN)
+run_cmake(CMP0092-OLD)
+run_cmake(CMP0092-NEW)
-- 
cgit v0.12