Merge topic 'no-override-flow-control'

8aee7fdb32 cmState: Prohibit override of flow control commands

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5409
diff --git a/.gitlab/ci/docker/fedora31/install_deps.sh b/.gitlab/ci/docker/fedora31/install_deps.sh
index fa57f61..c1391e3 100755
--- a/.gitlab/ci/docker/fedora31/install_deps.sh
+++ b/.gitlab/ci/docker/fedora31/install_deps.sh
@@ -39,8 +39,10 @@
     fontconfig-devel \
     freetype-devel \
     gdal-devel \
+    gettext \
     giflib-devel \
     glew-devel \
+    gmock \
     gnutls-devel \
     gsl-devel \
     gtest-devel \
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 315552b..bab4f5a 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -49,7 +49,7 @@
 ### Fedora
 
 .fedora31:
-    image: "kitware/cmake:ci-fedora31-x86_64-2020-10-20"
+    image: "kitware/cmake:ci-fedora31-x86_64-2020-10-22"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
diff --git a/Help/command/site_name.rst b/Help/command/site_name.rst
index 1bcaead..09b5a9f 100644
--- a/Help/command/site_name.rst
+++ b/Help/command/site_name.rst
@@ -6,3 +6,7 @@
 .. code-block:: cmake
 
   site_name(variable)
+
+On UNIX-like platforms, if the variable ``HOSTNAME`` is set, its value
+will be executed as a command expected to print out the host name,
+much like the ``hostname`` command-line tool.
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index 7040ad5..62c4b7c 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -130,34 +130,34 @@
       the ``architecture`` field instead.
 
     ``architecture``
-
-      An optional string representing the platform name to use for generators
-      that support platforms.
-
     ``toolset``
 
-      An optional string representing the toolset name to use for generators
-      that support toolsets.
+      Optional fields representing the platform and toolset, respectively, for
+      generators that support them. Each may be either a string or an object
+      with the following fields:
 
-    ``cmakeGeneratorConfig``
+      ``value``
 
-      An optional string telling CMake how to handle the ``architecture`` and
-      ``toolset`` fields. Valid values are:
+        An optional string representing the value.
 
-      ``"default"``
+      ``strategy``
 
-        Set the platform and toolset using the ``architecture`` and ``toolset``
-        fields respectively. On non-Visual Studio generators, this will result
-        in an error if ``architecture`` or ``toolset`` are set.
+        An optional string telling CMake how to handle the ``architecture`` or
+        ``toolset`` field. Valid values are:
 
-      ``"ignore"``
+        ``"set"``
 
-        Do not set the platform or toolset at all, even on Visual Studio
-        generators. This is useful if, for example, a preset uses the Ninja
-        generator, and an IDE knows how to set up the Visual C++ environment
-        from the ``architecture`` and ``toolset`` fields. In that case, CMake
-        will ignore ``architecture`` and ``toolset``, but the IDE can use them
-        to set up the environment before invoking CMake.
+          Set the respective value. This will result in an error for generators
+          that do not support the respective field.
+
+        ``"external"``
+
+          Do not set the value, even if the generator supports it. This is
+          useful if, for example, a preset uses the Ninja generator, and an IDE
+          knows how to set up the Visual C++ environment from the
+          ``architecture`` and ``toolset`` fields. In that case, CMake will
+          ignore the field, but the IDE can use them to set up the environment
+          before invoking CMake.
 
     ``binaryDir``
 
@@ -308,6 +308,11 @@
 
     Path to the project source directory's parent directory.
 
+  ``${sourceDirName}``
+
+    The last filename component of ``${sourceDir}``. For example, if
+    ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
+
   ``${presetName}``
 
     Name specified in the preset's ``name`` field.
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
index ba4568f..57b063e 100644
--- a/Help/manual/presets/schema.json
+++ b/Help/manual/presets/schema.json
@@ -85,19 +85,57 @@
             "description": "An optional string representing the generator to use for the preset. If generator is not specified, it must be inherited from the inherits preset (unless this preset is hidden). Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
           },
           "architecture": {
-            "type": "string",
-            "description": "An optional string representing the platform name to use for Visual Studio generators."
+            "anyOf": [
+              {
+                "type": "string",
+                "description": "An optional string representing the platform for generators that support it."
+              },
+              {
+                "type": "object",
+                "description": "An optional object representing the platform for generators that support it.",
+                "properties": {
+                  "value": {
+                    "type": "string",
+                    "description": "An optional string representing the value."
+                  },
+                  "strategy": {
+                    "type": "string",
+                    "description": "An optional string telling CMake how to handle the field. Valid values are: \"set\" Set the respective value. This will result in an error for generators that do not support the respective field. \"external\" Do not set the value, even if the generator supports it. This is useful if, for example, a preset uses the Ninja generator, and an IDE knows how to set up the Visual C++ environment from the architecture and toolset fields. In that case, CMake will ignore the field, but the IDE can use them to set up the environment before invoking CMake.",
+                    "enum": [
+                      "set",
+                      "external"
+                    ]
+                  }
+                },
+                "additionalProperties": false
+              }
+            ]
           },
           "toolset": {
-            "type": "string",
-            "description": "An optional string representing the toolset name to use for Visual Studio generators."
-          },
-          "cmakeGeneratorConfig": {
-            "type": "string",
-            "description": "An optional string telling CMake how to handle the architecture and toolset fields. Valid values are: \"default\": Set the platform and toolset using the architecture and toolset fields respectively. On non-Visual Studio generators, this will result in an error if architecture or toolset are set. \"ignore\": Do not set the platform or toolset at all, even on Visual Studio generators. This is useful if, for example, a preset uses the Ninja generator, and an IDE knows how to set up the Visual C++ environment from the architecture and toolset fields. In that case, CMake will ignore architecture and toolset, but the IDE can use them to set up the environment before invoking CMake.",
-            "enum": [
-              "default",
-              "ignore"
+            "anyOf": [
+              {
+                "type": "string",
+                "description": "An optional string representing the toolset for generators that support it."
+              },
+              {
+                "type": "object",
+                "description": "An optional object representing the toolset for generators that support it.",
+                "properties": {
+                  "value": {
+                    "type": "string",
+                    "description": "An optional string representing the value."
+                  },
+                  "strategy": {
+                    "type": "string",
+                    "description": "An optional string telling CMake how to handle the field. Valid values are: \"set\" Set the respective value. This will result in an error for generators that do not support the respective field. \"external\" Do not set the value, even if the generator supports it. This is useful if, for example, a preset uses the Ninja generator, and an IDE knows how to set up the Visual C++ environment from the architecture and toolset fields. In that case, CMake will ignore the field, but the IDE can use them to set up the environment before invoking CMake.",
+                    "enum": [
+                      "set",
+                      "external"
+                    ]
+                  }
+                },
+                "additionalProperties": false
+              }
             ]
           },
           "binaryDir": {
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index 8109108..ca9fcf5 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -194,7 +194,14 @@
     "Extra command line flags to pass to the coverage tool")
 
   # set the site name
-  site_name(SITE)
+  if(COMMAND cmake_host_system_information)
+    cmake_host_system_information(RESULT _ctest_hostname QUERY HOSTNAME)
+    set(SITE "${_ctest_hostname}" CACHE STRING "Name of the computer/site where compile is being run")
+    unset(_ctest_hostname)
+  else()
+    # This code path is needed for CMake itself during bootstrap.
+    site_name(SITE)
+  endif()
   # set the build name
   if(NOT BUILDNAME)
     set(DART_COMPILER "${CMAKE_CXX_COMPILER}")
diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake
index 10e31b2..ff50869 100644
--- a/Modules/FindGTest.cmake
+++ b/Modules/FindGTest.cmake
@@ -12,6 +12,15 @@
 
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
+``GTest::gtest``
+  The Google Test ``gtest`` library, if found; adds Thread::Thread
+  automatically
+``GTest::gtest_main``
+  The Google Test ``gtest_main`` library, if found
+
+For backwards compatibility, this module defines additionally the
+following deprecated :prop_tgt:`IMPORTED` targets:
+
 ``GTest::GTest``
   The Google Test ``gtest`` library, if found; adds Thread::Thread
   automatically
@@ -24,7 +33,7 @@
 
 This module will set the following variables in your project:
 
-``GTEST_FOUND``
+``GTest_FOUND``
   Found the Google Testing framework
 ``GTEST_INCLUDE_DIRS``
   the directory containing the Google Test headers
@@ -62,7 +71,7 @@
     find_package(GTest REQUIRED)
 
     add_executable(foo foo.cc)
-    target_link_libraries(foo GTest::GTest GTest::Main)
+    target_link_libraries(foo GTest::gtest GTest::gtest_main)
 
     add_test(AllTestsInFoo foo)
 
@@ -167,8 +176,41 @@
     endif()
 endfunction()
 
+function(__gtest_define_backwards_compatible_library_targets)
+    set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} PARENT_SCOPE)
+
+    # Add targets mapping the same library names as defined in
+    # older versions of CMake's FindGTest
+    if(NOT TARGET GTest::GTest)
+        add_library(GTest::GTest INTERFACE IMPORTED)
+        target_link_libraries(GTest::GTest INTERFACE GTest::gtest)
+    endif()
+    if(NOT TARGET GTest::Main)
+        add_library(GTest::Main INTERFACE IMPORTED)
+        target_link_libraries(GTest::Main INTERFACE GTest::gtest_main)
+    endif()
+endfunction()
+
 #
 
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# first specifically look for the CMake version of GTest
+find_package(GTest QUIET NO_MODULE)
+
+# if we found the GTest cmake package then we are done, and
+# can print what we found and return.
+if(GTest_FOUND)
+    FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest HANDLE_COMPONENTS CONFIG_MODE)
+
+    set(GTEST_LIBRARIES      GTest::gtest)
+    set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
+
+    __gtest_define_backwards_compatible_library_targets()
+
+    return()
+endif()
+
 if(NOT DEFINED GTEST_MSVC_SEARCH)
     set(GTEST_MSVC_SEARCH MD)
 endif()
