瀏覽代碼

Merge topic 'msvc-runtime-checks'

2b2344b412 MSVC: Add abstraction for runtime checks
49dcd1ce5d Help: Fix MSVC_DEBUG_INFORMATION_FORMAT description of example
2f8e643d9d CMP0141: Fix documentation copied from CMP0091

Acked-by: Kitware Robot <[email protected]>
Acked-by: Alex <[email protected]>
Merge-request: !10214
Brad King 10 月之前
父節點
當前提交
3e64c6a56e
共有 51 個文件被更改,包括 603 次插入26 次删除
  1. 2 0
      Auxiliary/vim/syntax/cmake.vim
  2. 6 0
      Help/command/try_compile.rst
  3. 1 0
      Help/manual/cmake-policies.7.rst
  4. 1 0
      Help/manual/cmake-properties.7.rst
  5. 1 0
      Help/manual/cmake-variables.7.rst
  6. 2 2
      Help/policy/CMP0141.rst
  7. 54 0
      Help/policy/CMP0184.rst
  8. 1 1
      Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst
  9. 16 0
      Help/prop_tgt/MSVC_RUNTIME_CHECKS-VALUES.txt
  10. 34 0
      Help/prop_tgt/MSVC_RUNTIME_CHECKS.rst
  11. 7 0
      Help/release/dev/msvc-runtime-checks.rst
  12. 1 1
      Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst
  13. 36 0
      Help/variable/CMAKE_MSVC_RUNTIME_CHECKS.rst
  14. 5 2
      Modules/CMakeASM_MARMASMInformation.cmake
  15. 5 2
      Modules/CMakeASM_MASMInformation.cmake
  16. 4 0
      Modules/Platform/Windows-Clang-ASM.cmake
  17. 15 0
      Modules/Platform/Windows-Clang.cmake
  18. 6 0
      Modules/Platform/Windows-Intel-Fortran.cmake
  19. 6 0
      Modules/Platform/Windows-IntelLLVM-Fortran.cmake
  20. 32 4
      Modules/Platform/Windows-MSVC.cmake
  21. 12 1
      Modules/Platform/Windows-NVIDIA-CUDA.cmake
  22. 10 0
      Source/cmCoreTryCompile.cxx
  23. 47 12
      Source/cmLocalGenerator.cxx
  24. 4 1
      Source/cmPolicies.h
  25. 2 0
      Source/cmTarget.cxx
  26. 8 0
      Tests/CMakeLists.txt
  27. 1 0
      Tests/FortranOnly/CMakeLists.txt
  28. 105 0
      Tests/MSVCRuntimeChecks/CMakeLists.txt
  29. 3 0
      Tests/MSVCRuntimeChecks/override-C.cmake
  30. 3 0
      Tests/MSVCRuntimeChecks/override-CUDA.cmake
  31. 3 0
      Tests/MSVCRuntimeChecks/override-CXX.cmake
  32. 3 0
      Tests/MSVCRuntimeChecks/override-Fortran.cmake
  33. 50 0
      Tests/MSVCRuntimeChecks/override-common.cmake
  34. 1 0
      Tests/MSVCRuntimeChecks/verify.F90
  35. 1 0
      Tests/MSVCRuntimeChecks/verify.c
  36. 1 0
      Tests/MSVCRuntimeChecks/verify.cu
  37. 1 0
      Tests/MSVCRuntimeChecks/verify.cxx
  38. 61 0
      Tests/MSVCRuntimeChecks/verify.h
  39. 1 0
      Tests/RunCMake/CMakeLists.txt
  40. 1 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW-result.txt
  41. 4 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW-stderr.txt
  42. 2 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW.cmake
  43. 4 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NoEffect.cmake
  44. 2 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-OLD.cmake
  45. 2 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-WARN.cmake
  46. 25 0
      Tests/RunCMake/MSVCRuntimeChecks/CMP0184-common.cmake
  47. 3 0
      Tests/RunCMake/MSVCRuntimeChecks/CMakeLists.txt
  48. 6 0
      Tests/RunCMake/MSVCRuntimeChecks/RunCMakeTest.cmake
  49. 0 0
      Tests/RunCMake/MSVCRuntimeChecks/empty.c
  50. 1 0
      Tests/VSMARMASM/CMakeLists.txt
  51. 1 0
      Tests/VSMASM/CMakeLists.txt

+ 2 - 0
Auxiliary/vim/syntax/cmake.vim

@@ -305,6 +305,7 @@ syn keyword cmakeProperty contained
             \ MEASUREMENT
             \ MEASUREMENT
             \ MODIFIED
             \ MODIFIED
             \ MSVC_DEBUG_INFORMATION_FORMAT
             \ MSVC_DEBUG_INFORMATION_FORMAT
+            \ MSVC_RUNTIME_CHECKS
             \ MSVC_RUNTIME_LIBRARY
             \ MSVC_RUNTIME_LIBRARY
             \ NAME
             \ NAME
             \ NO_SONAME
             \ NO_SONAME
@@ -1533,6 +1534,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_MODULE_PATH
             \ CMAKE_MODULE_PATH
             \ CMAKE_MSVCIDE_RUN_PATH
             \ CMAKE_MSVCIDE_RUN_PATH
             \ CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
             \ CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
+            \ CMAKE_MSVC_RUNTIME_CHECKS
             \ CMAKE_MSVC_RUNTIME_LIBRARY
             \ CMAKE_MSVC_RUNTIME_LIBRARY
             \ CMAKE_NETRC
             \ CMAKE_NETRC
             \ CMAKE_NETRC_FILE
             \ CMAKE_NETRC_FILE

+ 6 - 0
Help/command/try_compile.rst

@@ -349,6 +349,7 @@ as needed to honor the state of the calling project:
 * :policy:`CMP0155`
 * :policy:`CMP0155`
 * :policy:`CMP0157`
 * :policy:`CMP0157`
 * :policy:`CMP0181`
 * :policy:`CMP0181`
+* :policy:`CMP0184`
 
 
 .. versionadded:: 4.0
 .. versionadded:: 4.0
   The current setting of :policy:`CMP0181` policy is propagated through to the
   The current setting of :policy:`CMP0181` policy is propagated through to the
@@ -417,6 +418,11 @@ configuration:
   propagated into the test project's build configuration when using the
   propagated into the test project's build configuration when using the
   :ref:`whole-project signature <Try Compiling Whole Projects>`.
   :ref:`whole-project signature <Try Compiling Whole Projects>`.
 
 
