Merge topic 'iwyu_errors'

fcacc319d9 IWYU: Return error code if user enables error reporting

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !8406
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
index 7590ee3..6bd23bf 100644
--- a/Auxiliary/cmake-mode.el
+++ b/Auxiliary/cmake-mode.el
@@ -372,7 +372,7 @@
   (interactive "s")
   (let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
          (buffer  (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
-         (command (concat cmake-mode-cmake-executable " " type " " (shell-quote-argument topic)))
+         (command (concat cmake-mode-cmake-executable " " type " " (if topic (shell-quote-argument topic) topic)))
          ;; Turn of resizing of mini-windows for shell-command.
          (resize-mini-windows nil)
          )
@@ -391,7 +391,7 @@
   (interactive "s")
   (let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
          (buffer  (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
-         (command (concat cmake-mode-cmake-executable " " type " " (shell-quote-argument topic)))
+         (command (concat cmake-mode-cmake-executable " " type " " (if topic (shell-quote-argument topic) topic)))
          ;; Turn of resizing of mini-windows for shell-command.
          (resize-mini-windows nil)
          )
diff --git a/Help/command/list.rst b/Help/command/list.rst
index 191003a..0c7a562 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -188,7 +188,7 @@
 
   .. versionadded:: 3.12
 
-  Transforms the list by applying an action to all or, by specifying a
+  Transforms the list by applying an ``<ACTION>`` to all or, by specifying a
   ``<SELECTOR>``, to the selected elements of the list, storing the result
   in-place or in the specified output variable.
 
@@ -205,42 +205,42 @@
     :command:`APPEND <string(APPEND)>`, :command:`PREPEND <string(PREPEND)>`
       Append, prepend specified value to each element of the list.
 
-      .. code-block:: cmake
+      .. signature::
+        list(TRANSFORM <list> (APPEND|PREPEND) <value> ...)
+        :target: TRANSFORM_APPEND
 
-        list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
+    :command:`TOLOWER <string(TOLOWER)>`, :command:`TOUPPER <string(TOUPPER)>`
+      Convert each element of the list to lower, upper characters.
 
-    :command:`TOUPPER <string(TOUPPER)>`, :command:`TOLOWER <string(TOLOWER)>`
-      Convert each element of the list to upper, lower characters.
-
-      .. code-block:: cmake
-
-        list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
+      .. signature::
+        list(TRANSFORM <list> (TOLOWER|TOUPPER) ...)
+        :target: TRANSFORM_TOLOWER
 
     :command:`STRIP <string(STRIP)>`
       Remove leading and trailing spaces from each element of the list.
 
-      .. code-block:: cmake
-
+      .. signature::
         list(TRANSFORM <list> STRIP ...)
+        :target: TRANSFORM_STRIP
 
     :command:`GENEX_STRIP <string(GENEX_STRIP)>`
       Strip any
       :manual:`generator expressions <cmake-generator-expressions(7)>`
       from each element of the list.
 
-      .. code-block:: cmake
-
+      .. signature::
         list(TRANSFORM <list> GENEX_STRIP ...)
+        :target: TRANSFORM_GENEX_STRIP
 
     :command:`REPLACE <string(REGEX REPLACE)>`:
       Match the regular expression as many times as possible and substitute
       the replacement expression for the match for each element of the list
       (same semantic as :command:`string(REGEX REPLACE)`).
 
-      .. code-block:: cmake
-
+      .. signature::
         list(TRANSFORM <list> REPLACE <regular_expression>
                                       <replace_expression> ...)
+        :target: TRANSFORM_REPLACE
 
   ``<SELECTOR>`` determines which elements of the list will be transformed.
   Only one type of selector can be specified at a time.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 9da3799..9d29dc3 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -104,6 +104,17 @@
     VERBATIM
   )
 
+Finally, the above example can be expressed in a more simple and robust way
+using an alternate generator expression:
+
+.. code-block:: cmake
+
+  add_custom_target(run_some_tool
+    COMMAND some_tool "$<LIST:TRANSFORM,$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>,PREPEND,-I>"
+    COMMAND_EXPAND_LISTS
+    VERBATIM
+  )
+
 A common mistake is to try to split a generator expression across multiple
 lines with indenting:
 
@@ -318,6 +329,15 @@
 List Expressions
 ----------------
 
+Most of the expressions in this section are closely associated with the
+:command:`list` command, providing the same capabilities, but in
+the form of a generator expression.
+
+.. _GenEx List Comparisons:
+
+List Comparisons
+^^^^^^^^^^^^^^^^
+
 .. genex:: $<IN_LIST:string,list>
 
   .. versionadded:: 3.12
@@ -325,9 +345,186 @@
   ``1`` if ``string`` is an item in the semicolon-separated ``list``, else ``0``.
   It uses case-sensitive comparisons.
 
-.. genex:: $<JOIN:list,string>
+.. _GenEx List Queries:
 
-  Joins the list with the content of ``string`` inserted between each item.
+List Queries
+^^^^^^^^^^^^
+
+.. genex:: $<LIST:LENGTH,list>
+
+  .. versionadded:: 3.27
+
+  Returns the list's length.
+
+.. genex:: $<LIST:GET,list,index,...>
+
+  .. versionadded:: 3.27
+
+  Returns the list of elements specified by indices from the list.
+
+.. genex:: $<LIST:SUBLIST,list,begin,length>
+
+  .. versionadded:: 3.27
+
+  Returns a sublist of the given list. If <length> is 0, an empty list will be
+  returned. If <length> is -1 or the list is smaller than <begin>+<length> then
+  the remaining elements of the list starting at <begin> will be returned.
+
+.. genex:: $<LIST:FIND,list,value>
+
+  .. versionadded:: 3.27
+
+  Returns the index of the element specified in the list or -1 if it wasn't
+  found.
+
+.. _GenEx List Transformations:
+
+List Transformations
+^^^^^^^^^^^^^^^^^^^^
+
+.. genex:: $<LIST:JOIN,list,glue>
+
+  .. versionadded:: 3.27
+
+  Returns a string which joins the list with the content of the ``glue`` string
+  inserted between each item.
+
+.. genex:: $<LIST:APPEND,list,element,...>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the elements appended.
+
+.. genex:: $<LIST:PREPEND,list,element,...>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the elements inserted at the beginning of the list.
+
+.. genex:: $<LIST:INSERT,list,index,element,...>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the elements inserted at the specified index. It is an
+  error to specify an out-of-range index. Valid indexes are 0 to N where N is
+  the length of the list, inclusive. An empty list has length 0.
+
+.. genex:: $<LIST:POP_BACK,list>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the last element was removed.
+
+.. genex:: $<LIST:POP_FRONT,list>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the first element was removed.
+
+.. genex:: $<LIST:REMOVE_ITEM,list,value,...>
+
+  .. versionadded:: 3.27
+
+  Returns a list with all instances of the given values were removed.
+
+.. genex:: $<LIST:REMOVE_AT,list,index,...>
+
+  .. versionadded:: 3.27
+
+  Returns a list with all values at given indices were removed.
+
+.. genex:: $<LIST:REMOVE_DUPLICATES,list>
+
+  .. versionadded:: 3.27
+
+  Returns a list where duplicated items were removed. The relative order of
+  items is preserved, but if duplicates are encountered, only the first
+  instance is preserved.
+
+.. genex:: $<LIST:FILTER,list,INCLUDE|EXCLUDE,regex>
+
+  .. versionadded:: 3.27
+
+  Returns a list with the items that match the regular expression ``regex``
+  were included or removed.
+
+.. genex:: $<LIST:TRANSFORM,list,ACTION[,SELECTOR]>
+
+  .. versionadded:: 3.27
+
+  Returns the list transformed by applying an ``ACTION`` to all or, by
+  specifying a ``SELECTOR``, to the selected elements of the list.
+
+  .. note::
+
+    The ``TRANSFORM`` sub-command does not change the number of elements in the
+    list. If a ``SELECTOR`` is specified, only some elements will be changed,
+    the other ones will remain the same as before the transformation.
+
+  ``ACTION`` specifies the action to apply to the elements of the list.
+  The actions have exactly the same semantics as of the
+  :command:`list(TRANSFORM)` command.  ``ACTION`` must be one of the following:
+
+    :command:`APPEND <list(TRANSFORM_APPEND)>`, :command:`PREPEND <list(TRANSFORM_APPEND)>`
+      Append, prepend specified value to each element of the list.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,(APPEND|PREPEND),value[,SELECTOR]>
+
+    :command:`TOLOWER <list(TRANSFORM_TOLOWER)>`, :command:`TOUPPER <list(TRANSFORM_TOLOWER)>`
+      Convert each element of the list to lower, upper characters.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,(TOLOWER|TOUPPER)[,SELECTOR]>
+
+    :command:`STRIP <list(TRANSFORM_STRIP)>`
+      Remove leading and trailing spaces from each element of the list.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,STRIP[,SELECTOR]>
+
+    :command:`REPLACE <list(TRANSFORM_REPLACE)>`:
+      Match the regular expression as many times as possible and substitute
+      the replacement expression for the match for each element of the list.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,REPLACE,regular_expression,replace_expression[,SELECTOR]>
+
+  ``SELECTOR`` determines which elements of the list will be transformed.
+  Only one type of selector can be specified at a time. When given,
+  ``SELECTOR`` must be one of the following:
+
+    ``AT``
+      Specify a list of indexes.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,ACTION,AT,index[,index...]>
+
+    ``FOR``
+      Specify a range with, optionally, an increment used to iterate over the
+      range.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,ACTION,FOR,start,stop[,step]>
+
+    ``REGEX``
+      Specify a regular expression.
+      Only elements matching the regular expression will be transformed.
+
+      .. code-block:: cmake
+
+        $<LIST:TRANSFORM,list,ACTION,REGEX,regular_expression>
+
+.. genex:: $<JOIN:list,glue>
+
+  Joins the list with the content of the ``glue`` string inserted between each
+  item.
 
 .. genex:: $<REMOVE_DUPLICATES:list>
 
@@ -344,6 +541,69 @@
   Includes or removes items from ``list`` that match the regular expression
   ``regex``.
 
+.. _GenEx List Ordering:
+
+List Ordering
+^^^^^^^^^^^^^
+
+.. genex:: $<LIST:REVERSE,list>
+
+  .. versionadded:: 3.27
+
+  Returns the list with the elements in reverse order.
+
+.. genex:: $<LIST:SORT,list[,(COMPARE:option|CASE:option|ORDER:option)]...>
+
+  .. versionadded:: 3.27
+
+  Returns the list sorted according the specified options.
+
+  Use one of the ``COMPARE`` options to select the comparison method
+  for sorting:
+
+    ``STRING``
+      Sorts a list of strings alphabetically.
+      This is the default behavior if the ``COMPARE`` option is not given.
+
+    ``FILE_BASENAME``
+      Sorts a list of pathnames of files by their basenames.
+
+    ``NATURAL``
+      Sorts a list of strings using natural order
+      (see ``strverscmp(3)`` manual), i.e. such that contiguous digits
+      are compared as whole numbers.
+      For example: the following list `10.0 1.1 2.1 8.0 2.0 3.1`
+      will be sorted as `1.1 2.0 2.1 3.1 8.0 10.0` if the ``NATURAL``
+      comparison is selected where it will be sorted as
+      `1.1 10.0 2.0 2.1 3.1 8.0` with the ``STRING`` comparison.
+
+  Use one of the ``CASE`` options to select a case sensitive or case
+  insensitive sort mode:
+
+    ``SENSITIVE``
+      List items are sorted in a case-sensitive manner.
+      This is the default behavior if the ``CASE`` option is not given.
+
+    ``INSENSITIVE``
+      List items are sorted case insensitively.  The order of
+      items which differ only by upper/lowercase is not specified.
+
+  To control the sort order, one of the ``ORDER`` options can be given:
+
+    ``ASCENDING``
+      Sorts the list in ascending order.
+      This is the default behavior when the ``ORDER`` option is not given.
+
+    ``DESCENDING``
+      Sorts the list in descending order.
+
+  This is an error to specify multiple times the same option. Various options
+  can be specified in any order:
+
+  .. code-block:: cmake
+
+    $<LIST:SORT,list,CASE:SENSITIVE,COMPARE:STRING,ORDER:DESCENDING>
+
 Path Expressions
 ----------------
 
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index 7794e45..7aea8e6 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -1057,6 +1057,12 @@
   a workflow preset may have the same name as a configure, build, test, or
   package preset.
 
+``vendor``
+  An optional map containing vendor-specific information. CMake does not
+  interpret the contents of this field except to verify that it is a map
+  if it does exist. However, it should follow the same conventions as the
+  root-level ``vendor`` field.
+
 ``displayName``
   An optional string with a human-friendly name of the preset.
 
diff --git a/Help/policy/CMP0105.rst b/Help/policy/CMP0105.rst
index 097a59a..aadc8d6 100644
--- a/Help/policy/CMP0105.rst
+++ b/Help/policy/CMP0105.rst
@@ -8,12 +8,13 @@
 
 In CMake 3.17 and below, link options are not used by the device link step.
 
-The ``OLD`` behavior for this policy is to ignore the link options.
+The ``OLD`` behavior for this policy is to ignore the link options during the
+device link step.
 
 The ``NEW`` behavior of this policy is to use the link options during the
 device link step.
 
-This policy was introduced in CMake version 3.17.  Use the
+This policy was introduced in CMake version 3.18.  Use the
 :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 Unlike many policies, CMake version |release| does *not* warn
 when this policy is not set and simply uses ``OLD`` behavior.
diff --git a/Help/release/dev/GenEx-LIST.rst b/Help/release/dev/GenEx-LIST.rst
new file mode 100644
index 0000000..f65a092
--- /dev/null
+++ b/Help/release/dev/GenEx-LIST.rst
@@ -0,0 +1,4 @@
+GenEx-LIST
+----------
+
+* The :genex:`LIST` generator expression was added to manage lists.
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 67044fb..403766e 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -345,6 +345,7 @@
     set(id_platform ${CMAKE_VS_PLATFORM_NAME})
     set(id_lang "${lang}")
     set(id_PostBuildEvent_Command "")
+    set(id_api_level "")
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$")
       set(id_cl_var "ClangClExecutable")
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Cc][Ll][Aa][Nn][Gg]([Cc][Ll]$|_[0-9])")
@@ -430,9 +431,10 @@
       set(id_system "")
     endif()
     if(id_keyword STREQUAL "Android")
+      set(id_api_level "<AndroidAPILevel>android-${CMAKE_SYSTEM_VERSION}</AndroidAPILevel>")
       if(CMAKE_GENERATOR MATCHES "Visual Studio 14")
         set(id_system_version "<ApplicationTypeRevision>2.0</ApplicationTypeRevision>")
-      elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[56]")
+      elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[567]")
         set(id_system_version "<ApplicationTypeRevision>3.0</ApplicationTypeRevision>")
       else()
         set(id_system_version "")
diff --git a/Modules/Compiler/NVHPC-Fortran.cmake b/Modules/Compiler/NVHPC-Fortran.cmake
index 5c06457..879c140 100644
--- a/Modules/Compiler/NVHPC-Fortran.cmake
+++ b/Modules/Compiler/NVHPC-Fortran.cmake
@@ -1,4 +1,4 @@
 include(Compiler/PGI-Fortran)
 include(Compiler/NVHPC)
 __compiler_nvhpc(Fortran)
-set(CMAKE_Fortran_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX "(^| )-Werror +[a-z][a-z-]+( |$)")
+set(CMAKE_Fortran_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX "(^| )-Werror([=,][a-z][a-z-]+)?( |$)")
diff --git a/Modules/Compiler/NVHPC.cmake b/Modules/Compiler/NVHPC.cmake
index 474ac80..0593456 100644
--- a/Modules/Compiler/NVHPC.cmake
+++ b/Modules/Compiler/NVHPC.cmake
@@ -13,5 +13,5 @@
 macro(__compiler_nvhpc lang)
   # Logic specific to NVHPC.
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
-  set(CMAKE_${lang}_COMPILE_OPTIONS_WARNING_AS_ERROR "-Werror" "all-warnings")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_WARNING_AS_ERROR "-Werror")
 endmacro()
diff --git a/Modules/CompilerId/VS-10.vcxproj.in b/Modules/CompilerId/VS-10.vcxproj.in
index 3598fc7..fa324d8 100644
--- a/Modules/CompilerId/VS-10.vcxproj.in
+++ b/Modules/CompilerId/VS-10.vcxproj.in
@@ -26,6 +26,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'" Label="Configuration">
     <ConfigurationType>@id_config_type@</ConfigurationType>
     @id_toolset@
+    @id_api_level@
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -44,7 +45,7 @@
       <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <MinimalRebuild>false</MinimalRebuild>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
-      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(ApplicationType)'!='Android'">MultiThreadedDebugDLL</RuntimeLibrary>
       <PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>TurnOffAllWarnings</WarningLevel>
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 4423ebb..06457d9 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -1042,7 +1042,11 @@
   endif()
 
   _CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library
-  foreach (cuda_lib cublasLt cufft curand nppc nvjpeg)
+  foreach (cuda_lib cublasLt cufft nvjpeg)
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib})
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS cudart_static_deps culibos)
+  endforeach()
+  foreach (cuda_lib curand nppc)
     _CUDAToolkit_find_and_add_import_lib(${cuda_lib})
     _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos)
   endforeach()
@@ -1146,7 +1150,12 @@
   _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS nvrtc_builtins nvJitLink)
   if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.5.0)
     _CUDAToolkit_find_and_add_import_lib(nvrtc_builtins_static ALT nvrtc-builtins_static DEPS cuda_driver)
-    _CUDAToolkit_find_and_add_import_lib(nvrtc_static DEPS nvrtc_builtins_static nvptxcompiler_static nvJitLink_static)
+    if(NOT TARGET CUDA::nvrtc_static)
+      _CUDAToolkit_find_and_add_import_lib(nvrtc_static DEPS nvrtc_builtins_static nvptxcompiler_static nvJitLink_static)
+      if(TARGET CUDA::nvrtc_static AND WIN32 AND NOT (BORLAND OR MINGW OR CYGWIN))
+        target_link_libraries(CUDA::nvrtc_static INTERFACE Ws2_32.lib)
+      endif()
+    endif()
   endif()
 
   _CUDAToolkit_find_and_add_import_lib(nvml ALT nvidia-ml nvml)
diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake
index 715f68b..bc60222 100644
--- a/Modules/Platform/Android-Determine.cmake
+++ b/Modules/Platform/Android-Determine.cmake
@@ -34,18 +34,13 @@
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
 # If using Android tools for Visual Studio, compile a sample project to get the
-# sysroot.
+# NDK path
 if(CMAKE_GENERATOR MATCHES "Visual Studio")
-  if(NOT CMAKE_SYSROOT)
+  if(NOT CMAKE_ANDROID_NDK)
     set(vcx_platform ${CMAKE_GENERATOR_PLATFORM})
-    if(CMAKE_GENERATOR MATCHES "Visual Studio 1[45]")
-      set(vcx_sysroot_var "Sysroot")
-    else()
-      set(vcx_sysroot_var "SysrootLink")
-    endif()
     if(CMAKE_GENERATOR MATCHES "Visual Studio 14")
       set(vcx_revision "2.0")
-    elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[56]")
+    elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[567]")
       set(vcx_revision "3.0")
     else()
       set(vcx_revision "")
@@ -62,16 +57,16 @@
       RESULT_VARIABLE VCXPROJ_INSPECT_RESULT
       )
     unset(_msbuild)
-    if(NOT CMAKE_SYSROOT AND VCXPROJ_INSPECT_OUTPUT MATCHES "CMAKE_SYSROOT=([^%\r\n]+)[\r\n]")
+    if(VCXPROJ_INSPECT_OUTPUT MATCHES "CMAKE_ANDROID_NDK=([^%\r\n]+)[\r\n]")
       # Strip VS diagnostic output from the end of the line.