@@ -208,8 +250,6 @@
 )
 mark_as_advanced(GTEST_INCLUDE_DIR)
 
-# Allow GTEST_LIBRARY and GTEST_MAIN_LIBRARY to be set manually, as the
-# locations of the gtest and gtest_main libraries, respectively.
 if(NOT GTEST_LIBRARY)
     __gtest_find_and_select_library_configurations(GTEST gtest)
 endif()
@@ -217,54 +257,43 @@
     __gtest_find_and_select_library_configurations(GTEST_MAIN gtest_main)
 endif()
 
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
 
-if(GTEST_FOUND)
+if(GTest_FOUND)
     set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
     __gtest_append_debugs(GTEST_LIBRARIES      GTEST_LIBRARY)
     __gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY)
-    set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
 
     find_package(Threads QUIET)
 
-    if(NOT TARGET GTest::GTest)
+    if(NOT TARGET GTest::gtest)
         __gtest_determine_library_type(GTEST_LIBRARY)
-        add_library(GTest::GTest ${GTEST_LIBRARY_TYPE} IMPORTED)
+        add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED)
         if(TARGET Threads::Threads)
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_LINK_LIBRARIES Threads::Threads)
         endif()
         if(GTEST_LIBRARY_TYPE STREQUAL "SHARED")
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
         endif()
         if(GTEST_INCLUDE_DIRS)
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}")
         endif()
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "")
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "RELEASE")
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "DEBUG")
-    endif()
-    if(NOT TARGET GTest::Main)
-        __gtest_determine_library_type(GTEST_MAIN_LIBRARY)
-        add_library(GTest::Main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
-        set_target_properties(GTest::Main PROPERTIES
-            INTERFACE_LINK_LIBRARIES "GTest::GTest")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "RELEASE")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "DEBUG")
-    endif()
-
-    # Add targets mapping the same library names as defined in
-    # GTest's CMake package config.
-    if(NOT TARGET GTest::gtest)
-        add_library(GTest::gtest INTERFACE IMPORTED)
-        target_link_libraries(GTest::gtest INTERFACE GTest::GTest)
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "")
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "RELEASE")
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "DEBUG")
     endif()
     if(NOT TARGET GTest::gtest_main)
-        add_library(GTest::gtest_main INTERFACE IMPORTED)
-        target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
+        __gtest_determine_library_type(GTEST_MAIN_LIBRARY)
+        add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
+        set_target_properties(GTest::gtest_main PROPERTIES
+            INTERFACE_LINK_LIBRARIES "GTest::gtest")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "RELEASE")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG")
     endif()
+
+    __gtest_define_backwards_compatible_library_targets()
 endif()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 67d986a..48ea3f6 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 20201022)
+set(CMake_VERSION_PATCH 20201023)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index 7a04daa..a15614d 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -859,8 +859,10 @@
   if (presetData.isValid()) {
     auto preset = presetData.value<QCMakePreset>();
     dialog.setCurrentGenerator(preset.generator);
-    if (preset.setGenConfig) {
+    if (preset.setArchitecture) {
       dialog.setPlatform(preset.architecture);
+    }
+    if (preset.setToolset) {
       dialog.setToolset(preset.toolset);
     }
     dialog.setCompilerOption(CompilerOption::DefaultNative);
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 3789e93..2f41f70 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -551,9 +551,11 @@
     preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data()));
     preset.architecture =
       std::move(QString::fromLocal8Bit(p.Architecture.data()));
+    preset.setArchitecture = !p.ArchitectureStrategy ||
+      p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
     preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