+.. versionadded:: 4.0
+  If :policy:`CMP0184` is set to ``NEW``, one can use
+  :variable:`CMAKE_MSVC_RUNTIME_CHECKS` to specify the enabled MSVC runtime
+  checks.
+
 See Also
 See Also
 ^^^^^^^^
 ^^^^^^^^
 
 

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -98,6 +98,7 @@ Policies Introduced by CMake 4.0
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
+   CMP0184: MSVC runtime checks flags are selected by an abstraction. </policy/CMP0184>
    CMP0183: add_feature_info() supports full Condition Syntax. </policy/CMP0183>
    CMP0183: add_feature_info() supports full Condition Syntax. </policy/CMP0183>
    CMP0182: Create shared library archives by default on AIX. </policy/CMP0182>
    CMP0182: Create shared library archives by default on AIX. </policy/CMP0182>
    CMP0181: Link command-line fragment variables are parsed and re-quoted. </policy/CMP0181>
    CMP0181: Link command-line fragment variables are parsed and re-quoted. </policy/CMP0181>

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -359,6 +359,7 @@ Properties on Targets
    /prop_tgt/MANUALLY_ADDED_DEPENDENCIES
    /prop_tgt/MANUALLY_ADDED_DEPENDENCIES
    /prop_tgt/MAP_IMPORTED_CONFIG_CONFIG
    /prop_tgt/MAP_IMPORTED_CONFIG_CONFIG
    /prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT
    /prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT
+   /prop_tgt/MSVC_RUNTIME_CHECKS
    /prop_tgt/MSVC_RUNTIME_LIBRARY
    /prop_tgt/MSVC_RUNTIME_LIBRARY
    /prop_tgt/NAME
    /prop_tgt/NAME
    /prop_tgt/NO_SONAME
    /prop_tgt/NO_SONAME

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -519,6 +519,7 @@ Variables that Control the Build
    /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT
    /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT
    /variable/CMAKE_MODULE_LINKER_FLAGS_INIT
    /variable/CMAKE_MODULE_LINKER_FLAGS_INIT
    /variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
    /variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
+   /variable/CMAKE_MSVC_RUNTIME_CHECKS
    /variable/CMAKE_MSVC_RUNTIME_LIBRARY
    /variable/CMAKE_MSVC_RUNTIME_LIBRARY
    /variable/CMAKE_MSVCIDE_RUN_PATH
    /variable/CMAKE_MSVCIDE_RUN_PATH
    /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
    /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX

+ 2 - 2
Help/policy/CMP0141.rst

@@ -13,8 +13,8 @@ In CMake 3.24 and below, debug information format flags are added to
 the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
 the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
 automatically.  This allows users to edit their cache entries to adjust the
 automatically.  This allows users to edit their cache entries to adjust the
 flags.  However, the presence of such default flags is problematic for
 flags.  However, the presence of such default flags is problematic for
-projects that want to choose a different runtime library programmatically.
-In particular, it requires string editing of the
+projects that want to choose a different debug information format
+programmatically.  In particular, it requires string editing of the
 :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
 :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
 CMake builtin defaults so they can be replaced.
 CMake builtin defaults so they can be replaced.
 
 

+ 54 - 0
Help/policy/CMP0184.rst

@@ -0,0 +1,54 @@
+CMP0184
+-------
+
+.. versionadded:: 4.0
+
+MSVC runtime checks flags are selected by an abstraction.
+
+Compilers targeting the MSVC ABI have flags to select the runtime checks.
+Runtime checks selection typically varies with build
+configuration.
+
+In CMake 3.31 and below, runtime checks flags are added to
+the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
+automatically.  This allows users to edit their cache entries to adjust the
+flags.  However, the presence of such default flags is problematic for
+projects that want to choose different runtime checks programmatically.
+In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 4.0 and above prefer to leave the runtime checks flags
+out of the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values and instead
+offer a first-class abstraction.  The
+:variable:`CMAKE_MSVC_RUNTIME_CHECKS` variable and
+:prop_tgt:`MSVC_RUNTIME_CHECKS` target property may be set to
+select the MSVC runtime checks.  If they are not set, CMake
+enables runtime checks in ``Debug`` configuration using the default value
+``$<$<CONFIG:Debug>:StackFrameErrorCheck;UninitializedVariable>``, if
+supported by the compiler, or empty value otherwise.
+
+This policy provides compatibility with projects that have not been updated
+to be aware of the abstraction.  The policy setting takes effect as of the
+first :command:`project` or :command:`enable_language` command that enables
+a language whose compiler targets the MSVC ABI.
+
+.. note::
+
+  Once the policy has taken effect at the top of a project, that choice
+  will be used throughout the tree.  In projects that have nested projects
+  in subdirectories, be sure to confirm if everything is working with the
+  selected policy behavior.
+
+The ``OLD`` behavior for this policy is to place MSVC runtimes checks
+flags in the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache
+entries and ignore the :variable:`CMAKE_MSVC_RUNTIME_CHECKS`
+abstraction.  The ``NEW`` behavior for this policy is to *not* place MSVC
+runtime checks flags in the default cache entries and use
+the abstraction instead.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.0
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt

+ 1 - 1
Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst

@@ -19,7 +19,7 @@ support per-configuration specification.  For example, the code:
     MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>")
     MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>")
 
 
 selects for the target ``foo`` the program database debug information format
 selects for the target ``foo`` the program database debug information format
-for the Debug configuration.
+for the ``Debug`` and ``RelWithDebInfo`` configurations.
 
 
 This property is initialized from the value of the
 This property is initialized from the value of the
 :variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` variable, if it is set.
 :variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` variable, if it is set.

+ 16 - 0
Help/prop_tgt/MSVC_RUNTIME_CHECKS-VALUES.txt

@@ -0,0 +1,16 @@
+``PossibleDataLoss``
+  Compile with ``-RTCc`` or equivalent flag(s) to enable possible
+  data loss checks.
+``StackFrameErrorCheck``
+  Compile with ``-RTCs`` or equivalent flag(s) to enable stack frame
+  error checks.
+``UninitializedVariable``
+  Compile with ``-RTCu`` or equivalent flag(s) to enable uninitialized
+  variables checks.
+
+The value is ignored on compilers not targeting the MSVC ABI, but an
+unsupported value will be rejected as an error when using a compiler
+targeting the MSVC ABI.
+
+The value may also be the empty string (``""``), in which case no runtime
+error check flags will be added explicitly by CMake.

+ 34 - 0
Help/prop_tgt/MSVC_RUNTIME_CHECKS.rst

@@ -0,0 +1,34 @@
+MSVC_RUNTIME_CHECKS
+-------------------
+
+.. versionadded:: 4.0
+
+Select the list of enabled runtime checks when targeting the MSVC ABI.
+
+The allowed values are:
+
+.. include:: MSVC_RUNTIME_CHECKS-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification.  For example, the code:
+
+.. code-block:: cmake
+
+  add_executable(foo foo.c)
+  set_property(TARGET foo PROPERTY
+    MSVC_RUNTIME_CHECKS "$<$<CONFIG:Debug,RelWithDebInfo>:PossibleDataLoss;UninitializedVariable>")
+
+enables for the target ``foo`` the possible data loss and uninitialized variables checks
+for the ``Debug`` and ``RelWithDebInfo`` configurations.
+
+This property is initialized from the value of the
+:variable:`CMAKE_MSVC_RUNTIME_CHECKS` variable, if it is set.
+If this property is not set, CMake selects a runtime checks using
+the default value ``$<$<CONFIG:Debug>:StackFrameErrorCheck;UninitializedVariable>``, if
+supported by the compiler, or empty value otherwise.
+
+.. note::
+
+  This property has effect only when policy :policy:`CMP0184` is set to ``NEW``
+  prior to the first :command:`project` or :command:`enable_language` command
+  that enables a language using a compiler targeting the MSVC ABI.