-      string(REGEX REPLACE " \\(TaskId:[0-9]*\\)$" "" _sysroot "${CMAKE_MATCH_1}")
-      if(EXISTS "${_sysroot}")
-        file(TO_CMAKE_PATH "${_sysroot}" CMAKE_SYSROOT)
+      string(REGEX REPLACE " \\(TaskId:[0-9]*\\)$" "" _ndk "${CMAKE_MATCH_1}")
+      if(EXISTS "${_ndk}")
+        file(TO_CMAKE_PATH "${_ndk}" CMAKE_ANDROID_NDK)
       endif()
     endif()
     if(VCXPROJ_INSPECT_RESULT)
       message(CONFIGURE_LOG
-        "Determining the sysroot for the Android NDK failed.
+        "Determining the Android NDK failed from msbuild failed.
 The output was:
 ${VCXPROJ_INSPECT_RESULT}
 ${VCXPROJ_INSPECT_OUTPUT}
@@ -79,7 +74,7 @@
 ")
     else()
       message(CONFIGURE_LOG
-        "Determining the sysroot for the Android NDK succeeded.
+        "Determining the Android NDK succeeded.
 The output was:
 ${VCXPROJ_INSPECT_RESULT}
 ${VCXPROJ_INSPECT_OUTPUT}
diff --git a/Modules/Platform/Android/VCXProjInspect.vcxproj.in b/Modules/Platform/Android/VCXProjInspect.vcxproj.in
index 6919d2c..f87d59b 100644
--- a/Modules/Platform/Android/VCXProjInspect.vcxproj.in
+++ b/Modules/Platform/Android/VCXProjInspect.vcxproj.in
@@ -19,6 +19,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@vcx_platform@'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <CharacterSet>MultiByte</CharacterSet>
+    <AndroidAPILevel>android-21</AndroidAPILevel>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -29,7 +30,7 @@
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@vcx_platform@'">
     <PostBuildEvent>
-      <Command>%40echo CMAKE_SYSROOT=$(@vcx_sysroot_var@)</Command>
+      <Command>%40echo CMAKE_ANDROID_NDK=$(VS_NdkRoot)</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 345a668..75f8304 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 26)
-set(CMake_VERSION_PATCH 20230412)
+set(CMake_VERSION_PATCH 20230426)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/IFW/cmCPackIFWCommon.cxx b/Source/CPack/IFW/cmCPackIFWCommon.cxx
index 5d995c3..4ff3a10 100644
--- a/Source/CPack/IFW/cmCPackIFWCommon.cxx
+++ b/Source/CPack/IFW/cmCPackIFWCommon.cxx
@@ -5,12 +5,11 @@
 #include <cstddef> // IWYU pragma: keep
 #include <sstream>
 #include <utility>
-#include <vector>
 
 #include "cmCPackGenerator.h"
 #include "cmCPackIFWGenerator.h"
 #include "cmCPackLog.h" // IWYU pragma: keep
-#include "cmStringAlgorithms.h"
+#include "cmList.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
 #include "cmVersionConfig.h"
@@ -76,12 +75,12 @@
 void cmCPackIFWCommon::ExpandListArgument(
   const std::string& arg, std::map<std::string, std::string>& argsOut)
 {
-  std::vector<std::string> args = cmExpandedList(arg, false);
+  cmList args{ arg };
   if (args.empty()) {
     return;
   }
 
-  std::size_t i = 0;
+  cmList::index_type i = 0;
   std::size_t c = args.size();
   if (c % 2) {
     argsOut[""] = args[i];
@@ -89,7 +88,7 @@
   }
 
   --c;
-  for (; i < c; i += 2) {
+  for (; i < static_cast<cmList::index_type>(c); i += 2) {
     argsOut[args[i]] = args[i + 1];
   }
 }
@@ -97,12 +96,12 @@
 void cmCPackIFWCommon::ExpandListArgument(
   const std::string& arg, std::multimap<std::string, std::string>& argsOut)
 {
-  std::vector<std::string> args = cmExpandedList(arg, false);
+  cmList args{ arg };
   if (args.empty()) {
     return;
   }
 
-  std::size_t i = 0;
+  cmList::index_type i = 0;
   std::size_t c = args.size();
   if (c % 2) {
     argsOut.insert(std::pair<std::string, std::string>("", args[i]));
@@ -110,7 +109,7 @@
   }
 
   --c;
-  for (; i < c; i += 2) {
+  for (; i < static_cast<cmList::index_type>(c); i += 2) {
     argsOut.insert(std::pair<std::string, std::string>(args[i], args[i + 1]));
   }
 }
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index bc14eb4..5724175 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -14,6 +14,7 @@
 #include "cmCPackLog.h" // IWYU pragma: keep
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -409,8 +410,8 @@
 
   // Repositories
   if (cmValue RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
-    std::vector<std::string> RepoAllVector = cmExpandedList(RepoAllStr);
-    for (std::string const& r : RepoAllVector) {
+    cmList RepoAllList{ RepoAllStr };
+    for (std::string const& r : RepoAllList) {
       this->GetRepository(r);
     }
   }
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
index 1668fb5..b759eff 100644
--- a/Source/CPack/IFW/cmCPackIFWPackage.cxx
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -15,6 +15,7 @@
 #include "cmCPackIFWInstaller.h"
 #include "cmCPackLog.h" // IWYU pragma: keep
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
@@ -455,7 +456,7 @@
   if (this->IsSetToEmpty(option)) {
     this->AlienAutoDependOn.clear();
   } else if (cmValue value = this->GetOption(option)) {
-    std::vector<std::string> depsOn = cmExpandedList(value);
+    cmList depsOn{ value };
     for (std::string const& d : depsOn) {
       DependenceStruct dep(d);
       if (this->Generator->Packages.count(dep.Name)) {
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index aeb3db3..1ce346f 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -18,6 +18,7 @@
 #include "cmCryptoHash.h"
 #include "cmGeneratedFileStream.h"
 #include "cmInstalledFile.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmUuid.h"
@@ -239,7 +240,7 @@
 
   cmValue patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
   if (patchFilePath) {
-    std::vector<std::string> patchFilePaths = cmExpandedList(patchFilePath);
+    cmList patchFilePaths{ patchFilePath };
 
     for (std::string const& p : patchFilePaths) {
       if (!this->Patch->LoadFragments(p)) {
@@ -322,8 +323,7 @@
   if (!cpackWixExtraObjects)
     return;
 
-  std::vector<std::string> expandedExtraObjects =
-    cmExpandedList(cpackWixExtraObjects);
+  cmList expandedExtraObjects{ cpackWixExtraObjects };
 
   for (std::string const& obj : expandedExtraObjects) {
     stream << " " << QuotePath(obj);
@@ -1160,7 +1160,7 @@
   if (!variableContent)
     return;
 
-  std::vector<std::string> list = cmExpandedList(variableContent);
+  cmList list{ variableContent };
   extensions.insert(list.begin(), list.end());
 }
 
@@ -1172,7 +1172,7 @@
     return;
   }
 
-  std::vector<std::string> list = cmExpandedList(variableContent);
+  cmList list{ variableContent };
   for (std::string const& str : list) {
     auto pos = str.find('=');
     if (pos != std::string::npos) {
@@ -1200,7 +1200,7 @@
   if (!variableContent)
     return;
 
-  std::vector<std::string> list = cmExpandedList(variableContent);
+  cmList list{ variableContent };
 
   for (std::string const& i : list) {
     stream << " " << QuotePath(i);
diff --git a/Source/CPack/cmCPackBundleGenerator.cxx b/Source/CPack/cmCPackBundleGenerator.cxx
index b3d425a..7e6e473 100644
--- a/Source/CPack/cmCPackBundleGenerator.cxx
+++ b/Source/CPack/cmCPackBundleGenerator.cxx
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "cmCPackLog.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -191,7 +192,7 @@
 
     cmValue sign_files = this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES");
 
-    std::vector<std::string> relFiles = cmExpandedList(sign_files);
+    cmList relFiles{ sign_files };
 
     // sign the files supplied by the user, ie. frameworks.
     for (auto const& file : relFiles) {
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 6ba28d1..34c56c9 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -20,6 +20,7 @@
 #include "cmCPackLog.h"
 #include "cmCryptoHash.h"
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -427,8 +428,7 @@
     // default
     control_tar.ClearPermissions();
 
-    std::vector<std::string> controlExtraList =
-      cmExpandedList(this->ControlExtra);
+    cmList controlExtraList{ this->ControlExtra };
     for (std::string const& i : controlExtraList) {
       std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
       std::string localcopy = this->WorkDir + "/" + filenamename;
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 68e7ba3..2a0409d 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmCPackLog.h"
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -128,8 +129,7 @@
       return 0;
     }
 
-    std::vector<std::string> languages =
-      cmExpandedList(this->GetOption("CPACK_DMG_SLA_LANGUAGES"));
+    cmList languages{ this->GetOption("CPACK_DMG_SLA_LANGUAGES") };
     if (languages.empty()) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl);
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index ea7b24b..0840e33 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -2,15 +2,6 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCPackFreeBSDGenerator.h"
 
-#include "cmArchiveWrite.h"
-#include "cmCPackArchiveGenerator.h"
-#include "cmCPackLog.h"
-#include "cmGeneratedFileStream.h"
-#include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
-#include "cmWorkingDirectory.h"
-
-// Needed for ::open() and ::stat()
 #include <algorithm>
 #include <ostream>
 #include <utility>
@@ -21,6 +12,15 @@
 
 #include <sys/stat.h>
 
+#include "cmArchiveWrite.h"
+#include "cmCPackArchiveGenerator.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmList.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+
 // Suffix used to tell libpkg what compression to use
 static const char FreeBSDPackageCompression[] = "txz";
 static const char FreeBSDPackageSuffix_17[] = ".pkg";
@@ -292,8 +292,7 @@
   manifest << ManifestKeyValue(
     "desc", var_lookup("CPACK_FREEBSD_PACKAGE_DESCRIPTION"));
   manifest << ManifestKeyValue("www", var_lookup("CPACK_FREEBSD_PACKAGE_WWW"));
-  std::vector<std::string> licenses =
-    cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE"));
+  cmList licenses{ var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE") };
   std::string licenselogic("single");
   if (licenses.empty()) {
     cmSystemTools::SetFatalErrorOccurred();
@@ -302,12 +301,10 @@
   }
   manifest << ManifestKeyValue("licenselogic", licenselogic);
   manifest << (ManifestKeyListValue("licenses") << licenses);
-  std::vector<std::string> categories =
-    cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_CATEGORIES"));
+  cmList categories{ var_lookup("CPACK_FREEBSD_PACKAGE_CATEGORIES") };
   manifest << (ManifestKeyListValue("categories") << categories);
   manifest << ManifestKeyValue("prefix", var_lookup("CMAKE_INSTALL_PREFIX"));
-  std::vector<std::string> deps =
-    cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_DEPS"));
+  cmList deps{ var_lookup("CPACK_FREEBSD_PACKAGE_DEPS") };
   if (!deps.empty()) {
     manifest << (ManifestKeyDepsValue("deps") << deps);
   }
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 2ac5b3d..83194a6 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmFileTimes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
@@ -216,8 +217,7 @@
   cmValue default_dir_install_permissions =
     this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(default_dir_install_permissions)) {
-    std::vector<std::string> items =
-      cmExpandedList(default_dir_install_permissions);
+    cmList items{ default_dir_install_permissions };
     for (const auto& arg : items) {
       if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) {
         cmCPackLogger(cmCPackLog::LOG_ERROR,
@@ -266,7 +266,7 @@
   // Run pre-build actions
   cmValue preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS");
   if (preBuildScripts) {
-    const auto scripts = cmExpandedList(preBuildScripts, false);
+    const cmList scripts{ preBuildScripts };
     for (const auto& script : scripts) {
       cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                     "Executing pre-build script: " << script << std::endl);
@@ -296,8 +296,7 @@
     std::string tempInstallDirectoryEnv =
       cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory);
     cmSystemTools::PutEnv(tempInstallDirectoryEnv);
-    std::vector<std::string> installCommandsVector =
-      cmExpandedList(installCommands);
+    cmList installCommandsVector{ installCommands };
     for (std::string const& ic : installCommandsVector) {
       cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl);
       std::string output;
@@ -333,8 +332,7 @@
   std::vector<cmsys::RegularExpression> ignoreFilesRegex;
   cmValue cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
   if (cpackIgnoreFiles) {
-    std::vector<std::string> ignoreFilesRegexString =
-      cmExpandedList(cpackIgnoreFiles);
+    cmList ignoreFilesRegexString{ cpackIgnoreFiles };
     for (std::string const& ifr : ignoreFilesRegexString) {
       cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                     "Create ignore files regex for: " << ifr << std::endl);
@@ -343,9 +341,8 @@
   }
   cmValue installDirectories = this->GetOption("CPACK_INSTALLED_DIRECTORIES");
   if (cmNonempty(installDirectories)) {
-    std::vector<std::string> installDirectoriesVector =
-      cmExpandedList(installDirectories);
-    if (installDirectoriesVector.size() % 2 != 0) {
+    cmList installDirectoriesList{ installDirectories };
+    if (installDirectoriesList.size() % 2 != 0) {
       cmCPackLogger(
         cmCPackLog::LOG_ERROR,
         "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> "
@@ -355,10 +352,10 @@
           << std::endl);
       return 0;
     }
-    std::vector<std::string>::iterator it;
+    cmList::iterator it;
     const std::string& tempDir = tempInstallDirectory;
-    for (it = installDirectoriesVector.begin();
-         it != installDirectoriesVector.end(); ++it) {
+    for (it = installDirectoriesList.begin();
+         it != installDirectoriesList.end(); ++it) {
       std::vector<std::pair<std::string, std::string>> symlinkedFiles;
       cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
       cmsys::Glob gl;
@@ -485,7 +482,7 @@
   if (cmakeScripts && !cmakeScripts->empty()) {
     cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                   "- Install scripts: " << cmakeScripts << std::endl);
-    std::vector<std::string> cmakeScriptsVector = cmExpandedList(cmakeScripts);
+    cmList cmakeScriptsVector{ cmakeScripts };
     for (std::string const& installScript : cmakeScriptsVector) {
 
       cmCPackLogger(cmCPackLog::LOG_OUTPUT,
@@ -549,14 +546,12 @@
                       << std::endl);
       return 0;
     }
-    std::vector<std::string> cmakeProjectsVector =
-      cmExpandedList(cmakeProjects);
-    std::vector<std::string>::iterator it;
-    for (it = cmakeProjectsVector.begin(); it != cmakeProjectsVector.end();
-         ++it) {
-      if (it + 1 == cmakeProjectsVector.end() ||
-          it + 2 == cmakeProjectsVector.end() ||
-          it + 3 == cmakeProjectsVector.end()) {
+    cmList cmakeProjectsList{ cmakeProjects };
+    cmList::iterator it;
+    for (it = cmakeProjectsList.begin(); it != cmakeProjectsList.end(); ++it) {
+      if (it + 1 == cmakeProjectsList.end() ||
+          it + 2 == cmakeProjectsList.end() ||
+          it + 3 == cmakeProjectsList.end()) {
         cmCPackLogger(
           cmCPackLog::LOG_ERROR,
           "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. "
@@ -594,9 +589,8 @@
           cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
         cmValue installTypes = this->GetOption(installTypesVar);
         if (cmNonempty(installTypes)) {
-          std::vector<std::string> installTypesVector =
-            cmExpandedList(installTypes);
-          for (std::string const& installType : installTypesVector) {
+          cmList installTypesList{ installTypes };
+          for (std::string const& installType : installTypesList) {
             project.InstallationTypes.push_back(
               this->GetInstallationType(project.ProjectName, installType));
           }
@@ -1129,7 +1123,7 @@
     this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES",
                                      cmJoin(this->packageFileNames, ";"));
 
-    const auto scripts = cmExpandedList(postBuildScripts, false);
+    const cmList scripts{ postBuildScripts };
     for (const auto& script : scripts) {
       cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                     "Executing post-build script: " << script << std::endl);
@@ -1595,9 +1589,8 @@
     // Determine the installation types.
     cmValue installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
     if (cmNonempty(installTypes)) {
-      std::vector<std::string> installTypesVector =
-        cmExpandedList(installTypes);
-      for (std::string const& installType : installTypesVector) {
+      cmList installTypesList{ installTypes };
+      for (auto const& installType : installTypesList) {
         component->InstallationTypes.push_back(
           this->GetInstallationType(projectName, installType));
       }
@@ -1606,8 +1599,8 @@
     // Determine the component dependencies.
     cmValue depends = this->GetOption(macroPrefix + "_DEPENDS");
     if (cmNonempty(depends)) {
-      std::vector<std::string> dependsVector = cmExpandedList(depends);
-      for (std::string const& depend : dependsVector) {
+      cmList dependsList{ depends };
+      for (auto const& depend : dependsList) {
         cmCPackComponent* child = this->GetComponent(projectName, depend);
         component->Dependencies.push_back(child);
         child->ReverseDependencies.push_back(component);
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index d7119c5..38a9d59 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmCPackLog.h"
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -569,9 +570,8 @@
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "The cpackPackageExecutables: " << cpackPackageExecutables
                                                   << "." << std::endl);
-    std::vector<std::string> cpackPackageExecutablesVector =
-      cmExpandedList(cpackPackageExecutables);
-    if (cpackPackageExecutablesVector.size() % 2 != 0) {
+    cmList cpackPackageExecutablesList{ cpackPackageExecutables };
+    if (cpackPackageExecutablesList.size() % 2 != 0) {
       cmCPackLogger(
         cmCPackLog::LOG_ERROR,
         "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
@@ -579,9 +579,9 @@
           << std::endl);
       return 0;
     }
-    std::vector<std::string>::iterator it;
-    for (it = cpackPackageExecutablesVector.begin();
-         it != cpackPackageExecutablesVector.end(); ++it) {
+    cmList::iterator it;
+    for (it = cpackPackageExecutablesList.begin();
+         it != cpackPackageExecutablesList.end(); ++it) {
       std::string execName = *it;
       ++it;
       std::string linkName = *it;
@@ -622,9 +622,8 @@
   }
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "The cpackMenuLinks: " << cpackMenuLinks << "." << std::endl);
-  std::vector<std::string> cpackMenuLinksVector =
-    cmExpandedList(cpackMenuLinks);
-  if (cpackMenuLinksVector.size() % 2 != 0) {
+  cmList cpackMenuLinksList{ cpackMenuLinks };
+  if (cpackMenuLinksList.size() % 2 != 0) {
     cmCPackLogger(
       cmCPackLog::LOG_ERROR,
       "CPACK_NSIS_MENU_LINKS should contain pairs of <shortcut target> and "
@@ -636,9 +635,8 @@
   static cmsys::RegularExpression urlRegex(
     "^(mailto:|(ftps?|https?|news)://).*$");
 
-  std::vector<std::string>::iterator it;
-  for (it = cpackMenuLinksVector.begin(); it != cpackMenuLinksVector.end();
-       ++it) {
+  cmList::iterator it;
+  for (it = cpackMenuLinksList.begin(); it != cpackMenuLinksList.end(); ++it) {
     std::string sourceName = *it;
     const bool url = urlRegex.find(sourceName);
 
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 234bc59..90716e6 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -29,6 +29,7 @@
 #include "cmDocumentationEntry.h"
 #include "cmGlobalGenerator.h"
 #include "cmJSONState.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
@@ -509,8 +510,8 @@
       cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
                   "CPack generator not specified\n");
     } else {
-      std::vector<std::string> generatorsVector = cmExpandedList(*genList);
-      for (std::string const& gen : generatorsVector) {
+      cmList generatorsList{ *genList };
+      for (std::string const& gen : generatorsList) {
         cmMakefile::ScopePushPop raii(&globalMF);
         cmMakefile* mf = &globalMF;
         cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index b2fb069..a6e7ac5 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -14,6 +14,7 @@
 
 #include "cmCTest.h"
 #include "cmCTestVC.h"
+#include "cmList.h"
 #include "cmProcessOutput.h"
 #include "cmProcessTools.h"
 #include "cmStringAlgorithms.h"
@@ -215,7 +216,7 @@
 
 bool cmCTestGIT::UpdateByCustom(std::string const& custom)
 {
-  std::vector<std::string> git_custom_command = cmExpandedList(custom, true);
+  cmList git_custom_command{ custom, cmList::EmptyElements::Yes };
   std::vector<char const*> git_custom;
   git_custom.reserve(git_custom_command.size() + 1);
   for (std::string const& i : git_custom_command) {
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 0e67c41..e22ec4b 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -13,9 +13,9 @@
 
 #include "cmCTest.h"
 #include "cmCTestVC.h"
+#include "cmList.h"
 #include "cmProcessTools.h"
 #include "cmRange.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log)
@@ -460,7 +460,7 @@
 
 bool cmCTestP4::UpdateCustom(const std::string& custom)
 {
-  std::vector<std::string> p4_custom_command = cmExpandedList(custom, true);
+  cmList p4_custom_command{ custom, cmList::EmptyElements::Yes };
 
   std::vector<char const*> p4_custom;
   p4_custom.reserve(p4_custom_command.size() + 1);
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index ee06b29..461ad1a 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -33,6 +33,7 @@
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -521,7 +522,7 @@
 
   // set any environment variables
   if (!this->CTestEnv.empty()) {
-    std::vector<std::string> envArgs = cmExpandedList(this->CTestEnv);
+    cmList envArgs{ this->CTestEnv };
     cmSystemTools::AppendEnv(envArgs);
   }
 
@@ -625,7 +626,7 @@
   // do an initial cvs update as required
   command = this->UpdateCmd;
   for (std::string const& eu : this->ExtraUpdates) {
-    std::vector<std::string> cvsArgs = cmExpandedList(eu);
+    cmList cvsArgs{ eu };
     if (cvsArgs.size() == 2) {
       std::string fullCommand = cmStrCat(command, " update ", cvsArgs[1]);
       output.clear();
@@ -764,7 +765,7 @@
   }
 
   // run ctest, it may be more than one command in here
-  std::vector<std::string> ctestCommands = cmExpandedList(this->CTestCmd);
+  cmList ctestCommands{ this->CTestCmd };
   // for each variable/argument do a putenv
   for (std::string const& ctestCommand : ctestCommands) {
     command = ctestCommand;
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index a1933cc..a92f9f2 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -13,10 +13,10 @@
 #include "cmCTest.h"
 #include "cmCTestSubmitHandler.h"
 #include "cmCommand.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -64,14 +64,14 @@
   cmValue notesFilesVariable =
     this->Makefile->GetDefinition("CTEST_NOTES_FILES");
   if (notesFilesVariable) {
-    std::vector<std::string> notesFiles = cmExpandedList(*notesFilesVariable);
+    cmList notesFiles{ *notesFilesVariable };
     this->CTest->GenerateNotesFile(notesFiles);
   }
 
   cmValue extraFilesVariable =
     this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
   if (extraFilesVariable) {
-    std::vector<std::string> extraFiles = cmExpandedList(*extraFilesVariable);
+    cmList extraFiles{ *extraFilesVariable };
     if (!this->CTest->SubmitExtraFiles(extraFiles)) {
       this->SetError("problem submitting extra files.");
       return nullptr;
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 3ff8c8f..a095e5d 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -22,6 +22,7 @@
 #include "cmCurl.h"
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -160,7 +161,7 @@
   /* In windows, this will init the winsock stuff */
   ::curl_global_init(CURL_GLOBAL_ALL);
   std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
-  std::vector<std::string> args = cmExpandedList(curlopt);
+  cmList args{ curlopt };
   bool verifyPeerOff = false;
   bool verifyHostOff = false;
   for (std::string const& arg : args) {
@@ -499,7 +500,7 @@
   cmCTestCurl curl(this->CTest);
   curl.SetQuiet(this->Quiet);
   std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
-  std::vector<std::string> args = cmExpandedList(curlopt);
+  cmList args{ curlopt };
   curl.SetCurlOptions(args);
   auto submitInactivityTimeout = this->GetSubmitInactivityTimeout();
   if (submitInactivityTimeout != 0) {
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index f693ace..3adf33e 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -38,6 +38,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmJSONState.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
@@ -2235,19 +2236,19 @@
           } else if (key == "ATTACHED_FILES_ON_FAIL"_s) {
             cmExpandList(val, rt.AttachOnFail);
           } else if (key == "RESOURCE_LOCK"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
 
             rt.LockedResources.insert(lval.begin(), lval.end());
           } else if (key == "FIXTURES_SETUP"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
 
             rt.FixturesSetup.insert(lval.begin(), lval.end());
           } else if (key == "FIXTURES_CLEANUP"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
 
             rt.FixturesCleanup.insert(lval.begin(), lval.end());
           } else if (key == "FIXTURES_REQUIRED"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
 
             rt.FixturesRequired.insert(lval.begin(), lval.end());
           } else if (key == "TIMEOUT"_s) {
@@ -2260,12 +2261,12 @@
           } else if (key == "RUN_SERIAL"_s) {
             rt.RunSerial = cmIsOn(val);
           } else if (key == "FAIL_REGULAR_EXPRESSION"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
             for (std::string const& cr : lval) {
               rt.ErrorRegularExpressions.emplace_back(cr, cr);
             }
           } else if (key == "SKIP_REGULAR_EXPRESSION"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
             for (std::string const& cr : lval) {
               rt.SkipRegularExpressions.emplace_back(cr, cr);
             }
@@ -2292,7 +2293,7 @@
           } else if (key == "ENVIRONMENT_MODIFICATION"_s) {
             cmExpandList(val, rt.EnvironmentModification);
           } else if (key == "LABELS"_s) {
-            std::vector<std::string> Labels = cmExpandedList(val);
+            cmList Labels{ val };
             rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
             // sort the array
             std::sort(rt.Labels.begin(), rt.Labels.end());
@@ -2309,21 +2310,21 @@
               rt.Measurements[val] = "1";
             }
           } else if (key == "PASS_REGULAR_EXPRESSION"_s) {
-            std::vector<std::string> lval = cmExpandedList(val);
+            cmList lval{ val };
             for (std::string const& cr : lval) {
               rt.RequiredRegularExpressions.emplace_back(cr, cr);
             }
           } else if (key == "WORKING_DIRECTORY"_s) {
             rt.Directory = val;
           } else if (key == "TIMEOUT_AFTER_MATCH"_s) {
-            std::vector<std::string> propArgs = cmExpandedList(val);
+            cmList propArgs{ val };
             if (propArgs.size() != 2) {
               cmCTestLog(this->CTest, WARNING,
                          "TIMEOUT_AFTER_MATCH expects two arguments, found "
                            << propArgs.size() << std::endl);
             } else {
               rt.AlternateTimeout = cmDuration(atof(propArgs[0].c_str()));
-              std::vector<std::string> lval = cmExpandedList(propArgs[1]);
+              cmList lval{ propArgs[1] };
               for (std::string const& cr : lval) {
                 rt.TimeoutRegularExpressions.emplace_back(cr, cr);
               }
@@ -2365,7 +2366,7 @@
       std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
       if (cwd == rt.Directory) {
         if (key == "LABELS"_s) {
-          std::vector<std::string> DirectoryLabels = cmExpandedList(val);
+          cmList DirectoryLabels{ val };
           rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(),
                            DirectoryLabels.end());
 
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
index e9ec09e..fc5450e 100644
--- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -4,7 +4,6 @@
 
 #include <cassert>
 #include <utility>
-#include <vector>
 
 #include <cm/memory>
 
@@ -15,9 +14,9 @@
 #include "cmCursesPathWidget.h"
 #include "cmCursesStringWidget.h"
 #include "cmCursesWidget.h"
+#include "cmList.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -76,7 +75,7 @@
       if (stringsProp) {
         auto ow =
           cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1);
-        for (std::string const& opt : cmExpandedList(*stringsProp)) {
+        for (auto const& opt : cmList{ *stringsProp }) {
           ow->AddOption(opt);
         }
         ow->SetOption(*value);
diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake
index 3dc099f..d6e3e88 100644
--- a/Source/Modules/CMakeBuildUtilities.cmake
+++ b/Source/Modules/CMakeBuildUtilities.cmake
@@ -279,7 +279,7 @@
   set(ENABLE_LIBXML2 OFF)
   set(ENABLE_EXPAT OFF)
   set(ENABLE_PCREPOSIX OFF)
-  set(ENABLE_LibGCC OFF)
+  set(ENABLE_LIBGCC OFF)
   set(ENABLE_CNG OFF)
   set(ENABLE_TAR OFF)
   set(ENABLE_TAR_SHARED OFF)
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index c8eea38..c763cc6 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -55,6 +55,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmJSONState.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
 #include "cmState.h"
@@ -1468,7 +1469,7 @@
       ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
     if (labels) {
       xml.StartElement("Labels");
-      std::vector<std::string> args = cmExpandedList(*labels);
+      cmList args{ *labels };
       for (std::string const& i : args) {
         xml.Element("Label", i);
       }
@@ -1500,7 +1501,7 @@
 {
   std::string labelsForSubprojects =
     this->GetCTestConfiguration("LabelsForSubprojects");
-  std::vector<std::string> subprojects = cmExpandedList(labelsForSubprojects);
+  cmList subprojects{ labelsForSubprojects };
 
   // sort the array
   std::sort(subprojects.begin(), subprojects.end());
@@ -1508,7 +1509,7 @@
   auto new_end = std::unique(subprojects.begin(), subprojects.end());
   subprojects.erase(new_end, subprojects.end());
 
-  return subprojects;
+  return std::move(subprojects.data());
 }
 
 void cmCTest::EndXML(cmXMLWriter& xml)
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index b9d1f66..d95dcc4 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -12,6 +12,7 @@
 #include "cmsys/Glob.hxx"
 
 #include "cmGeneratedFileStream.h"
+#include "cmList.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
 #include "cmState.h"
@@ -531,15 +532,11 @@
   // make sure we only use unix style paths
   if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
     if (e.Value.find(';') != std::string::npos) {
-      std::vector<std::string> paths = cmExpandedList(e.Value);
-      const char* sep = "";
-      e.Value = "";
+      cmList paths{ e.Value };
       for (std::string& i : paths) {
         cmSystemTools::ConvertToUnixSlashes(i);
-        e.Value += sep;
-        e.Value += i;
-        sep = ";";
       }
+      e.Value = paths.to_string();
     } else {
       cmSystemTools::ConvertToUnixSlashes(e.Value);
     }
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index f6fdd48..1cb62b3 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -15,6 +15,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -303,8 +304,7 @@
       *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget,
       &dagChecker, this->GeneratorTarget, lang);
     // Convert ;-delimited list to single string
-    std::vector<std::string> args =
-      cmExpandedList(evaluatedLinklauncher, true);
+    cmList args{ evaluatedLinklauncher, cmList::EmptyElements::Yes };
     if (!args.empty()) {
       args[0] = this->LocalCommonGenerator->ConvertToOutputFormat(
         args[0], cmOutputConverter::SHELL);
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 5f408d0..f51a1c8 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -20,6 +20,7 @@
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -627,7 +628,7 @@
   // This is called to add the dependencies named by
   // <item>_LIB_DEPENDS.  The variable contains a semicolon-separated
   // list.  The list contains link-type;item pairs and just items.
-  std::vector<std::string> deplist = cmExpandedList(value);
+  cmList deplist{ value };
 
   // Look for entries meant for this configuration.
   std::vector<cmLinkItem> actual_libs;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index a93477b..6a5b4cc 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -15,6 +15,7 @@
 #include "cmComputeLinkDepends.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -858,8 +859,8 @@
     return false;
   }
 
-  auto items = cmExpandListWithBacktrace(*langFeature,
-                                         this->Target->GetBacktrace(), true);
+  auto items = cmExpandListWithBacktrace(
+    *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
 
   if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
       (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
@@ -1016,8 +1017,8 @@
       .first->second;
   }
 
-  auto items = cmExpandListWithBacktrace(*langFeature,
-                                         this->Target->GetBacktrace(), true);
+  auto items = cmExpandListWithBacktrace(
+    *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
 
   // replace LINKER: pattern
   this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
@@ -1072,8 +1073,8 @@
   }
   if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(cmStrCat(
         "CMAKE_", lang, "_RUNTIME_LIBRARY_LINK_OPTIONS_", runtimeLibrary))) {
-    std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
-    for (std::string const& i : libsVec) {
+    cmList libs{ *runtimeLinkOptions };
+    for (auto const& i : libs) {
       if (!cm::contains(this->ImplicitLinkLibs, i)) {
         this->AddItem({ i });
       }
@@ -1087,8 +1088,8 @@
   // linker language.
   std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
   if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
-    std::vector<std::string> libsVec = cmExpandedList(*libs);
-    for (std::string const& i : libsVec) {
+    cmList libsList{ *libs };
+    for (auto const& i : libsList) {
       if (!cm::contains(this->ImplicitLinkLibs, i)) {
         this->AddItem({ i });
       }
@@ -1099,8 +1100,8 @@
   // implied by the linker language.
   std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
   if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
-    std::vector<std::string> dirsVec = cmExpandedList(*dirs);
-    this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
+    cmList dirsList{ *dirs };
+    this->OrderLinkerSearchPath->AddLanguageDirectories(dirsList);
   }
 }
 
@@ -1370,15 +1371,15 @@
                          LinkUnknown);
   if (cmValue linkSuffixes =
         mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
-    std::vector<std::string> linkSuffixVec = cmExpandedList(*linkSuffixes);
-    for (std::string const& i : linkSuffixVec) {
+    cmList linkSuffixList{ *linkSuffixes };
+    for (auto const& i : linkSuffixList) {
       this->AddLinkExtension(i, LinkUnknown);
     }
   }
   if (cmValue sharedSuffixes =
         mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
-    std::vector<std::string> sharedSuffixVec = cmExpandedList(*sharedSuffixes);
-    for (std::string const& i : sharedSuffixVec) {
+    cmList sharedSuffixList{ *sharedSuffixes };
+    for (std::string const& i : sharedSuffixList) {
       this->AddLinkExtension(i, LinkShared);
     }
   }
@@ -2279,7 +2280,7 @@
                                    std::vector<std::string>& out,
                                    std::set<std::string>& emitted)
 {
-  std::vector<std::string> tmp = cmExpandedList(str);
+  cmList tmp{ str };
   for (std::string const& i : tmp) {
     if (emitted.insert(i).second) {
       out.push_back(i);
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 5de012a..288e107 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -18,6 +18,7 @@
 
 #include "cmCMakePath.h"
 #include "cmExpandedCommandArgument.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmState.h"
@@ -764,7 +765,9 @@
         cmValue rhs = this->Makefile.GetDefinition(args.nextnext->GetValue());
 
         newArgs.ReduceTwoArgs(
-          rhs && cm::contains(cmExpandedList(*rhs, true), *lhs), args);
+          rhs &&
+            cm::contains(cmList{ *rhs, cmList::EmptyElements::Yes }, *lhs),
+          args);
       }
 
       else if (this->Policy57Status == cmPolicies::WARN) {
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 3149ccf..02ee9e2 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -20,6 +20,7 @@
 #include "cmConfigureLog.h"
 #include "cmExportTryCompileFileGenerator.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
@@ -1024,7 +1025,7 @@
 
     if (cmValue varListStr = this->Makefile->GetDefinition(
           kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
-      std::vector<std::string> varList = cmExpandedList(*varListStr);
+      cmList varList{ *varListStr };
       vars.insert(varList.begin(), varList.end());
     }
 
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 14c22e3..7623ccf 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -17,6 +17,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmStateTypes.h"
@@ -116,7 +117,7 @@
                                /*outputConfig=*/outputConfig,
                                /*commandConfig=*/commandConfig,
                                /*target=*/nullptr);
-    cm::append(depends, cmExpandedList(ep));
+    cm::append(depends, cmList{ ep });
   }
   for (std::string& p : depends) {
     if (cmSystemTools::FileIsFullPath(p)) {
@@ -196,7 +197,7 @@
         clarg, ge, this->LG, useOutputConfig, this->OutputConfig,
         this->CommandConfig, target, &this->Utilities);
       if (this->CC->GetCommandExpandLists()) {
-        cm::append(argv, cmExpandedList(parsed_arg));
+        cm::append(argv, cmList{ parsed_arg });
       } else {
         argv.push_back(std::move(parsed_arg));
       }
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
index 5d0b208..5e7008b 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -10,6 +10,7 @@
 
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -148,7 +149,7 @@
         }
       } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") {
         std::string includes = property.second;
-        std::vector<std::string> includeList = cmExpandedList(includes);
+        cmList includeList{ includes };
         os << "LOCAL_EXPORT_C_INCLUDES := ";
         std::string end;
         for (std::string const& i : includeList) {
@@ -158,9 +159,8 @@
         os << "\n";
       } else if (property.first == "INTERFACE_LINK_OPTIONS") {
         os << "LOCAL_EXPORT_LDFLAGS := ";
-        std::vector<std::string> linkFlagsList =
-          cmExpandedList(property.second);
-        os << cmJoin(linkFlagsList, " ") << "\n";
+        cmList linkFlagsList{ property.second };
+        os << linkFlagsList.join(" ") << "\n";
       } else {
         os << "# " << property.first << " " << (property.second) << "\n";
       }
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 6e7ef4e..2ad2b47 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -17,6 +17,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -507,7 +508,7 @@
   if (!p) {
     return;
   }
-  std::vector<std::string> content = cmExpandedList(*p);
+  cmList content{ *p };
   ifaceProperties.insert(content.begin(), content.end());
 }
 
@@ -1245,7 +1246,7 @@
   const auto& targetProperties = gte->Target->GetProperties();
   if (cmValue exportProperties =
         targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
-    for (auto& prop : cmExpandedList(*exportProperties)) {
+    for (auto& prop : cmList{ *exportProperties }) {
       /* Black list reserved properties */
       if (cmHasLiteralPrefix(prop, "IMPORTED_") ||
           cmHasLiteralPrefix(prop, "INTERFACE_")) {
@@ -1309,7 +1310,22 @@
          << this->GetFileSetFiles(gte, fileSet, te) << "\n";
     }
 
-    os << "  )\nendif()\n\n";
+    os << "  )\nelse()\n  set_property(TARGET " << targetName
+       << "\n    APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES";
+    for (auto const& name : interfaceFileSets) {
+      auto* fileSet = gte->Target->GetFileSet(name);
+      if (!fileSet) {
+        gte->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("File set \"", name,
+                   "\" is listed in interface file sets of ", gte->GetName(),
+                   " but has not been created"));
+        return;
+      }
+
+      os << "\n      " << this->GetFileSetDirectories(gte, fileSet, te);
+    }
+    os << "\n  )\nendif()\n\n";
   }
 }
 
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index c6ebad5..f30c3c3 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -12,6 +12,7 @@
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -126,7 +127,7 @@
       std::string evalResult =
         this->FindTargets(p, target, std::string(), emitted);
 
-      std::vector<std::string> depends = cmExpandedList(evalResult);
+      cmList depends{ evalResult };
       for (std::string const& li : depends) {
         cmGeneratorTarget* tgt =
           target->GetLocalGenerator()->FindGeneratorTargetToUse(li);
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index e9e2921..8d7f33e 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -14,6 +14,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
@@ -567,13 +568,13 @@
     std::string systemIncludeDirs = makefile->GetSafeDefinition(
       "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
     if (!systemIncludeDirs.empty()) {
-      cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+      cm::append(allIncludeDirs, cmList{ systemIncludeDirs });
     }
 
     systemIncludeDirs = makefile->GetSafeDefinition(
       "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
     if (!systemIncludeDirs.empty()) {
-      cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+      cm::append(allIncludeDirs, cmList{ systemIncludeDirs });
     }
 
     auto end = cmRemoveDuplicates(allIncludeDirs);
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index 6201889..c7ce5b0 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -16,6 +16,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -418,7 +419,7 @@
 
   if (cmValue extraNaturesProp =
         mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) {
-    std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp);
+    cmList extraNatures{ *extraNaturesProp };
     for (std::string const& n : extraNatures) {
       xml.Element("nature", n);
     }
@@ -798,7 +799,7 @@
     mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
   if (this->CEnabled && cDefs) {
     // Expand the list.
-    std::vector<std::string> defs = cmExpandedList(*cDefs, true);
+    cmList defs{ *cDefs, cmList::EmptyElements::Yes };
 
     // the list must contain only definition-value pairs:
     if ((defs.size() % 2) == 0) {
@@ -830,7 +831,7 @@
     mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
   if (this->CXXEnabled && cxxDefs) {
     // Expand the list.
-    std::vector<std::string> defs = cmExpandedList(*cxxDefs, true);
+    cmList defs{ *cxxDefs, cmList::EmptyElements::Yes };
 
     // the list must contain only definition-value pairs:
     if ((defs.size() % 2) == 0) {
@@ -879,14 +880,14 @@
   if (this->CEnabled && !compiler.empty()) {
     std::string systemIncludeDirs =
       mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
-    std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs);
+    cmList dirs{ systemIncludeDirs };
     this->AppendIncludeDirectories(xml, dirs, emitted);
   }
   compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
   if (this->CXXEnabled && !compiler.empty()) {
     std::string systemIncludeDirs =
       mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
-    std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs);
+    cmList dirs{ systemIncludeDirs };
     this->AppendIncludeDirectories(xml, dirs, emitted);
   }
 
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 33901ac..205a691 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -14,6 +14,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -138,7 +139,7 @@
   // End of build_systems
   fout << "\n\t]";
   std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
-  std::vector<std::string> tokens = cmExpandedList(this->EnvSettings);
+  cmList tokens{ this->EnvSettings };
 
   if (!this->EnvSettings.empty()) {
     fout << ",";
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
index ef55abf..663bddc 100644
--- a/Source/cmFileCopier.cxx
+++ b/Source/cmFileCopier.cxx
@@ -9,6 +9,7 @@
 #include "cmExecutionStatus.h"
 #include "cmFSPermissions.h"
 #include "cmFileTimes.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -169,8 +170,7 @@
   cmValue default_dir_install_permissions = this->Makefile->GetDefinition(
     "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(default_dir_install_permissions)) {
-    std::vector<std::string> items =
-      cmExpandedList(*default_dir_install_permissions);
+    cmList items{ *default_dir_install_permissions };
     for (const auto& arg : items) {
       if (!this->CheckPermissions(arg, **mode)) {
         this->Status.SetError(
diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx
index b96ba6e..48a2570 100644
--- a/Source/cmFileSet.cxx
+++ b/Source/cmFileSet.cxx
@@ -12,6 +12,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -113,7 +114,7 @@
   std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
 
   for (auto const& entry : this->FileEntries) {
-    for (auto const& ex : cmExpandedList(entry.Value)) {
+    for (auto const& ex : cmList{ entry.Value }) {
       cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
       auto cge = ge.Parse(ex);
       result.push_back(std::move(cge));
@@ -129,7 +130,7 @@
   std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
 
   for (auto const& entry : this->DirectoryEntries) {
-    for (auto const& ex : cmExpandedList(entry.Value)) {
+    for (auto const& ex : cmList{ entry.Value }) {
       cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
       auto cge = ge.Parse(ex);
       result.push_back(std::move(cge));
@@ -148,7 +149,7 @@
   std::vector<std::string> result;
   for (auto const& cge : cges) {
     auto entry = cge->Evaluate(lg, config, target, dagChecker);
-    auto dirs = cmExpandedList(entry);
+    cmList dirs{ entry };
     for (std::string dir : dirs) {
       if (!cmSystemTools::FileIsFullPath(dir)) {
         dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
@@ -184,7 +185,7 @@
   cmGeneratorExpressionDAGChecker* dagChecker) const
 {
   auto files = cge->Evaluate(lg, config, target, dagChecker);
-  for (std::string file : cmExpandedList(files)) {
+  for (std::string file : cmList{ files }) {
     if (!cmSystemTools::FileIsFullPath(file)) {
       file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file);
     }
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 4df81d5..929c6c1 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -15,6 +15,7 @@
 
 #include "cmCMakePath.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -154,7 +155,7 @@
       }
       // ensure a macro is not specified as validator
       const auto& validatorName = args[j];
-      auto macros = cmExpandedList(this->Makefile->GetProperty("MACROS"));
+      cmList macros{ this->Makefile->GetProperty("MACROS") };
       if (std::find_if(macros.begin(), macros.end(),
                        [&validatorName](const std::string& item) {
                          return cmSystemTools::Strucmp(validatorName.c_str(),
@@ -403,7 +404,7 @@
       this->Makefile->GetDefinition("CMAKE_SYSTEM_PREFIX_PATH");
 
     // remove entries from CMAKE_SYSTEM_PREFIX_PATH
-    std::vector<std::string> expanded = cmExpandedList(*prefix_paths);
+    cmList expanded{ *prefix_paths };
     install_entry.remove_self(expanded);
     staging_entry.remove_self(expanded);
 
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index b1029e6..656703c 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -23,6 +23,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmDependencyProvider.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -2338,7 +2339,7 @@
     cmValue prefix_paths =
       this->Makefile->GetDefinition("CMAKE_SYSTEM_PREFIX_PATH");
     // remove entry from CMAKE_SYSTEM_PREFIX_PATH
-    std::vector<std::string> expanded = cmExpandedList(*prefix_paths);
+    cmList expanded{ *prefix_paths };
     long count = 0;
     for (const auto& path : expanded) {
       bool const to_add =
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index a47366b..9dcbc39 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -635,22 +635,48 @@
 
 using Arguments = Range<std::vector<std::string>>;
 
-bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx,
-                           const GeneratorExpressionContent* cnt,
-                           cm::string_view option, std::size_t count,
-                           int required = 1, bool exactly = true)
+bool CheckGenExParameters(cmGeneratorExpressionContext* ctx,
+                          const GeneratorExpressionContent* cnt,
+                          cm::string_view genex, cm::string_view option,
+                          std::size_t count, int required = 1,
+                          bool exactly = true)
 {
   if (static_cast<int>(count) < required ||
       (exactly && static_cast<int>(count) > required)) {
+    std::string nbParameters;
+    switch (required) {
+      case 1:
+        nbParameters = "one parameter";
+        break;
+      case 2:
+        nbParameters = "two parameters";
+        break;
+      case 3:
+        nbParameters = "three parameters";
+        break;
+      case 4:
+        nbParameters = "four parameters";
+        break;
+      default:
+        nbParameters = cmStrCat(std::to_string(required), " parameters");
+    }
     reportError(ctx, cnt->GetOriginalExpression(),
-                cmStrCat("$<PATH:", option, "> expression requires ",
-                         (exactly ? "exactly" : "at least"), ' ',
-                         (required == 1 ? "one parameter" : "two parameters"),
+                cmStrCat("$<", genex, ':', option, "> expression requires ",
+                         (exactly ? "exactly" : "at least"), ' ', nbParameters,
                          '.'));
     return false;
   }
   return true;
 };
+
+bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx,
+                           const GeneratorExpressionContent* cnt,
+                           cm::string_view option, std::size_t count,
+                           int required = 1, bool exactly = true)
+{
+  return CheckGenExParameters(ctx, cnt, "PATH"_s, option, count, required,
+                              exactly);
+}
 bool CheckPathParameters(cmGeneratorExpressionContext* ctx,
                          const GeneratorExpressionContent* cnt,
                          cm::string_view option, const Arguments& args,
@@ -658,6 +684,7 @@
 {
   return CheckPathParametersEx(ctx, cnt, option, args.size(), required);
 };
+
 std::string ToString(bool isTrue)
 {
   return isTrue ? "1" : "0";
@@ -681,9 +708,9 @@
     static auto processList =
       [](std::string const& arg,
          std::function<void(std::string&)> transform) -> std::string {
-      auto list = cmExpandedList(arg);
+      cmList list{ arg };
       std::for_each(list.begin(), list.end(), std::move(transform));
-      return cmJoin(list, ";");
+      return list.to_string();
     };
 
     static std::unordered_map<
@@ -1108,6 +1135,670 @@
   }
 } pathEqualNode;
 
+namespace {
+inline bool CheckListParametersEx(cmGeneratorExpressionContext* ctx,
+                                  const GeneratorExpressionContent* cnt,
+                                  cm::string_view option, std::size_t count,
+                                  int required = 1, bool exactly = true)
+{
+  return CheckGenExParameters(ctx, cnt, "LIST"_s, option, count, required,
+                              exactly);
+}
+inline bool CheckListParameters(cmGeneratorExpressionContext* ctx,
+                                const GeneratorExpressionContent* cnt,
+                                cm::string_view option, const Arguments& args,
+                                int required = 1)
+{
+  return CheckListParametersEx(ctx, cnt, option, args.size(), required);
+};
+
+inline cmList GetList(std::string const& list)
+{
+  return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes };
+}
+
+bool GetNumericArgument(const std::string& arg, int& value)
+{
+  try {
+    std::size_t pos;
+
+    value = std::stoi(arg, &pos);
+    if (pos != arg.length()) {
+      // this is not a number
+      return false;
+    }
+  } catch (const std::invalid_argument&) {
+    return false;
+  }
+
+  return true;
+}
+
+bool GetNumericArguments(
+  cmGeneratorExpressionContext* ctx, const GeneratorExpressionContent* cnt,
+  Arguments const& args, std::vector<int>& indexes,
+  cmList::ExpandElements expandElements = cmList::ExpandElements::No)
+{
+  using IndexRange = cmRange<Arguments::const_iterator>;
+  IndexRange arguments(args.begin(), args.end());
+  cmList list;
+  if (expandElements == cmList::ExpandElements::Yes) {
+    list = cmList{ args.begin(), args.end(), expandElements };
+    arguments = IndexRange{ list.begin(), list.end() };
+  }
+
+  for (auto const& value : arguments) {
+    int index;
+    if (!GetNumericArgument(value, index)) {
+      reportError(ctx, cnt->GetOriginalExpression(),
+                  cmStrCat("index: \"", value, "\" is not a valid index"));
+      return false;
+    }
+    indexes.push_back(index);
+  }
+  return true;
+}
+}
+
+static const struct ListNode : public cmGeneratorExpressionNode
+{
+  ListNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+  bool AcceptsArbitraryContentParameter() const override { return true; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    static std::unordered_map<
+      cm::string_view,
+      std::function<std::string(cmGeneratorExpressionContext*,
+                                const GeneratorExpressionContent*,
+                                Arguments&)>>
+      listCommands{
+        { "LENGTH"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "LENGTH"_s, args)) {
+              return std::to_string(GetList(args.front()).size());
+            }
+            return std::string{};
+          } },
+        { "GET"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "GET"_s, args.size(), 2,
+                                      false)) {
+              auto list = GetList(args.front());
+              if (list.empty()) {
+                reportError(ctx, cnt->GetOriginalExpression(),
+                            "given empty list");
+                return std::string{};
+              }
+
+              std::vector<int> indexes;
+              if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes,
+                                       cmList::ExpandElements::Yes)) {
+                return std::string{};
+              }
+              try {
+                return list.get_items(indexes.begin(), indexes.end())
+                  .to_string();
+              } catch (std::out_of_range& e) {
+                reportError(ctx, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "JOIN"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "JOIN"_s, args, 2)) {
+              return GetList(args.front()).join(args[1]);
+            }
+            return std::string{};
+          } },
+        { "SUBLIST"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "SUBLIST"_s, args, 3)) {
+              auto list = GetList(args.front());
+              if (!list.empty()) {
+                std::vector<int> indexes;
+                if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes)) {
+                  return std::string{};
+                }
+                if (indexes[0] < 0) {
+                  reportError(ctx, cnt->GetOriginalExpression(),
+                              cmStrCat("begin index: ", indexes[0],
+                                       " is out of range 0 - ",
+                                       list.size() - 1));
+                  return std::string{};
+                }
+                if (indexes[1] < -1) {
+                  reportError(ctx, cnt->GetOriginalExpression(),
+                              cmStrCat("length: ", indexes[1],
+                                       " should be -1 or greater"));
+                  return std::string{};
+                }
+                try {
+                  return list
+                    .sublist(static_cast<cmList::size_type>(indexes[0]),
+                             static_cast<cmList::size_type>(indexes[1]))
+                    .to_string();
+                } catch (std::out_of_range& e) {
+                  reportError(ctx, cnt->GetOriginalExpression(), e.what());
+                  return std::string{};
+                }
+              }
+            }
+            return std::string{};
+          } },
+        { "FIND"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "FIND"_s, args, 2)) {
+              auto list = GetList(args.front());
+              auto index = list.find(args[1]);
+              return index == cmList::npos ? "-1" : std::to_string(index);
+            }
+            return std::string{};
+          } },
+        { "APPEND"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "APPEND"_s, args.size(), 2,
+                                      false)) {
+              auto list = args.front();
+              args.advance(1);
+              return cmList::append(args.begin(), args.end(), list);
+            }
+            return std::string{};
+          } },
+        { "PREPEND"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "PREPEND"_s, args.size(), 2,
+                                      false)) {
+              auto list = args.front();
+              args.advance(1);
+              return cmList::prepend(args.begin(), args.end(), list);
+            }
+            return std::string{};
+          } },
+        { "INSERT"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "INSERT"_s, args.size(), 3,
+                                      false)) {
+              int index;
+              if (!GetNumericArgument(args[1], index)) {
+                reportError(
+                  ctx, cnt->GetOriginalExpression(),
+                  cmStrCat("index: \"", args[1], "\" is not a valid index"));
+                return std::string{};
+              }
+              try {
+                auto list = GetList(args.front());
+                args.advance(2);
+                list.insert_items(index, args.begin(), args.end());
+                return list.to_string();
+              } catch (std::out_of_range& e) {
+                reportError(ctx, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "POP_BACK"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "POP_BACK"_s, args)) {
+              auto list = GetList(args.front());
+              if (!list.empty()) {
+                list.pop_back();
+                return list.to_string();
+              }
+            }
+            return std::string{};
+          } },
+        { "POP_FRONT"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "POP_FRONT"_s, args)) {
+              auto list = GetList(args.front());
+              if (!list.empty()) {
+                list.pop_front();
+                return list.to_string();
+              }
+            }
+            return std::string{};
+          } },
+        { "REMOVE_DUPLICATES"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "REMOVE_DUPLICATES"_s, args)) {
+              return GetList(args.front()).remove_duplicates().to_string();
+            }
+            return std::string{};
+          } },
+        { "REMOVE_ITEM"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "REMOVE_ITEM"_s, args.size(),
+                                      2, false)) {
+              auto list = GetList(args.front());
+              args.advance(1);
+              cmList items{ args.begin(), args.end(),
+                            cmList::ExpandElements::Yes };
+              return list.remove_items(items.begin(), items.end()).to_string();
+            }
+            return std::string{};
+          } },
+        { "REMOVE_AT"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "REMOVE_AT"_s, args.size(), 2,
+                                      false)) {
+              auto list = GetList(args.front());
+              std::vector<int> indexes;
+              if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes,
+                                       cmList::ExpandElements::Yes)) {
+                return std::string{};
+              }
+              try {
+                return list.remove_items(indexes.begin(), indexes.end())
+                  .to_string();
+              } catch (std::out_of_range& e) {
+                reportError(ctx, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "FILTER"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "FILTER"_s, args, 3)) {
+              auto const& op = args[1];
+              if (op != "INCLUDE"_s && op != "EXCLUDE"_s) {
+                reportError(
+                  ctx, cnt->GetOriginalExpression(),
+                  cmStrCat("sub-command FILTER does not recognize operator \"",
+                           op, "\". It must be either INCLUDE or EXCLUDE."));
+                return std::string{};
+              }
+              try {
+                return GetList(args.front())
+                  .filter(args[2],
+                          op == "INCLUDE"_s ? cmList::FilterMode::INCLUDE
+                                            : cmList::FilterMode::EXCLUDE)
+                  .to_string();
+              } catch (std::invalid_argument&) {
+                reportError(
+                  ctx, cnt->GetOriginalExpression(),
+                  cmStrCat("sub-command FILTER, failed to compile regex \"",
+                           args[2], "\"."));
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "TRANSFORM"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "TRANSFORM"_s, args.size(), 2,
+                                      false)) {
+              auto list = GetList(args.front());
+              if (!list.empty()) {
+                struct ActionDescriptor
+                {
+                  ActionDescriptor(std::string name)
+                    : Name(std::move(name))
+                  {
+                  }
+                  ActionDescriptor(std::string name,
+                                   cmList::TransformAction action, int arity)
+                    : Name(std::move(name))
+                    , Action(action)
+                    , Arity(arity)
+                  {
+                  }
+
+                  operator const std::string&() const { return this->Name; }
+
+                  std::string Name;
+                  cmList::TransformAction Action;
+                  int Arity = 0;
+                };
+
+                static std::set<
+                  ActionDescriptor,
+                  std::function<bool(const std::string&, const std::string&)>>
+                  descriptors{
+                    { { "APPEND", cmList::TransformAction::APPEND, 1 },
+                      { "PREPEND", cmList::TransformAction::PREPEND, 1 },
+                      { "TOUPPER", cmList::TransformAction::TOUPPER, 0 },
+                      { "TOLOWER", cmList::TransformAction::TOLOWER, 0 },
+                      { "STRIP", cmList::TransformAction::STRIP, 0 },
+                      { "REPLACE", cmList::TransformAction::REPLACE, 2 } },
+                    [](const std::string& x, const std::string& y) {
+                      return x < y;
+                    }
+                  };
+
+                auto descriptor = descriptors.find(args.advance(1).front());
+                if (descriptor == descriptors.end()) {
+                  reportError(ctx, cnt->GetOriginalExpression(),
+                              cmStrCat(" sub-command TRANSFORM, ",
+                                       args.front(), " invalid action."));
+                  return std::string{};
+                }
+
+                // Action arguments
+                args.advance(1);
+                if (args.size() < descriptor->Arity) {
+                  reportError(ctx, cnt->GetOriginalExpression(),
+                              cmStrCat("sub-command TRANSFORM, action ",
+                                       descriptor->Name, " expects ",
+                                       descriptor->Arity, " argument(s)."));
+                  return std::string{};
+                }
+                std::vector<std::string> arguments;
+                if (descriptor->Arity > 0) {
+                  arguments = std::vector<std::string>(
+                    args.begin(), args.begin() + descriptor->Arity);
+                  args.advance(descriptor->Arity);
+                }
+
+                const std::string REGEX{ "REGEX" };
+                const std::string AT{ "AT" };
+                const std::string FOR{ "FOR" };
+                std::unique_ptr<cmList::TransformSelector> selector;
+
+                try {
+                  // handle optional arguments
+                  while (!args.empty()) {
+                    if ((args.front() == REGEX || args.front() == AT ||
+                         args.front() == FOR) &&
+                        selector) {
+                      reportError(ctx, cnt->GetOriginalExpression(),
+                                  cmStrCat("sub-command TRANSFORM, selector "
+                                           "already specified (",
+                                           selector->GetTag(), ")."));
+
+                      return std::string{};
+                    }
+
+                    // REGEX selector
+                    if (args.front() == REGEX) {
+                      if (args.advance(1).empty()) {
+                        reportError(
+                          ctx, cnt->GetOriginalExpression(),
+                          "sub-command TRANSFORM, selector REGEX expects "
+                          "'regular expression' argument.");
+                        return std::string{};
+                      }
+
+                      selector = cmList::TransformSelector::New<
+                        cmList::TransformSelector::REGEX>(args.front());
+
+                      args.advance(1);
+                      continue;
+                    }
+
+                    // AT selector
+                    if (args.front() == AT) {
+                      args.advance(1);
+                      // get all specified indexes
+                      std::vector<cmList::index_type> indexes;
+                      while (!args.empty()) {
+                        cmList indexList{ args.front() };
+                        for (auto const& index : indexList) {
+                          int value;
+
+                          if (!GetNumericArgument(index, value)) {
+                            // this is not a number, stop processing
+                            reportError(
+                              ctx, cnt->GetOriginalExpression(),
+                              cmStrCat("sub-command TRANSFORM, selector AT: '",
+                                       index, "': unexpected argument."));
+                            return std::string{};
+                          }
+                          indexes.push_back(value);
+                        }
+                        args.advance(1);
+                      }
+
+                      if (indexes.empty()) {
+                        reportError(ctx, cnt->GetOriginalExpression(),
+                                    "sub-command TRANSFORM, selector AT "
+                                    "expects at least one "
+                                    "numeric value.");
+                        return std::string{};
+                      }
+
+                      selector = cmList::TransformSelector::New<
+                        cmList::TransformSelector::AT>(std::move(indexes));
+
+                      continue;
+                    }
+
+                    // FOR selector
+                    if (args.front() == FOR) {
+                      if (args.advance(1).size() < 2) {
+                        reportError(ctx, cnt->GetOriginalExpression(),
+                                    "sub-command TRANSFORM, selector FOR "
+                                    "expects, at least,"
+                                    " two arguments.");
+                        return std::string{};
+                      }
+
+                      cmList::index_type start = 0;
+                      cmList::index_type stop = 0;
+                      cmList::index_type step = 1;
+                      bool valid = false;
+
+                      if (GetNumericArgument(args.front(), start) &&
+                          GetNumericArgument(args.advance(1).front(), stop)) {
+                        valid = true;
+                      }
+
+                      if (!valid) {
+                        reportError(
+                          ctx, cnt->GetOriginalExpression(),
+                          "sub-command TRANSFORM, selector FOR expects, "
+                          "at least, two numeric values.");
+                        return std::string{};
+                      }
+                      // try to read a third numeric value for step
+                      if (!args.advance(1).empty()) {
+                        if (!GetNumericArgument(args.front(), step)) {
+                          // this is not a number
+                          step = -1;
+                        }
+                        args.advance(1);
+                      }
+
+                      if (step <= 0) {
+                        reportError(
+                          ctx, cnt->GetOriginalExpression(),
+                          "sub-command TRANSFORM, selector FOR expects "
+                          "positive numeric value for <step>.");
+                        return std::string{};
+                      }
+
+                      selector = cmList::TransformSelector::New<
+                        cmList::TransformSelector::FOR>({ start, stop, step });
+                      continue;
+                    }
+
+                    reportError(ctx, cnt->GetOriginalExpression(),
+                                cmStrCat("sub-command TRANSFORM, '",
+                                         cmJoin(args, ", "),
+                                         "': unexpected argument(s)."));
+                    return std::string{};
+                  }
+
+                  return list
+                    .transform(descriptor->Action, arguments,
+                               std::move(selector))
+                    .to_string();
+                } catch (cmList::transform_error& e) {
+                  reportError(ctx, cnt->GetOriginalExpression(), e.what());
+                  return std::string{};
+                }
+              }
+            }
+            return std::string{};
+          } },
+        { "REVERSE"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParameters(ctx, cnt, "REVERSE"_s, args)) {
+              return GetList(args.front()).reverse().to_string();
+            }
+            return std::string{};
+          } },
+        { "SORT"_s,
+          [](cmGeneratorExpressionContext* ctx,
+             const GeneratorExpressionContent* cnt,
+             Arguments& args) -> std::string {
+            if (CheckListParametersEx(ctx, cnt, "SORT"_s, args.size(), 1,
+                                      false)) {
+              auto list = GetList(args.front());
+              args.advance(1);
+              const auto COMPARE = "COMPARE:"_s;
+              const auto CASE = "CASE:"_s;
+              const auto ORDER = "ORDER:"_s;
+              using SortConfig = cmList::SortConfiguration;
+              SortConfig sortConfig;
+              for (auto const& arg : args) {
+                if (cmHasPrefix(arg, COMPARE)) {
+                  if (sortConfig.Compare !=
+                      SortConfig::CompareMethod::DEFAULT) {
+                    reportError(ctx, cnt->GetOriginalExpression(),
+                                "sub-command SORT, COMPARE option has been "
+                                "specified multiple times.");
+                    return std::string{};
+                  }
+                  auto option =
+                    cm::string_view{ arg.c_str() + COMPARE.length() };
+                  if (option == "STRING"_s) {
+                    sortConfig.Compare = SortConfig::CompareMethod::STRING;
+                    continue;
+                  }
+                  if (option == "FILE_BASENAME"_s) {
+                    sortConfig.Compare =
+                      SortConfig::CompareMethod::FILE_BASENAME;
+                    continue;
+                  }
+                  if (option == "NATURAL"_s) {
+                    sortConfig.Compare = SortConfig::CompareMethod::NATURAL;
+                    continue;
+                  }
+                  reportError(
+                    ctx, cnt->GetOriginalExpression(),
+                    cmStrCat(
+                      "sub-command SORT, an invalid COMPARE option has been "
+                      "specified: \"",
+                      option, "\"."));
+                  return std::string{};
+                }
+                if (cmHasPrefix(arg, CASE)) {
+                  if (sortConfig.Case !=
+                      SortConfig::CaseSensitivity::DEFAULT) {
+                    reportError(ctx, cnt->GetOriginalExpression(),
+                                "sub-command SORT, CASE option has been "
+                                "specified multiple times.");
+                    return std::string{};
+                  }
+                  auto option = cm::string_view{ arg.c_str() + CASE.length() };
+                  if (option == "SENSITIVE"_s) {
+                    sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE;
+                    continue;
+                  }
+                  if (option == "INSENSITIVE"_s) {
+                    sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE;
+                    continue;
+                  }
+                  reportError(
+                    ctx, cnt->GetOriginalExpression(),
+                    cmStrCat(
+                      "sub-command SORT, an invalid CASE option has been "
+                      "specified: \"",
+                      option, "\"."));
+                  return std::string{};
+                }
+                if (cmHasPrefix(arg, ORDER)) {
+                  if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) {
+                    reportError(ctx, cnt->GetOriginalExpression(),
+                                "sub-command SORT, ORDER option has been "
+                                "specified multiple times.");
+                    return std::string{};
+                  }
+                  auto option =
+                    cm::string_view{ arg.c_str() + ORDER.length() };
+                  if (option == "ASCENDING"_s) {
+                    sortConfig.Order = SortConfig::OrderMode::ASCENDING;
+                    continue;
+                  }
+                  if (option == "DESCENDING"_s) {
+                    sortConfig.Order = SortConfig::OrderMode::DESCENDING;
+                    continue;
+                  }
+                  reportError(
+                    ctx, cnt->GetOriginalExpression(),
+                    cmStrCat(
+                      "sub-command SORT, an invalid ORDER option has been "
+                      "specified: \"",
+                      option, "\"."));
+                  return std::string{};
+                }
+                reportError(ctx, cnt->GetOriginalExpression(),
+                            cmStrCat("sub-command SORT, option \"", arg,
+                                     "\" is invalid."));
+                return std::string{};
+              }
+
+              return list.sort(sortConfig).to_string();
+            }
+            return std::string{};
+          } }
+      };
+
+    if (cm::contains(listCommands, parameters.front())) {
+      auto args = Arguments{ parameters }.advance(1);
+      return listCommands[parameters.front()](context, content, args);
+    }
+
+    reportError(context, content->GetOriginalExpression(),
+                cmStrCat(parameters.front(), ": invalid option."));
+    return std::string{};
+  }
+} listNode;
+
 static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
 {
   MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
@@ -1559,7 +2250,8 @@
       // reportError(context, content->GetOriginalExpression(), "");
       reportError(
         context, content->GetOriginalExpression(),
-        "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
+        "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary "
+        "targets "
         "to specify include directories, compile definitions, and compile "
         "options.  It may not be used with the add_custom_command, "
         "add_custom_target, or file(GENERATE) commands.");
@@ -1704,7 +2396,8 @@
       reportError(
         context, content->GetOriginalExpression(),
         "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
-        "to specify link libraries, link directories, link options, and link "
+        "to specify link libraries, link directories, link options, and "
+        "link "
         "depends.");
       return std::string();
     }
@@ -2086,7 +2779,8 @@
         reportError(
           context, content->GetOriginalExpression(),
           "$<TARGET_PROPERTY:prop>  may only be used with binary targets.  "
-          "It may not be used with add_custom_command or add_custom_target.  "
+          "It may not be used with add_custom_command or add_custom_target. "
+          " "
           " "
           "Specify the target to read a property from using the "
           "$<TARGET_PROPERTY:tgt,prop> signature instead.");
@@ -3669,7 +4363,7 @@
     const GeneratorExpressionContent* content,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    std::vector<std::string> listIn = cmExpandedList(parameters.front());
+    cmList listIn{ parameters.front() };
     if (listIn.empty()) {
       reportError(context, content->GetOriginalExpression(),
                   "\"\" is not an absolute path.");
@@ -3780,6 +4474,7 @@
     { "IN_LIST", &inListNode },
     { "FILTER", &filterNode },
     { "REMOVE_DUPLICATES", &removeDuplicatesNode },
+    { "LIST", &listNode },
     { "LOWER_CASE", &lowerCaseNode },
     { "UPPER_CASE", &upperCaseNode },
     { "PATH", &pathNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 90cddb5..db3d7e6 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -36,6 +36,7 @@
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpressionNode.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -1634,20 +1635,20 @@
                        EvaluatedTargetPropertyEntries& entries)
 {
   for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) {
-    for (auto const& name : cmExpandedList(entry.Value)) {
+    for (auto const& name : cmList{ entry.Value }) {
       auto const* headerSet = headTarget->Target->GetFileSet(name);
       addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
     }
   }
   for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) {
-    for (auto const& name : cmExpandedList(entry.Value)) {
+    for (auto const& name : cmList{ entry.Value }) {
       auto const* cxxModuleSet = headTarget->Target->GetFileSet(name);
       addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries);
     }
   }
   for (auto const& entry :
        headTarget->Target->GetCxxModuleHeaderSetsEntries()) {
-    for (auto const& name : cmExpandedList(entry.Value)) {
+    for (auto const& name : cmList{ entry.Value }) {
       auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name);
       addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet,
                       entries);
@@ -1740,8 +1741,8 @@
 
     cmBTStringRange sourceEntries = this->Target->GetSourceEntries();
     for (auto const& entry : sourceEntries) {
-      std::vector<std::string> items = cmExpandedList(entry.Value);
-      for (std::string const& item : items) {
+      cmList items{ entry.Value };
+      for (auto const& item : items) {
         if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
             item.back() == '>') {
           continue;
@@ -3105,8 +3106,8 @@
 
     // Queue dependencies added explicitly by the user.
     if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
-      std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
-      for (std::string& objDep : objDeps) {
+      cmList objDeps{ *additionalDeps };
+      for (auto& objDep : objDeps) {
         if (cmSystemTools::FileIsFullPath(objDep)) {
           objDep = cmSystemTools::CollapseFullPath(objDep);
         }
@@ -4606,7 +4607,7 @@
     // wrap host link options
     const std::string wrapper(this->Makefile->GetSafeDefinition(
       "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
-    std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
+    cmList wrapperFlag{ wrapper };
     const std::string wrapperSep(this->Makefile->GetSafeDefinition(
       "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
     bool concatFlagAndArgs = true;
@@ -4665,7 +4666,7 @@
     "CMAKE_" + language +
     (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
                           : "_LINKER_WRAPPER_FLAG")));
-  std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
+  cmList wrapperFlag{ wrapper };
   const std::string wrapperSep(this->Makefile->GetSafeDefinition(
     "CMAKE_" + language +
     (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
@@ -4911,7 +4912,7 @@
 
   EvaluatedTargetPropertyEntries entries;
   if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
-    std::vector<std::string> depends = cmExpandedList(*linkDepends);
+    cmList depends{ *linkDepends };
     for (const auto& depend : depends) {
       std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry(
         *this->LocalGenerator->GetCMakeInstance(), depend);
@@ -5590,8 +5591,8 @@
 
   // Process public headers to mark the source files.
   if (cmValue files = this->GetProperty("PUBLIC_HEADER")) {
-    std::vector<std::string> relFiles = cmExpandedList(*files);
-    for (std::string const& relFile : relFiles) {
+    cmList relFiles{ *files };
+    for (auto const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
         SourceFileFlags& flags = this->SourceFlagsMap[sf];
         flags.MacFolder = "Headers";
@@ -5603,8 +5604,8 @@
   // Process private headers after public headers so that they take
   // precedence if a file is listed in both.
   if (cmValue files = this->GetProperty("PRIVATE_HEADER")) {
-    std::vector<std::string> relFiles = cmExpandedList(*files);
-    for (std::string const& relFile : relFiles) {
+    cmList relFiles{ *files };
+    for (auto const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
         SourceFileFlags& flags = this->SourceFlagsMap[sf];
         flags.MacFolder = "PrivateHeaders";
@@ -5615,8 +5616,8 @@
 
   // Mark sources listed as resources.
   if (cmValue files = this->GetProperty("RESOURCE")) {
-    std::vector<std::string> relFiles = cmExpandedList(*files);
-    for (std::string const& relFile : relFiles) {
+    cmList relFiles{ *files };
+    for (auto const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
         SourceFileFlags& flags = this->SourceFlagsMap[sf];
         flags.MacFolder = "";
@@ -5757,7 +5758,7 @@
     return;
   }
 
-  std::vector<std::string> props = cmExpandedList(*prop);
+  cmList props{ *prop };
   std::string pdir =
     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
 
@@ -6799,10 +6800,10 @@
                              entry.Backtrace);
     std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value);
     cge->SetEvaluateForBuildsystem(true);
-    std::vector<std::string> libs = cmExpandedList(
-      cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker,
-                    this, headTarget->LinkerLanguage));
-    for (std::string const& lib : libs) {
+    cmList libs{ cge->Evaluate(this->LocalGenerator, config, headTarget,
+                               &dagChecker, this,
+                               headTarget->LinkerLanguage) };
+    for (auto const& lib : libs) {
       if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
             lib, cge->GetBacktrace(), &scope,
             field == LinkInterfaceField::Libraries ? LookupSelf::No
@@ -7466,10 +7467,10 @@
     currentTarget->GetRuntimeLinkLibrary(lang, config);
   if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition(
         "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) {
-    std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
-    result.reserve(libsVec.size());
+    cmList libsList{ *runtimeLinkOptions };
+    result.reserve(libsList.size());
 
-    for (std::string const& i : libsVec) {
+    for (auto const& i : libsList) {
       cmGeneratorTarget::TargetOrString resolved =
         currentTarget->ResolveTargetReference(i, lg);
       if (resolved.Target) {
@@ -7550,9 +7551,9 @@
     this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries),
                           config, headTarget, interfaceFor,
                           LinkInterfaceField::Libraries, iface);
-    std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
+    cmList deps{ info->SharedDeps };
     LookupLinkItemScope scope{ this->LocalGenerator };
-    for (std::string const& dep : deps) {
+    for (auto const& dep : deps) {
       if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
             dep, cmListFileBacktrace(), &scope, LookupSelf::No)) {
         iface.SharedDeps.emplace_back(std::move(*maybeItem));
@@ -7873,8 +7874,8 @@
   // behavior of CMP0024 and CMP0026 only.
   cmBTStringRange rng = this->Target->GetSourceEntries();
   for (auto const& entry : rng) {
-    std::vector<std::string> files = cmExpandedList(entry.Value);
-    for (std::string const& li : files) {
+    cmList files{ entry.Value };
+    for (auto const& li : files) {
       if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
         std::string objLibName = li.substr(17, li.size() - 18);
 
@@ -8636,7 +8637,7 @@
   const bool all = verifyValue.IsEmpty();
   std::set<std::string> verifySet;
   if (!all) {
-    auto verifyList = cmExpandedList(verifyValue);
+    cmList verifyList{ verifyValue };
     verifySet.insert(verifyList.begin(), verifyList.end());
   }
 
@@ -8649,7 +8650,7 @@
 
   std::set<cmFileSet*> fileSets;
   for (auto const& entry : interfaceFileSetEntries) {
-    for (auto const& name : cmExpandedList(entry.Value)) {
+    for (auto const& name : cmList{ entry.Value }) {
       if (all || verifySet.count(name)) {
         fileSets.insert(this->Target->GetFileSet(name));
         verifySet.erase(name);
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 8471dfe..a1e0650 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -17,6 +17,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGhsMultiGenerator.h"
 #include "cmLinkLineComputer.h" // IWYU pragma: keep
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
@@ -484,7 +485,7 @@
 {
   cmValue prop = sf->GetProperty(propName);
   if (prop) {
-    std::vector<std::string> list = cmExpandedList(*prop);
+    cmList list{ *prop };
     for (const std::string& p : list) {
       fout << "    " << propFlag << p << '\n';
     }
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 3563a1a..d0a0fdf 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -42,6 +42,7 @@
 #include "cmInstallGenerator.h"
 #include "cmInstallRuntimeDependencySet.h"
 #include "cmLinkLineComputer.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMSVC60LinkLineComputer.h"
 #include "cmMakefile.h"
@@ -670,7 +671,7 @@
     mf->GetState()->SetInTopLevelIncludes(true);
     std::string includes =
       mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES");
-    std::vector<std::string> includesList = cmExpandedList(includes);
+    cmList includesList{ includes };
     for (std::string const& setupFile : includesList) {
       std::string absSetupFile = cmSystemTools::CollapseFullPath(
         setupFile, mf->GetCurrentSourceDirectory());
@@ -1234,7 +1235,7 @@
   std::string ignoreExtensionsVar =
     std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS");
   std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
-  std::vector<std::string> extensionList = cmExpandedList(ignoreExts);
+  cmList extensionList{ ignoreExts };
   for (std::string const& i : extensionList) {
     this->IgnoreExtensions[i] = true;
   }
@@ -1246,7 +1247,7 @@
   std::string extensionsVar = std::string("CMAKE_") + std::string(l) +
     std::string("_SOURCE_FILE_EXTENSIONS");
   const std::string& exts = mf->GetSafeDefinition(extensionsVar);
-  std::vector<std::string> extensionList = cmExpandedList(exts);
+  cmList extensionList{ exts };
   for (std::string const& i : extensionList) {
     this->ExtensionToLanguage[i] = l;
   }
@@ -1887,10 +1888,9 @@
         "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES";
       std::string const& standardIncludesStr =
         mf->GetSafeDefinition(standardIncludesVar);
-      std::vector<std::string> standardIncludesVec =
-        cmExpandedList(standardIncludesStr);
-      standardIncludesSet.insert(standardIncludesVec.begin(),
-                                 standardIncludesVec.end());
+      cmList standardIncludesList{ standardIncludesStr };
+      standardIncludesSet.insert(standardIncludesList.begin(),
+                                 standardIncludesList.end());
     }
     mf->AddSystemIncludeDirectories(standardIncludesSet);
   }
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index b1f2b4a..578e805 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -18,6 +18,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGhsMultiGpj.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
@@ -531,7 +532,7 @@
   fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
   cmValue ghsGpjMacros = root->GetMakefile()->GetDefinition("GHS_GPJ_MACROS");
   if (ghsGpjMacros) {
-    std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros);
+    cmList expandedList{ *ghsGpjMacros };
     for (std::string const& arg : expandedList) {
       fout << "macro " << arg << '\n';
     }
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 5de3a55..694698e 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -17,6 +17,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalVisualStudio7Generator.h"
 #include "cmMakefile.h"
@@ -580,7 +581,7 @@
         }
         fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n";
         cmValue p = root->GetMakefile()->GetProperty(it);
-        std::vector<std::string> keyValuePairs = cmExpandedList(p ? *p : "");
+        cmList keyValuePairs{ *p };
         for (std::string const& itPair : keyValuePairs) {
           const std::string::size_type posEqual = itPair.find('=');
           if (posEqual != std::string::npos) {
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 1396357..1328f4b 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -30,6 +30,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmLinkItem.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalXCodeGenerator.h"
@@ -1027,7 +1028,7 @@
   cmValue extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
   if (extraFileAttributes) {
     // Expand the list of attributes.
-    std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes);
+    cmList attributes{ *extraFileAttributes };
 
     // Store the attributes.
     for (const auto& attribute : attributes) {
@@ -1171,7 +1172,7 @@
 std::string GetTargetObjectDirArch(T const& target,
                                    const std::string& defaultVal)
 {
-  auto archs = cmExpandedList(target.GetSafeProperty("OSX_ARCHITECTURES"));
+  cmList archs{ target.GetSafeProperty("OSX_ARCHITECTURES") };
   if (archs.size() > 1) {
     return "$(CURRENT_ARCH)";
   } else if (archs.size() == 1) {
@@ -3127,8 +3128,8 @@
 std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
                                                       cmGeneratorTarget* gtgt)
 {
-  std::vector<std::string> const configVector = cmExpandedList(
-    this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES"));
+  cmList const configList{ this->CurrentMakefile->GetRequiredDefinition(
+    "CMAKE_CONFIGURATION_TYPES") };
   cmXCodeObject* configlist =
     this->CreateObject(cmXCodeObject::XCConfigurationList);
   cmXCodeObject* buildConfigurations =
@@ -3140,7 +3141,7 @@
   configlist->SetComment(comment);
   target->AddAttribute("buildConfigurationList",
                        this->CreateObjectReference(configlist));
-  for (auto const& i : configVector) {
+  for (auto const& i : configList) {
     cmXCodeObject* config =
       this->CreateObject(cmXCodeObject::XCBuildConfiguration);
     buildConfigurations->AddObject(config);
@@ -3153,12 +3154,12 @@
 
     this->CreateTargetXCConfigSettings(gtgt, config, i);
   }
-  if (!configVector.empty()) {
+  if (!configList.empty()) {
     configlist->AddAttribute("defaultConfigurationName",
-                             this->CreateString(configVector[0]));
+                             this->CreateString(configList[0]));
     configlist->AddAttribute("defaultConfigurationIsVisible",
                              this->CreateString("0"));
-    return configVector[0];
+    return configList[0];
   }
   return "";
 }
@@ -4029,7 +4030,7 @@
                                     this->CreateString("0"));
   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
   // Collect all embedded frameworks and dylibs and add them to build phase
-  std::vector<std::string> relFiles = cmExpandedList(*files);
+  cmList relFiles{ *files };
   for (std::string const& relFile : relFiles) {
     cmXCodeObject* buildFile{ nullptr };
     std::string filePath = relFile;
@@ -5008,7 +5009,7 @@
   }
 
   // Expand the list of definitions.
-  std::vector<std::string> defines = cmExpandedList(defines_list);
+  cmList defines{ defines_list };
 
   // Store the definitions in the string.
   this->AppendDefines(defs, defines, dflag);
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 2bb438d..a8a7abb 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -15,6 +15,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
@@ -255,9 +256,8 @@
 
   this->TargetsToIgnoreRegex.clear();
   if (!ignoreTargetsRegexes.empty()) {
-    std::vector<std::string> ignoreTargetsRegExVector =
-      cmExpandedList(ignoreTargetsRegexes);
-    for (std::string const& currentRegexString : ignoreTargetsRegExVector) {
+    cmList ignoreTargetsRegExList{ ignoreTargetsRegexes };
+    for (std::string const& currentRegexString : ignoreTargetsRegExList) {
       cmsys::RegularExpression currentRegex;
       if (!currentRegex.compile(currentRegexString)) {
         std::cerr << "Could not compile bad regex \"" << currentRegexString
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 40230d9..7f5f15b 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -39,6 +39,7 @@
 #include "cmInstallRuntimeDependencySetGenerator.h"
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallTargetGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -1079,7 +1080,7 @@
     if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
       cmValue files = target.GetProperty("PRIVATE_HEADER");
       if (cmNonempty(files)) {
-        std::vector<std::string> relFiles = cmExpandedList(*files);
+        cmList relFiles{ *files };
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
           return false;
@@ -1101,7 +1102,7 @@
 
       files = target.GetProperty("PUBLIC_HEADER");
       if (cmNonempty(files)) {
-        std::vector<std::string> relFiles = cmExpandedList(*files);
+        cmList relFiles{ *files };
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
           return false;
@@ -1123,7 +1124,7 @@
 
       files = target.GetProperty("RESOURCE");
       if (cmNonempty(files)) {
-        std::vector<std::string> relFiles = cmExpandedList(*files);
+        cmList relFiles{ *files };
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
           return false;
@@ -1145,8 +1146,8 @@
     if (!namelinkOnly) {
       for (std::size_t i = 0; i < fileSetArgs.size(); i++) {
         if (auto* fileSet = target.GetFileSet(fileSetArgs[i].GetFileSet())) {
-          auto interfaceFileSetEntries = cmExpandedList(target.GetSafeProperty(
-            cmTarget::GetInterfaceFileSetsPropertyName(fileSet->GetType())));
+          cmList interfaceFileSetEntries{ target.GetSafeProperty(
+            cmTarget::GetInterfaceFileSetsPropertyName(fileSet->GetType())) };
           if (std::find(interfaceFileSetEntries.begin(),
                         interfaceFileSetEntries.end(),
                         fileSetArgs[i].GetFileSet()) !=
diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx
index cce6178..0752b33 100644
--- a/Source/cmLDConfigLDConfigTool.cxx
+++ b/Source/cmLDConfigLDConfigTool.cxx
@@ -9,9 +9,9 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmRuntimeDependencyArchive.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmUVProcessChain.h"
 
@@ -34,7 +34,7 @@
     }
   }
 
-  std::vector<std::string> ldConfigCommand = cmExpandedList(ldConfigPath);
+  cmList ldConfigCommand{ ldConfigPath };
   ldConfigCommand.emplace_back("-v");
   ldConfigCommand.emplace_back("-N"); // Don't rebuild the cache.
   ldConfigCommand.emplace_back("-X"); // Don't update links.
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
index bf5a654..2064afb 100644
--- a/Source/cmList.cxx
+++ b/Source/cmList.cxx
@@ -835,18 +835,19 @@
         cmStrCat("index: ", pos, " out of range (0, 0)"));
     }
 
+    auto index = pos;
     if (!this->Values.empty()) {
       auto length = this->Values.size();
-      if (pos < 0) {
-        pos = static_cast<index_type>(length) + pos;
+      if (index < 0) {
+        index = static_cast<index_type>(length) + index;
       }
-      if (pos < 0 || length <= static_cast<size_type>(pos)) {
+      if (index < 0 || length <= static_cast<size_type>(index)) {
         throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
                                          this->Values.size(), ", ",
                                          this->Values.size() - 1, ")"));
       }
     }
-    return pos;
+    return index;
   }
 
   return pos < 0 ? this->Values.size() + pos : pos;
@@ -860,18 +861,19 @@
         cmStrCat("index: ", pos, " out of range (0, 0)"));
     }
 
+    auto index = pos;
     if (!this->Values.empty()) {
       auto length = this->Values.size();
-      if (pos < 0) {
-        pos = static_cast<index_type>(length) + pos;
+      if (index < 0) {
+        index = static_cast<index_type>(length) + index;
       }
-      if (pos < 0 || length < static_cast<size_type>(pos)) {
+      if (index < 0 || length < static_cast<size_type>(index)) {
         throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
                                          this->Values.size(), ", ",
                                          this->Values.size(), ")"));
       }
     }
-    return pos;
+    return index;
   }
 
   return pos < 0 ? this->Values.size() + pos : pos;
diff --git a/Source/cmList.h b/Source/cmList.h
index d994ad3..8a1cb8e 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -16,6 +16,8 @@
 #include <vector>
 
 #include <cm/string_view>
+#include <cm/type_traits>
+#include <cmext/iterator>
 
 #include "cmValue.h"
 
@@ -1177,6 +1179,13 @@
   return l;
 }
 
+namespace std {
+inline void swap(cmList& lhs, cmList& rhs) noexcept
+{
+  lhs.swap(rhs);
+}
+} // namespace std
+
 namespace cm {
 inline void erase(cmList& list, const std::string& value)
 {
@@ -1188,11 +1197,52 @@
 {
   list.erase(std::remove_if(list.begin(), list.end(), pred), list.end());
 }
+
+//
+// Provide a special implementation of cm::append because, in this case,
+// expansion must not be applied to the inserted elements
+//
+#if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// templates with constraints.
+// So, on this platform, use only simple templates.
+template <typename InputIt,
+          cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = 0>
+void append(cmList& v, InputIt first, InputIt last)
+{
+  v.append(first, last, cmList::ExpandElements::No);
 }
 
-namespace srd {
-inline void swap(cmList& lhs, cmList& rhs) noexcept
+template <typename Range,
+          cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0>
+void append(cmList& v, Range const& r)
 {
-  lhs.swap(rhs);
+  v.append(r.begin(), r.end(), cmList::ExpandElements::No);
 }
+
+#else
+
+template <
+  typename InputIt,
+  cm::enable_if_t<
+    cm::is_input_iterator<InputIt>::value &&
+      std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
+                          cmList::value_type>::value,
+    int> = 0>
+void append(cmList& v, InputIt first, InputIt last)
+{
+  v.append(first, last, cmList::ExpandElements::No);
 }
+
+template <typename Range,
+          cm::enable_if_t<cm::is_input_range<Range>::value &&
+                            std::is_convertible<typename Range::value_type,
+                                                cmList::value_type>::value,
+                          int> = 0>
+void append(cmList& v, Range const& r)
+{
+  v.append(r.begin(), r.end(), cmList::ExpandElements::No);
+}
+#endif
+
+} // namespace cm
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 6270c82..97f5de9 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -11,10 +11,10 @@
 #  include <cmsys/Encoding.hxx>
 #endif
 
+#include "cmList.h"
 #include "cmListFileLexer.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 struct cmListFileParser
@@ -496,10 +496,11 @@
 }
 
 std::vector<BT<std::string>> cmExpandListWithBacktrace(
-  std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs)
+  std::string const& list, cmListFileBacktrace const& bt,
+  cmList::EmptyElements emptyArgs)
 {
   std::vector<BT<std::string>> result;
-  std::vector<std::string> tmp = cmExpandedList(list, emptyArgs);
+  cmList tmp{ list, emptyArgs };
   result.reserve(tmp.size());
   for (std::string& i : tmp) {
     result.emplace_back(std::move(i), bt);
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 0553989..e4e6eb3 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -13,6 +13,7 @@
 #include <cm/optional>
 
 #include "cmConstStack.h"
+#include "cmList.h"
 #include "cmSystemTools.h"
 
 /** \class cmListFileCache
@@ -232,7 +233,7 @@
 std::vector<BT<std::string>> cmExpandListWithBacktrace(
   std::string const& list,
   cmListFileBacktrace const& bt = cmListFileBacktrace(),
-  bool emptyArgs = false);
+  cmList::EmptyElements emptyArgs = cmList::EmptyElements::No);
 
 struct cmListFile
 {
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 01e4241..e00341c 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -38,6 +38,7 @@
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h"
 #include "cmLinkLineDeviceComputer.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
@@ -347,7 +348,7 @@
 
   cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
   if (testIncludeFiles) {
-    std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles);
+    cmList includesList{ *testIncludeFiles };
     for (std::string const& i : includesList) {
       fout << "include(\"" << i << "\")\n";
     }
@@ -1064,9 +1065,9 @@
         std::string isJMCEnabled =
           cmGeneratorExpression::Evaluate(*jmcExprGen, this, config);
         if (cmIsOn(isJMCEnabled)) {
-          std::vector<std::string> optVec = cmExpandedList(*jmc);
+          cmList optList{ *jmc };
           std::string jmcFlags;
-          this->AppendCompileOptions(jmcFlags, optVec);
+          this->AppendCompileOptions(jmcFlags, optList);
           if (!jmcFlags.empty()) {
             flags.emplace_back(std::move(jmcFlags));
           }
@@ -1954,8 +1955,8 @@
       cmValue opt =
         target->Target->GetMakefile()->GetDefinition(optionFlagDef);
       if (opt) {
-        std::vector<std::string> optVec = cmExpandedList(*opt);
-        for (std::string const& i : optVec) {
+        cmList optList{ *opt };
+        for (std::string const& i : optList) {
           this->AppendFlagEscape(flags, i);
         }
       }
@@ -2426,7 +2427,7 @@
       cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC"));
   }
   if (!picFlags.empty()) {
-    std::vector<std::string> options = cmExpandedList(picFlags);
+    cmList options{ picFlags };
     for (std::string const& o : options) {
       this->AppendFlagEscape(flags, o);
     }
@@ -3163,7 +3164,7 @@
     return;
   }
 
-  std::vector<std::string> flagsList = cmExpandedList(*rawFlagsList);
+  cmList flagsList{ *rawFlagsList };
   for (std::string const& o : flagsList) {
     this->AppendFlagEscape(flags, o);
   }
@@ -3198,7 +3199,7 @@
     return;
   }
 
-  std::vector<std::string> flagsList = cmExpandedList(pieFlags);
+  cmList flagsList{ pieFlags };
   for (const auto& flag : flagsList) {
     this->AppendFlagEscape(flags, flag);
   }
@@ -3264,7 +3265,7 @@
   }
 
   // Expand the list of options.
-  std::vector<std::string> options_vec = cmExpandedList(options_list);
+  cmList options_vec{ options_list };
   this->AppendCompileOptions(options, options_vec, regex);
 }
 
@@ -3322,7 +3323,7 @@
   }
 
   // Expand the list of includes.
-  std::vector<std::string> includes_vec = cmExpandedList(includes_list);
+  cmList includes_vec{ includes_list };
   this->AppendIncludeDirectories(includes, includes_vec, sourceFile);
 }
 
@@ -3454,7 +3455,7 @@
   cmValue optionList = this->Makefile->GetDefinition(
     cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature));
   if (optionList) {
-    std::vector<std::string> options = cmExpandedList(*optionList);
+    cmList options{ *optionList };
     for (std::string const& o : options) {
       this->AppendFlagEscape(flags, o);
     }
@@ -4500,11 +4501,11 @@
 std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
   cmCompiledGeneratorExpression const& cge, std::string const& config)
 {
-  std::vector<std::string> paths = cmExpandedList(cge.Evaluate(this, config));
+  cmList paths{ cge.Evaluate(this, config) };
   for (std::string& p : paths) {
     p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory());
   }
-  return paths;
+  return std::move(paths.data());
 }
 
 std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index d0bd375..42fa298 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -22,6 +22,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalNinjaGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -301,7 +302,7 @@
   if (jobpools) {
     cmGlobalNinjaGenerator::WriteComment(
       os, "Pools defined by global property JOB_POOLS");
-    std::vector<std::string> pools = cmExpandedList(*jobpools);
+    cmList pools{ *jobpools };
     for (std::string const& pool : pools) {
       const std::string::size_type eq = pool.find('=');
       unsigned int jobs;
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 56a41b1..12cecbd 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -29,6 +29,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -1434,7 +1435,7 @@
     this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
   if (!depends.empty()) {
     // dependencies are managed by compiler
-    auto depFiles = cmExpandedList(depends, true);
+    cmList depFiles{ depends, cmList::EmptyElements::Yes };
     std::string const internalDepFile =
       targetDir + "/compiler_depend.internal";
     std::string const depFile = targetDir + "/compiler_depend.make";
@@ -1556,8 +1557,7 @@
   this->WriteDisclaimer(internalRuleFileStream);
 
   // for each language we need to scan, scan it
-  std::vector<std::string> langs =
-    cmExpandedList(mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"));
+  cmList langs{ mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES") };
   for (std::string const& lang : langs) {
     // construct the checker
     // Create the scanner for this language
@@ -1602,7 +1602,7 @@
   }
 
   // Convert the string to a list and preserve empty entries.
-  std::vector<std::string> pairs = cmExpandedList(*pairs_string, true);
+  cmList pairs{ *pairs_string, cmList::EmptyElements::Yes };
   for (auto i = pairs.begin(); i != pairs.end() && (i + 1) != pairs.end();) {
     const std::string& depender = *i++;
     const std::string& dependee = *i++;
@@ -1822,7 +1822,7 @@
   if (!infoDef) {
     return;
   }
-  std::vector<std::string> files = cmExpandedList(*infoDef);
+  cmList files{ *infoDef };
 
   // Each depend information file corresponds to a target.  Clear the
   // dependencies for that target.
@@ -1863,7 +1863,7 @@
       cmSystemTools::Touch(DepTimestamp.GenericString(), true);
 
       // clear the dependencies files generated by the compiler
-      std::vector<std::string> dependencies = cmExpandedList(depsFiles, true);
+      cmList dependencies{ depsFiles, cmList::EmptyElements::Yes };
       cmDependsCompiler depsManager;
       depsManager.SetVerbose(verbose);
       depsManager.ClearDependencies(dependencies);
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 239748d..a7ea0df 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -29,6 +29,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmGlobalVisualStudio7Generator.h"
 #include "cmGlobalVisualStudioGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
@@ -1576,12 +1577,12 @@
 
     // Check for extra object-file dependencies.
     if (cmValue deps = sf.GetProperty("OBJECT_DEPENDS")) {
-      std::vector<std::string> depends = cmExpandedList(*deps);
-      const char* sep = "";
-      for (const std::string& d : depends) {
-        fc.AdditionalDeps += sep;
-        fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d);
-        sep = ";";
+      cmList depends{ *deps };
+      if (!depends.empty()) {
+        for (std::string& d : depends) {
+          d = lg->ConvertToXMLOutputPath(d);
+        }
+        fc.AdditionalDeps += depends.to_string();
         needfc = true;
       }
     }
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 3a69b2e..490a905 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -43,6 +43,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmInstallGenerator.h" // IWYU pragma: keep
 #include "cmInstallSubdirectoryGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMessageType.h"
@@ -1448,15 +1449,13 @@
   if (remove) {
     if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
       // Expand the list.
-      std::vector<std::string> defs = cmExpandedList(*cdefs);
+      cmList defs{ *cdefs };
 
       // Recompose the list without the definition.
-      auto defEnd = std::remove(defs.begin(), defs.end(), define);
-      auto defBegin = defs.begin();
-      std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";");
+      defs.remove_items({ define });
 
       // Store the new list.
-      this->SetProperty("COMPILE_DEFINITIONS", ndefs);
+      this->SetProperty("COMPILE_DEFINITIONS", defs.to_string());
     }
   } else {
     // Append the definition to the directory property.
@@ -2064,7 +2063,7 @@
   }
 
   if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
-    std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
+    cmList linkLibs{ *linkLibsProp };
 
     for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) {
       std::string libraryName = *j;
@@ -2378,7 +2377,7 @@
   }
 
   if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
-    std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
+    cmList linkLibs{ *linkLibsProp };
 
     for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) {
       std::string libName = *l;
@@ -3406,7 +3405,7 @@
     if (i.Delim == cmListFileArgument::Quoted) {
       outArgs.emplace_back(value, true);
     } else {
-      std::vector<std::string> stringArgs = cmExpandedList(value);
+      cmList stringArgs{ value };
       for (std::string const& stringArg : stringArgs) {
         outArgs.emplace_back(stringArg, false);
       }
@@ -3812,7 +3811,7 @@
   // Always search in CMAKE_MODULE_PATH:
   cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
   if (cmakeModulePath) {
-    std::vector<std::string> modulePath = cmExpandedList(*cmakeModulePath);
+    cmList modulePath{ *cmakeModulePath };
 
     // Look through the possible module directories.
     for (std::string itempl : modulePath) {
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 3e4a08e..43062d9 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -16,6 +16,7 @@
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLinkLineComputer.h"
 #include "cmLinkLineDeviceComputer.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
@@ -965,7 +966,7 @@
       this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) {
     auto genStubsRule =
       this->Makefile->GetDefinition("CMAKE_CREATE_TEXT_STUBS");
-    auto genStubs_commands = cmExpandedList(genStubsRule);
+    cmList genStubs_commands{ genStubsRule };
 
     std::string TBDFullPath =
       cmStrCat(outpathImp, this->TargetNames.ImportOutput);
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 3112acd..1e35fe7 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -29,6 +29,7 @@
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLinkLineComputer.h" // IWYU pragma: keep
+#include "cmList.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
@@ -1200,7 +1201,7 @@
     // If compiler launcher was specified and not consumed above, it
     // goes to the beginning of the command line.
     if (!compileCommands.empty() && !compilerLauncher.empty()) {
-      std::vector<std::string> args = cmExpandedList(compilerLauncher, true);
+      cmList args{ compilerLauncher, cmList::EmptyElements::Yes };
       if (!args.empty()) {
         args[0] = this->LocalGenerator->ConvertToOutputFormat(
           args[0], cmOutputConverter::SHELL);
@@ -1240,7 +1241,7 @@
       const auto& extraCommands = this->Makefile->GetSafeDefinition(
         cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
       if (!extraCommands.empty()) {
-        auto commandList = cmExpandedList(extraCommands);
+        cmList commandList{ extraCommands };
         compileCommands.insert(compileCommands.end(), commandList.cbegin(),
                                commandList.cend());
       }
@@ -1341,8 +1342,7 @@
         cmStrCat("CMAKE_", lang, "_CREATE_PREPROCESSED_SOURCE");
       if (cmValue preprocessRule =
             this->Makefile->GetDefinition(preprocessRuleVar)) {
-        std::vector<std::string> preprocessCommands =
-          cmExpandedList(*preprocessRule);
+        cmList preprocessCommands{ *preprocessRule };
 
         std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat(
           objI, cmOutputConverter::SHELL);
@@ -1386,8 +1386,7 @@
         cmStrCat("CMAKE_", lang, "_CREATE_ASSEMBLY_SOURCE");
       if (cmValue assemblyRule =
             this->Makefile->GetDefinition(assemblyRuleVar)) {
-        std::vector<std::string> assemblyCommands =
-          cmExpandedList(*assemblyRule);
+        cmList assemblyCommands{ *assemblyRule };
 
         std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat(
           objS, cmOutputConverter::SHELL);
@@ -1674,7 +1673,7 @@
   }
 
   cmLocalUnixMakefileGenerator3* localGen{ this->LocalGenerator };
-  std::vector<std::string> architectures = cmExpandedList(architecturesStr);
+  cmList architectures{ architecturesStr };
   std::string const& relPath = localGen->GetHomeRelativeOutputPath();
 
   // Ensure there are no duplicates.
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 52373f3..baf40f8 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -10,6 +10,7 @@
 
 #include "cmConfigureLog.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
@@ -31,13 +32,13 @@
 std::string IndentText(std::string text, cmMakefile& mf)
 {
   auto indent =
-    cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), "");
+    cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT") }.join("");
 
   const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
     mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
   if (showContext) {
-    auto context = cmJoin(
-      cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), ".");
+    auto context =
+      cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT") }.join(".");
     if (!context.empty()) {
       indent.insert(0u, cmStrCat("["_s, context, "] "_s));
     }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 4d68460..091acd6 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -23,6 +23,7 @@
 #include "cmGlobalNinjaGenerator.h"
 #include "cmLinkLineComputer.h"
 #include "cmLinkLineDeviceComputer.h"
+#include "cmList.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
@@ -213,6 +214,22 @@
     '_', config);
 }
 
+bool cmNinjaNormalTargetGenerator::CheckUseResponseFileForLibraries(
+  const std::string& l) const
+{
+  // Check for an explicit setting one way or the other.
+  std::string const responseVar =
+    "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES";
+
+  // If the option is defined, read it's value
+  if (cmValue val = this->Makefile->GetDefinition(responseVar)) {
+    return val.IsOn();
+  }
+
+  // Default to true
+  return true;
+}
+
 struct cmNinjaRemoveNoOpCommands
 {
   bool operator()(std::string const& cmd)
@@ -251,9 +268,16 @@
       } else {
         rule.RspContent = "$in_newline";
       }
-      rule.RspContent += " $LINK_LIBRARIES";
+
+      // add the link command in the file if necessary
+      if (this->CheckUseResponseFileForLibraries("CUDA")) {
+        rule.RspContent += " $LINK_LIBRARIES";
+        vars.LinkLibraries = "";
+      } else {
+        vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
+      }
+
       vars.Objects = responseFlag.c_str();
-      vars.LinkLibraries = "";
     }
 
     vars.ObjectDir = "$OBJECT_DIR";
@@ -416,13 +440,20 @@
       } else {
         rule.RspContent = "$in_newline";
       }
-      rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
+
+      // If libraries in rsp is enable
+      if (this->CheckUseResponseFileForLibraries(lang)) {
+        rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
+        vars.LinkLibraries = "";
+      } else {
+        vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
+      }
+
       if (this->TargetLinkLanguage(config) == "Swift") {
         vars.SwiftSources = responseFlag.c_str();
       } else {
         vars.Objects = responseFlag.c_str();
       }
-      vars.LinkLibraries = "";
     }
 
     vars.ObjectDir = "$OBJECT_DIR";
@@ -754,7 +785,7 @@
     }
 
     this->WriteDeviceLinkRules(config);
-    this->WriteDeviceLinkStatements(config, cmExpandedList(architecturesStr),
+    this->WriteDeviceLinkStatements(config, cmList{ architecturesStr },
                                     targetOutputReal);
   } else {
     this->WriteNvidiaDeviceLinkStatement(config, fileConfig, targetOutputDir,
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index 85f42a4..187ea46 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -26,7 +26,7 @@
     const std::string& config) const;
   std::string LanguageLinkerCudaFatbinaryRule(const std::string& config) const;
   std::string TextStubsGeneratorRule(const std::string& config) const;
-
+  bool CheckUseResponseFileForLibraries(const std::string& config) const;
   const char* GetVisibleTypeName() const;
   void WriteLanguagesRules(const std::string& config);
 
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 5dbc283..905c68e 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -32,6 +32,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalNinjaGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmMakefile.h"
@@ -1038,7 +1039,7 @@
   // If compiler launcher was specified and not consumed above, it
   // goes to the beginning of the command line.
   if (!compileCmds.empty() && !compilerLauncher.empty()) {
-    std::vector<std::string> args = cmExpandedList(compilerLauncher, true);
+    cmList args{ compilerLauncher, cmList::EmptyElements::Yes };
     if (!args.empty()) {
       args[0] = this->LocalGenerator->ConvertToOutputFormat(
         args[0], cmOutputConverter::SHELL);
@@ -1046,7 +1047,7 @@
         i = this->LocalGenerator->EscapeForShell(i);
       }
     }
-    compileCmds.front().insert(0, cmStrCat(cmJoin(args, " "), ' '));
+    compileCmds.front().insert(0, cmStrCat(args.join(" "), ' '));
   }
 
   if (!compileCmds.empty()) {
@@ -1056,7 +1057,7 @@
   const auto& extraCommands = this->GetMakefile()->GetSafeDefinition(
     cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
   if (!extraCommands.empty()) {
-    auto commandList = cmExpandedList(extraCommands);
+    cmList commandList{ extraCommands };
     compileCmds.insert(compileCmds.end(), commandList.cbegin(),
                        commandList.cend());
   }
@@ -1468,7 +1469,7 @@
   }
 
   if (cmValue objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
-    std::vector<std::string> objDepList = cmExpandedList(*objectDeps);
+    cmList objDepList{ *objectDeps };
     std::copy(objDepList.begin(), objDepList.end(),
               std::back_inserter(depList));
   }
@@ -1688,7 +1689,7 @@
     if (!evaluatedObjectOutputs.empty()) {
       cmNinjaBuild build("phony");
       build.Comment = "Additional output files.";
-      build.Outputs = cmExpandedList(evaluatedObjectOutputs);
+      build.Outputs = cmList{ evaluatedObjectOutputs }.data();
       std::transform(build.Outputs.begin(), build.Outputs.end(),
                      build.Outputs.begin(), this->MapToNinjaPath());
       build.ExplicitDeps = objBuild.Outputs;
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index 6c54e01..40fed80 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -6,16 +6,15 @@
 #include <cassert>
 #include <cctype>
 #include <set>
-#include <vector>
 
 #ifdef _WIN32
 #  include <unordered_map>
 #  include <utility>
 #endif
 
+#include "cmList.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -319,7 +318,7 @@
 {
   FortranFormat format = FortranFormatNone;
   if (!value.empty()) {
-    for (std::string const& fi : cmExpandedList(value)) {
+    for (std::string const& fi : cmList(value)) {
       if (fi == "FIXED") {
         format = FortranFormatFixed;
       }
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index ad276d2..f147ed2 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -14,6 +14,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -126,9 +127,9 @@
       std::string incDirs = cmGeneratorExpression::Preprocess(
         *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
 
-      std::vector<std::string> includes = cmExpandedList(incDirs);
+      cmList includes{ incDirs };
 
-      for (std::string& path : includes) {
+      for (auto& path : includes) {
         this->Makefile->ExpandVariablesInString(path);
         if (uniqueIncludes.insert(path).second) {
           orderedAndUniqueIncludes.push_back(path);
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 7e19566..3e677e6 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -12,6 +12,7 @@
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
@@ -169,7 +170,7 @@
   };
 
   // the second argument is a (cmake) list of options without argument
-  std::vector<std::string> list = cmExpandedList(*argIter++);
+  cmList list{ *argIter++ };
   parser.Bind(list, options, duplicateKey);
 
   // the third argument is a (cmake) list of single argument options
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 782c154..4c45949 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -35,6 +35,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -507,7 +508,7 @@
       std::string const& deps =
         this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
       if (!deps.empty()) {
-        for (std::string const& depName : cmExpandedList(deps)) {
+        for (auto const& depName : cmList{ deps }) {
           // Allow target and file dependencies
           auto* depTarget = this->Makefile->FindTargetToUse(depName);
           if (depTarget) {
@@ -545,8 +546,8 @@
       this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
                                  this->Moc.MacroNames.end());
       {
-        auto filterList = cmExpandedList(
-          this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS"));
+        cmList filterList = { this->GenTarget->GetSafeProperty(
+          "AUTOMOC_DEPEND_FILTERS") };
         if ((filterList.size() % 2) != 0) {
           cmSystemTools::Error(
             cmStrCat("AutoMoc: AUTOMOC_DEPEND_FILTERS predefs size ",
@@ -558,7 +559,9 @@
           "Q_PLUGIN_METADATA",
           "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
           "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
-        for (std::size_t ii = 0; ii != filterList.size(); ii += 2) {
+        for (cmList::index_type ii = 0;
+             ii != static_cast<cmList::index_type>(filterList.size());
+             ii += 2) {
           this->Moc.DependFilters.emplace_back(filterList[ii],
                                                filterList[ii + 1]);
         }
@@ -701,7 +704,7 @@
       this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
     if (!usp.empty()) {
       this->Uic.SearchPaths =
-        SearchPathSanitizer(this->Makefile)(cmExpandedList(usp));
+        SearchPathSanitizer(this->Makefile)(cmList{ usp });
     }
   }
   // Uic target options
@@ -961,8 +964,8 @@
           if (uicOpts.empty()) {
             this->Uic.UiFilesNoOptions.emplace_back(fullPath);
           } else {
-            this->Uic.UiFilesWithOptions.emplace_back(fullPath,
-                                                      cmExpandedList(uicOpts));
+            this->Uic.UiFilesWithOptions.emplace_back(
+              fullPath, std::move(cmList{ uicOpts }.data()));
           }
 
           auto uiHeaderRelativePath = cmSystemTools::RelativePath(
@@ -1063,8 +1066,8 @@
   if (!this->Rcc.Qrcs.empty()) {
     const bool modernQt = (this->QtVersion.Major >= 5);
     // Target rcc options
-    std::vector<std::string> optionsTarget =
-      cmExpandedList(this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS));
+    cmList optionsTarget{ this->GenTarget->GetSafeProperty(
+      kw.AUTORCC_OPTIONS) };
 
     // Check if file name is unique
     for (Qrc& qrc : this->Rcc.Qrcs) {
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
index 8af13ae..65a2268 100644
--- a/Source/cmRemoveCommand.cxx
+++ b/Source/cmRemoveCommand.cxx
@@ -3,8 +3,8 @@
 #include "cmRemoveCommand.h"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
-#include "cmStringAlgorithms.h"
 #include "cmValue.h"
 
 // cmRemoveCommand
@@ -25,12 +25,11 @@
   }
 
   // expand the variable
-  std::vector<std::string> const varArgsExpanded = cmExpandedList(*cacheValue);
+  cmList const varArgsExpanded{ *cacheValue };
 
   // expand the args
   // check for REMOVE(VAR v1 v2 ... vn)
-  std::vector<std::string> const argsExpanded =
-    cmExpandedLists(args.begin() + 1, args.end());
+  cmList const argsExpanded{ args.begin() + 1, args.end() };
 
   // now create the new value
   std::string value;
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index d5f6f0d..2b992ef 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -9,6 +9,7 @@
 #include <cm/optional>
 
 #include "cmFindCommon.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -71,7 +72,7 @@
 
   // Get a path from a CMake variable.
   if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
-    std::vector<std::string> expanded = cmExpandedList(*value);
+    cmList expanded{ *value };
 
     for (std::string const& p : expanded) {
       this->AddPathInternal(
@@ -95,7 +96,7 @@
 
   // Get a path from a CMake variable.
   if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
-    std::vector<std::string> expanded = cmExpandedList(*value);
+    cmList expanded{ *value };
 
     this->AddPrefixPaths(
       expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index d2eac0c..f6e8bc6 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -18,6 +18,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -349,7 +350,7 @@
     for (size_t i = 0; i < this->Levels.size(); ++i) {
       if (cmValue prop = makefile->GetDefinition(
             cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) {
-        std::vector<std::string> props = cmExpandedList(*prop);
+        cmList props{ *prop };
         if (cm::contains(props, feature)) {
           maxLevel = { static_cast<int>(i), this->Levels[i] };
         }
@@ -468,7 +469,7 @@
     return false;
   }
 
-  std::vector<std::string> availableFeatures = cmExpandedList(features);
+  cmList availableFeatures{ features };
   if (!cm::contains(availableFeatures, feature)) {
     std::ostringstream e;
     e << "The compiler feature \"" << feature << "\" is not known to " << lang
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index 66bf383..e352d8d 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -80,77 +80,6 @@
   return tokens;
 }
 
-void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
-                  bool emptyArgs)
-{
-  // If argument is empty, it is an empty list.
-  if (!emptyArgs && arg.empty()) {
-    return;
-  }
-
-  // if there are no ; in the name then just copy the current string
-  if (arg.find(';') == cm::string_view::npos) {
-    argsOut.emplace_back(arg);
-    return;
-  }
-
-  std::string newArg;
-  // Break the string at non-escaped semicolons not nested in [].
-  int squareNesting = 0;
-  cm::string_view::iterator last = arg.begin();
-  cm::string_view::iterator const cend = arg.end();
-  for (cm::string_view::iterator c = last; c != cend; ++c) {
-    switch (*c) {
-      case '\\': {
-        // We only want to allow escaping of semicolons.  Other
-        // escapes should not be processed here.
-        cm::string_view::iterator cnext = c + 1;
-        if ((cnext != cend) && *cnext == ';') {
-          newArg.append(last, c);
-          // Skip over the escape character
-          last = cnext;
-          c = cnext;
-        }
-      } break;
-      case '[': {
-        ++squareNesting;
-      } break;
-      case ']': {
-        --squareNesting;
-      } break;
-      case ';': {
-        // Break the string here if we are not nested inside square
-        // brackets.
-        if (squareNesting == 0) {
-          newArg.append(last, c);
-          // Skip over the semicolon
-          last = c + 1;
-          if (!newArg.empty() || emptyArgs) {
-            // Add the last argument if the string is not empty.
-            argsOut.push_back(newArg);
-            newArg.clear();
-          }
-        }
-      } break;
-      default: {
-        // Just append this character.
-      } break;
-    }
-  }
-  newArg.append(last, cend);
-  if (!newArg.empty() || emptyArgs) {
-    // Add the last argument if the string is not empty.
-    argsOut.push_back(std::move(newArg));
-  }
-}
-
-std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs)
-{
-  std::vector<std::string> argsOut;
-  cmExpandList(arg, argsOut, emptyArgs);
-  return argsOut;
-}
-
 namespace {
 template <std::size_t N, typename T>
 inline void MakeDigits(cm::string_view& view, char (&digits)[N],
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 9ea7491..4ccbb8e 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -14,6 +14,7 @@
 
 #include <cm/string_view>
 
+#include "cmList.h"
 #include "cmRange.h"
 #include "cmValue.h"
 
@@ -92,14 +93,20 @@
  * Expand the ; separated string @a arg into multiple arguments.
  * All found arguments are appended to @a argsOut.
  */
-void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
-                  bool emptyArgs = false);
+inline void cmExpandList(cm::string_view arg,
+                         std::vector<std::string>& argsOut,
+                         bool emptyArgs = false)
+{
+  cmList::append(arg, argsOut,
+                 emptyArgs ? cmList::EmptyElements::Yes
+                           : cmList::EmptyElements::No);
+}
 inline void cmExpandList(cmValue arg, std::vector<std::string>& argsOut,
                          bool emptyArgs = false)
 {
-  if (arg) {
-    cmExpandList(*arg, argsOut, emptyArgs);
-  }
+  cmList::append(arg, argsOut,
+                 emptyArgs ? cmList::EmptyElements::Yes
+                           : cmList::EmptyElements::No);
 }
 
 /**
@@ -111,38 +118,7 @@
 void cmExpandLists(InputIt first, InputIt last,
                    std::vector<std::string>& argsOut)
 {
-  for (; first != last; ++first) {
-    cmExpandList(*first, argsOut);
-  }
-}
-
-/**
- * Same as cmExpandList but a new vector is created containing
- * the expanded arguments from the string @a arg.
- */
-std::vector<std::string> cmExpandedList(cm::string_view arg,
-                                        bool emptyArgs = false);
-inline std::vector<std::string> cmExpandedList(cmValue arg,
-                                               bool emptyArgs = false)
-{
-  if (!arg) {
-    return {};
-  }
-  return cmExpandedList(*arg, emptyArgs);
-}
-
-/**
- * Same as cmExpandList but a new vector is created containing the expanded
- * versions of all arguments in the string range [@a first, @a last).
- */
-template <class InputIt>
-std::vector<std::string> cmExpandedLists(InputIt first, InputIt last)
-{
-  std::vector<std::string> argsOut;
-  for (; first != last; ++first) {
-    cmExpandList(*first, argsOut);
-  }
-  return argsOut;
+  cmList::append(first, last, argsOut);
 }
 
 /** Concatenate string pieces into a single string.  */
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 5e55871..4f14648 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -23,6 +23,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -92,7 +93,7 @@
   std::ostringstream ss;
   const char* sep = "";
   for (auto const& entry : entries) {
-    std::vector<std::string> files = cmExpandedList(entry.Value);
+    cmList files{ entry.Value };
     for (std::string const& file : files) {
       if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
           file.back() == '>') {
@@ -1115,7 +1116,7 @@
   if (globals) {
     const std::string genName = mf->GetGlobalGenerator()->GetName();
     if (cmHasLiteralPrefix(genName, "Visual Studio")) {
-      std::vector<std::string> props = cmExpandedList(*globals);
+      cmList props{ *globals };
       const std::string vsGlobal = "VS_GLOBAL_";
       for (const std::string& i : props) {
         // split NAME=VALUE
@@ -1428,7 +1429,7 @@
 
   bool operator()(BT<std::string> const& entry)
   {
-    std::vector<std::string> files = cmExpandedList(entry.Value);
+    cmList files{ entry.Value };
     std::vector<cmSourceFileLocation> locations;
     locations.reserve(files.size());
     std::transform(files.begin(), files.end(), std::back_inserter(locations),
@@ -2967,7 +2968,7 @@
 
   auto appendEntries = [=](const std::vector<BT<std::string>>& entries) {
     for (auto const& entry : entries) {
-      auto expanded = cmExpandedList(entry.Value);
+      cmList expanded{ entry.Value };
       std::copy(expanded.begin(), expanded.end(), inserter);
     }
   };
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 53e25b5..cd7ff74 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -13,6 +13,7 @@
 #include "cmExperimental.h"
 #include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -320,7 +321,7 @@
     fileSet.first->AddDirectoryEntry(
       BT<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
     if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
-      for (auto const& dir : cmExpandedList(baseDirectories)) {
+      for (auto const& dir : cmList{ baseDirectories }) {
         auto interfaceDirectoriesGenex =
           cmStrCat("$<BUILD_INTERFACE:", dir, ">");
         if (cmFileSetVisibilityIsForSelf(visibility)) {
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 5e325dd..c4a2bc2 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -13,6 +13,7 @@
 
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -147,16 +148,15 @@
   }
 
   // Evaluate command line arguments
-  std::vector<std::string> argv =
-    this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config);
-
-  // Expand arguments if COMMAND_EXPAND_LISTS is set
-  if (this->Test->GetCommandExpandLists()) {
-    argv = cmExpandedLists(argv.begin(), argv.end());
-    // Expanding lists on an empty command may have left it empty
-    if (argv.empty()) {
-      argv.emplace_back();
-    }
+  cmList argv{
+    this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config),
+    // Expand arguments if COMMAND_EXPAND_LISTS is set
+    this->Test->GetCommandExpandLists() ? cmList::ExpandElements::Yes
+                                        : cmList::ExpandElements::No
+  };
+  // Expanding lists on an empty command may have left it empty
+  if (argv.empty()) {
+    argv.emplace_back();
   }
 
   // Check whether the command executable is a target whose name is to
@@ -170,7 +170,7 @@
     // Prepend with the emulator when cross compiling if required.
     cmValue emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
     if (cmNonempty(emulator)) {
-      std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator);
+      cmList emulatorWithArgs{ *emulator };
       std::string emulatorExe(emulatorWithArgs[0]);
       cmSystemTools::ConvertToUnixSlashes(emulatorExe);
       os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index b648d9b..368155c 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -15,6 +15,7 @@
 #include "cmCoreTryCompile.h"
 #include "cmDuration.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
@@ -271,7 +272,7 @@
   const std::string& emulator =
     this->Makefile->GetSafeDefinition("CMAKE_CROSSCOMPILING_EMULATOR");
   if (!emulator.empty()) {
-    std::vector<std::string> emulatorWithArgs = cmExpandedList(emulator);
+    cmList emulatorWithArgs{ emulator };
     finalCommand +=
       cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]);
     finalCommand += " ";
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 8926f9e..6266328 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -31,6 +31,7 @@
 #include "cmGlobalVisualStudio7Generator.h"
 #include "cmGlobalVisualStudioGenerator.h"
 #include "cmLinkLineDeviceComputer.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalVisualStudio10Generator.h"
@@ -1167,7 +1168,7 @@
   cmValue imports =
     this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT");
   if (imports) {
-    std::vector<std::string> argsSplit = cmExpandedList(*imports, false);
+    cmList argsSplit{ *imports };
     for (auto& path : argsSplit) {
       if (!cmsys::SystemTools::FileIsFullPath(path)) {
         path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
@@ -2113,8 +2114,8 @@
     for (const std::string& config : this->Configurations) {
       std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
 
-      std::vector<std::string> settings = cmExpandedList(evaluated);
-      for (const std::string& setting : settings) {
+      cmList settings{ evaluated };
+      for (const auto& setting : settings) {
         const std::string::size_type assignment = setting.find('=');
         if (assignment != std::string::npos) {
           const std::string propName = setting.substr(0, assignment);
@@ -2714,16 +2715,11 @@
 
   if (lang == "ASM_NASM") {
     if (cmValue objectDeps = sf.GetProperty("OBJECT_DEPENDS")) {
-      std::string dependencies;
-      std::vector<std::string> depends = cmExpandedList(*objectDeps);
-      const char* sep = "";
-      for (std::string& d : depends) {
+      cmList depends{ *objectDeps };
+      for (auto& d : depends) {
         ConvertToWindowsSlash(d);
-        dependencies += sep;
-        dependencies += d;
-        sep = ";";
       }
-      e2.Element("AdditionalDependencies", dependencies);
+      e2.Element("AdditionalDependencies", depends.join(";"));
     }
   }
 
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index e727d22..7f26fd8 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -13,6 +13,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
+#include "cmList.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -270,7 +271,7 @@
 
   if (cmValue argList =
         this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) {
-    std::vector<std::string> arguments = cmExpandedList(*argList);
+    cmList arguments{ *argList };
     if (!arguments.empty()) {
       xout.StartElement("CommandLineArguments");
 
@@ -290,7 +291,7 @@
 
   if (cmValue envList =
         this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) {
-    std::vector<std::string> envs = cmExpandedList(*envList);
+    cmList envs{ *envList };
     if (!envs.empty()) {
       xout.StartElement("EnvironmentVariables");
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 8dee5cc..623478e 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -53,6 +53,7 @@
 #  include "cmMakefileProfilingData.h"
 #endif
 #include "cmJSONState.h"
+#include "cmList.h"
 #include "cmMessenger.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -813,7 +814,7 @@
     }
   } else if (mode == "COMPILE"_s) {
     std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
-    std::vector<std::string> includeDirs = cmExpandedList(includes);
+    cmList includeDirs{ includes };
 
     this->GlobalGenerator->CreateGenerationObjects();
     const auto& lg = this->GlobalGenerator->LocalGenerators[0];
@@ -829,7 +830,7 @@
     tgt->SetProperty("LINKER_LANGUAGE", language);
 
     std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
-    std::vector<std::string> libList = cmExpandedList(libs);
+    cmList libList{ libs };
     for (std::string const& lib : libList) {
       tgt->AddLinkLibrary(*mf, lib, GENERAL_LibraryType);
     }
@@ -1026,7 +1027,7 @@
 
     CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
                      [](std::string const& value, cmake* state) -> bool {
-                       std::vector<std::string> values = cmExpandedList(value);
+                       cmList values{ value };
                        state->CheckBuildSystemArgument = values[0];
                        state->ClearBuildSystem = (atoi(values[1].c_str()) > 0);
                        return true;
@@ -2163,7 +2164,7 @@
 
 int cmake::HandleDeleteCacheVariables(const std::string& var)
 {
-  std::vector<std::string> argsSplit = cmExpandedList(var, true);
+  cmList argsSplit{ var, cmList::EmptyElements::Yes };
   // erase the property to avoid infinite recursion
   this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
   if (this->GetIsInTryCompile()) {
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index f4e602b..ad27443 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -26,6 +26,7 @@
 #include "cmConsoleBuf.h"
 #include "cmDocumentationEntry.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageMetadata.h"
 #include "cmState.h"
@@ -457,7 +458,7 @@
   };
   auto targetLambda = [&](std::string const& value) -> bool {
     if (!value.empty()) {
-      std::vector<std::string> values = cmExpandedList(value);
+      cmList values{ value };
       for (auto const& v : values) {
         targets.emplace_back(v);
         if (v == "clean") {
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index c9beeff..f4d17f8 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -15,6 +15,7 @@
 #include "cmConsoleBuf.h"
 #include "cmDuration.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmQtAutoMocUic.h"
@@ -343,7 +344,7 @@
 {
   // Construct the iwyu command line by taking what was given
   // and adding all the arguments we give to the compiler.
-  std::vector<std::string> iwyu_cmd = cmExpandedList(runCmd, true);
+  cmList iwyu_cmd{ runCmd, cmList::EmptyElements::Yes };
   cm::append(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
   // Run the iwyu command line.  Capture its stderr and hide its stdout.
   std::string stdErr;
@@ -373,7 +374,7 @@
 int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
                const std::vector<std::string>& orig_cmd)
 {
-  std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true);
+  cmList tidy_cmd{ runCmd, cmList::EmptyElements::Yes };
   tidy_cmd.push_back(sourceFile);
 
   for (auto const& arg : tidy_cmd) {
@@ -423,7 +424,7 @@
 {
   // Construct the ldd -r -u (link what you use lwyu) command line
   // ldd -u -r lwuy target
-  std::vector<std::string> lwyu_cmd = cmExpandedList(runCmd, true);
+  cmList lwyu_cmd{ runCmd, cmList::EmptyElements::Yes };
   lwyu_cmd.push_back(sourceFile);
 
   // Run the lwyu check command line,  currently ldd is expected.
@@ -451,7 +452,7 @@
                   const std::vector<std::string>&)
 {
   // Construct the cpplint command line.
-  std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true);
+  cmList cpplint_cmd{ runCmd, cmList::EmptyElements::Yes };
   cpplint_cmd.push_back(sourceFile);
 
   // Run the cpplint command line.  Capture its output.
@@ -478,7 +479,7 @@
                    const std::vector<std::string>& orig_cmd)
 {
   // Construct the cpplint command line.
-  std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true);
+  cmList cppcheck_cmd{ runCmd, cmList::EmptyElements::Yes };
   // extract all the -D, -U, and -I options from the compile line
   for (auto const& opt : orig_cmd) {
     if (opt.size() > 2) {
diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in
index c47266a..3bb2fd6 100644
--- a/Templates/TestDriver.cxx.in
+++ b/Templates/TestDriver.cxx.in
@@ -20,11 +20,19 @@
 #  else
 #    define CM_NULL NULL
 #  endif
+#  define CM_NAMESPACE_BEGIN namespace {
+#  define CM_NAMESPACE_END }
+#  define CM_LOCAL
 #else
 #  define CM_CAST(TYPE, EXPR) (TYPE)(EXPR)
 #  define CM_NULL NULL
+#  define CM_NAMESPACE_BEGIN
+#  define CM_NAMESPACE_END
+#  define CM_LOCAL static
 #endif
 
+CM_NAMESPACE_BEGIN
+
 /* Create map.  */
 
 typedef int (*MainFuncPointer)(int, char* []); /* NOLINT */
@@ -34,17 +42,17 @@
   MainFuncPointer func;
 } functionMapEntry;
 
-static functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
+CM_LOCAL const functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
   @CMAKE_FUNCTION_TABLE_ENTRIES@
   { CM_NULL, CM_NULL } /* NOLINT */
 };
 
-static const int NumTests = CM_CAST(int,
+CM_LOCAL const int NumTests = CM_CAST(int,
   sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1;
 
 /* Allocate and create a lowercased copy of string
    (note that it has to be free'd manually) */
-static char* lowercase(const char* string)
+CM_LOCAL char* lowercase(const char* string)
 {
   char *new_string;
   char *p;
@@ -63,7 +71,7 @@
   return new_string;
 }
 
-static int isTestSkipped(const char *name, int n_skipped_tests, char *skipped_tests[]) {
+CM_LOCAL int isTestSkipped(const char *name, int n_skipped_tests, char *skipped_tests[]) {
   int i;
   for (i = 0; i < n_skipped_tests; i++) {
     if (strcmp(name, skipped_tests[i]) == 0) {
@@ -74,6 +82,8 @@
   return 0;
 }
 
+CM_NAMESPACE_END
+
 int main(int ac, char* av[])
 {
   int i;
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
index 5a03559..ac01c80 100644
--- a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
@@ -1,5 +1,5 @@
 CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
-  list index: (-2147483643|2147483647) out of range \(-5, 4\)
+  list index: (-2147483648|2147483647) out of range \(-5, 4\)
 Call Stack \(most recent call first\):
   CMP0121-ERANGE-OLD.cmake:2 \(include\)
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
index cb4ea46..c644dd3 100644
--- a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
@@ -9,7 +9,7 @@
 This warning is for project developers.  Use -Wno-dev to suppress it.
 .*
 CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
-  list index: (-2147483643|2147483647) out of range \(-5, 4\)
+  list index: (-2147483648|2147483647) out of range \(-5, 4\)
 Call Stack \(most recent call first\):
   CMP0121-ERANGE-WARN.cmake:2 \(include\)
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index f05f784..90feeb6 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -370,6 +370,7 @@
 add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
 add_RunCMake_test(GenEx-PATH)
 add_RunCMake_test(GenEx-PATH_EQUAL)
+add_RunCMake_test(GenEx-LIST)
 add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)
diff --git a/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx b/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx
index 65f17b6..2824fbf 100644
--- a/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx
+++ b/Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx
@@ -19,6 +19,7 @@
 #include "cmCTestTestHandler.h"
 #include "cmFileLock.h"
 #include "cmFileLockResult.h"
+#include "cmList.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -282,7 +283,7 @@
   if (argc == 5) {
     testNames = argv[4];
   }
-  auto testNameList = cmExpandedList(testNames, false);
+  cmList testNameList{ testNames };
   std::set<std::string> testNameSet(testNameList.begin(), testNameList.end());
 
   cmCTestResourceSpec spec;
diff --git a/Tests/RunCMake/GenEx-LIST/APPEND.cmake.in b/Tests/RunCMake/GenEx-LIST/APPEND.cmake.in
new file mode 100644
index 0000000..19e1d12
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/APPEND.cmake.in
@@ -0,0 +1,34 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(APPEND listvar e)
+set (output "$<LIST:APPEND,a;b;c;d,e>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(APPEND listvar e f)
+set (output "$<LIST:APPEND,a;b;c;d,e,f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(APPEND listvar e f)
+set (output "$<LIST:APPEND,a;b;c;d,e;f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+unset(listvar)
+list(APPEND listvar e f)
+set (output "$<LIST:APPEND,,e,f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:APPEND..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/CMakeLists.txt b/Tests/RunCMake/GenEx-LIST/CMakeLists.txt
new file mode 100644
index 0000000..5161b99
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.18...3.25)
+
+project(${RunCMake_TEST} NONE)
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-result.txt b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-stderr.txt b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-stderr.txt
new file mode 100644
index 0000000..3064c00
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at FILTER-wrong-operator.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:FILTER,a;b;c,WRONG_OPERATOR,\^a>
+
+  sub-command FILTER does not recognize operator "WRONG_OPERATOR".  It must
+  be either INCLUDE or EXCLUDE.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator.cmake b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator.cmake
new file mode 100644
index 0000000..e01b4fe
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-operator.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:FILTER,a;b;c,WRONG_OPERATOR,^a>")
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-result.txt b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-stderr.txt b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-stderr.txt
new file mode 100644
index 0000000..b2f9b8a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at FILTER-wrong-regex.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:FILTER,a;b;c,INCLUDE,\^\(a>
+
+  sub-command FILTER, failed to compile regex "\^\(a".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex.cmake b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex.cmake
new file mode 100644
index 0000000..1311f31
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FILTER-wrong-regex.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:FILTER,a;b;c,INCLUDE,^(a>")
diff --git a/Tests/RunCMake/GenEx-LIST/FIND.cmake.in b/Tests/RunCMake/GenEx-LIST/FIND.cmake.in
new file mode 100644
index 0000000..e2242c3
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/FIND.cmake.in
@@ -0,0 +1,20 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(FIND listvar "c" reference)
+set (output "$<LIST:FIND,a;b;c;d,c>")
+if (NOT output EQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(FIND listvar "e" reference)
+set (output "$<LIST:FIND,a;b;c;d,e>")
+if (NOT output EQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:FIND..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-result.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-stderr.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-stderr.txt
new file mode 100644
index 0000000..dcd1f2f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at GET-wrong-index1.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:GET,,0>
+
+  given empty list
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index1.cmake b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1.cmake
new file mode 100644
index 0000000..4c395b3
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index1.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,,0>")
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-result.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-stderr.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-stderr.txt
new file mode 100644
index 0000000..20f1af4
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at GET-wrong-index2.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:GET,a;b,2>
+
+  index: 2 out of range \(-2, 1\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index2.cmake b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2.cmake
new file mode 100644
index 0000000..28c97e2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index2.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,a;b,2>")
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-result.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-stderr.txt b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-stderr.txt
new file mode 100644
index 0000000..a5dccbe
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at GET-wrong-index3.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:GET,a;b,1,-3>
+
+  index: -3 out of range \(-2, 1\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/GET-wrong-index3.cmake b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3.cmake
new file mode 100644
index 0000000..fd7be17
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET-wrong-index3.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,a;b,1,-3>")
diff --git a/Tests/RunCMake/GenEx-LIST/GET.cmake.in b/Tests/RunCMake/GenEx-LIST/GET.cmake.in
new file mode 100644
index 0000000..102eb42
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/GET.cmake.in
@@ -0,0 +1,20 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(GET listvar 0 2 reference)
+set (output "$<LIST:GET,a;b;c;d,0,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(GET listvar 0 -3 2 reference)
+set (output "$<LIST:GET,a;b;c;d,0,-3,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:GET..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-result.txt b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-stderr.txt b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-stderr.txt
new file mode 100644
index 0000000..ce36fb1
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at INSERT-wrong-index1.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:INSERT,a;b;c,4,d>
+
+  index: 4 out of range \(-3, 3\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1.cmake b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1.cmake
new file mode 100644
index 0000000..ead5832
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index1.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:INSERT,a;b;c,4,d>")
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-result.txt b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-stderr.txt b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-stderr.txt
new file mode 100644
index 0000000..f0ea1d7
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at INSERT-wrong-index2.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:INSERT,a;b;c,-4,d>
+
+  index: -4 out of range \(-3, 3\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2.cmake b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2.cmake
new file mode 100644
index 0000000..c057b87
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT-wrong-index2.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:INSERT,a;b;c,-4,d>")
diff --git a/Tests/RunCMake/GenEx-LIST/INSERT.cmake.in b/Tests/RunCMake/GenEx-LIST/INSERT.cmake.in
new file mode 100644
index 0000000..d3bb9b9
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/INSERT.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(INSERT listvar 1 e)
+set (output "$<LIST:INSERT,a;b;c;d,1,e>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+
+list(INSERT listvar 2 e f)
+set (output "$<LIST:INSERT,a;b;c;d,2,e,f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(INSERT listvar 0 e f)
+set (output "$<LIST:INSERT,a;b;c;d,0,e;f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(INSERT listvar -2 e f)
+set (output "$<LIST:INSERT,a;b;c;d,-2,e;f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(INSERT listvar 3 e f)
+set (output "$<LIST:INSERT,a;b;c;d,3,e;f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+unset(listvar)
+list(INSERT listvar 0 e f)
+set (output "$<LIST:INSERT,,0,e,f>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:INSERT..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/JOIN.cmake.in b/Tests/RunCMake/GenEx-LIST/JOIN.cmake.in
new file mode 100644
index 0000000..0a56450
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/JOIN.cmake.in
@@ -0,0 +1,35 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(JOIN listvar ":" reference)
+set (output "$<LIST:JOIN,a;b;c;d,:>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(JOIN listvar "" reference)
+set (output "$<LIST:JOIN,a;b;c;d,>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a)
+
+list(JOIN listvar ":" reference)
+set (output "$<LIST:JOIN,a,:>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+unset(listvar)
+
+list(JOIN listvar ":" reference)
+set (output "$<LIST:JOIN,,:>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+check_errors("LIST:JOIN..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/LENGTH.cmake.in b/Tests/RunCMake/GenEx-LIST/LENGTH.cmake.in
new file mode 100644
index 0000000..0840e11
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/LENGTH.cmake.in
@@ -0,0 +1,30 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(LENGTH listvar reference)
+set (output "$<LIST:LENGTH,a;b;c;d>")
+if (NOT output EQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar "")
+
+list(LENGTH listvar reference)
+set (output "$<LIST:LENGTH,>")
+if (NOT output EQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+unset(listvar)
+
+list(LENGTH listvar reference)
+set (output "$<LIST:LENGTH,>")
+if (NOT output EQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:LENGTH..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/POP_BACK.cmake.in b/Tests/RunCMake/GenEx-LIST/POP_BACK.cmake.in
new file mode 100644
index 0000000..ba95c83
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/POP_BACK.cmake.in
@@ -0,0 +1,18 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(POP_BACK listvar)
+set (output "$<LIST:POP_BACK,a;b;c;d>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set (output "$<LIST:POP_BACK,>")
+if (NOT output STREQUAL "")
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:POP_BACK..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/POP_FRONT.cmake.in b/Tests/RunCMake/GenEx-LIST/POP_FRONT.cmake.in
new file mode 100644
index 0000000..0d676af
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/POP_FRONT.cmake.in
@@ -0,0 +1,18 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(POP_FRONT listvar)
+set (output "$<LIST:POP_FRONT,a;b;c;d>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set (output "$<LIST:POP_FRONT,>")
+if (NOT output STREQUAL "")
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:POP_FRONT..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/PREPEND.cmake.in b/Tests/RunCMake/GenEx-LIST/PREPEND.cmake.in
new file mode 100644
index 0000000..49b8f98
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/PREPEND.cmake.in
@@ -0,0 +1,34 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(PREPEND listvar e)
+set (output "$<LIST:PREPEND,a;b;c;d,e>")
+if (NOT output STREQUAL listvar)
+  list (PREPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(PREPEND listvar e f)
+set (output "$<LIST:PREPEND,a;b;c;d,e,f>")
+if (NOT output STREQUAL listvar)
+  list (PREPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(PREPEND listvar e f)
+set (output "$<LIST:PREPEND,a;b;c;d,e;f>")
+if (NOT output STREQUAL listvar)
+  list (PREPEND errors "returns bad value: ${output}")
+endif()
+
+unset(listvar)
+list(PREPEND listvar e f)
+set (output "$<LIST:PREPEND,,e,f>")
+if (NOT output STREQUAL listvar)
+  list (PREPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:PREPEND..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-result.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-stderr.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-stderr.txt
new file mode 100644
index 0000000..b874f1d
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at REMOVE_AT-wrong-index1.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:REMOVE_AT,,0>
+
+  index: 0 out of range \(0, 0\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1.cmake b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1.cmake
new file mode 100644
index 0000000..d87559e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index1.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,,0>")
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-result.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-stderr.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-stderr.txt
new file mode 100644
index 0000000..509eed4
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at REMOVE_AT-wrong-index2.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:REMOVE_AT,a;b;c,3>
+
+  index: 3 out of range \(-3, 2\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2.cmake b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2.cmake
new file mode 100644
index 0000000..7ecfad2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index2.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,a;b;c,3>")
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-result.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-stderr.txt b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-stderr.txt
new file mode 100644
index 0000000..c8fc465
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at REMOVE_AT-wrong-index3.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:REMOVE_AT,a;b;c,-4>
+
+  index: -4 out of range \(-3, 2\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3.cmake b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3.cmake
new file mode 100644
index 0000000..f8f9a3e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT-wrong-index3.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,a;b;c,-4>")
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_AT.cmake.in b/Tests/RunCMake/GenEx-LIST/REMOVE_AT.cmake.in
new file mode 100644
index 0000000..42a9476
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_AT.cmake.in
@@ -0,0 +1,25 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(REMOVE_AT listvar 1 3)
+set (output "$<LIST:REMOVE_AT,a;b;c;d,1,3>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(REMOVE_AT listvar 1 -2)
+set (output "$<LIST:REMOVE_AT,a;b;c;d,1;-2>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set (output "$<LIST:REMOVE_AT,a;b;c;d,1,0,3;2>")
+if (NOT output STREQUAL "")
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:REMOVE_AT..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_DUPLICATES.cmake.in b/Tests/RunCMake/GenEx-LIST/REMOVE_DUPLICATES.cmake.in
new file mode 100644
index 0000000..8785ae5
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_DUPLICATES.cmake.in
@@ -0,0 +1,20 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(REMOVE_DUPLICATES listvar)
+set (output "$<LIST:REMOVE_DUPLICATES,a;b;c;d>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar "b;c;b;a;a;c;b;a;c;b")
+list(REMOVE_DUPLICATES listvar)
+set (output "$<LIST:REMOVE_DUPLICATES,b;c;b;a;a;c;b;a;c;b>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:REMOVE_DUPLICATES..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/REMOVE_ITEM.cmake.in b/Tests/RunCMake/GenEx-LIST/REMOVE_ITEM.cmake.in
new file mode 100644
index 0000000..5434a5d
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REMOVE_ITEM.cmake.in
@@ -0,0 +1,32 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+list(REMOVE_ITEM listvar b d)
+set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b,d>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(REMOVE_ITEM listvar b e)
+set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b,e>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar a b c d)
+list(REMOVE_ITEM listvar b a d c)
+set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b;a;d;c>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set (output "$<LIST:REMOVE_ITEM,,b;a;d;c>")
+if (NOT output STREQUAL "")
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:REMOVE_ITEM..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/REVERSE.cmake.in b/Tests/RunCMake/GenEx-LIST/REVERSE.cmake.in
new file mode 100644
index 0000000..295e1a3
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/REVERSE.cmake.in
@@ -0,0 +1,19 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(REVERSE listvar)
+set (output "$<LIST:REVERSE,a;b;c;d>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set (output "$<LIST:REVERSE,>")
+if (NOT output STREQUAL "")
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:REVERSE..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-LIST/RunCMakeTest.cmake
new file mode 100644
index 0000000..1946e84
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/RunCMakeTest.cmake
@@ -0,0 +1,130 @@
+
+include(RunCMake)
+
+run_cmake(no-arguments)
+run_cmake(bad-option)
+
+function(check_list_syntax name test)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-${test}-build)
+  set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}")
+  run_cmake_with_options(${test} ${ARGN})
+endfunction()
+
+## Unexpected arguments
+### sub-commands with one argument
+foreach (subcommand IN ITEMS LENGTH POP_BACK POP_FRONT REMOVE_DUPLICATES REVERSE)
+  check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2")
+endforeach()
+
+### sub-commands with two arguments
+foreach (subcommand IN ITEMS FIND JOIN)
+  check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3")
+endforeach()
+
+### sub-commands with three arguments
+foreach (subcommand IN ITEMS SUBLIST FILTER)
+  check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3,ARG4")
+endforeach()
+
+# TRANSFORM sub-commands
+  set(RunCMake-stderr-file "TRANSFORM-unexpected-arg-stderr.txt")
+foreach (action IN ITEMS TOLOWER TOUPPER STRIP)
+  check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2")
+endforeach()
+foreach (action IN ITEMS APPEND PREPEND)
+  check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2,ARG3")
+endforeach()
+foreach (action IN ITEMS REPLACE)
+  check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2,ARG3,ARG4")
+endforeach()
+check_list_syntax (TRANSFORM-SELECTOR-REGEX unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,STRIP,REGEX,ARG2,ARG3")
+check_list_syntax (TRANSFORM-SELECTOR-FOR unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,STRIP,FOR,1,2,3,4")
+unset(RunCMake-stderr-file)
+
+## Missing arguments
+### sub-command with, at least, two arguments
+foreach (subcommand IN ITEMS GET APPEND PREPEND REMOVE_ITEM REMOVE_AT TRANSFORM)
+  check_list_syntax (${subcommand} missing-arg "-DLIST_ARGUMENTS=${subcommand},ARG1")
+endforeach()
+
+### sub-command with, at least, three arguments
+foreach (subcommand IN ITEMS INSERT)
+  check_list_syntax (${subcommand} missing-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2")
+endforeach()
+
+# TRANSFORM sub-commands
+set(RunCMake-stderr-file "TRANSFORM-missing-arg-stderr.txt")
+foreach (action IN ITEMS APPEND PREPEND)
+  check_list_syntax (TRANSFORM-${action} missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action}")
+endforeach()
+check_list_syntax (TRANSFORM-REPLACE-1 missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,REPLACE,ARG2")
+check_list_syntax (TRANSFORM-REPLACE-2 missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,REPLACE")
+unset(RunCMake-stderr-file)
+
+
+run_cmake(GET-wrong-index1)
+run_cmake(GET-wrong-index2)
+run_cmake(GET-wrong-index3)
+run_cmake(SUBLIST-wrong-argument1)
+run_cmake(SUBLIST-wrong-argument2)
+run_cmake(INSERT-wrong-index1)
+run_cmake(INSERT-wrong-index2)
+run_cmake(REMOVE_AT-wrong-index1)
+run_cmake(REMOVE_AT-wrong-index2)
+run_cmake(REMOVE_AT-wrong-index3)
+run_cmake(FILTER-wrong-operator)
+run_cmake(FILTER-wrong-regex)
+run_cmake(TRANSFORM-wrong-action)
+run_cmake(TRANSFORM-REPLACE-wrong-regex)
+run_cmake(TRANSFORM-REPLACE-invalid-replace1)
+run_cmake(TRANSFORM-REPLACE-invalid-replace2)
+run_cmake(TRANSFORM-selector-REGEX-no-arguments)
+run_cmake(TRANSFORM-selector-REGEX-wrong-regex)
+run_cmake(TRANSFORM-selector-AT-no-arguments)
+run_cmake(TRANSFORM-selector-AT-wrong-argument)
+run_cmake(TRANSFORM-selector-AT-wrong-index)
+run_cmake(TRANSFORM-selector-FOR-no-arguments)
+run_cmake(TRANSFORM-selector-FOR-missing-arguments)
+run_cmake(TRANSFORM-selector-FOR-wrong-argument)
+run_cmake(TRANSFORM-selector-FOR-wrong-index)
+run_cmake(TRANSFORM-selector-FOR-zero-step)
+run_cmake(TRANSFORM-selector-FOR-negative-step)
+run_cmake(TRANSFORM-selector-FOR-backwards-range)
+run_cmake(SORT-wrong-option)
+run_cmake(SORT-wrong-COMPARE-option)
+run_cmake(SORT-wrong-CASE-option)
+run_cmake(SORT-wrong-ORDER-option)
+run_cmake(SORT-duplicate-COMPARE-option)
+run_cmake(SORT-duplicate-CASE-option)
+run_cmake(SORT-duplicate-ORDER-option)
+
+
+function(check_list_execution name)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}")
+  run_cmake_with_options(generate -DLIST_TEST=${name})
+  run_cmake_command(check "${CMAKE_COMMAND}" "-DRunCMake_SOURCE_DIR=${RunCMake_SOURCE_DIR}" -P "${RunCMake_TEST_BINARY_DIR}/${name}.cmake")
+endfunction()
+
+check_list_execution (LENGTH)
+check_list_execution (GET)
+check_list_execution (JOIN)
+check_list_execution (SUBLIST)
+check_list_execution (FIND)
+check_list_execution (APPEND)
+check_list_execution (PREPEND)
+check_list_execution (INSERT)
+check_list_execution (POP_BACK)
+check_list_execution (POP_FRONT)
+check_list_execution (REMOVE_ITEM)
+check_list_execution (REMOVE_AT)
+check_list_execution (REMOVE_DUPLICATES)
+check_list_execution (TRANSFORM-TOUPPER)
+check_list_execution (TRANSFORM-TOLOWER)
+check_list_execution (TRANSFORM-STRIP)
+check_list_execution (TRANSFORM-APPEND)
+check_list_execution (TRANSFORM-PREPEND)
+check_list_execution (TRANSFORM-REPLACE)
+check_list_execution (REVERSE)
+check_list_execution (SORT)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-stderr.txt
new file mode 100644
index 0000000..4f3121a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SORT-duplicate-CASE-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,CASE:SENSITIVE>
+
+  sub-command SORT, CASE option has been specified multiple times.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option.cmake
new file mode 100644
index 0000000..e09dc6c
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-CASE-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,CASE:SENSITIVE>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-stderr.txt
new file mode 100644
index 0000000..fbb96bb
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SORT-duplicate-COMPARE-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,COMPARE:STRING,COMPARE:NATURAL>
+
+  sub-command SORT, COMPARE option has been specified multiple times.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option.cmake
new file mode 100644
index 0000000..cf8da0d
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-COMPARE-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,COMPARE:NATURAL>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-stderr.txt
new file mode 100644
index 0000000..b45034a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SORT-duplicate-ORDER-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,ORDER:ASCENDING,COMPARE:STRING,ORDER:DESCENDING,CASE:SENSITIVE>
+
+  sub-command SORT, ORDER option has been specified multiple times.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option.cmake
new file mode 100644
index 0000000..3826072
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-duplicate-ORDER-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,ORDER:ASCENDING,COMPARE:STRING,ORDER:DESCENDING,CASE:SENSITIVE>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-stderr.txt
new file mode 100644
index 0000000..d36e63b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at SORT-wrong-CASE-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,COMPARE:STRING,CASE:WRONG_OPTION>
+
+  sub-command SORT, an invalid CASE option has been specified:
+  "WRONG_OPTION".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option.cmake
new file mode 100644
index 0000000..58df9ea
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-CASE-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:WRONG_OPTION>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-stderr.txt
new file mode 100644
index 0000000..70a99c6
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at SORT-wrong-COMPARE-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,COMPARE:WRONG_OPTION>
+
+  sub-command SORT, an invalid COMPARE option has been specified:
+  "WRONG_OPTION".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option.cmake
new file mode 100644
index 0000000..73727bb
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-COMPARE-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:WRONG_OPTION>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-stderr.txt
new file mode 100644
index 0000000..2e23d8c
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at SORT-wrong-ORDER-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,ORDER:WRONG_OPTION>
+
+  sub-command SORT, an invalid ORDER option has been specified:
+  "WRONG_OPTION".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option.cmake
new file mode 100644
index 0000000..135c935
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-ORDER-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,ORDER:WRONG_OPTION>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-result.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-stderr.txt
new file mode 100644
index 0000000..3c2d492
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SORT-wrong-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SORT,a;b,WRONG_OPTION>
+
+  sub-command SORT, option "WRONG_OPTION" is invalid.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SORT-wrong-option.cmake b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option.cmake
new file mode 100644
index 0000000..fca268b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT-wrong-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,WRONG_OPTION>")
diff --git a/Tests/RunCMake/GenEx-LIST/SORT.cmake.in b/Tests/RunCMake/GenEx-LIST/SORT.cmake.in
new file mode 100644
index 0000000..aca6691
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SORT.cmake.in
@@ -0,0 +1,92 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(source_unsorted c/B.h a/c.h B/a.h)
+
+set(listvar ${source_unsorted})
+list(SORT listvar)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE INSENSITIVE ORDER ASCENDING COMPARE STRING)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:ASCENDING,COMPARE:STRING>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE INSENSITIVE ORDER DESCENDING COMPARE STRING)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE STRING)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:STRING>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE STRING)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE INSENSITIVE ORDER ASCENDING COMPARE FILE_BASENAME)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:ASCENDING,COMPARE:FILE_BASENAME>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE INSENSITIVE ORDER DESCENDING COMPARE FILE_BASENAME)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:DESCENDING,COMPARE:FILE_BASENAME>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE FILE_BASENAME)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:FILE_BASENAME>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar ${source_unsorted})
+list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE FILE_BASENAME)
+set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:FILE_BASENAME>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
+list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE STRING)
+set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
+list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE NATURAL)
+set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:NATURAL>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
+list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE NATURAL)
+set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:NATURAL>")
+if (NOT output STREQUAL listvar)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:SORT..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-result.txt b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-stderr.txt b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-stderr.txt
new file mode 100644
index 0000000..078f345
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SUBLIST-wrong-argument1.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SUBLIST,a;b;c,3,-1>
+
+  begin index: 3 is out of range 0 - 2
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1.cmake b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1.cmake
new file mode 100644
index 0000000..293c2ae
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument1.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SUBLIST,a;b;c,3,-1>")
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-result.txt b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-stderr.txt b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-stderr.txt
new file mode 100644
index 0000000..7271b30
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at SUBLIST-wrong-argument2.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:SUBLIST,a;b;c,1,-2>
+
+  length: -2 should be -1 or greater
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2.cmake b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2.cmake
new file mode 100644
index 0000000..9d1db53
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST-wrong-argument2.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SUBLIST,a;b;c,1,-2>")
diff --git a/Tests/RunCMake/GenEx-LIST/SUBLIST.cmake.in b/Tests/RunCMake/GenEx-LIST/SUBLIST.cmake.in
new file mode 100644
index 0000000..9fcb6d5
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/SUBLIST.cmake.in
@@ -0,0 +1,32 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar a b c d)
+
+list(SUBLIST listvar 1 2 reference)
+set (output "$<LIST:SUBLIST,a;b;c;d,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(SUBLIST listvar 1 -1 reference)
+set (output "$<LIST:SUBLIST,a;b;c;d,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(SUBLIST listvar 1 0 reference)
+set (output "$<LIST:SUBLIST,a;b;c;d,1,0>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(SUBLIST listvar 1 5 reference)
+set (output "$<LIST:SUBLIST,a;b;c;d,1,5>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:SUBLIST..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-APPEND.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-APPEND.cmake.in
new file mode 100644
index 0000000..a6529ec
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-APPEND.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar alpha bravo charlie delta)
+
+list(TRANSFORM listvar APPEND "_A" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar APPEND "_A" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,REGEX,(r|t)a>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,APPEND..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-PREPEND.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-PREPEND.cmake.in
new file mode 100644
index 0000000..5ec6acd
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-PREPEND.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar alpha bravo charlie delta)
+
+list(TRANSFORM listvar PREPEND "P_" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar PREPEND "P_" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,REGEX,(r|t)a>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,PREPEND..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-stderr.txt
new file mode 100644
index 0000000..6674b30
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-REPLACE-invalid-replace1.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,REPLACE,\^a,b\\>
+
+  sub-command TRANSFORM, action REPLACE: replace-expression ends in a
+  backslash.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1.cmake
new file mode 100644
index 0000000..d45e1fd
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace1.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,^a,b\\>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-stderr.txt
new file mode 100644
index 0000000..2351b72
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-REPLACE-invalid-replace2.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,REPLACE,\^a,\\b>
+
+  sub-command TRANSFORM, action REPLACE: Unknown escape "\\b" in
+  replace-expression.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2.cmake
new file mode 100644
index 0000000..b800f24
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-invalid-replace2.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,^a,\\b>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-stderr.txt
new file mode 100644
index 0000000..617c3d6
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-REPLACE-wrong-regex.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,REPLACE,\(a,b>
+
+  sub-command TRANSFORM, action REPLACE: Failed to compile regex "\(a".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex.cmake
new file mode 100644
index 0000000..941e3e7
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE-wrong-regex.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,(a,b>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE.cmake.in
new file mode 100644
index 0000000..5fba231
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-REPLACE.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar alpha bravo charlie delta)
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,REGEX,(r|t)a>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,REPLACE..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-STRIP.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-STRIP.cmake.in
new file mode 100644
index 0000000..860faec
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-STRIP.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar " alpha" "bravo " " charlie " delta)
+
+list(TRANSFORM listvar STRIP OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar STRIP REGEX "(r|t)a" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,REGEX,(r|t)a>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,STRIP..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOLOWER.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOLOWER.cmake.in
new file mode 100644
index 0000000..43e9955
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOLOWER.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar ALPHA BRAVO CHARLIE DELTA)
+
+list(TRANSFORM listvar TOLOWER OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOLOWER REGEX "(R|T)A" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,REGEX,(R|T)A>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,TOLOWER..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOUPPER.cmake.in b/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOUPPER.cmake.in
new file mode 100644
index 0000000..be2bc30
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-TOUPPER.cmake.in
@@ -0,0 +1,50 @@
+
+include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
+unset (errors)
+
+set(listvar alpha bravo charlie delta)
+
+list(TRANSFORM listvar TOUPPER OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER AT 1 3 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,AT,1,3>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER AT 1 -2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,AT,1,-2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER FOR 1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER FOR 1 -1 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,-1>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER FOR 1 -1 2 OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,-1,2>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+list(TRANSFORM listvar TOUPPER REGEX "(r|t)a" OUTPUT_VARIABLE reference)
+set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,REGEX,(r|t)a>")
+if (NOT output STREQUAL reference)
+  list (APPEND errors "returns bad value: ${output}")
+endif()
+
+
+check_errors("LIST:TRANSFORM,TOUPPER..." ${errors})
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-missing-arg-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-missing-arg-stderr.txt
new file mode 100644
index 0000000..46e36c3
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-missing-arg-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at missing-arg.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,ARG1,[A-Z]+(,ARG[0-9])?>
+
+  sub-command TRANSFORM, action [A-Z]+ expects (1|2) argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-stderr.txt
new file mode 100644
index 0000000..69b4915
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-AT-no-arguments.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,AT>
+
+  sub-command TRANSFORM, selector AT expects at least one numeric value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments.cmake
new file mode 100644
index 0000000..2447511
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-no-arguments.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,AT>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-stderr.txt
new file mode 100644
index 0000000..40007a1
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-AT-wrong-argument.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,AT,0,1x,2>
+
+  sub-command TRANSFORM, selector AT: '1x': unexpected argument.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument.cmake
new file mode 100644
index 0000000..49f4e90
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-argument.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,AT,0,1x,2>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-stderr.txt
new file mode 100644
index 0000000..66085ab
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-AT-wrong-index.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,AT,0,3,2>
+
+  sub-command TRANSFORM, selector AT, index: 3 out of range \(-3, 2\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index.cmake
new file mode 100644
index 0000000..fd6c3ed
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-AT-wrong-index.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,AT,0,3,2>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-stderr.txt
new file mode 100644
index 0000000..77cffdc
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-selector-FOR-backwards-range.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,2,0>
+
+  sub-command TRANSFORM, selector FOR expects <start> to be no greater than
+  <stop> \(2 > 0\)
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range.cmake
new file mode 100644
index 0000000..17f57f5
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-backwards-range.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,2,0>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-stderr.txt
new file mode 100644
index 0000000..a9de7f8
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-FOR-missing-arguments.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,FOR,0>
+
+  sub-command TRANSFORM, selector FOR expects, at least, two arguments.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments.cmake
new file mode 100644
index 0000000..5ae481a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-missing-arguments.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,FOR,0>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-stderr.txt
new file mode 100644
index 0000000..9c81de4
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-selector-FOR-negative-step.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,2,-1>
+
+  sub-command TRANSFORM, selector FOR expects positive numeric value for
+  <step>.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step.cmake
new file mode 100644
index 0000000..b8e6433
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-negative-step.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,2,-1>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-stderr.txt
new file mode 100644
index 0000000..d31f171
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-FOR-no-arguments.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,FOR>
+
+  sub-command TRANSFORM, selector FOR expects, at least, two arguments.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments.cmake
new file mode 100644
index 0000000..6545ff9
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-no-arguments.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,FOR>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-stderr.txt
new file mode 100644
index 0000000..727be10
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-FOR-wrong-argument.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,1x,2>
+
+  sub-command TRANSFORM, selector FOR expects, at least, two numeric values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument.cmake
new file mode 100644
index 0000000..a50b62c
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-argument.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,1x,2>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-stderr.txt
new file mode 100644
index 0000000..664e35a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-FOR-wrong-index.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,4,2>
+
+  sub-command TRANSFORM, selector FOR, index: 4 out of range \(-3, 2\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index.cmake
new file mode 100644
index 0000000..f35bfbf
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-wrong-index.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,4,2>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-stderr.txt
new file mode 100644
index 0000000..e542fbf
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-selector-FOR-zero-step.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,2,0>
+
+  sub-command TRANSFORM, selector FOR expects positive numeric value for
+  <step>.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step.cmake
new file mode 100644
index 0000000..2bfaab0
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-FOR-zero-step.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,TOUPPER,FOR,0,2,0>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-stderr.txt
new file mode 100644
index 0000000..079172b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TRANSFORM-selector-REGEX-no-arguments.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,REGEX>
+
+  sub-command TRANSFORM, selector REGEX expects 'regular expression'
+  argument.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments.cmake
new file mode 100644
index 0000000..1f802b7
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-no-arguments.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,REGEX>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-stderr.txt
new file mode 100644
index 0000000..3fe2b01
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TRANSFORM-selector-REGEX-wrong-regex.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b,TOUPPER,REGEX,\(a>
+
+  sub-command TRANSFORM, selector REGEX failed to compile regex "\(a".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex.cmake
new file mode 100644
index 0000000..1648092
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-selector-REGEX-wrong-regex.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,TOUPPER,REGEX,(a>")
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-unexpected-arg-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-unexpected-arg-stderr.txt
new file mode 100644
index 0000000..04e9df1
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-unexpected-arg-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at unexpected-arg.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,ARG1,[A-Z_]+(,[A-Z0-9]+)+>
+
+  sub-command TRANSFORM, '[A-Z0-9]+': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-result.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-stderr.txt b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-stderr.txt
new file mode 100644
index 0000000..1c30c4f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error at TRANSFORM-wrong-action.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:TRANSFORM,a;b;c,WRONG_ACTION>
+   sub-command TRANSFORM, WRONG_ACTION invalid action.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action.cmake b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action.cmake
new file mode 100644
index 0000000..fba6c90
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/TRANSFORM-wrong-action.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b;c,WRONG_ACTION>")
diff --git a/Tests/RunCMake/GenEx-LIST/bad-option-result.txt b/Tests/RunCMake/GenEx-LIST/bad-option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/bad-option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/bad-option-stderr.txt b/Tests/RunCMake/GenEx-LIST/bad-option-stderr.txt
new file mode 100644
index 0000000..37048c5
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/bad-option-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at bad-option.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:BAD_OPTION,ARG>
+
+  BAD_OPTION: invalid option.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/bad-option.cmake b/Tests/RunCMake/GenEx-LIST/bad-option.cmake
new file mode 100644
index 0000000..d1dc85f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/bad-option.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:BAD_OPTION,ARG>")
diff --git a/Tests/RunCMake/GenEx-LIST/check_errors.cmake b/Tests/RunCMake/GenEx-LIST/check_errors.cmake
new file mode 100644
index 0000000..7e60fc7
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/check_errors.cmake
@@ -0,0 +1,13 @@
+
+function (CHECK_ERRORS command)
+  set (errors ${ARGN})
+  set (command "$<${command}>")
+  if (errors)
+    string (LENGTH "${command}" length)
+    math (EXPR count "${length} + 2")
+    string (REPEAT " " ${count} shift)
+    list (TRANSFORM errors PREPEND "${shift}")
+    list (JOIN errors "\n" msg)
+    message (FATAL_ERROR "${command}: ${msg}")
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/GenEx-LIST/generate.cmake b/Tests/RunCMake/GenEx-LIST/generate.cmake
new file mode 100644
index 0000000..92cdca2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/generate.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT "${LIST_TEST}.cmake" INPUT "${LIST_TEST}.cmake.in")
diff --git a/Tests/RunCMake/GenEx-LIST/missing-arg-result.txt b/Tests/RunCMake/GenEx-LIST/missing-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/missing-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/missing-arg-stderr.txt b/Tests/RunCMake/GenEx-LIST/missing-arg-stderr.txt
new file mode 100644
index 0000000..c7cbe4b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/missing-arg-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at missing-arg.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:[A-Z_]+,.+>
+
+  \$<LIST:[A-Z_]+> expression requires at least (two|three) parameters.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/missing-arg.cmake b/Tests/RunCMake/GenEx-LIST/missing-arg.cmake
new file mode 100644
index 0000000..48b26e1
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/missing-arg.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:${LIST_ARGUMENTS}>")
diff --git a/Tests/RunCMake/GenEx-LIST/no-arguments-result.txt b/Tests/RunCMake/GenEx-LIST/no-arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/no-arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LIST/no-arguments-stderr.txt
new file mode 100644
index 0000000..ee782ec
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/no-arguments-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at no-arguments.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:>
+
+  \$<LIST> expression requires at least two parameters.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/no-arguments.cmake b/Tests/RunCMake/GenEx-LIST/no-arguments.cmake
new file mode 100644
index 0000000..f704e2b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/no-arguments.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:>")
diff --git a/Tests/RunCMake/GenEx-LIST/unexpected-arg-result.txt b/Tests/RunCMake/GenEx-LIST/unexpected-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/unexpected-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LIST/unexpected-arg-stderr.txt b/Tests/RunCMake/GenEx-LIST/unexpected-arg-stderr.txt
new file mode 100644
index 0000000..a7b1f25
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/unexpected-arg-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at unexpected-arg.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<LIST:[A-Z_]+,.+>
+
+  \$<LIST:[A-Z_]+(,[A-Z_]+)?> expression requires exactly (one|two|three) parameters?.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-LIST/unexpected-arg.cmake b/Tests/RunCMake/GenEx-LIST/unexpected-arg.cmake
new file mode 100644
index 0000000..48b26e1
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LIST/unexpected-arg.cmake
@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT result.txt CONTENT "$<LIST:${LIST_ARGUMENTS}>")
diff --git a/Utilities/Scripts/update-libarchive.bash b/Utilities/Scripts/update-libarchive.bash
index 856a6ea..5a4f11a 100755
--- a/Utilities/Scripts/update-libarchive.bash
+++ b/Utilities/Scripts/update-libarchive.bash
@@ -8,7 +8,7 @@
 readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
 readonly subtree="Utilities/cmlibarchive"
 readonly repo="https://github.com/libarchive/libarchive.git"
-readonly tag="v3.6.0"
+readonly tag="v3.6.2"
 readonly shortlog=false
 readonly paths="
   CMakeLists.txt
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index b38e653..027de5c 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -238,7 +238,7 @@
 OPTION(ENABLE_LIBXML2 "Enable the use of the system libxml2 library if found" ON)
 OPTION(ENABLE_EXPAT "Enable the use of the system EXPAT library if found" ON)
 OPTION(ENABLE_PCREPOSIX "Enable the use of the system PCREPOSIX library if found" ON)
-OPTION(ENABLE_LibGCC "Enable the use of the system LibGCC library if found" ON)
+OPTION(ENABLE_LIBGCC "Enable the use of the system LibGCC library if found" ON)
 # CNG is used for encrypt/decrypt Zip archives on Windows.
 OPTION(ENABLE_CNG "Enable the use of CNG(Crypto Next Generation)" ON)
 
@@ -257,7 +257,7 @@
 
 SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
 SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
-SET(WINDOWS_VERSION "WIN7" CACHE STRING "Set Windows version to use (Windows only)")
+SET(WINDOWS_VERSION "WIN10" CACHE STRING "Set Windows version to use (Windows only)")
 
 IF(ENABLE_COVERAGE)
        include(LibarchiveCodeCoverage)
@@ -268,7 +268,11 @@
 ENDIF(ENABLE_TEST)
 
 IF(WIN32)
-  IF(WINDOWS_VERSION STREQUAL "WIN8")
+  IF(WINDOWS_VERSION STREQUAL "WIN10")
+    SET(NTDDI_VERSION 0x0A000000)
+    SET(_WIN32_WINNT 0x0A00)
+    SET(WINVER 0x0A00)
+  ELSEIF(WINDOWS_VERSION STREQUAL "WIN8")
     SET(NTDDI_VERSION 0x06020000)
     SET(_WIN32_WINNT 0x0602)
     SET(WINVER 0x0602)
@@ -292,12 +296,12 @@
     SET(NTDDI_VERSION 0x05010000)
     SET(_WIN32_WINNT 0x0501)
     SET(WINVER 0x0501)
-  ELSE(WINDOWS_VERSION STREQUAL "WIN8")
+  ELSE(WINDOWS_VERSION STREQUAL "WIN10")
     # Default to Windows Server 2003 API if we don't recognize the specifier
     SET(NTDDI_VERSION 0x05020000)
     SET(_WIN32_WINNT 0x0502)
     SET(WINVER 0x0502)
-  ENDIF(WINDOWS_VERSION STREQUAL "WIN8")
+  ENDIF(WINDOWS_VERSION STREQUAL "WIN10")
 ENDIF(WIN32)
 
 IF(MSVC)
@@ -632,8 +636,15 @@
     SET(ZSTD_FIND_QUIETLY TRUE)
   ENDIF (ZSTD_INCLUDE_DIR)
 
-  FIND_PATH(ZSTD_INCLUDE_DIR zstd.h)
-  FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd)
+  IF(0) # CMake does not let pkg-config override its search paths.
+  IF(UNIX)
+    FIND_PACKAGE(PkgConfig QUIET)
+    PKG_SEARCH_MODULE(PC_ZSTD libzstd)
+  ENDIF()
+  ENDIF()
+
+  FIND_PATH(ZSTD_INCLUDE_DIR zstd.h HINTS ${PC_ZSTD_INCLUDEDIR} ${PC_ZSTD_INCLUDE_DIRS})
+  FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd HINTS ${PC_ZSTD_LIBDIR} ${PC_ZSTD_LIBRARY_DIRS})
   INCLUDE(FindPackageHandleStandardArgs)
   FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZSTD DEFAULT_MSG ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
 ELSE(ENABLE_ZSTD)
@@ -1284,9 +1295,10 @@
   #
   # If requested, try finding library for PCREPOSIX
   #
-  IF(ENABLE_LibGCC)
-    FIND_PACKAGE(LibGCC)
+  IF(ENABLE_LIBGCC)
+    FIND_PACKAGE(LIBGCC)
   ELSE()
+    MESSAGE(FATAL_ERROR "libgcc not found.")
     SET(LIBGCC_FOUND FALSE) # Override cached value
   ENDIF()
   IF(ENABLE_PCREPOSIX)
@@ -1996,6 +2008,19 @@
 
 CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
 
+IF(0) # CMake does not build libarchive's shared library.
+# Check visibility annotations
+SET(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fvisibility=hidden -Werror")
+CHECK_C_SOURCE_COMPILES("void __attribute__((visibility(\"default\"))) foo(void);
+int main() { return 0; }" HAVE_VISIBILITY_ATTR)
+IF (HAVE_VISIBILITY_ATTR)
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
+  ADD_DEFINITIONS(-D__LIBARCHIVE_ENABLE_VISIBILITY)
+ENDIF(HAVE_VISIBILITY_ATTR)
+SET(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
+ENDIF()
+
 # Generate "config.h" from "build/cmake/config.h.in"
 CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
 	${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake b/Utilities/cmlibarchive/build/cmake/FindLIBGCC.cmake
similarity index 100%
rename from Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake
rename to Utilities/cmlibarchive/build/cmake/FindLIBGCC.cmake
diff --git a/Utilities/cmlibarchive/build/cmake/config.h.in b/Utilities/cmlibarchive/build/cmake/config.h.in
index 72467a5..e44a514 100644
--- a/Utilities/cmlibarchive/build/cmake/config.h.in
+++ b/Utilities/cmlibarchive/build/cmake/config.h.in
@@ -147,13 +147,13 @@
 #cmakedefine ARCHIVE_XATTR_LINUX 1
 
 /* Version number of bsdcpio */
-#cmakedefine BSDCPIO_VERSION_STRING "${BSDCPIO_VERSION_STRING}"
+#cmakedefine BSDCPIO_VERSION_STRING "@BSDCPIO_VERSION_STRING@"
 
 /* Version number of bsdtar */
-#cmakedefine BSDTAR_VERSION_STRING "${BSDTAR_VERSION_STRING}"
+#cmakedefine BSDTAR_VERSION_STRING "@BSDTAR_VERSION_STRING@"
 
 /* Version number of bsdcat */
-#cmakedefine BSDCAT_VERSION_STRING "${BSDCAT_VERSION_STRING}"
+#cmakedefine BSDCAT_VERSION_STRING "@BSDCAT_VERSION_STRING@"
 
 /* Define to 1 if you have the `acl_create_entry' function. */
 #cmakedefine HAVE_ACL_CREATE_ENTRY 1
@@ -1012,13 +1012,13 @@
 #cmakedefine HAVE__MKGMTIME64 1
 
 /* Define as const if the declaration of iconv() needs const. */
-#define ICONV_CONST ${ICONV_CONST}
+#define ICONV_CONST @ICONV_CONST@
 
 /* Version number of libarchive as a single integer */
-#cmakedefine LIBARCHIVE_VERSION_NUMBER "${LIBARCHIVE_VERSION_NUMBER}"
+#cmakedefine LIBARCHIVE_VERSION_NUMBER "@LIBARCHIVE_VERSION_NUMBER@"
 
 /* Version number of libarchive */
-#cmakedefine LIBARCHIVE_VERSION_STRING "${LIBARCHIVE_VERSION_STRING}"
+#cmakedefine LIBARCHIVE_VERSION_STRING "@LIBARCHIVE_VERSION_STRING@"
 
 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing
    slash. */
@@ -1036,7 +1036,7 @@
 #cmakedefine NO_MINUS_C_MINUS_O 1
 
 /* The size of `wchar_t', as computed by sizeof. */
-#cmakedefine SIZEOF_WCHAR_T ${SIZEOF_WCHAR_T}
+#cmakedefine SIZEOF_WCHAR_T @SIZEOF_WCHAR_T@
 
 /* Define to 1 if strerror_r returns char *. */
 #cmakedefine STRERROR_R_CHAR_P 1
@@ -1072,56 +1072,56 @@
 #endif /* SAFE_TO_DEFINE_EXTENSIONS */
 
 /* Version number of package */
-#cmakedefine VERSION "${VERSION}"
+#cmakedefine VERSION "@VERSION@"
 
 /* Number of bits in a file offset, on hosts where this is settable. */
-#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
+#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@
 
 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 #cmakedefine _LARGEFILE_SOURCE 1
 
 /* Define for large files, on AIX-style hosts. */
-#cmakedefine _LARGE_FILES ${_LARGE_FILES}
+#cmakedefine _LARGE_FILES @_LARGE_FILES@
 
 /* Define to control Windows SDK version */
 #ifndef NTDDI_VERSION
-#cmakedefine NTDDI_VERSION ${NTDDI_VERSION}
+#cmakedefine NTDDI_VERSION @NTDDI_VERSION@
 #endif // NTDDI_VERSION
 
 #ifndef _WIN32_WINNT
-#cmakedefine _WIN32_WINNT ${_WIN32_WINNT}
+#cmakedefine _WIN32_WINNT @_WIN32_WINNT@
 #endif // _WIN32_WINNT
 
 #ifndef WINVER
-#cmakedefine WINVER ${WINVER}
+#cmakedefine WINVER @WINVER@
 #endif // WINVER
 
 /* Define to empty if `const' does not conform to ANSI C. */
-#cmakedefine const ${const}
+#cmakedefine const @const@
 
 /* Define to `int' if <sys/types.h> doesn't define. */
-#cmakedefine gid_t ${gid_t}
+#cmakedefine gid_t @gid_t@
 
 /* Define to `unsigned long' if <sys/types.h> does not define. */
-#cmakedefine id_t ${id_t}
+#cmakedefine id_t @id_t@
 
 /* Define to `int' if <sys/types.h> does not define. */
-#cmakedefine mode_t ${mode_t}
+#cmakedefine mode_t @mode_t@
 
 /* Define to `long long' if <sys/types.h> does not define. */
-#cmakedefine off_t ${off_t}
+#cmakedefine off_t @off_t@
 
 /* Define to `int' if <sys/types.h> doesn't define. */
-#cmakedefine pid_t ${pid_t}
+#cmakedefine pid_t @pid_t@
 
 /* Define to `unsigned int' if <sys/types.h> does not define. */
-#cmakedefine size_t ${size_t}
+#cmakedefine size_t @size_t@
 
 /* Define to `int' if <sys/types.h> does not define. */
-#cmakedefine ssize_t ${ssize_t}
+#cmakedefine ssize_t @ssize_t@
 
 /* Define to `int' if <sys/types.h> doesn't define. */
-#cmakedefine uid_t ${uid_t}
+#cmakedefine uid_t @uid_t@
 
 #include <cm3p/kwiml/int.h>
 
diff --git a/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in b/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
index 4b631e6..1f51e77 100644
--- a/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
+++ b/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
@@ -10,3 +10,4 @@
 Cflags.private: -DLIBARCHIVE_STATIC
 Libs: -L${libdir} -larchive
 Libs.private: @LIBS@
+Requires.private: @LIBSREQUIRED@
diff --git a/Utilities/cmlibarchive/build/version b/Utilities/cmlibarchive/build/version
index 102ec29..1af1bec 100644
--- a/Utilities/cmlibarchive/build/version
+++ b/Utilities/cmlibarchive/build/version
@@ -1 +1 @@
-3006000
+3006002
diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
index feb8697..bee69c2 100644
--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
@@ -5,6 +5,10 @@
 #
 ############################################
 
+if (ANDROID)
+  include_directories(${PROJECT_SOURCE_DIR}/contrib/android/include)
+endif()
+
 # Public headers
 SET(include_HEADERS
   archive.h
@@ -78,6 +82,7 @@
   archive_read_set_format.c
   archive_read_set_options.c
   archive_read_support_filter_all.c
+  archive_read_support_filter_by_code.c
   archive_read_support_filter_bzip2.c
   archive_read_support_filter_compress.c
   archive_read_support_filter_gzip.c
diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h
index ac01738..180f3e4 100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3006000
+#define	ARCHIVE_VERSION_NUMBER 3006002
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -120,6 +120,8 @@
 #   define __LA_DECL	__declspec(dllimport)
 #  endif
 # endif
+#elif defined __LIBARCHIVE_ENABLE_VISIBILITY
+#  define __LA_DECL __attribute__((visibility("default")))
 #else
 /* Static libraries or non-Windows needs no special declaration. */
 # define __LA_DECL
@@ -152,7 +154,7 @@
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.6.0"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.6.2"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/Utilities/cmlibarchive/libarchive/archive_digest.c b/Utilities/cmlibarchive/libarchive/archive_digest.c
index 410df01..3361b19 100644
--- a/Utilities/cmlibarchive/libarchive/archive_digest.c
+++ b/Utilities/cmlibarchive/libarchive/archive_digest.c
@@ -49,16 +49,16 @@
  * Initialize a Message digest.
  */
 static int
-win_crypto_init(Digest_CTX *ctx, ALG_ID algId)
+win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
 {
 
 	ctx->valid = 0;
 	if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
-	    PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+	    prov, CRYPT_VERIFYCONTEXT)) {
 		if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
 			return (ARCHIVE_FAILED);
 		if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
-		    PROV_RSA_FULL, CRYPT_NEWKEYSET))
+		    prov, CRYPT_NEWKEYSET))
 			return (ARCHIVE_FAILED);
 	}
 
@@ -243,7 +243,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_md5());
+  if (!EVP_DigestInit(*ctx, EVP_md5()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -275,7 +276,7 @@
 static int
 __archive_md5init(archive_md5_ctx *ctx)
 {
-  return (win_crypto_init(ctx, CALG_MD5));
+  return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
 }
 
 static int
@@ -434,7 +435,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_ripemd160());
+  if (!EVP_DigestInit(*ctx, EVP_ripemd160()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -624,7 +626,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_sha1());
+  if (!EVP_DigestInit(*ctx, EVP_sha1()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -656,7 +659,7 @@
 static int
 __archive_sha1init(archive_sha1_ctx *ctx)
 {
-  return (win_crypto_init(ctx, CALG_SHA1));
+  return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
 }
 
 static int
@@ -887,7 +890,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_sha256());
+  if (!EVP_DigestInit(*ctx, EVP_sha256()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -915,7 +919,7 @@
 static int
 __archive_sha256init(archive_sha256_ctx *ctx)
 {
-  return (win_crypto_init(ctx, CALG_SHA_256));
+  return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
 }
 
 static int
@@ -1122,7 +1126,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_sha384());
+  if (!EVP_DigestInit(*ctx, EVP_sha384()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -1150,7 +1155,7 @@
 static int
 __archive_sha384init(archive_sha384_ctx *ctx)
 {
-  return (win_crypto_init(ctx, CALG_SHA_384));
+  return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
 }
 
 static int
@@ -1381,7 +1386,8 @@
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
 	return (ARCHIVE_FAILED);
-  EVP_DigestInit(*ctx, EVP_sha512());
+  if (!EVP_DigestInit(*ctx, EVP_sha512()))
+	return (ARCHIVE_FAILED);
   return (ARCHIVE_OK);
 }
 
@@ -1409,7 +1415,7 @@
 static int
 __archive_sha512init(archive_sha512_ctx *ctx)
 {
-  return (win_crypto_init(ctx, CALG_SHA_512));
+  return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
 }
 
 static int
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.c b/Utilities/cmlibarchive/libarchive/archive_entry.c
index ca7a4bd..ae6dc33 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.c
@@ -568,6 +568,13 @@
 	return (entry->ae_stat.aest_nlink);
 }
 
+/* Instead, our caller could have chosen a specific encoding
+ * (archive_mstring_get_mbs, archive_mstring_get_utf8,
+ * archive_mstring_get_wcs).  So we should try multiple
+ * encodings.  Try mbs first because of history, even though
+ * utf8 might be better for pathname portability.
+ * Also omit wcs because of type mismatch (char * versus wchar *)
+ */
 const char *
 archive_entry_pathname(struct archive_entry *entry)
 {
@@ -575,6 +582,13 @@
 	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 		return (p);
+#if HAVE_EILSEQ  /*{*/
+    if (errno == EILSEQ) {
+	    if (archive_mstring_get_utf8(
+	        entry->archive, &entry->ae_pathname, &p) == 0)
+		    return (p);
+    }
+#endif  /*}*/
 	if (errno == ENOMEM)
 		__archive_errx(1, "No memory");
 	return (NULL);
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h
index 221ef80..91ef0c9 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3006000
+#define	ARCHIVE_VERSION_NUMBER 3006002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -122,6 +122,8 @@
 #   define __LA_DECL	__declspec(dllimport)
 #  endif
 # endif
+#elif defined __LIBARCHIVE_ENABLE_VISIBILITY
+#  define __LA_DECL __attribute__((visibility("default")))
 #else
 /* Static libraries on all platforms and shared libraries on non-Windows. */
 # define __LA_DECL
diff --git a/Utilities/cmlibarchive/libarchive/archive_hmac.c b/Utilities/cmlibarchive/libarchive/archive_hmac.c
index 2a9d04c..012fe15 100644
--- a/Utilities/cmlibarchive/libarchive/archive_hmac.c
+++ b/Utilities/cmlibarchive/libarchive/archive_hmac.c
@@ -230,10 +230,23 @@
 static int
 __hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_PARAM params[2];
+
+	EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+	*ctx = EVP_MAC_CTX_new(mac);
+	if (*ctx == NULL)
+		return -1;
+	EVP_MAC_free(mac);
+	params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA1", 0);
+	params[1] = OSSL_PARAM_construct_end();
+	EVP_MAC_init(*ctx, key, key_len, params);
+#else
 	*ctx = HMAC_CTX_new();
 	if (*ctx == NULL)
 		return -1;
 	HMAC_Init_ex(*ctx, key, key_len, EVP_sha1(), NULL);
+#endif
 	return 0;
 }
 
@@ -241,22 +254,38 @@
 __hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
     size_t data_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_update(*ctx, data, data_len);
+#else
 	HMAC_Update(*ctx, data, data_len);
+#endif
 }
 
 static void
 __hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	size_t len = *out_len;
+#else
 	unsigned int len = (unsigned int)*out_len;
+#endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_final(*ctx, out, &len, *out_len);
+#else
 	HMAC_Final(*ctx, out, &len);
+#endif
 	*out_len = len;
 }
 
 static void
 __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_CTX_free(*ctx);
+#else
 	HMAC_CTX_free(*ctx);
+#endif
 	*ctx = NULL;
 }
 
diff --git a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
index 13a67d4..50044a0 100644
--- a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
@@ -74,9 +74,16 @@
 typedef	struct hmac_sha1_ctx archive_hmac_sha1_ctx;
 
 #elif defined(HAVE_LIBCRYPTO)
+#include <openssl/opensslv.h>
+#include <openssl/hmac.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+typedef EVP_MAC_CTX *archive_hmac_sha1_ctx;
+
+#else
 #include "archive_openssl_hmac_private.h"
 
 typedef	HMAC_CTX* archive_hmac_sha1_ctx;
+#endif
 
 #else
 
diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h
index f87b423..63b255e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_platform.h
+++ b/Utilities/cmlibarchive/libarchive/archive_platform.h
@@ -188,8 +188,9 @@
 
 /*
  * glibc 2.24 deprecates readdir_r
+ * bionic c deprecates readdir_r too
  */
-#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24))
+#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) && (!defined(__ANDROID__))
 #define	USE_READDIR_R	1
 #else
 #undef	USE_READDIR_R
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
index d0e1f35..5a94ec5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
@@ -34,9 +34,6 @@
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -54,6 +51,8 @@
 #endif
 #ifdef HAVE_LINUX_FS_H
 #include <linux/fs.h>
+#elif HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
 #endif
 /*
  * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
@@ -109,6 +108,11 @@
 #define O_CLOEXEC	0
 #endif
 
+#if defined(__hpux) && !defined(HAVE_DIRFD)
+#define dirfd(x) ((x)->__dd_fd)
+#define HAVE_DIRFD
+#endif
+
 /*-
  * This is a new directory-walking system that addresses a number
  * of problems I've had with fts(3).  In particular, it has no
@@ -2098,6 +2102,8 @@
 	struct tree_entry *te;
 
 	te = calloc(1, sizeof(*te));
+	if (te == NULL)
+		__archive_errx(1, "Out of memory");
 	te->next = t->stack;
 	te->parent = t->current;
 	if (te->parent)
@@ -2428,7 +2434,7 @@
 #else /* HAVE_FDOPENDIR */
 		if (tree_enter_working_dir(t) == 0) {
 			t->d = opendir(".");
-#if HAVE_DIRFD || defined(dirfd)
+#ifdef HAVE_DIRFD
 			__archive_ensure_cloexec_flag(dirfd(t->d));
 #endif
 		}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
index ea32e2a..f9d1395 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
@@ -418,8 +418,9 @@
 	    FILE_FLAG_OPEN_REPARSE_POINT;
 	int ret;
 
-	h = CreateFileW(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, flag,
-	    NULL);
+	h = CreateFileW(path, 0,
+	    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+	    OPEN_EXISTING, flag, NULL);
 	if (h == INVALID_HANDLE_VALUE) {
 		la_dosmaperr(GetLastError());
 		return (-1);
@@ -1073,7 +1074,9 @@
 		else
 			flags |= FILE_FLAG_SEQUENTIAL_SCAN;
 		t->entry_fh = CreateFileW(tree_current_access_path(t),
-		    GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL);
+		    GENERIC_READ,
+		    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+		    NULL, OPEN_EXISTING, flags, NULL);
 		if (t->entry_fh == INVALID_HANDLE_VALUE) {
 			la_dosmaperr(GetLastError());
 			archive_set_error(&a->archive, errno,
@@ -2046,7 +2049,8 @@
 	
 	if (sim_lstat && tree_current_is_physical_link(t))
 		flag |= FILE_FLAG_OPEN_REPARSE_POINT;
-	h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL,
+	h = CreateFileW(tree_current_access_path(t), 0,
+	    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
 	    OPEN_EXISTING, flag, NULL);
 	if (h == INVALID_HANDLE_VALUE) {
 		la_dosmaperr(GetLastError());
@@ -2275,7 +2279,8 @@
 			} else
 				desiredAccess = GENERIC_READ;
 
-			h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL,
+			h = CreateFileW(path, desiredAccess,
+			    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
 			    OPEN_EXISTING, flag, NULL);
 			if (h == INVALID_HANDLE_VALUE) {
 				la_dosmaperr(GetLastError());
@@ -2337,7 +2342,8 @@
 		if (fd >= 0) {
 			h = (HANDLE)_get_osfhandle(fd);
 		} else {
-			h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
+			h = CreateFileW(path, GENERIC_READ,
+			    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
 			    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 			if (h == INVALID_HANDLE_VALUE) {
 				la_dosmaperr(GetLastError());
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c
index ae0b080..1e99542 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c
@@ -450,7 +450,9 @@
 	chsum = (chsum >> 8) & 0xff;
 	chsum_verifier = read_buf[descriptor_bytes-1] & 0xff;
 	if (chsum != chsum_verifier)
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		goto malformed_error;
+#endif
 
 	__archive_read_filter_consume(self->upstream, descriptor_bytes);
 
@@ -521,7 +523,9 @@
 		unsigned int chsum_block =
 		    archive_le32dec(read_buf + 4 + compressed_size);
 		if (chsum != chsum_block)
+#ifndef DONT_FAIL_ON_CRC_ERROR
 			goto malformed_error;
+#endif
 	}
 
 
@@ -652,10 +656,12 @@
 			    state->xxh32_state);
 			state->xxh32_state = NULL;
 			if (checksum != checksum_stream) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 				archive_set_error(&self->archive->archive,
 				    ARCHIVE_ERRNO_MISC,
 				    "lz4 stream checksum error");
 				return (ARCHIVE_FATAL);
+#endif
 			}
 		} else if (ret > 0)
 			__archive_xxhash.XXH32_update(state->xxh32_state,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
index 42e2636..cc1572f 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
@@ -283,7 +283,9 @@
 	else
 		checksum = adler32(adler32(0, NULL, 0), p, len);
 	if (archive_be32dec(p + len) != checksum)
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		goto corrupted;
+#endif
 	__archive_read_filter_consume(self->upstream, len + 4);
 	if (flags & EXTRA_FIELD) {
 		/* Skip extra field */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
index b978eb0..90b0da2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
@@ -612,9 +612,11 @@
 	/* Check the crc32 value of the uncompressed data of the current
 	 * member */
 	if (state->crc32 != archive_le32dec(f)) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
 		    "Lzip: CRC32 error");
 		return (ARCHIVE_FAILED);
+#endif
 	}
 
 	/* Check the uncompressed size of the current member */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
index 7d7e702..722edf1 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
@@ -287,6 +287,7 @@
 		const unsigned char	*next_in;
 		int64_t			 avail_in;
 		int64_t			 total_in;
+		int64_t			 stream_in;
 		unsigned char		*next_out;
 		int64_t			 avail_out;
 		int64_t			 total_out;
@@ -775,7 +776,7 @@
 	}
 
 	/* Set up a more descriptive format name. */
-	sprintf(zip->format_name, "7-Zip");
+	snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");
 	a->archive.archive_format_name = zip->format_name;
 
 	return (ret);
@@ -986,15 +987,30 @@
 	struct _7zip *zip = (struct _7zip *)(a->format->data);
 	Byte b;
 
-	if (zip->ppstream.avail_in == 0) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Truncated RAR file data");
-		zip->ppstream.overconsumed = 1;
-		return (0);
+	if (zip->ppstream.avail_in <= 0) {
+		/*
+		 * Ppmd7_DecodeSymbol might require reading multiple bytes
+		 * and we are on boundary;
+		 * last resort to read using __archive_read_ahead.
+		 */
+		ssize_t bytes_avail = 0;
+		const uint8_t* data = __archive_read_ahead(a,
+		    zip->ppstream.stream_in+1, &bytes_avail);
+		if(bytes_avail < zip->ppstream.stream_in+1) {
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
+			    "Truncated 7z file data");
+			zip->ppstream.overconsumed = 1;
+			return (0);
+		}
+		zip->ppstream.next_in++;
+		b = data[zip->ppstream.stream_in];
+	} else {
+		b = *zip->ppstream.next_in++;
 	}
-	b = *zip->ppstream.next_in++;
 	zip->ppstream.avail_in--;
 	zip->ppstream.total_in++;
+	zip->ppstream.stream_in++;
 	return (b);
 }
 
@@ -1485,6 +1501,7 @@
 		}
 		zip->ppstream.next_in = t_next_in;
 		zip->ppstream.avail_in = t_avail_in;
+		zip->ppstream.stream_in = 0;
 		zip->ppstream.next_out = t_next_out;
 		zip->ppstream.avail_out = t_avail_out;
 		if (zip->ppmd7_stat == 0) {
@@ -2840,8 +2857,10 @@
 	/* CRC check. */
 	if (crc32(0, (const unsigned char *)p + 12, 20)
 	    != archive_le32dec(p + 8)) {
+#ifdef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&a->archive, -1, "Header CRC error");
 		return (ARCHIVE_FATAL);
+#endif
 	}
 
 	next_header_offset = archive_le64dec(p + 12);
@@ -2891,8 +2910,10 @@
 		/* Check the EncodedHeader CRC.*/
 		if (r == 0 && zip->header_crc32 != next_header_crc) {
 			archive_set_error(&a->archive, -1,
+#ifndef DONT_FAIL_ON_CRC_ERROR
 			    "Damaged 7-Zip archive");
 			r = -1;
+#endif
 		}
 		if (r == 0) {
 			if (zip->si.ci.folders[0].digest_defined)
@@ -2943,9 +2964,11 @@
 
 		/* Check the Header CRC.*/
 		if (check_header_crc && zip->header_crc32 != next_header_crc) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 			archive_set_error(&a->archive, -1,
 			    "Malformed 7-Zip archive");
 			return (ARCHIVE_FATAL);
+#endif
 		}
 		break;
 	default:
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
index 8742378..6fcfbfc 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
@@ -996,7 +996,7 @@
 		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 
 	/* Set up a more descriptive format name. */
-	sprintf(cab->format_name, "CAB %d.%d (%s)",
+	snprintf(cab->format_name, sizeof(cab->format_name), "CAB %d.%d (%s)",
 	    hd->major, hd->minor, cab->entry_cffolder->compname);
 	a->archive.archive_format_name = cab->format_name;
 
@@ -1134,7 +1134,7 @@
 	}
 	if (sumbytes) {
 		int odd = sumbytes & 3;
-		if (sumbytes - odd > 0)
+		if ((int)(sumbytes - odd) > 0)
 			cfdata->sum_calculated = cab_checksum_cfdata_4(
 			    p, sumbytes - odd, cfdata->sum_calculated);
 		if (odd)
@@ -1171,12 +1171,14 @@
 	cfdata->sum_calculated = cab_checksum_cfdata(
 	    cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
 	if (cfdata->sum_calculated != cfdata->sum) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Checksum error CFDATA[%d] %" PRIx32 ":%" PRIx32 " in %d bytes",
 		    cab->entry_cffolder->cfdata_index -1,
 		    cfdata->sum, cfdata->sum_calculated,
 		    cfdata->compressed_size);
 		return (ARCHIVE_FAILED);
+#endif
 	}
 	return (ARCHIVE_OK);
 }
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
index 9121166..380cbb8 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
@@ -1007,7 +1007,8 @@
 		p = b;
 		b += iso9660->logical_block_size;
 		step -= iso9660->logical_block_size;
-		for (; *p != 0 && p < b && p + *p <= b; p += *p) {
+		for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;
+			p += *p) {
 			struct file_info *child;
 
 			/* N.B.: these special directory identifiers
@@ -1756,7 +1757,7 @@
 	size_t name_len;
 	const unsigned char *rr_start, *rr_end;
 	const unsigned char *p;
-	size_t dr_len;
+	size_t dr_len = 0;
 	uint64_t fsize, offset;
 	int32_t location;
 	int flags;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
index 1357f9a..8b7bf66 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
@@ -739,7 +739,7 @@
 	if (lha->directory || lha->compsize == 0)
 		lha->end_of_entry = 1;
 
-	sprintf(lha->format_name, "lha -%c%c%c-",
+	snprintf(lha->format_name, sizeof(lha->format_name), "lha -%c%c%c-",
 	    lha->method[0], lha->method[1], lha->method[2]);
 	a->archive.archive_format_name = lha->format_name;
 
@@ -1039,9 +1039,11 @@
 	}
 
 	if (header_crc != lha->header_crc) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "LHa header CRC error");
 		return (ARCHIVE_FATAL);
+#endif
 	}
 	return (err);
 }
@@ -1107,9 +1109,11 @@
 		return (err);
 
 	if (header_crc != lha->header_crc) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "LHa header CRC error");
 		return (ARCHIVE_FATAL);
+#endif
 	}
 	return (err);
 invalid:
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
index 88bca76..2bc3ba0 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
@@ -692,7 +692,7 @@
 {
 	const char *p;
 	ssize_t avail, ravail;
-	ssize_t detected_bytes = 0, len, nl;
+	ssize_t len, nl;
 	int entry_cnt = 0, multiline = 0;
 	int form_D = 0;/* The archive is generated by `NetBSD mtree -D'
 			* (In this source we call it `form D') . */
@@ -728,8 +728,6 @@
 			 * character of previous line was '\' character. */
 			if (bid_keyword_list(p, len, 0, 0) <= 0)
 				break;
-			if (multiline == 1)
-				detected_bytes += len;
 			if (p[len-nl-1] != '\\') {
 				if (multiline == 1 &&
 				    ++entry_cnt >= MAX_BID_ENTRY)
@@ -745,7 +743,6 @@
 
 			keywords = bid_entry(p, len, nl, &last_is_path);
 			if (keywords >= 0) {
-				detected_bytes += len;
 				if (form_D == 0) {
 					if (last_is_path)
 						form_D = 1;
@@ -997,9 +994,11 @@
 			struct mtree_entry *alt;
 			alt = (struct mtree_entry *)__archive_rb_tree_find_node(
 			    &mtree->rbtree, entry->name);
-			while (alt->next_dup)
-				alt = alt->next_dup;
-			alt->next_dup = entry;
+			if (alt != NULL) {
+				while (alt->next_dup)
+					alt = alt->next_dup;
+				alt->next_dup = entry;
+			}
 		}
 	}
 
@@ -1074,7 +1073,7 @@
 			continue;
 		/* Non-printable characters are not allowed */
 		for (s = p;s < p + len - 1; s++) {
-			if (!isprint((unsigned char)*s)) {
+			if (!isprint((unsigned char)*s) && *s != '\t') {
 				r = ARCHIVE_FATAL;
 				break;
 			}
@@ -1253,9 +1252,17 @@
 				archive_entry_filetype(entry) == AE_IFDIR) {
 			mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
 			__archive_ensure_cloexec_flag(mtree->fd);
-			if (mtree->fd == -1 &&
-				(errno != ENOENT ||
-				 archive_strlen(&mtree->contents_name) > 0)) {
+			if (mtree->fd == -1 && (
+#if defined(_WIN32) && !defined(__CYGWIN__)
+        /*
+         * On Windows, attempting to open a file with an
+         * invalid name result in EINVAL (Error 22)
+         */
+				(errno != ENOENT && errno != EINVAL)
+#else
+				errno != ENOENT
+#endif
+        || archive_strlen(&mtree->contents_name) > 0)) {
 				archive_set_error(&a->archive, errno,
 						"Can't open %s", path);
 				r = ARCHIVE_WARN;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
index 5c02a25..1c9a057 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
@@ -430,7 +430,7 @@
 static int make_table(struct archive_read *, struct huffman_code *);
 static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
                               struct huffman_table_entry *, int, int);
-static int64_t expand(struct archive_read *, int64_t);
+static int expand(struct archive_read *, int64_t *);
 static int copy_from_lzss_window_to_unp(struct archive_read *, const void **,
                                         int64_t, int);
 static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
@@ -1007,9 +1007,11 @@
 
       crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
       if ((crc32_val & 0xffff) != archive_le16dec(p)) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Header CRC error");
         return (ARCHIVE_FATAL);
+#endif
       }
       __archive_read_consume(a, skip);
       break;
@@ -1065,9 +1067,11 @@
 	      skip -= to_read;
       }
       if ((crc32_val & 0xffff) != crc32_expected) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 	      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		  "Header CRC error");
 	      return (ARCHIVE_FATAL);
+#endif
       }
       if (head_type == ENDARC_HEAD)
 	      return (ARCHIVE_EOF);
@@ -1432,9 +1436,11 @@
   /* File Header CRC check. */
   crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7));
   if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
       "Header CRC error");
     return (ARCHIVE_FATAL);
+#endif
   }
   /* If no CRC error, Go on parsing File Header. */
   p = h;
@@ -1952,9 +1958,11 @@
     *size = 0;
     *offset = rar->offset;
     if (rar->file_crc != rar->crc_calculated) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                         "File CRC error");
       return (ARCHIVE_FATAL);
+#endif
     }
     rar->entry_eof = 1;
     return (ARCHIVE_EOF);
@@ -1988,7 +1996,7 @@
     return (ARCHIVE_FATAL);
 
   struct rar *rar;
-  int64_t start, end, actualend;
+  int64_t start, end;
   size_t bs;
   int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;
 
@@ -2045,9 +2053,11 @@
       *size = 0;
       *offset = rar->offset;
       if (rar->file_crc != rar->crc_calculated) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                           "File CRC error");
         return (ARCHIVE_FATAL);
+#endif
       }
       rar->entry_eof = 1;
       return (ARCHIVE_EOF);
@@ -2179,11 +2189,12 @@
         end = rar->filters.filterstart;
       }
 
-      if ((actualend = expand(a, end)) < 0)
-        return ((int)actualend);
+      ret = expand(a, &end);
+      if (ret != ARCHIVE_OK)
+	      return (ret);
 
-      rar->bytes_uncopied = actualend - start;
-      rar->filters.lastend = actualend;
+      rar->bytes_uncopied = end - start;
+      rar->filters.lastend = end;
       if (rar->filters.lastend != rar->filters.filterstart && rar->bytes_uncopied == 0) {
           /* Broken RAR files cause this case.
           * NOTE: If this case were possible on a normal RAR file
@@ -2825,8 +2836,8 @@
   return ret;
 }
 
-static int64_t
-expand(struct archive_read *a, int64_t end)
+static int
+expand(struct archive_read *a, int64_t *end)
 {
   static const unsigned char lengthbases[] =
     {   0,   1,   2,   3,   4,   5,   6,
@@ -2873,16 +2884,19 @@
   struct rar *rar = (struct rar *)(a->format->data);
   struct rar_br *br = &(rar->br);
 
-  if (rar->filters.filterstart < end)
-    end = rar->filters.filterstart;
+  if (rar->filters.filterstart < *end)
+    *end = rar->filters.filterstart;
 
   while (1)
   {
-    if(lzss_position(&rar->lzss) >= end)
-      return end;
+    if(lzss_position(&rar->lzss) >= *end) {
+      return (ARCHIVE_OK);
+    }
 
-    if(rar->is_ppmd_block)
-      return lzss_position(&rar->lzss);
+    if(rar->is_ppmd_block) {
+      *end = lzss_position(&rar->lzss);
+      return (ARCHIVE_OK);
+    }
 
     if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
       return (ARCHIVE_FATAL);
@@ -2906,7 +2920,8 @@
           goto truncated_data;
         rar->start_new_table = rar_br_bits(br, 1);
         rar_br_consume(br, 1);
-        return lzss_position(&rar->lzss);
+        *end = lzss_position(&rar->lzss);
+        return (ARCHIVE_OK);
       }
       else
       {
@@ -2917,7 +2932,7 @@
     }
     else if(symbol==257)
     {
-      if (!read_filter(a, &end))
+      if (!read_filter(a, end))
           return (ARCHIVE_FATAL);
       continue;
     }
@@ -3323,14 +3338,43 @@
   struct rar *rar = (struct rar *)(a->format->data);
   struct rar_filters *filters = &rar->filters;
   struct rar_filter *filter = filters->stack;
-  size_t start = filters->filterstart;
-  size_t end = start + filter->blocklength;
+  struct rar_filter *f;
+  size_t start, end;
+  int64_t tend;
   uint32_t lastfilteraddress;
   uint32_t lastfilterlength;
   int ret;
 
+  if (filters == NULL || filter == NULL)
+    return (0);
+
+  start = filters->filterstart;
+  end = start + filter->blocklength;
+
   filters->filterstart = INT64_MAX;
-  end = (size_t)expand(a, end);
+  tend = (int64_t)end;
+  ret = expand(a, &tend);
+  if (ret != ARCHIVE_OK)
+    return 0;
+
+  /* Check if filter stack was modified in expand() */
+  ret = ARCHIVE_FATAL;
+  f = filters->stack;
+  while (f)
+  {
+    if (f == filter)
+    {
+      ret = ARCHIVE_OK;
+      break;
+    }
+    f = f->next;
+  }
+  if (ret != ARCHIVE_OK)
+    return 0;
+
+  if (tend < 0)
+    return 0;
+  end = (size_t)tend;
   if (end != start + filter->blocklength)
     return 0;
 
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c
index 8850c93..548da4e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c
@@ -2821,11 +2821,13 @@
 	    ^ (uint8_t) (*block_size >> 16);
 
 	if(calculated_cksum != hdr->block_cksum) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Block checksum error: got 0x%x, expected 0x%x",
 		    hdr->block_cksum, calculated_cksum);
 
 		return ARCHIVE_FATAL;
+#endif
 	}
 
 	return ARCHIVE_OK;
@@ -3911,6 +3913,13 @@
 			case GOOD:
 				/* fallthrough */
 			case BEST:
+				/* No data is returned here. But because a sparse-file aware
+				 * caller (like archive_read_data_into_fd) may treat zero-size
+				 * as a sparse file block, we need to update the offset
+				 * accordingly. At this point the decoder doesn't have any
+				 * pending uncompressed data blocks, so the current position in
+				 * the output file should be last_write_ptr. */
+				if (offset) *offset = rar->cstate.last_write_ptr;
 				return uncompress_file(a);
 			default:
 				archive_set_error(&a->archive,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
index bfdad7f..93c3fd5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
@@ -407,14 +407,13 @@
 	/*
 	 * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
 	 */
-	if (bid > 0 && (
-	    validate_number_field(header->mode, sizeof(header->mode)) == 0
+	if (validate_number_field(header->mode, sizeof(header->mode)) == 0
 	    || validate_number_field(header->uid, sizeof(header->uid)) == 0
 	    || validate_number_field(header->gid, sizeof(header->gid)) == 0
 	    || validate_number_field(header->mtime, sizeof(header->mtime)) == 0
 	    || validate_number_field(header->size, sizeof(header->size)) == 0
 	    || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0
-	    || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) {
+	    || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0) {
 		bid = 0;
 	}
 
@@ -2108,6 +2107,21 @@
 			/* "size" is the size of the data in the entry. */
 			tar->entry_bytes_remaining
 			    = tar_atol10(value, strlen(value));
+			if (tar->entry_bytes_remaining < 0) {
+				tar->entry_bytes_remaining = 0;
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_MISC,
+				    "Tar size attribute is negative");
+				return (ARCHIVE_FATAL);
+			}
+			if (tar->entry_bytes_remaining == INT64_MAX) {
+				/* Note: tar_atol returns INT64_MAX on overflow */
+				tar->entry_bytes_remaining = 0;
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_MISC,
+				    "Tar size attribute overflow");
+				return (ARCHIVE_FATAL);
+			}
 			/*
 			 * The "size" pax header keyword always overrides the
 			 * "size" field in the tar header.
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
index 2e60cf7..330df58 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
@@ -624,7 +624,9 @@
 		__archive_read_consume(a, xar->toc_chksum_size);
 		xar->offset += xar->toc_chksum_size;
 		if (r != ARCHIVE_OK)
+#ifndef DONT_FAIL_ON_CRC_ERROR
 			return (ARCHIVE_FATAL);
+#endif
 	}
 
 	/*
@@ -827,10 +829,12 @@
 		    xattr->a_sum.val, xattr->a_sum.len,
 		    xattr->e_sum.val, xattr->e_sum.len);
 		if (r != ARCHIVE_OK) {
+#ifndef DONT_FAIL_ON_CRC_ERROR
 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 			    "Xattr checksum error");
 			r = ARCHIVE_WARN;
 			break;
+#endif
 		}
 		if (xattr->name.s == NULL) {
 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
index 8ad73b6..e126ae3 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
@@ -1667,7 +1667,7 @@
 	 */
 
 	/* Read magic1,magic2,lzma_params from the ZIPX stream. */
-	if((p = __archive_read_ahead(a, 9, NULL)) == NULL) {
+	if(zip->entry_bytes_remaining < 9 || (p = __archive_read_ahead(a, 9, NULL)) == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Truncated lzma data");
 		return (ARCHIVE_FATAL);
diff --git a/Utilities/cmlibarchive/libarchive/archive_string.c b/Utilities/cmlibarchive/libarchive/archive_string.c
index d7f2c46..69458e1 100644
--- a/Utilities/cmlibarchive/libarchive/archive_string.c
+++ b/Utilities/cmlibarchive/libarchive/archive_string.c
@@ -3988,10 +3988,10 @@
 archive_mstring_get_mbs_l(struct archive *a, struct archive_mstring *aes,
     const char **p, size_t *length, struct archive_string_conv *sc)
 {
-	int r, ret = 0;
-
-	(void)r; /* UNUSED */
+	int ret = 0;
 #if defined(_WIN32) && !defined(__CYGWIN__)
+	int r;
+
 	/*
 	 * Internationalization programming on Windows must use Wide
 	 * characters because Windows platform cannot make locale UTF-8.
diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c
index 66592e8..27626b5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write.c
@@ -201,6 +201,10 @@
 	struct archive_write_filter *f;
 
 	f = calloc(1, sizeof(*f));
+
+	if (f == NULL)
+		return (NULL);
+
 	f->archive = _a;
 	f->state = ARCHIVE_WRITE_FILTER_STATE_NEW;
 	if (a->filter_first == NULL)
@@ -548,6 +552,10 @@
 	a->client_data = client_data;
 
 	client_filter = __archive_write_allocate_filter(_a);
+
+	if (client_filter == NULL)
+		return (ARCHIVE_FATAL);
+
 	client_filter->open = archive_write_client_open;
 	client_filter->write = archive_write_client_write;
 	client_filter->close = archive_write_client_close;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
index b6d3d0a..bd5180e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
@@ -1996,6 +1996,8 @@
 		free(a);
 		return (NULL);
 	}
+	a->path_safe.s[0] = 0;
+
 #ifdef HAVE_ZLIB_H
 	a->decmpfs_compression_level = 5;
 #endif
@@ -2793,7 +2795,7 @@
 	char *tail;
 	char *head;
 	int last;
-	char c;
+	char c = '\0';
 	int r;
 	struct stat st;
 	int chdir_fd;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
index 1b12a29..88df3ce 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
@@ -1370,6 +1370,7 @@
 		free(a);
 		return (NULL);
 	}
+	a->path_safe.s[0] = 0;
 	return (&a->archive);
 }
 
@@ -2154,6 +2155,8 @@
 				return (ARCHIVE_FAILED);
 			}
 		}
+		if (!c)
+			break;
 		pn[0] = c;
 		pn++;
 	}
@@ -2258,6 +2261,9 @@
 			return (ARCHIVE_FAILED);
 		} else
 			p += 4;
+    /* Network drive path like "\\<server-name>\<share-name>\file" */
+    } else if (p[0] == L'\\' && p[1] == L'\\') {
+        p += 2;
 	}
 
 	/* Skip leading drive letter from archives created
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open.3 b/Utilities/cmlibarchive/libarchive/archive_write_open.3
index 29bffe4..6bceb96 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_open.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_open.3
@@ -218,6 +218,7 @@
 .Fn archive_set_error
 to register an error code and message and
 return
+.Cm ARCHIVE_FATAL .
 .Bl -item -offset indent
 .It
 .Ft typedef int
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
index 5291149..cf1f477 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
@@ -1717,7 +1717,7 @@
 	 * to having clients override it.
 	 */
 #if HAVE_GETPID && 0  /* Disable this for now; see above comment. */
-	sprintf(buff, "PaxHeader.%d", getpid());
+	snprintf(buff, sizeof(buff), "PaxHeader.%d", getpid());
 #else
 	/* If the platform can't fetch the pid, don't include it. */
 	strcpy(buff, "PaxHeader");
diff --git a/Utilities/cmlibarchive/libarchive/cpio.5 b/Utilities/cmlibarchive/libarchive/cpio.5
index 837a456..c71018b 100644
--- a/Utilities/cmlibarchive/libarchive/cpio.5
+++ b/Utilities/cmlibarchive/libarchive/cpio.5
@@ -354,7 +354,7 @@
 It appeared in 1977 as part of PWB/UNIX 1.0, the
 .Dq Programmer's Work Bench
 derived from
-.At 6th Edition UNIX
+.At v6
 that was used internally at AT&T.
 Both the new binary and old character formats were in use
 by 1980, according to the System III source released
diff --git a/Utilities/cmlibarchive/libarchive/filter_fork_posix.c b/Utilities/cmlibarchive/libarchive/filter_fork_posix.c
index ac255c4..62085a7 100644
--- a/Utilities/cmlibarchive/libarchive/filter_fork_posix.c
+++ b/Utilities/cmlibarchive/libarchive/filter_fork_posix.c
@@ -76,7 +76,7 @@
 __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
 		pid_t *out_child)
 {
-	pid_t child;
+	pid_t child = -1;
 	int stdin_pipe[2], stdout_pipe[2], tmp;
 #if HAVE_POSIX_SPAWNP
 	posix_spawn_file_actions_t actions;