-    preset.setGenConfig = !p.GeneratorConfig ||
-      p.GeneratorConfig == cmCMakePresetsFile::CMakeGeneratorConfig::Default;
+    preset.setToolset = !p.ToolsetStrategy ||
+      p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
     preset.enabled = it.Expanded &&
       std::find_if(this->AvailableGenerators.begin(),
                    this->AvailableGenerators.end(),
diff --git a/Source/QtDialog/QCMakePreset.cxx b/Source/QtDialog/QCMakePreset.cxx
index b10cf07..176f532 100644
--- a/Source/QtDialog/QCMakePreset.cxx
+++ b/Source/QtDialog/QCMakePreset.cxx
@@ -6,8 +6,9 @@
 {
   return lhs.name == rhs.name && lhs.displayName == rhs.displayName &&
     lhs.description == rhs.description && lhs.generator == rhs.generator &&
-    lhs.architecture == rhs.architecture && lhs.toolset == rhs.toolset &&
-    lhs.setGenConfig == rhs.setGenConfig && lhs.enabled == rhs.enabled;
+    lhs.architecture == rhs.architecture &&
+    lhs.setArchitecture == rhs.setArchitecture && lhs.toolset == rhs.toolset &&
+    lhs.setToolset == rhs.setToolset && lhs.enabled == rhs.enabled;
 }
 
 bool operator!=(const QCMakePreset& lhs, const QCMakePreset& rhs)
@@ -27,11 +28,13 @@
           (lhs.generator == rhs.generator &&
            (lhs.architecture < rhs.architecture ||
             (lhs.architecture == rhs.architecture &&
-             (lhs.toolset < rhs.toolset ||
-              (lhs.toolset == rhs.toolset &&
-               (lhs.setGenConfig < rhs.setGenConfig ||
-                (lhs.setGenConfig == rhs.setGenConfig &&
-                 (lhs.enabled < rhs.enabled))))))))))))));
+             (lhs.setArchitecture < rhs.setArchitecture ||
+              (lhs.setArchitecture == rhs.setArchitecture &&
+               (lhs.toolset < rhs.toolset ||
+                (lhs.toolset == rhs.toolset &&
+                 (lhs.setToolset < rhs.setToolset ||
+                  (lhs.setToolset == rhs.setToolset &&
+                   (lhs.enabled < rhs.enabled))))))))))))))));
 }
 
 bool operator<=(const QCMakePreset& lhs, const QCMakePreset& rhs)
diff --git a/Source/QtDialog/QCMakePreset.h b/Source/QtDialog/QCMakePreset.h
index 93d70d8..1609fcb 100644
--- a/Source/QtDialog/QCMakePreset.h
+++ b/Source/QtDialog/QCMakePreset.h
@@ -15,8 +15,9 @@
   QString description;
   QString generator;
   QString architecture;
+  bool setArchitecture;
   QString toolset;
-  bool setGenConfig;
+  bool setToolset;
   bool enabled;
 };
 
diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx
index b3bb6df..cf5db6e 100644
--- a/Source/cmCMakePresetsFile.cxx
+++ b/Source/cmCMakePresetsFile.cxx
@@ -30,7 +30,7 @@
 using CacheVariable = cmCMakePresetsFile::CacheVariable;
 using UnexpandedPreset = cmCMakePresetsFile::UnexpandedPreset;
 using ExpandedPreset = cmCMakePresetsFile::ExpandedPreset;
-using CMakeGeneratorConfig = cmCMakePresetsFile::CMakeGeneratorConfig;
+using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
 
 constexpr int MIN_VERSION = 1;
 constexpr int MAX_VERSION = 1;
@@ -212,8 +212,8 @@
     .Bind("find"_s, &UnexpandedPreset::DebugFind, PresetOptionalBoolHelper,
           false);
 