+ 7 - 0
Help/release/dev/msvc-runtime-checks.rst

@@ -0,0 +1,7 @@
+msvc-runtime-checks
+-------------------
+
+* The :variable:`CMAKE_MSVC_RUNTIME_CHECKS` variable and
+  :prop_tgt:`MSVC_RUNTIME_CHECKS` target property were introduced
+  to select runtime checks for compilers targeting the MSVC ABI.
+  See policy :policy:`CMP0184`.

+ 1 - 1
Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst

@@ -21,7 +21,7 @@ support per-configuration specification.  For example, the code:
   set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>")
   set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>")
 
 
 selects for all following targets the program database debug information format
 selects for all following targets the program database debug information format
-for the Debug configuration.
+for the ``Debug`` and ``RelWithDebInfo`` configurations.
 
 
 If this variable is not set, the :prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT`
 If this variable is not set, the :prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT`
 target property will not be set automatically.  If that property is not set,
 target property will not be set automatically.  If that property is not set,

+ 36 - 0
Help/variable/CMAKE_MSVC_RUNTIME_CHECKS.rst

@@ -0,0 +1,36 @@
+CMAKE_MSVC_RUNTIME_CHECKS
+-------------------------
+
+.. versionadded:: 4.0
+
+Select the list of enabled runtime checks when targeting the MSVC ABI.
+This variable is used to initialize the
+:prop_tgt:`MSVC_RUNTIME_CHECKS` property on all targets as they are
+created. It is also propagated by calls to the :command:`try_compile` command
+into the test project.
+
+The allowed values are:
+
+.. include:: ../prop_tgt/MSVC_RUNTIME_CHECKS-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+  set(CMAKE_MSVC_RUNTIME_CHECKS "$<$<CONFIG:Debug,RelWithDebInfo>:PossibleDataLoss;UninitializedVariable>")
+
+enables for the target ``foo`` the possible data loss and uninitialized variables checks
+for the ``Debug`` and ``RelWithDebInfo`` configurations.
+
+If this variable is not set, the :prop_tgt:`MSVC_RUNTIME_CHECKS`
+target property will not be set automatically.  If that property is not set,
+CMake selects runtime checks using the default value
+``$<$<CONFIG:Debug>:StackFrameErrorCheck;UninitializedVariable>``,
+if supported by the compiler, or empty value otherwise.
+
+.. note::
+
+  This variable has effect only when policy :policy:`CMP0184` is set to ``NEW``
+  prior to the first :command:`project` or :command:`enable_language` command
+  that enables a language using a compiler targeting the MSVC ABI.

+ 5 - 2
Modules/CMakeASM_MARMASMInformation.cmake

@@ -11,12 +11,15 @@ set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
 set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 
 
-# The ASM_MARMASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
+# The ASM_MARMASM compiler id for this compiler is "MSVC", so fill out the abstraction tables.
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
-
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        "-g")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        "-g")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue "")

+ 5 - 2
Modules/CMakeASM_MASMInformation.cmake

@@ -11,12 +11,15 @@ set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -c -Fo <OBJECT> <SOURCE>")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -c -Fo <OBJECT> <SOURCE>")
 set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 
 
-# The ASM_MASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
+# The ASM_MASM compiler id for this compiler is "MSVC", so fill out the abstraction tables.
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
-
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        "-Zi")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        "-Zi")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue "")
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue "")

+ 4 - 0
Modules/Platform/Windows-Clang-ASM.cmake

@@ -1,6 +1,10 @@
 include(Platform/Windows-Clang)
 include(Platform/Windows-Clang)
 __windows_compiler_clang(ASM)
 __windows_compiler_clang(ASM)
 
 
+set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "")
+set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
 set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")

+ 15 - 0
Modules/Platform/Windows-Clang.cmake

@@ -117,6 +117,13 @@ macro(__windows_compiler_clang_gnu lang)
     string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG${_RTL_FLAGS}")
     string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG${_RTL_FLAGS}")
     string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -DNDEBUG${_DBG_FLAGS}${_RTL_FLAGS}")
     string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -DNDEBUG${_DBG_FLAGS}${_RTL_FLAGS}")
 
 
+    # clang-cl accepts -RTC* flags but ignores them.  Simulate this
+    # with the GNU-like drivers by simply passing no flags at all.
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
+
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        -g -Xclang -gcodeview)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded        -g -Xclang -gcodeview)
     #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase) # not supported by Clang
     #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase) # not supported by Clang
     #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue) # not supported by Clang
     #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue) # not supported by Clang
@@ -239,6 +246,14 @@ endmacro()
     endif()
     endif()
     unset(__WINDOWS_MSVC_CMP0141)
     unset(__WINDOWS_MSVC_CMP0141)
 
 
+    cmake_policy(GET CMP0184 __WINDOWS_MSVC_CMP0184)
+    if(__WINDOWS_MSVC_CMP0184 STREQUAL "NEW")
+      set(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT "$<$<CONFIG:Debug>:StackFrameErrorCheck;UninitializedVariable>")
+    else()
+      set(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT "")
+    endif()
+    unset(__WINDOWS_MSVC_CMP0184)
+
     set(CMAKE_BUILD_TYPE_INIT Debug)
     set(CMAKE_BUILD_TYPE_INIT Debug)
 
 
     __enable_llvm_rc_preprocessing("" "-x c")
     __enable_llvm_rc_preprocessing("" "-x c")

+ 6 - 0
Modules/Platform/Windows-Intel-Fortran.cmake

@@ -29,6 +29,12 @@ unset(_LIBSDLL)
 unset(_DBGLIBS)
 unset(_DBGLIBS)
 unset(_THREADS)
 unset(_THREADS)
 
 
+# icl accepts -RTC* flags but ignores them.  ifort accepts -RTCu only.
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable -RTCu)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
+
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -threads -libs:static)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -threads -libs:static)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -threads -libs:dll)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -threads -libs:dll)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -threads -libs:static -dbglibs)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -threads -libs:static -dbglibs)

+ 6 - 0
Modules/Platform/Windows-IntelLLVM-Fortran.cmake

@@ -29,6 +29,12 @@ unset(_LIBSDLL)
 unset(_DBGLIBS)
 unset(_DBGLIBS)
 unset(_THREADS)
 unset(_THREADS)
 
 
+# icx accepts -RTC* flags but ignores them.  ifx accepts -RTCu only.
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "")
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "")
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable -RTCu)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "")
+
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -threads -libs:static)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -threads -libs:static)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -threads -libs:dll)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -threads -libs:dll)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -threads -libs:static -dbglibs)
 set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -threads -libs:static -dbglibs)

+ 32 - 4
Modules/Platform/Windows-MSVC.cmake

@@ -192,6 +192,9 @@ if(WINCE)
   set(_PLATFORM_DEFINES_CXX " /D${_MSVC_CXX_ARCHITECTURE_FAMILY} /D_${_MSVC_CXX_ARCHITECTURE_FAMILY_UPPER}_")
   set(_PLATFORM_DEFINES_CXX " /D${_MSVC_CXX_ARCHITECTURE_FAMILY} /D_${_MSVC_CXX_ARCHITECTURE_FAMILY_UPPER}_")
 
 
   set(_RTC1 "")
   set(_RTC1 "")
+  set(_RTCc "")
+  set(_RTCs "")
+  set(_RTCu "")
   set(_FLAGS_C "")
   set(_FLAGS_C "")
   set(_FLAGS_CXX "${_GR} /EHsc")
   set(_FLAGS_CXX "${_GR} /EHsc")
 
 
@@ -248,17 +251,24 @@ else()
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       # Clang/C2 in MSVC14 Update 1 seems to not support -fsantinize (yet?)
       # Clang/C2 in MSVC14 Update 1 seems to not support -fsantinize (yet?)
       # set(_RTC1 "-fsantinize=memory,safe-stack")
       # set(_RTC1 "-fsantinize=memory,safe-stack")
+      # set(_RTCs "-fsantinize=safe-stack")
+      # set(_RTCu "-fsantinize=memory")
       set(_FLAGS_CXX " -frtti -fexceptions")
       set(_FLAGS_CXX " -frtti -fexceptions")
     else()
     else()
-      set(_RTC1 "/RTC1")
+      set(_RTC1 "-RTC1")
+      set(_RTCc "-RTCc")
+      set(_RTCs "-RTCs")
+      set(_RTCu "-RTCu")
       set(_FLAGS_CXX "${_GR} /EHsc")
       set(_FLAGS_CXX "${_GR} /EHsc")
     endif()
     endif()
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib")
   else()
   else()
-    set(_RTC1 "/GZ")
+    set(_RTC1 "-GZ")
+    set(_RTCs "-GZ")
     set(_FLAGS_CXX "${_GR} /GX")
     set(_FLAGS_CXX "${_GR} /GX")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib")
   endif()
   endif()
+  set(_RTCsu "${_RTC1}")
 
 
   if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
   if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
     string(APPEND CMAKE_C_STANDARD_LIBRARIES_INIT " softintrin.lib")
     string(APPEND CMAKE_C_STANDARD_LIBRARIES_INIT " softintrin.lib")
@@ -353,6 +363,13 @@ else()
 endif()
 endif()
 unset(__WINDOWS_MSVC_CMP0141)
 unset(__WINDOWS_MSVC_CMP0141)
 
 
+cmake_policy(GET CMP0184 __WINDOWS_MSVC_CMP0184)
+if(__WINDOWS_MSVC_CMP0184 STREQUAL "NEW")
+  set(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT "$<$<CONFIG:Debug>:StackFrameErrorCheck;UninitializedVariable>")
+else()
+  set(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT "")
+endif()
+unset(__WINDOWS_MSVC_CMP0184)
 
 
 macro(__windows_compiler_msvc lang)
 macro(__windows_compiler_msvc lang)
   if(NOT MSVC_VERSION LESS 1400)
   if(NOT MSVC_VERSION LESS 1400)
@@ -467,17 +484,23 @@ macro(__windows_compiler_msvc lang)
       set(_Zi " /Zi")
       set(_Zi " /Zi")
     endif()
     endif()
 
 
+    if(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT)
+      set(_RTC1_local "")
+    else()
+      string(REPLACE " -" " /" _RTC1_local " ${_RTC1}")
+    endif()
+
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
     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
       # 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.
       # 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_DEBUG_INIT "${_MDd} -gline-tables-only -fno-inline -O0${_RTC1_local}")
       string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} -O2 -DNDEBUG")
       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_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
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
     else()
     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_DEBUG_INIT "${_MDd}${_Zi} /Ob0 /Od${_RTC1_local}")
       string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG")
       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_RELWITHDEBINFO_INIT "${_MD}${_Zi} /O2 /Ob1 /DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
@@ -487,7 +510,12 @@ macro(__windows_compiler_msvc lang)
     unset(_MDd)
     unset(_MDd)
     unset(_MD)
     unset(_MD)
     unset(_Zi)
     unset(_Zi)
+    unset(_RTC1_local)
 
 
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "${_RTCc}")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "${_RTCs}")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "${_RTCu}")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "${_RTCsu}")
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -MT)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -MT)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -MD)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -MD)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -MTd)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -MTd)

+ 12 - 1
Modules/Platform/Windows-NVIDIA-CUDA.cmake

@@ -68,6 +68,12 @@ else()
   set(_Zi " -Zi")
   set(_Zi " -Zi")
 endif()
 endif()
 
 
+if(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT)
+  set(_RTC1_local "")
+else()
+  string(REPLACE " -" " /" _RTC1_local " ${_RTC1}")
+endif()
+
 cmake_policy(GET CMP0092 _cmp0092)
 cmake_policy(GET CMP0092 _cmp0092)
 if(_cmp0092 STREQUAL "NEW")
 if(_cmp0092 STREQUAL "NEW")
   set(_W3 "")
   set(_W3 "")
@@ -77,7 +83,7 @@ endif()
 unset(_cmp0092)
 unset(_cmp0092)
 
 
 string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
 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_DEBUG_INIT " -Xcompiler=\"${_MDd}${_Zi} -Ob0 -Od${_RTC1_local}\"")
 string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG")
 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_RELWITHDEBINFO_INIT " -Xcompiler=\"${_MD}${_Zi} -O2 -Ob1\" -DNDEBUG")
 string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"${_MD}-O1 -Ob1\" -DNDEBUG")
 string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"${_MD}-O1 -Ob1\" -DNDEBUG")
@@ -85,7 +91,12 @@ unset(_W3)
 unset(_Zi)
 unset(_Zi)
 unset(_MDd)
 unset(_MDd)
 unset(_MD)
 unset(_MD)
+unset(_RTC1_local)
 
 
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss      "-Xcompiler=${_RTCc} -D_ALLOW_RTCc_IN_STL")
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck  "-Xcompiler=${_RTCs}")
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable "-Xcompiler=${_RTCu}")
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu                 "-Xcompiler=${_RTCsu}")
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xcompiler=-MT)
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xcompiler=-MT)
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -Xcompiler=-MD)
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -Xcompiler=-MD)
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -Xcompiler=-MTd)
 set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -Xcompiler=-MTd)

+ 10 - 0
Source/cmCoreTryCompile.cxx

@@ -110,6 +110,8 @@ std::string const kCMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT =
   "CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT";
   "CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT";
 std::string const kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT =
 std::string const kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT =
   "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT";
   "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT";
+std::string const kCMAKE_MSVC_RUNTIME_CHECKS_DEFAULT =
+  "CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT";
 
 
 /* GHS Multi platform variables */
 /* GHS Multi platform variables */
 std::set<std::string> const ghs_platform_vars{
 std::set<std::string> const ghs_platform_vars{
@@ -683,6 +685,13 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
               !msvcDebugInformationFormatDefault->empty() ? "NEW" : "OLD");
               !msvcDebugInformationFormatDefault->empty() ? "NEW" : "OLD");
     }
     }
 
 