-ReadFileResult CMakeGeneratorConfigHelper(
-  cm::optional<CMakeGeneratorConfig>& out, const Json::Value* value)
+ReadFileResult ArchToolsetStrategyHelper(
+  cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
 {
   if (!value) {
     out = cm::nullopt;
@@ -224,19 +224,56 @@
     return ReadFileResult::INVALID_PRESET;
   }
 
-  if (value->asString() == "default") {
-    out = CMakeGeneratorConfig::Default;
+  if (value->asString() == "set") {
+    out = ArchToolsetStrategy::Set;
     return ReadFileResult::READ_OK;
   }
 
-  if (value->asString() == "ignore") {
-    out = CMakeGeneratorConfig::Ignore;
+  if (value->asString() == "external") {
+    out = ArchToolsetStrategy::External;
     return ReadFileResult::READ_OK;
   }
 
   return ReadFileResult::INVALID_PRESET;
 }
 
+std::function<ReadFileResult(UnexpandedPreset&, const Json::Value*)>
+ArchToolsetHelper(
+  std::string UnexpandedPreset::*valueField,
+  cm::optional<ArchToolsetStrategy> UnexpandedPreset::*strategyField)
+{
+  auto const objectHelper =
+    cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("value", valueField, PresetStringHelper, false)
+      .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
+  return [valueField, strategyField, objectHelper](
+           UnexpandedPreset& out, const Json::Value* value) -> ReadFileResult {
+    if (!value) {
+      (out.*valueField).clear();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isString()) {
+      out.*valueField = value->asString();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isObject()) {
+      return objectHelper(out, value);
+    }
+
+    return ReadFileResult::INVALID_PRESET;
+  };
+}
+
+auto const ArchitectureHelper = ArchToolsetHelper(
+  &UnexpandedPreset::Architecture, &UnexpandedPreset::ArchitectureStrategy);
+auto const ToolsetHelper = ArchToolsetHelper(
+  &UnexpandedPreset::Toolset, &UnexpandedPreset::ToolsetStrategy);
+
 auto const PresetHelper =
   cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
@@ -252,11 +289,8 @@
           false)
     .Bind("generator"_s, &UnexpandedPreset::Generator, PresetStringHelper,
           false)
-    .Bind("architecture"_s, &UnexpandedPreset::Architecture,
-          PresetStringHelper, false)
-    .Bind("toolset"_s, &UnexpandedPreset::Toolset, PresetStringHelper, false)
-    .Bind("cmakeGeneratorConfig"_s, &UnexpandedPreset::GeneratorConfig,
-          CMakeGeneratorConfigHelper, false)
+    .Bind("architecture"_s, ArchitectureHelper, false)
+    .Bind("toolset"_s, ToolsetHelper, false)
     .Bind("binaryDir"_s, &UnexpandedPreset::BinaryDir, PresetStringHelper,
           false)
     .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
@@ -353,8 +387,12 @@
     InheritString(preset.Generator, parent->second.Unexpanded.Generator);
     InheritString(preset.Architecture, parent->second.Unexpanded.Architecture);
     InheritString(preset.Toolset, parent->second.Unexpanded.Toolset);
-    if (!preset.GeneratorConfig) {
-      preset.GeneratorConfig = parent->second.Unexpanded.GeneratorConfig;
+    if (!preset.ArchitectureStrategy) {
+      preset.ArchitectureStrategy =
+        parent->second.Unexpanded.ArchitectureStrategy;
+    }
+    if (!preset.ToolsetStrategy) {
+      preset.ToolsetStrategy = parent->second.Unexpanded.ToolsetStrategy;
     }
     InheritString(preset.BinaryDir, parent->second.Unexpanded.BinaryDir);
     InheritOptionalBool(preset.WarnDev, parent->second.Unexpanded.WarnDev);
@@ -638,6 +676,10 @@
       out += cmSystemTools::GetParentDirectory(file.SourceDir);
       return ExpandMacroResult::Ok;
     }
+    if (macroName == "sourceDirName") {
+      out += cmSystemTools::GetFilenameName(file.SourceDir);
+      return ExpandMacroResult::Ok;
+    }
     if (macroName == "presetName") {
       out += preset.Name;
       return ExpandMacroResult::Ok;
diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsFile.h
index 87797d7..f6b159a 100644
--- a/Source/cmCMakePresetsFile.h
+++ b/Source/cmCMakePresetsFile.h
@@ -12,10 +12,10 @@
 class cmCMakePresetsFile
 {
 public:
-  enum class CMakeGeneratorConfig
+  enum class ArchToolsetStrategy
   {
-    Default,
-    Ignore,
+    Set,
+    External,
   };
 
   class CacheVariable
@@ -50,8 +50,9 @@
     std::string Description;
     std::string Generator;
     std::string Architecture;
+    cm::optional<ArchToolsetStrategy> ArchitectureStrategy;
     std::string Toolset;
-    cm::optional<CMakeGeneratorConfig> GeneratorConfig;
+    cm::optional<ArchToolsetStrategy> ToolsetStrategy;
     std::string BinaryDir;
 
     std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 70ef5af..3658d11 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -30,6 +30,7 @@
   bool ParseFunction(const char* name, long line);
   bool AddArgument(cmListFileLexer_Token* token,
                    cmListFileArgument::Delimiter delim);
+  cm::optional<cmListFileContext> CheckNesting();
   cmListFile* ListFile;
   cmListFileBacktrace Backtrace;
   cmMessenger* Messenger;
@@ -158,6 +159,17 @@
       return false;
     }
   }
+
+  // Check if all functions are nested properly.
+  if (auto badNesting = this->CheckNesting()) {
+    this->Messenger->IssueMessage(
+      MessageType::FATAL_ERROR,
+      "Flow control statements are not properly nested.",
+      this->Backtrace.Push(*badNesting));
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
   return true;
 }
 
@@ -317,6 +329,112 @@
   return true;
 }
 
+namespace {
+enum class NestingStateEnum
+{
+  If,
+  Else,
+  While,
+  Foreach,
+  Function,
+  Macro,
+};
+
+struct NestingState
+{
+  NestingStateEnum State;
+  cmListFileContext Context;
+};
+
+bool TopIs(std::vector<NestingState>& stack, NestingStateEnum state)
+{
+  return !stack.empty() && stack.back().State == state;
+}
+}
+
+cm::optional<cmListFileContext> cmListFileParser::CheckNesting()
+{
+  std::vector<NestingState> stack;
+
+  for (auto const& func : this->ListFile->Functions) {
+    auto const& name = func.LowerCaseName();
+    if (name == "if") {
+      stack.push_back({
+        NestingStateEnum::If,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "elseif") {
+      if (!TopIs(stack, NestingStateEnum::If)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.back() = {
+        NestingStateEnum::If,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      };
+    } else if (name == "else") {
+      if (!TopIs(stack, NestingStateEnum::If)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.back() = {
+        NestingStateEnum::Else,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      };
+    } else if (name == "endif") {
+      if (!TopIs(stack, NestingStateEnum::If) &&
+          !TopIs(stack, NestingStateEnum::Else)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "while") {
+      stack.push_back({
+        NestingStateEnum::While,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endwhile") {
+      if (!TopIs(stack, NestingStateEnum::While)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "foreach") {
+      stack.push_back({
+        NestingStateEnum::Foreach,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endforeach") {
+      if (!TopIs(stack, NestingStateEnum::Foreach)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "function") {
+      stack.push_back({
+        NestingStateEnum::Function,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endfunction") {
+      if (!TopIs(stack, NestingStateEnum::Function)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "macro") {
+      stack.push_back({
+        NestingStateEnum::Macro,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endmacro") {
+      if (!TopIs(stack, NestingStateEnum::Macro)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    }
+  }
+
+  if (!stack.empty()) {
+    return stack.back().Context;
+  }
+
+  return cm::nullopt;
+}
+
 // We hold either the bottom scope of a directory or a call/file context.
 // Discriminate these cases via the parent pointer.
 struct cmListFileBacktrace::Entry
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 727fc60..ed45c07 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -89,6 +89,14 @@
   {
   }
 
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+  cmListFileContext(const cmListFileContext& /*other*/) = default;
+  cmListFileContext(cmListFileContext&& /*other*/) = default;
+
+  cmListFileContext& operator=(const cmListFileContext& /*other*/) = default;
+  cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete;
+#endif
+
   static cmListFileContext FromCommandContext(
     cmCommandContext const& lfcc, std::string const& fileName,
     cm::optional<std::string> deferId = {})
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index fdf8307..d2cdb99 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -275,10 +275,9 @@
   { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
   { "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 },
   { "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 },
-  { "DebugInformationFormat", "Zi", "full debug", "debugEnabled", 0 },
   { "DebugInformationFormat", "debug:full", "full debug", "debugEnabled", 0 },
-  { "DebugInformationFormat", "Z7", "c7 compat", "debugOldStyleInfo", 0 },
-  { "DebugInformationFormat", "Zd", "line numbers", "debugLineInfoOnly", 0 },
+  { "DebugInformationFormat", "debug:minimal", "line numbers",
+    "debugLineInfoOnly", 0 },
   { "Optimization", "Od", "disable optimization", "optimizeDisabled", 0 },
   { "Optimization", "O1", "min space", "optimizeMinSpace", 0 },
   { "Optimization", "O3", "full optimize", "optimizeFull", 0 },
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 7d044ec..1771f0a 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1069,12 +1069,16 @@
     this->UnprocessedPresetVariables = expandedPreset->CacheVariables;
     this->UnprocessedPresetEnvironment = expandedPreset->Environment;
 
-    if (!expandedPreset->GeneratorConfig ||
-        expandedPreset->GeneratorConfig ==
-          cmCMakePresetsFile::CMakeGeneratorConfig::Default) {
+    if (!expandedPreset->ArchitectureStrategy ||
+        expandedPreset->ArchitectureStrategy ==
+          cmCMakePresetsFile::ArchToolsetStrategy::Set) {
       if (!this->GeneratorPlatformSet) {
         this->SetGeneratorPlatform(expandedPreset->Architecture);
       }
+    }
+    if (!expandedPreset->ToolsetStrategy ||
+        expandedPreset->ToolsetStrategy ==
+          cmCMakePresetsFile::ArchToolsetStrategy::Set) {
       if (!this->GeneratorToolsetSet) {
         this->SetGeneratorToolset(expandedPreset->Toolset);
       }
diff --git a/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx
index 6ee55c3..a95d008 100644
--- a/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx
+++ b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx
@@ -24,8 +24,9 @@
       /*description=*/"",
       /*generator=*/"Ninja",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/true,
     },
   });
@@ -48,8 +49,9 @@
       /*description=*/"",
       /*generator=*/"Ninja Multi-Config",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/true,
     },
   });
diff --git a/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx
index ee45d39..97dbb30 100644
--- a/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx
+++ b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx
@@ -32,8 +32,9 @@
       /*description=*/"",
       /*generator=*/"",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/true,
     },
     QCMakePreset{
@@ -42,8 +43,9 @@
       /*description=*/"",
       /*generator=*/"",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/true,
     },
     QCMakePreset{
@@ -52,8 +54,9 @@
       /*description=*/"Long Description",
       /*generator=*/"",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/true,
     },
     QCMakePreset{
@@ -62,8 +65,9 @@
       /*description=*/"",
       /*generator=*/"",
       /*architecture=*/"",
+      /*setArchitecture=*/true,
       /*toolset=*/"",
-      /*setGenConfig=*/true,
+      /*setToolset=*/true,
       /*enabled=*/false,
     },
   };
diff --git a/Tests/CMakeGUI/QCMakePresetTest.cxx b/Tests/CMakeGUI/QCMakePresetTest.cxx
index 8fd07e7..2081055 100644
--- a/Tests/CMakeGUI/QCMakePresetTest.cxx
+++ b/Tests/CMakeGUI/QCMakePresetTest.cxx
@@ -16,8 +16,9 @@
     /*description=*/"description",
     /*generator=*/"generator",
     /*architecture=*/"architecture",
+    /*setArchitecture=*/true,
     /*toolset=*/"toolset",
-    /*setGenConfig=*/true,
+    /*setToolset=*/true,
     /*enabled=*/true,
   };
 }
@@ -69,12 +70,14 @@
   QTest::newRow("architecture")
     << makePreset(&QCMakePreset::architecture, "other-architecture") << false
     << true << false;
+  QTest::newRow("setArchitecture")
+    << makePreset(&QCMakePreset::setArchitecture, false) << false << false
+    << true;
   QTest::newRow("toolset") << makePreset(&QCMakePreset::toolset,
                                          "other-toolset")
                            << false << false << true;
-  QTest::newRow("setGenConfig")
-    << makePreset(&QCMakePreset::setGenConfig, false) << false << false
-    << true;
+  QTest::newRow("setToolset")
+    << makePreset(&QCMakePreset::setToolset, false) << false << false << true;
   QTest::newRow("enabled") << makePreset(&QCMakePreset::enabled, false)
                            << false << false << true;
 }
diff --git a/Tests/CMakeLib/testOptional.cxx b/Tests/CMakeLib/testOptional.cxx
index de09c0f..2d7dd7c 100644
--- a/Tests/CMakeLib/testOptional.cxx
+++ b/Tests/CMakeLib/testOptional.cxx
@@ -82,6 +82,18 @@
   int Value = 0;
 };
 
+class NoMoveAssignEventLogger : public EventLogger
+{
+public:
+  using EventLogger::EventLogger;
+
+  NoMoveAssignEventLogger(const NoMoveAssignEventLogger&) = default;
+  NoMoveAssignEventLogger(NoMoveAssignEventLogger&&) = default;
+
+  NoMoveAssignEventLogger& operator=(const NoMoveAssignEventLogger&) = default;
+  NoMoveAssignEventLogger& operator=(NoMoveAssignEventLogger&&) = delete;
+};
+
 #define ASSERT_TRUE(x)                                                        \
   do {                                                                        \
     if (!(x)) {                                                               \
@@ -328,12 +340,28 @@
   o1 = o4; // Intentionally duplicated to test assigning an empty optional to
   // an empty optional
 
+  cm::optional<NoMoveAssignEventLogger> o5{ 1 };
+  auto const* v5 = &*o5;
+  const cm::optional<NoMoveAssignEventLogger> o6{ 2 };
+  auto const* v6 = &*o6;
+  o5 = std::move(o6);
+  const NoMoveAssignEventLogger e7{ 3 };
+  o5 = std::move(e7);
+
   expected = {
     { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
     { Event::COPY_CONSTRUCT, v1, v2, 4 },
     { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
     { Event::COPY_ASSIGN, v1, v3, 5 },
     { Event::DESTRUCT, v1, nullptr, 5 },
+    { Event::VALUE_CONSTRUCT, v5, nullptr, 1 },
+    { Event::VALUE_CONSTRUCT, v6, nullptr, 2 },
+    { Event::COPY_ASSIGN, v5, v6, 2 },
+    { Event::VALUE_CONSTRUCT, &e7, nullptr, 3 },
+    { Event::COPY_ASSIGN, v5, &e7, 3 },
+    { Event::DESTRUCT, &e7, nullptr, 3 },
+    { Event::DESTRUCT, v6, nullptr, 2 },
+    { Event::DESTRUCT, v5, nullptr, 3 },
     { Event::DESTRUCT, v3, nullptr, 5 },
     { Event::DESTRUCT, v2, nullptr, 4 },
   };
diff --git a/Tests/CMakeTests/EndStuffTestScript.cmake b/Tests/CMakeTests/EndStuffTestScript.cmake
index 9f40818..6a6b162 100644
--- a/Tests/CMakeTests/EndStuffTestScript.cmake
+++ b/Tests/CMakeTests/EndStuffTestScript.cmake
@@ -1,68 +1,40 @@
 message(STATUS "testname='${testname}'")
 
-if(testname STREQUAL bad_else) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"else()
-")
+function(do_end content)
+  file(WRITE "${dir}/${testname}.cmake" "${content}")
   execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
     RESULT_VARIABLE rv)
   if(NOT rv EQUAL 0)
     message(FATAL_ERROR "${testname} failed")
   endif()
+endfunction()
+
+if(testname STREQUAL bad_else) # fail
+  do_end("else()\n")
 
 elseif(testname STREQUAL bad_elseif) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"elseif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+  do_end("elseif()\n")
 
 elseif(testname STREQUAL bad_endforeach) # fail
-  endforeach()
+  do_end("endforeach()\n")
 
 elseif(testname STREQUAL bad_endfunction) # fail
-  endfunction()
+  do_end("endfunction()\n")
 
 elseif(testname STREQUAL bad_endif) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"cmake_minimum_required(VERSION 2.8)
-endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+  do_end("cmake_minimum_required(VERSION 2.8)\nendif()\n")
 
-elseif(testname STREQUAL endif_low_min_version) # pass
-  file(WRITE "${dir}/${testname}.cmake"
-"cmake_minimum_required(VERSION 1.2)
-endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+elseif(testname STREQUAL endif_low_min_version) # fail
+  do_end("cmake_minimum_required(VERSION 1.2)\nendif()\n")
 
-elseif(testname STREQUAL endif_no_min_version) # pass
-  file(WRITE "${dir}/${testname}.cmake"
-"endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+elseif(testname STREQUAL endif_no_min_version) # fail
+  do_end("endif()\n")
 
 elseif(testname STREQUAL bad_endmacro) # fail
-  endmacro()
+  do_end("endmacro()\n")
 
 elseif(testname STREQUAL bad_endwhile) # fail
-  endwhile()
+  do_end("endwhile()\n")
 
 else() # fail
   message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt
similarity index 100%
rename from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt
rename to Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-stderr.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-stderr.txt
rename to Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigIgnore.cmake b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake
similarity index 100%
rename from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigIgnore.cmake
rename to Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt
similarity index 100%
rename from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt
rename to Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-stderr.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-stderr.txt
rename to Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt
diff --git a/Tests/RunCMake/CMakePresets/CMakePresets.json.in b/Tests/RunCMake/CMakePresets/CMakePresets.json.in
index ea7df45..a8f89ff 100644
--- a/Tests/RunCMake/CMakePresets/CMakePresets.json.in
+++ b/Tests/RunCMake/CMakePresets/CMakePresets.json.in
@@ -72,6 +72,7 @@
         "TEST_DOLLAR": {
           "value": "${dollar}"
         },
+        "TEST_SOURCE_DIR_NAME": "${sourceDirName}",
         "TEST_ENV_REF": "$env{TEST_ENV_REF}",
         "TEST_ENV": "$env{TEST_ENV}",
         "TEST_D_ENV_REF": "$env{TEST_D_ENV_REF}",
@@ -451,28 +452,38 @@
       "binaryDir": "${sourceDir}/build"
     },
     {
-      "name": "CMakeGeneratorConfigNone",
+      "name": "ArchToolsetStrategyNone",
       "generator": "@RunCMake_GENERATOR@",
       "architecture": "a",
       "toolset": "a",
       "binaryDir": "${sourceDir}/build"
     },
     {
-      "name": "CMakeGeneratorConfigBase",
+      "name": "ArchToolsetStrategyBase",
       "generator": "@RunCMake_GENERATOR@",
-      "architecture": "a",
-      "toolset": "a",
-      "cmakeGeneratorConfig": "ignore",
+      "architecture": {
+        "value": "a",
+        "strategy": "external"
+      },
+      "toolset": {
+        "value": "a",
+        "strategy": "external"
+      },
       "binaryDir": "${sourceDir}/build"
     },
     {
-      "name": "CMakeGeneratorConfigDefault",
-      "inherits": "CMakeGeneratorConfigBase",
-      "cmakeGeneratorConfig": "default"
+      "name": "ArchToolsetStrategyDefault",
+      "inherits": "ArchToolsetStrategyBase",
+      "architecture": {
+        "strategy": "set"
+      },
+      "toolset": {
+        "strategy": "set"
+      }
     },
     {
-      "name": "CMakeGeneratorConfigIgnore",
-      "inherits": "CMakeGeneratorConfigBase"
+      "name": "ArchToolsetStrategyIgnore",
+      "inherits": "ArchToolsetStrategyBase"
     }
   ]
 }
diff --git a/Tests/RunCMake/CMakePresets/Good-stdout.txt b/Tests/RunCMake/CMakePresets/Good-stdout.txt
index 7adf1ca..75003c7 100644
--- a/Tests/RunCMake/CMakePresets/Good-stdout.txt
+++ b/Tests/RunCMake/CMakePresets/Good-stdout.txt
@@ -26,6 +26,7 @@
   TEST_PRESET_NAME:STRING="xGoodx"
   TEST_SOURCE_DIR:PATH="[^
 ]*/Tests/RunCMake/CMakePresets/Good"
+  TEST_SOURCE_DIR_NAME="Good"
   TEST_SOURCE_LIST:FILEPATH="[^
 ]*/Tests/RunCMake/CMakePresets/Good/CMakeLists\.txt"
   TEST_SOURCE_PARENT_DIR:PATH="[^
diff --git a/Tests/RunCMake/CMakePresets/Good.cmake b/Tests/RunCMake/CMakePresets/Good.cmake
index 55b85da..73a618d 100644
--- a/Tests/RunCMake/CMakePresets/Good.cmake
+++ b/Tests/RunCMake/CMakePresets/Good.cmake
@@ -17,6 +17,7 @@
 test_variable(TEST_PRESET_NAME "STRING" "xGoodx")
 test_variable(TEST_GENERATOR "UNINITIALIZED" "x${CMAKE_GENERATOR}x")
 test_variable(TEST_DOLLAR "UNINITIALIZED" "$")
+test_variable(TEST_SOURCE_DIR_NAME "UNINITIALIZED" "Good")
 test_variable(TEST_ENV_REF "UNINITIALIZED" "Environment variable")
 test_variable(TEST_ENV "UNINITIALIZED" "Environment variable")
 test_variable(TEST_D_ENV_REF "UNINITIALIZED" "xEnvironment variablex")
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt
similarity index 100%
copy from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt
copy to Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt
diff --git a/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt
new file mode 100644
index 0000000..4a4d4ce
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in
new file mode 100644
index 0000000..9ec2cee
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in
@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "InvalidArchitectureStrategy",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "architecture": {
+        "strategy": {}
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-result.txt b/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-stderr.txt
deleted file mode 100644
index 72a20d5..0000000
--- a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig-stderr.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-^CMake Error: Could not read presets from [^
-]*/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig.json.in b/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig.json.in
deleted file mode 100644
index 1479c66..0000000
--- a/Tests/RunCMake/CMakePresets/InvalidCMakeGeneratorConfig.json.in
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "version": 1,
-  "configurePresets": [
-    {
-      "name": "InvalidCMakeGeneratorConfig",
-      "generator": "@RunCMake_GENERATOR@",
-      "binaryDir": "${sourceDir}/build",
-      "cmakeGeneratorConfig": {}
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt
similarity index 100%
copy from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt
copy to Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt
diff --git a/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt
new file mode 100644
index 0000000..fab3766
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig.json.in b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in
similarity index 61%
rename from Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig.json.in
rename to Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in
index 900c6df..7d2ab1f 100644
--- a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig.json.in
+++ b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in
@@ -2,10 +2,12 @@
   "version": 1,
   "configurePresets": [
     {
-      "name": "UnknownCMakeGeneratorConfig",
+      "name": "InvalidToolsetStrategy",
       "generator": "@RunCMake_GENERATOR@",
       "binaryDir": "${sourceDir}/build",
-      "cmakeGeneratorConfig": "unknown"
+      "toolset": {
+        "strategy": {}
+      }
     }
   ]
 }
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index dddf05f..bd84510 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -117,8 +117,10 @@
 run_cmake_presets(ErrorNoWarningDev)
 run_cmake_presets(ErrorNoWarningDeprecated)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
-run_cmake_presets(InvalidCMakeGeneratorConfig)
-run_cmake_presets(UnknownCMakeGeneratorConfig)
+run_cmake_presets(InvalidArchitectureStrategy)
+run_cmake_presets(UnknownArchitectureStrategy)
+run_cmake_presets(InvalidToolsetStrategy)
+run_cmake_presets(UnknownToolsetStrategy)
 run_cmake_presets(EmptyCacheKey)
 run_cmake_presets(EmptyEnvKey)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
@@ -196,9 +198,9 @@
     run_cmake_presets(VisualStudioInheritanceMultiSecond)
   endif()
 else()
-  run_cmake_presets(CMakeGeneratorConfigNone)
-  run_cmake_presets(CMakeGeneratorConfigDefault)
-  run_cmake_presets(CMakeGeneratorConfigIgnore)
+  run_cmake_presets(ArchToolsetStrategyNone)
+  run_cmake_presets(ArchToolsetStrategyDefault)
+  run_cmake_presets(ArchToolsetStrategyIgnore)
 endif()
 
 # Test bad command line arguments
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt
similarity index 100%
copy from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigDefault-result.txt
copy to Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt
diff --git a/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt
new file mode 100644
index 0000000..cf17881
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in
new file mode 100644
index 0000000..a3bf7c8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in
@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "UnknownArchitectureStrategy",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "architecture": {
+        "strategy": "unknown"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-result.txt b/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-stderr.txt b/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-stderr.txt
deleted file mode 100644
index b1759b0..0000000
--- a/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig-stderr.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-^CMake Error: Could not read presets from [^
-]*/Tests/RunCMake/CMakePresets/UnknownCMakeGeneratorConfig: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt
similarity index 100%
copy from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt
copy to Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt
diff --git a/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt
new file mode 100644
index 0000000..8f9be29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in
new file mode 100644
index 0000000..1668700
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in
@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "UnknownToolsetStrategy",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "toolset": {
+        "strategy": "unknown"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CTest/RunCMakeTest.cmake b/Tests/RunCMake/CTest/RunCMakeTest.cmake
index ffc8f78..b81f319 100644
--- a/Tests/RunCMake/CTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTest/RunCMakeTest.cmake
@@ -5,6 +5,7 @@
 unset(RunCMake_TEST_OPTIONS)
 
 run_cmake(NotOn)
+run_cmake(Site)
 
 function(run_CMakeCTestArguments)
   run_cmake_with_options(CMakeCTestArguments "-DCMAKE_CTEST_ARGUMENTS=--quiet\\;--output-log\\;output-log.txt")
diff --git a/Tests/RunCMake/CTest/Site.cmake b/Tests/RunCMake/CTest/Site.cmake
new file mode 100644
index 0000000..2c96f23
--- /dev/null
+++ b/Tests/RunCMake/CTest/Site.cmake
@@ -0,0 +1,5 @@
+include(CTest)
+get_property(site CACHE SITE PROPERTY VALUE)
+if(NOT "${site}" STREQUAL "${SITE}")
+  message(FATAL_ERROR "SITE is not a cache entry")
+endif()
diff --git a/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt b/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt
index 306c255..87fa746 100644
--- a/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt
+++ b/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt
@@ -1,8 +1,4 @@
-^CMake Error in FunctionUnmatched.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/FunctionUnmatched.cmake:[0-9]+ \(function\)
-
-  is not closed.
+^CMake Error at FunctionUnmatched\.cmake:[0-9]+ \(function\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt b/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt
index f4ff709..7904b87 100644
--- a/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt
+++ b/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt
@@ -1,8 +1,4 @@
-^CMake Error at FunctionUnmatchedForeach.cmake:[0-9]+ \(f\):
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/FunctionUnmatchedForeach.cmake:[0-9]+ \(foreach\)
-
-  is not closed.
+^CMake Error at FunctionUnmatchedForeach\.cmake:[0-9]+ \(endfunction\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt b/Tests/RunCMake/Syntax/ImproperNesting-result.txt
similarity index 100%
copy from Tests/RunCMake/CMakePresets/CMakeGeneratorConfigNone-result.txt
copy to Tests/RunCMake/Syntax/ImproperNesting-result.txt
diff --git a/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt b/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt
new file mode 100644
index 0000000..a209ef6
--- /dev/null
+++ b/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at ImproperNesting\.cmake:[0-9]+ \(endforeach\):
+  Flow control statements are not properly nested\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/ImproperNesting.cmake b/Tests/RunCMake/Syntax/ImproperNesting.cmake
new file mode 100644
index 0000000..47ff9f9
--- /dev/null
+++ b/Tests/RunCMake/Syntax/ImproperNesting.cmake
@@ -0,0 +1,7 @@
+message(FATAL_ERROR "This should not happen")
+
+foreach(i 1 2)
+  if(1)
+endforeach()
+endif()
+endif()
diff --git a/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt b/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt
index 440d863..a7af590 100644
--- a/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt
+++ b/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt
@@ -1,8 +1,4 @@
-^CMake Error in MacroUnmatched.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/MacroUnmatched.cmake:[0-9]+ \(macro\)
-
-  is not closed.
+^CMake Error at MacroUnmatched\.cmake:[0-9]+ \(macro\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt b/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt
index 820cd2e..30c4a4c 100644
--- a/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt
+++ b/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt
@@ -1,8 +1,4 @@
-^CMake Error at MacroUnmatchedForeach.cmake:[0-9]+ \(m\):
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/MacroUnmatchedForeach.cmake:[0-9]+ \(foreach\)
-
-  is not closed.
+^CMake Error at MacroUnmatchedForeach\.cmake:[0-9]+ \(endmacro\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/RunCMakeTest.cmake b/Tests/RunCMake/Syntax/RunCMakeTest.cmake
index 3fc769d..4d24657 100644
--- a/Tests/RunCMake/Syntax/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Syntax/RunCMakeTest.cmake
@@ -72,6 +72,7 @@
 run_cmake(UnterminatedBracket0)
 run_cmake(UnterminatedBracket1)
 run_cmake(UnterminatedBracketComment)
+run_cmake(ImproperNesting)
 
 # Variable expansion tests
 run_cmake(ExpandInAt)
diff --git a/Tests/RunCMake/if/duplicate-deep-else-stderr.txt b/Tests/RunCMake/if/duplicate-deep-else-stderr.txt
index ac2335c..ee886e0 100644
--- a/Tests/RunCMake/if/duplicate-deep-else-stderr.txt
+++ b/Tests/RunCMake/if/duplicate-deep-else-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at duplicate-deep-else.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-deep-else\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt b/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt
index ba6765c..60c8484 100644
--- a/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt
+++ b/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at duplicate-else-after-elseif.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-else-after-elseif\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/if/duplicate-else-stderr.txt b/Tests/RunCMake/if/duplicate-else-stderr.txt
index e0dd01f..518c43f 100644
--- a/Tests/RunCMake/if/duplicate-else-stderr.txt
+++ b/Tests/RunCMake/if/duplicate-else-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at duplicate-else.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-else\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/if/misplaced-elseif-stderr.txt b/Tests/RunCMake/if/misplaced-elseif-stderr.txt
index c4b0266..5138f11 100644
--- a/Tests/RunCMake/if/misplaced-elseif-stderr.txt
+++ b/Tests/RunCMake/if/misplaced-elseif-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at misplaced-elseif.cmake:[0-9]+ \(elseif\):
-  An ELSEIF command was found after an ELSE command.
+CMake Error at misplaced-elseif\.cmake:[0-9]+ \(elseif\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/while/EndAlone-stderr.txt b/Tests/RunCMake/while/EndAlone-stderr.txt
index 5fe6655..3195fa0 100644
--- a/Tests/RunCMake/while/EndAlone-stderr.txt
+++ b/Tests/RunCMake/while/EndAlone-stderr.txt
@@ -1,5 +1,4 @@
-^CMake Error at EndAlone.cmake:1 \(endwhile\):
-  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
-  structure.  Or its arguments did not match the opening WHILE command.
+^CMake Error at EndAlone\.cmake:[0-9]+ \(endwhile\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/while/EndAloneArgs-stderr.txt b/Tests/RunCMake/while/EndAloneArgs-stderr.txt
index a8c043d..1634e3b 100644
--- a/Tests/RunCMake/while/EndAloneArgs-stderr.txt
+++ b/Tests/RunCMake/while/EndAloneArgs-stderr.txt
@@ -1,5 +1,4 @@
-^CMake Error at EndAloneArgs.cmake:1 \(endwhile\):
-  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
-  structure.  Or its arguments did not match the opening WHILE command.
+^CMake Error at EndAloneArgs\.cmake:[0-9]+ \(endwhile\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/while/EndMissing-stderr.txt b/Tests/RunCMake/while/EndMissing-stderr.txt
index 964792f..1e3be4d 100644
--- a/Tests/RunCMake/while/EndMissing-stderr.txt
+++ b/Tests/RunCMake/while/EndMissing-stderr.txt
@@ -1,8 +1,4 @@
-^CMake Error in EndMissing.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/while/EndMissing.cmake:1 \(while\)
-
-  is not closed.
+^CMake Error at EndMissing\.cmake:[0-9]+ \(while\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/while/MissingArgument-stderr.txt b/Tests/RunCMake/while/MissingArgument-stderr.txt
index 7ff0971..59e8ee3 100644
--- a/Tests/RunCMake/while/MissingArgument-stderr.txt
+++ b/Tests/RunCMake/while/MissingArgument-stderr.txt
@@ -1,4 +1,11 @@
-^CMake Error at MissingArgument.cmake:1 \(while\):
+^CMake Error at MissingArgument\.cmake:[0-9]+ \(while\):
   while called with incorrect number of arguments
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at MissingArgument\.cmake:[0-9]+ \(endwhile\):
+  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
+  structure\.  Or its arguments did not match the opening WHILE command\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/while/MissingArgument.cmake b/Tests/RunCMake/while/MissingArgument.cmake
index 32eaa26..3fe2d97 100644
--- a/Tests/RunCMake/while/MissingArgument.cmake
+++ b/Tests/RunCMake/while/MissingArgument.cmake
@@ -1 +1,2 @@
 while()
+endwhile()
diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional
index 9a5d840..0defae1 100644
--- a/Utilities/std/cm/optional
+++ b/Utilities/std/cm/optional
@@ -68,16 +68,22 @@
 
   optional& operator=(nullopt_t) noexcept;
   optional& operator=(const optional& other);
-  optional& operator=(optional&& other) noexcept;
 
-  template <
-    typename U = T,
-    typename = typename std::enable_if<
-      !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
-      std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value &&
+  template <typename U = T>
+  typename std::enable_if<std::is_constructible<T, U&&>::value &&
+                            std::is_assignable<T&, U&&>::value,
+                          optional&>::type
+  operator=(optional<U>&& other) noexcept;
+
+  template <typename U = T>
+  typename std::enable_if<
+    !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
+      std::is_constructible<T, U&&>::value &&
+      std::is_assignable<T&, U&&>::value &&
       (!std::is_scalar<T>::value ||
-       !std::is_same<typename std::decay<U>::type, T>::value)>::type>
-  optional& operator=(U&& v);
+       !std::is_same<typename std::decay<U>::type, T>::value),
+    optional&>::type
+  operator=(U&& v);
 
   const T* operator->() const;
   T* operator->();
@@ -134,19 +140,24 @@
 
 template <typename T>
 optional<T>::optional(nullopt_t) noexcept
+  : optional()
 {
 }
 
 template <typename T>
 optional<T>::optional(const optional& other)
 {
-  *this = other;
+  if (other.has_value()) {
+    this->emplace(*other);
+  }
 }
 
 template <typename T>
 optional<T>::optional(optional&& other) noexcept
 {
-  *this = std::move(other);
+  if (other.has_value()) {
+    this->emplace(std::move(*other));
+  }
 }
 
 template <typename T>
@@ -192,7 +203,11 @@
 }
 
 template <typename T>
-optional<T>& optional<T>::operator=(optional&& other) noexcept
+template <typename U>
+typename std::enable_if<std::is_constructible<T, U&&>::value &&
+                          std::is_assignable<T&, U&&>::value,
+                        optional<T>&>::type
+optional<T>::operator=(optional<U>&& other) noexcept
 {
   if (other.has_value()) {
     if (this->has_value()) {
@@ -207,8 +222,15 @@
 }
 
 template <typename T>
-template <typename U, typename>
-optional<T>& optional<T>::operator=(U&& v)
+template <typename U>
+typename std::enable_if<
+  !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
+    std::is_constructible<T, U&&>::value &&
+    std::is_assignable<T&, U&&>::value &&
+    (!std::is_scalar<T>::value ||
+     !std::is_same<typename std::decay<U>::type, T>::value),
+  optional<T>&>::type
+optional<T>::operator=(U&& v)
 {
   if (this->has_value()) {
     this->value() = v;