+    /* Set MSVC runtime checks policy to match our selection.  */
+    if (cmValue msvcRuntimeChecksDefault =
+          this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_CHECKS_DEFAULT)) {
+      fprintf(fout, "cmake_policy(SET CMP0184 %s)\n",
+              !msvcRuntimeChecksDefault->empty() ? "NEW" : "OLD");
+    }
+
     /* Set cache/normal variable policy to match outer project.
     /* Set cache/normal variable policy to match outer project.
        It may affect toolchain files.  */
        It may affect toolchain files.  */
     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) !=
     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) !=
@@ -1111,6 +1120,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
     vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
     vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
     vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
     vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
     vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s);
     vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s);
+    vars.emplace("CMAKE_MSVC_RUNTIME_CHECKS"_s);
     vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s);
     vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s);
     vars.emplace("CMAKE_VS_USE_DEBUG_LIBRARIES"_s);
     vars.emplace("CMAKE_VS_USE_DEBUG_LIBRARIES"_s);
 
 

+ 47 - 12
Source/cmLocalGenerator.cxx

@@ -2193,10 +2193,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
             "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
             "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
             msvcRuntimeLibrary)) {
             msvcRuntimeLibrary)) {
         this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions);
         this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions);
-      } else if ((this->Makefile->GetSafeDefinition(
-                    "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
-                  this->Makefile->GetSafeDefinition(
-                    "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
+      } else if ((compiler == "MSVC" || compilerSimulateId == "MSVC") &&
                  !cmSystemTools::GetErrorOccurredFlag()) {
                  !cmSystemTools::GetErrorOccurredFlag()) {
         // The compiler uses the MSVC ABI so it needs a known runtime library.
         // The compiler uses the MSVC ABI so it needs a known runtime library.
         this->IssueMessage(MessageType::FATAL_ERROR,
         this->IssueMessage(MessageType::FATAL_ERROR,
@@ -2224,10 +2221,8 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
             "CMAKE_" + lang + "_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_" +
             "CMAKE_" + lang + "_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_" +
             watcomRuntimeLibrary)) {
             watcomRuntimeLibrary)) {
         this->AppendCompileOptions(flags, *watcomRuntimeLibraryOptions);
         this->AppendCompileOptions(flags, *watcomRuntimeLibraryOptions);
-      } else if ((this->Makefile->GetSafeDefinition(
-                    "CMAKE_" + lang + "_COMPILER_ID") == "OpenWatcom" ||
-                  this->Makefile->GetSafeDefinition(
-                    "CMAKE_" + lang + "_SIMULATE_ID") == "OpenWatcom") &&
+      } else if ((compiler == "OpenWatcom" ||
+                  compilerSimulateId == "OpenWatcom") &&
                  !cmSystemTools::GetErrorOccurredFlag()) {
                  !cmSystemTools::GetErrorOccurredFlag()) {
         // The compiler uses the Watcom ABI so it needs a known runtime
         // The compiler uses the Watcom ABI so it needs a known runtime
         // library.
         // library.
@@ -2239,6 +2234,49 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
     }
     }
   }
   }
 
 
+  // Add MSVC runtime checks flags. This is activated by the presence
+  // of a default selection whether or not it is overridden by a property.
+  cmValue msvcRuntimeChecksDefault =
+    this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT");
+  if (cmNonempty(msvcRuntimeChecksDefault)) {
+    cmValue msvcRuntimeChecksValue =
+      target->GetProperty("MSVC_RUNTIME_CHECKS");
+    if (!msvcRuntimeChecksValue) {
+      msvcRuntimeChecksValue = msvcRuntimeChecksDefault;
+    }
+    cmList msvcRuntimeChecksList = cmGeneratorExpression::Evaluate(
+      *msvcRuntimeChecksValue, this, config, target);
+    msvcRuntimeChecksList.remove_duplicates();
+
+    // RTC1/RTCsu VS GUI workaround
+    std::string const stackFrameErrorCheck = "StackFrameErrorCheck";
+    std::string const unitinitializedVariable = "UninitializedVariable";
+    std::string const rtcSU = "RTCsu";
+    if ((cm::contains(msvcRuntimeChecksList, stackFrameErrorCheck) &&
+         cm::contains(msvcRuntimeChecksList, unitinitializedVariable)) ||
+        cm::contains(msvcRuntimeChecksList, rtcSU)) {
+      msvcRuntimeChecksList.remove_items(
+        { stackFrameErrorCheck, unitinitializedVariable, rtcSU });
+      msvcRuntimeChecksList.append(rtcSU);
+    }
+
+    for (std::string const& msvcRuntimeChecks : msvcRuntimeChecksList) {
+      if (cmValue msvcRuntimeChecksOptions =
+            this->Makefile->GetDefinition(cmStrCat(
+              "CMAKE_", lang,
+              "_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_" + msvcRuntimeChecks))) {
+        this->AppendCompileOptions(flags, *msvcRuntimeChecksOptions);
+      } else if ((compiler == "MSVC" || compilerSimulateId == "MSVC") &&
+                 !cmSystemTools::GetErrorOccurredFlag()) {
+        // The compiler uses the MSVC ABI so it needs a known runtime checks.
+        this->IssueMessage(MessageType::FATAL_ERROR,
+                           cmStrCat("MSVC_RUNTIME_CHECKS value '",
+                                    msvcRuntimeChecks, "' not known for this ",
+                                    lang, " compiler."));
+      }
+    }
+  }
+
   // Add MSVC debug information format flags if CMP0141 is NEW.
   // Add MSVC debug information format flags if CMP0141 is NEW.
   if (cm::optional<std::string> msvcDebugInformationFormat =
   if (cm::optional<std::string> msvcDebugInformationFormat =
         this->GetMSVCDebugFormatName(config, target)) {
         this->GetMSVCDebugFormatName(config, target)) {
@@ -2249,10 +2287,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
                        "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_",
                        "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_",
                        *msvcDebugInformationFormat))) {
                        *msvcDebugInformationFormat))) {
         this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions);
         this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions);
-      } else if ((this->Makefile->GetSafeDefinition(
-                    cmStrCat("CMAKE_", lang, "_COMPILER_ID")) == "MSVC"_s ||
-                  this->Makefile->GetSafeDefinition(
-                    cmStrCat("CMAKE_", lang, "_SIMULATE_ID")) == "MSVC"_s) &&
+      } else if ((compiler == "MSVC" || compilerSimulateId == "MSVC") &&
                  !cmSystemTools::GetErrorOccurredFlag()) {
                  !cmSystemTools::GetErrorOccurredFlag()) {
         // The compiler uses the MSVC ABI so it needs a known runtime library.
         // The compiler uses the MSVC ABI so it needs a known runtime library.
         this->IssueMessage(MessageType::FATAL_ERROR,
         this->IssueMessage(MessageType::FATAL_ERROR,

+ 4 - 1
Source/cmPolicies.h

@@ -549,7 +549,10 @@ class cmMakefile;
   SELECT(POLICY, CMP0182,                                                     \
   SELECT(POLICY, CMP0182,                                                     \
          "Create shared library archives by default on AIX.", 4, 0, 0, WARN)  \
          "Create shared library archives by default on AIX.", 4, 0, 0, WARN)  \
   SELECT(POLICY, CMP0183,                                                     \
   SELECT(POLICY, CMP0183,                                                     \
-         "add_feature_info() supports full Condition Syntax.", 4, 0, 0, WARN)
+         "add_feature_info() supports full Condition Syntax.", 4, 0, 0, WARN) \
+  SELECT(POLICY, CMP0184,                                                     \
+         "MSVC runtime check flags are selected by an abstraction.", 4, 0, 0, \
+         WARN)
 
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 2 - 0
Source/cmTarget.cxx

@@ -330,6 +330,7 @@ TargetProperty const StaticTargetProperties[] = {
   { "OSX_ARCHITECTURES"_s, IC::CanCompileSources },
   { "OSX_ARCHITECTURES"_s, IC::CanCompileSources },
   // ---- Windows
   // ---- Windows
   { "MSVC_DEBUG_INFORMATION_FORMAT"_s, IC::CanCompileSources },
   { "MSVC_DEBUG_INFORMATION_FORMAT"_s, IC::CanCompileSources },
+  { "MSVC_RUNTIME_CHECKS"_s, IC::CanCompileSources },
   { "MSVC_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
   { "MSVC_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
   { "VS_JUST_MY_CODE_DEBUGGING"_s, IC::CanCompileSources },
   { "VS_JUST_MY_CODE_DEBUGGING"_s, IC::CanCompileSources },
   { "VS_DEBUGGER_COMMAND"_s, IC::ExecutableTarget },
   { "VS_DEBUGGER_COMMAND"_s, IC::ExecutableTarget },
@@ -1763,6 +1764,7 @@ void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
     "OSX_ARCHITECTURES",
     "OSX_ARCHITECTURES",
     // ---- Windows
     // ---- Windows
     "MSVC_DEBUG_INFORMATION_FORMAT",
     "MSVC_DEBUG_INFORMATION_FORMAT",
+    "MSVC_RUNTIME_CHECKS",
     "MSVC_RUNTIME_LIBRARY",
     "MSVC_RUNTIME_LIBRARY",
     "VS_PLATFORM_TOOLSET",
     "VS_PLATFORM_TOOLSET",
     // ---- OpenWatcom
     // ---- OpenWatcom

+ 8 - 0
Tests/CMakeLists.txt

@@ -2128,6 +2128,14 @@ if(BUILD_TESTING)
     set_property(TEST MSVCDebugInformationFormat APPEND
     set_property(TEST MSVCDebugInformationFormat APPEND
       PROPERTY LABELS "CUDA" "Fortran")
       PROPERTY LABELS "CUDA" "Fortran")
 
 
+    set(MSVCRuntimeChecks_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+    if(CMAKE_Fortran_COMPILER)
+      list(APPEND MSVCRuntimeChecks_BUILD_OPTIONS -DCMake_TEST_Fortran=1)
+    endif()
+    ADD_TEST_MACRO(MSVCRuntimeChecks)
+    set_property(TEST MSVCRuntimeChecks APPEND
+      PROPERTY LABELS "CUDA" "Fortran")
+
     set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
     set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
     ADD_TEST_MACRO(MSVCRuntimeLibrary)
     ADD_TEST_MACRO(MSVCRuntimeLibrary)
     set_property(TEST MSVCRuntimeLibrary APPEND
     set_property(TEST MSVCRuntimeLibrary APPEND

+ 1 - 0
Tests/FortranOnly/CMakeLists.txt

@@ -1,4 +1,5 @@
 cmake_minimum_required(VERSION 3.10...3.25) # Enable CMP0091 and CMP0141.
 cmake_minimum_required(VERSION 3.10...3.25) # Enable CMP0091 and CMP0141.
+cmake_policy(SET CMP0184 NEW)
 project(FortranOnly Fortran)
 project(FortranOnly Fortran)
 message("CTEST_FULL_OUTPUT ")
 message("CTEST_FULL_OUTPUT ")
 
 

+ 105 - 0
Tests/MSVCRuntimeChecks/CMakeLists.txt

@@ -0,0 +1,105 @@
+cmake_minimum_required(VERSION 3.31)
+cmake_policy(SET CMP0184 NEW)
+
+# All runtime checks flags enables single preprocessor definition,
+# so override our table of flags to artificially add a definition we can check.
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/override-C.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/override-CXX.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_CUDA ${CMAKE_CURRENT_SOURCE_DIR}/override-CUDA.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran ${CMAKE_CURRENT_SOURCE_DIR}/override-Fortran.cmake)
+
+project(MSVCRuntimeChecks)
+if(CMake_TEST_CUDA STREQUAL "NVIDIA")
+  enable_language(CUDA)
+endif()
+if(CMake_TEST_Fortran)
+  enable_language(Fortran)
+endif()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+set(verify_default VERIFY_RTCsu)
+
+set(verify_def_PossibleDataLoss      -DVERIFY_RTCc)
+set(verify_def_StackFrameErrorCheck  -DVERIFY_RTCs)
+set(verify_def_UninitializedVariable -DVERIFY_RTCu)
+set(verify_def_RTCsu                 -DVERIFY_RTCsu)
+
+function(verify_combination format verify_format_defs lang src)
+  # Test that try_compile builds with this runtime check.
+  set(CMAKE_MSVC_RUNTIME_CHECKS "${format}")
+  set(CMAKE_TRY_COMPILE_CONFIGURATION "Debug")
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+
+  string(REPLACE ";" "_" format_var_name "${format}")
+  if (NOT format_var_name)
+    set(format_var_name "Empty")
+  endif()
+
+  if (NOT verify_format_defs)
+    foreach(format_for_def IN LISTS format)
+      list(APPEND verify_format_defs ${verify_def_${format_for_def}})
+    endforeach()
+  endif()
+
+  try_compile(${format_var_name}_COMPILES
+    ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${format_var_name}
+    ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+    COMPILE_DEFINITIONS ${verify_format_defs}
+    CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}
+    OUTPUT_VARIABLE ${format_var_name}_OUTPUT
+    )
+  if(${format_var_name}_COMPILES)
+    message(STATUS "try_compile ${lang} with \"${format}\" worked")
+  else()
+    string(REPLACE "\n" "\n  " ${format_var_name}_OUTPUT "  ${${format_var_name}_OUTPUT}")
+    message(SEND_ERROR "try_compile ${lang} with \"${format}\" failed:\n${${format_var_name}_OUTPUT}")
+  endif()
+
+  # Test that targets build with this runtime check.
+  set(CMAKE_MSVC_RUNTIME_CHECKS "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${format}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+  add_library(${format_var_name}-${lang} ${src})
+  set_property(TARGET ${format_var_name}-${lang} PROPERTY BOOL_TRUE TRUE)
+  target_compile_definitions(${format_var_name}-${lang} PRIVATE ${verify_format_defs})
+endfunction()
+
+function(verify lang src)
+  add_library(default-${lang} ${src})
+  target_compile_definitions(default-${lang} PRIVATE "$<$<CONFIG:Debug>:${verify_default}>")
+
+  # zero checkers
+  verify_combination("" "" ${lang} ${src})
+
+  # single checker
+  verify_combination(PossibleDataLoss "" ${lang} ${src})
+  verify_combination(StackFrameErrorCheck "" ${lang} ${src})
+  verify_combination(UninitializedVariable "" ${lang} ${src})
+  verify_combination(RTCsu "" ${lang} ${src})
+
+  # multiple checkers (without RTCsu merging)
+  verify_combination("PossibleDataLoss;StackFrameErrorCheck" "" ${lang} ${src})
+  verify_combination("PossibleDataLoss;UninitializedVariable" "" ${lang} ${src})
+
+  # multiple checkers (only RTCsu merging)
+  set(defs "${verify_def_RTCsu}")
+  verify_combination("StackFrameErrorCheck;UninitializedVariable" "${defs}" ${lang} ${src})
+  verify_combination("StackFrameErrorCheck;RTCsu" "${defs}" ${lang} ${src})
+  verify_combination("UninitializedVariable;RTCsu" "${defs}" ${lang} ${src})
+  verify_combination("StackFrameErrorCheck;UninitializedVariable;RTCsu" "${defs}" ${lang} ${src})
+
+  # multiple checkers (with RTCsu merging)
+  list(APPEND defs "${verify_def_PossibleDataLoss}")
+  verify_combination("PossibleDataLoss;StackFrameErrorCheck;UninitializedVariable" "${defs}" ${lang} ${src})
+  verify_combination("PossibleDataLoss;StackFrameErrorCheck;RTCsu" "${defs}" ${lang} ${src})
+  verify_combination("PossibleDataLoss;UninitializedVariable;RTCsu" "${defs}" ${lang} ${src})
+  verify_combination("PossibleDataLoss;StackFrameErrorCheck;UninitializedVariable;RTCsu" "${defs}" ${lang} ${src})
+endfunction()
+
+verify(C verify.c)
+verify(CXX verify.cxx)
+if(CMake_TEST_CUDA STREQUAL "NVIDIA")
+  verify(CUDA verify.cu)
+endif()
+if(CMake_TEST_Fortran)
+  verify(Fortran verify.F90)
+endif()

+ 3 - 0
Tests/MSVCRuntimeChecks/override-C.cmake

@@ -0,0 +1,3 @@
+set(delimiter ";")
+set(lang "C")
+include(${CMAKE_CURRENT_LIST_DIR}/override-common.cmake)

+ 3 - 0
Tests/MSVCRuntimeChecks/override-CUDA.cmake

@@ -0,0 +1,3 @@
+set(delimiter " ")
+set(lang "CUDA")
+include(${CMAKE_CURRENT_LIST_DIR}/override-common.cmake)

+ 3 - 0
Tests/MSVCRuntimeChecks/override-CXX.cmake

@@ -0,0 +1,3 @@
+set(delimiter ";")
+set(lang "CXX")
+include(${CMAKE_CURRENT_LIST_DIR}/override-common.cmake)

+ 3 - 0
Tests/MSVCRuntimeChecks/override-Fortran.cmake

@@ -0,0 +1,3 @@
+set(delimiter ";")
+set(lang "Fortran")
+include(${CMAKE_CURRENT_LIST_DIR}/override-common.cmake)

+ 50 - 0
Tests/MSVCRuntimeChecks/override-common.cmake

@@ -0,0 +1,50 @@
+if("${CMAKE_${lang}_COMPILER_ID};${CMAKE_${lang}_SIMULATE_ID};${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" STREQUAL "Clang;MSVC;GNU")
+  # Clang does not actually support these, so Windows-Clang passes no flags.
+  set(empty_PossibleDataLoss 1)
+  set(empty_StackFrameErrorCheck 1)
+  set(empty_UninitializedVariable 1)
+  set(empty_RTCsu 1)
+elseif("${CMAKE_${lang}_COMPILER_ID};${CMAKE_${lang}_SIMULATE_ID};${lang}" MATCHES "^Intel(LLVM)?;MSVC;Fortran$")
+  # IntelLLVM Fortran does not actually support these, so Windows-IntelLLVM-Fortran passes no flags.
+  set(empty_PossibleDataLoss 1)
+  set(empty_StackFrameErrorCheck 1)
+  set(empty_UninitializedVariable 0) # this one is supported
+  set(empty_RTCsu 1)
+elseif(CMAKE_${lang}_COMPILER_ID STREQUAL "MSVC" AND CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 14)
+  set(empty_PossibleDataLoss 1)
+  set(empty_StackFrameErrorCheck 0)
+  set(empty_UninitializedVariable 1)
+  set(empty_RTCsu 0)
+else()
+  set(empty_PossibleDataLoss 0)
+  set(empty_StackFrameErrorCheck 0)
+  set(empty_UninitializedVariable 0)
+  set(empty_RTCsu 0)
+endif()
+
+set(var "CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_PossibleDataLoss")
+if(empty_PossibleDataLoss AND ${var} STREQUAL "")
+  set("${var}" "-DTEST_RTCc")
+else()
+  string(REPLACE "-RTCc" "-RTCc${delimiter}-DTEST_RTCc" "${var}" "${${var}}")
+endif()
+set(var "CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_StackFrameErrorCheck")
+if(empty_StackFrameErrorCheck AND ${var} STREQUAL "")
+  set("${var}" "-DTEST_RTCs")
+else()
+  string(REPLACE "-RTCs" "-RTCs${delimiter}-DTEST_RTCs" "${var}" "${${var}}")
+  string(REPLACE "-GZ" "-GZ${delimiter}-DTEST_RTCs" "${var}" "${${var}}")
+endif()
+set(var "CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_UninitializedVariable")
+if(empty_UninitializedVariable AND ${var} STREQUAL "")
+  set("${var}" "-DTEST_RTCu")
+else()
+  string(REPLACE "-RTCu" "-RTCu${delimiter}-DTEST_RTCu" "${var}" "${${var}}")
+endif()
+set(var "CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_RTCsu")
+if(empty_RTCsu AND ${var} STREQUAL "")
+  set("${var}" "-DTEST_RTCsu")
+else()
+  string(REPLACE "-RTC1" "-RTC1${delimiter}-DTEST_RTCsu" "${var}" "${${var}}")
+  string(REPLACE "-GZ" "-GZ${delimiter}-DTEST_RTCsu" "${var}" "${${var}}")
+endif()

+ 1 - 0
Tests/MSVCRuntimeChecks/verify.F90

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCRuntimeChecks/verify.c

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCRuntimeChecks/verify.cu

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCRuntimeChecks/verify.cxx

@@ -0,0 +1 @@
+#include "verify.h"

+ 61 - 0
Tests/MSVCRuntimeChecks/verify.h

@@ -0,0 +1,61 @@
+/* Some compilers ignore the -RTC flags even if specified.  */
+#if (defined(_MSC_VER) && _MSC_VER <= 1310) || defined(__clang__) ||          \
+  defined(__INTEL_LLVM_COMPILER) || defined(__INTEL_COMPILER)
+#  define NO__MSVC_RUNTIME_CHECKS
+#endif
+
+#ifdef VERIFY_RTCc
+#  ifndef TEST_RTCc
+#    error "TEST_RTCc incorrectly not defined by enabled runtime check"
+#  endif
+#  if !defined(__MSVC_RUNTIME_CHECKS) && !defined(NO__MSVC_RUNTIME_CHECKS)
+#    error                                                                    \
+      "__MSVC_RUNTIME_CHECKS incorrectly not defined by enabled RTCc runtime check"
+#  endif
+#else
+#  ifdef TEST_RTCc
+#    error "TEST_RTCc incorrectly defined by disabled runtime check"
+#  endif
+#endif
+
+#ifdef VERIFY_RTCs
+#  ifndef TEST_RTCs
+#    error "TEST_RTCs incorrectly not defined by enabled runtime check"
+#  endif
+#  if !defined(__MSVC_RUNTIME_CHECKS) && !defined(NO__MSVC_RUNTIME_CHECKS)
+#    error                                                                    \
+      "__MSVC_RUNTIME_CHECKS incorrectly not defined by enabled RTCs runtime check"
+#  endif
+#else
+#  ifdef TEST_RTCs
+#    error "TEST_RTCs incorrectly defined by disabled runtime check"
+#  endif
+#endif
+
+#ifdef VERIFY_RTCu
+#  ifndef TEST_RTCu
+#    error "TEST_RTCu incorrectly not defined by enabled runtime check"
+#  endif
+#  if !defined(__MSVC_RUNTIME_CHECKS) && !defined(NO__MSVC_RUNTIME_CHECKS)
+#    error                                                                    \
+      "__MSVC_RUNTIME_CHECKS incorrectly not defined by enabled RTCu runtime check"
+#  endif
+#else
+#  ifdef TEST_RTCu
+#    error "TEST_RTCu incorrectly defined by disabled runtime check"
+#  endif
+#endif
+
+#ifdef VERIFY_RTCsu
+#  ifndef TEST_RTCsu
+#    error "TEST_RTCsu incorrectly not defined by enabled runtime check"
+#  endif
+#  if !defined(__MSVC_RUNTIME_CHECKS) && !defined(NO__MSVC_RUNTIME_CHECKS)
+#    error                                                                    \
+      "__MSVC_RUNTIME_CHECKS incorrectly not defined by enabled RTCsu runtime check"
+#  endif
+#else
+#  ifdef TEST_RTCsu
+#    error "TEST_RTCsu incorrectly defined by disabled runtime check"
+#  endif
+#endif

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -483,6 +483,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IBMClang|Fujitsu|F
   add_RunCMake_test(MetaCompileFeatures)
   add_RunCMake_test(MetaCompileFeatures)
 endif()
 endif()
 if(MSVC)
 if(MSVC)
+  add_RunCMake_test(MSVCRuntimeChecks)
   add_RunCMake_test(MSVCRuntimeLibrary)
   add_RunCMake_test(MSVCRuntimeLibrary)
   add_RunCMake_test(MSVCRuntimeTypeInfo)
   add_RunCMake_test(MSVCRuntimeTypeInfo)
   add_RunCMake_test(MSVCWarningFlags)
   add_RunCMake_test(MSVCWarningFlags)

+ 1 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error in CMakeLists.txt:
+  MSVC_RUNTIME_CHECKS value 'BogusValue' not known for this C compiler.
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$

+ 2 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NEW.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0184 NEW)
+include(CMP0184-common.cmake)

+ 4 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-NoEffect.cmake

@@ -0,0 +1,4 @@
+include(CMP0184-common.cmake)
+
+# Setting this policy after enable_language command has no effect.
+cmake_policy(SET CMP0184 NEW)

+ 2 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-OLD.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0184 OLD)
+include(CMP0184-common.cmake)

+ 2 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-WARN.cmake

@@ -0,0 +1,2 @@
+
+include(CMP0184-common.cmake)

+ 25 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMP0184-common.cmake

@@ -0,0 +1,25 @@
+enable_language(C)
+
+cmake_policy(GET CMP0184 cmp0184)
+if(cmp0184 STREQUAL "NEW")
+  if(NOT CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT)
+    message(SEND_ERROR "CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT not set under NEW behavior")
+  endif()
+else()
+  if(CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT)
+    message(SEND_ERROR "CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT is set under OLD behavior")
+  endif()
+endif()
+
+if(cmp0184 STREQUAL "NEW")
+  if(CMAKE_C_FLAGS_DEBUG MATCHES "[/-](RTC1|GZ)( |$)")
+    message(SEND_ERROR "CMAKE_C_FLAGS_DEBUG has -RTC1 flag under NEW behavior:\n ${CMAKE_C_FLAGS_DEBUG}")
+  endif()
+else()
+  if(NOT (CMAKE_C_FLAGS_DEBUG MATCHES "/(RTC1|GZ)( |$)"))
+    message(SEND_ERROR "CMAKE_C_FLAGS_DEBUG does not have /RTC1 flag under OLD behavior:\n ${CMAKE_C_FLAGS_DEBUG}")
+  endif()
+endif()
+
+set(CMAKE_MSVC_RUNTIME_CHECKS BogusValue)
+add_library(foo empty.c)

+ 3 - 0
Tests/RunCMake/MSVCRuntimeChecks/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.31)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 6 - 0
Tests/RunCMake/MSVCRuntimeChecks/RunCMakeTest.cmake

@@ -0,0 +1,6 @@
+include(RunCMake)
+
+run_cmake(CMP0184-WARN)
+run_cmake(CMP0184-OLD)
+run_cmake(CMP0184-NEW)
+run_cmake(CMP0184-NoEffect)

+ 0 - 0
Tests/RunCMake/MSVCRuntimeChecks/empty.c


+ 1 - 0
Tests/VSMARMASM/CMakeLists.txt

@@ -1,4 +1,5 @@
 cmake_minimum_required(VERSION 3.25) # Enable CMP0141
 cmake_minimum_required(VERSION 3.25) # Enable CMP0141
+cmake_policy(SET CMP0184 NEW)
 project(VSMARMASM C ASM_MARMASM)
 project(VSMARMASM C ASM_MARMASM)
 add_executable(VSMARMASM main.c foo.asm)
 add_executable(VSMARMASM main.c foo.asm)
 target_compile_options(VSMARMASM PRIVATE
 target_compile_options(VSMARMASM PRIVATE

+ 1 - 0
Tests/VSMASM/CMakeLists.txt

@@ -1,4 +1,5 @@
 cmake_minimum_required(VERSION 3.25) # Enable CMP0141
 cmake_minimum_required(VERSION 3.25) # Enable CMP0141
+cmake_policy(SET CMP0184 NEW)
 project(VSMASM C ASM_MASM)
 project(VSMASM C ASM_MASM)
 if(CMAKE_SIZEOF_VOID_P EQUAL 8)
 if(CMAKE_SIZEOF_VOID_P EQUAL 8)
   add_definitions(-DTESTx64)
   add_definitions(-DTESTx64)