diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7f4bec564e23918cf912052af8e92081b96e3fa1..dd8e7d6368d2c980f4c1ca381b91018c701f856f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,8 +9,7 @@ variables:
 include:
   - local: '/.gitlab-ci/gcc8-seq-dbg.yml'
   - local: '/.gitlab-ci/gcc8-seq-release.yml'
-#  - local: '/.gitlab-ci/gcc8-seq-coverage.yml'
-  - local: '/.gitlab-ci/clang8-seq-release.yml'
-  - local: '/.gitlab-ci/clang8-mpi-release.yml'
-  - local: '/.gitlab-ci/clang8-seq-coverage.yml'
-  - local: '/.gitlab-ci/clang8-mpi-coverage.yml'
+  - local: '/.gitlab-ci/clang10-seq-release.yml'
+  - local: '/.gitlab-ci/clang10-mpi-release.yml'
+  - local: '/.gitlab-ci/clang10-seq-coverage.yml'
+  - local: '/.gitlab-ci/clang10-mpi-coverage.yml'
diff --git a/.gitlab-ci/clang10-mpi-coverage.yml b/.gitlab-ci/clang10-mpi-coverage.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8d18ed109e0d929a7a66dcd44885eee8dbc55d68
--- /dev/null
+++ b/.gitlab-ci/clang10-mpi-coverage.yml
@@ -0,0 +1,14 @@
+coverage:clang10-mpi-coverage:
+  image: localhost:5000/ubuntu_clang10_mpi
+  stage: coverage
+  script:
+    - mkdir -p build/clang10-cov-mpi
+    - cd build/clang10-cov-mpi
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Coverage -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make pugs
+    - make coverage
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-cov-mpi"
+    paths:
+      - build/clang10-cov-mpi
+    untracked: true
diff --git a/.gitlab-ci/clang10-mpi-release.yml b/.gitlab-ci/clang10-mpi-release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6a7b914c42d5122c8fcdd5b2d1229185658e80c7
--- /dev/null
+++ b/.gitlab-ci/clang10-mpi-release.yml
@@ -0,0 +1,29 @@
+build:clang10-mpi-release:
+  image: localhost:5000/ubuntu_clang10_mpi
+  stage: build
+  script:
+    - mkdir -p build/clang10-release-mpi
+    - cd build/clang10-release-mpi
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make pugs
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-release-mpi"
+    paths:
+      - build/clang10-release-mpi
+    untracked: true
+
+test:clang10-mpi-release:
+  image: localhost:5000/ubuntu_clang10_mpi
+  stage: test
+  dependencies:
+    - build:clang10-mpi-release
+  script:
+    - mkdir -p build/clang10-release-mpi
+    - cd build/clang10-release-mpi
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make run_unit_tests
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-release-mpi"
+    paths:
+      - build/clang10-release-mpi
+    untracked: true
diff --git a/.gitlab-ci/clang10-seq-coverage.yml b/.gitlab-ci/clang10-seq-coverage.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c9bb772d63cabed996f3fe3834e858aded8cef4b
--- /dev/null
+++ b/.gitlab-ci/clang10-seq-coverage.yml
@@ -0,0 +1,14 @@
+coverage:clang10-seq-coverage:
+  image: localhost:5000/ubuntu_clang10
+  stage: coverage
+  script:
+    - mkdir -p build/clang10-cov
+    - cd build/clang10-cov
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Coverage -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make pugs
+    - make coverage
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-cov"
+    paths:
+      - build/clang10-cov
+    untracked: true
diff --git a/.gitlab-ci/clang10-seq-release.yml b/.gitlab-ci/clang10-seq-release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bfd921abdd8b60a7fcb273d55a7821ace695bbeb
--- /dev/null
+++ b/.gitlab-ci/clang10-seq-release.yml
@@ -0,0 +1,29 @@
+build:clang10-seq-release:
+  image: localhost:5000/ubuntu_clang10
+  stage: build
+  script:
+    - mkdir -p build/clang10-release-seq
+    - cd build/clang10-release-seq
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make pugs
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-release-seq"
+    paths:
+      - build/clang10-release-seq
+    untracked: true
+
+test:clang10-seq-release:
+  image: localhost:5000/ubuntu_clang10
+  stage: test
+  dependencies:
+    - build:clang10-seq-release
+  script:
+    - mkdir -p build/clang10-release-seq
+    - cd build/clang10-release-seq
+    - CXX=clang++-10 CC=clang-10 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-10
+    - make run_unit_tests
+  cache:
+    key: "${CI_COMMIT_REF_SLUG}-clang10-release-seq"
+    paths:
+      - build/clang10-release-seq
+    untracked: true
diff --git a/.gitlab-ci/clang8-mpi-coverage.yml b/.gitlab-ci/clang8-mpi-coverage.yml
deleted file mode 100644
index 34d8c132238ab5f43b117ae468c045fa11e71f7b..0000000000000000000000000000000000000000
--- a/.gitlab-ci/clang8-mpi-coverage.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-coverage:clang8-mpi-coverage:
-  image: localhost:5000/ubuntu_clang8_mpi
-  stage: coverage
-  script:
-    - mkdir -p build/clang8-cov-mpi
-    - cd build/clang8-cov-mpi
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Coverage -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make pugs
-    - make coverage
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-cov-mpi"
-    paths:
-      - build/clang8-cov-mpi
-    untracked: true
diff --git a/.gitlab-ci/clang8-mpi-release.yml b/.gitlab-ci/clang8-mpi-release.yml
deleted file mode 100644
index 92f03c34e2c852df0b62ef7c9c72421b705a2bd1..0000000000000000000000000000000000000000
--- a/.gitlab-ci/clang8-mpi-release.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-build:clang8-mpi-release:
-  image: localhost:5000/ubuntu_clang8_mpi
-  stage: build
-  script:
-    - mkdir -p build/clang8-release-mpi
-    - cd build/clang8-release-mpi
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make pugs
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-release-mpi"
-    paths:
-      - build/clang8-release-mpi
-    untracked: true
-
-test:clang8-mpi-release:
-  image: localhost:5000/ubuntu_clang8_mpi
-  stage: test
-  dependencies:
-    - build:clang8-mpi-release
-  script:
-    - mkdir -p build/clang8-release-mpi
-    - cd build/clang8-release-mpi
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make run_unit_tests
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-release-mpi"
-    paths:
-      - build/clang8-release-mpi
-    untracked: true
diff --git a/.gitlab-ci/clang8-seq-coverage.yml b/.gitlab-ci/clang8-seq-coverage.yml
deleted file mode 100644
index b7e407188efefe87fef4ab149460cb755b5455ce..0000000000000000000000000000000000000000
--- a/.gitlab-ci/clang8-seq-coverage.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-coverage:clang8-seq-coverage:
-  image: localhost:5000/ubuntu_clang8
-  stage: coverage
-  script:
-    - mkdir -p build/clang8-cov
-    - cd build/clang8-cov
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Coverage -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make pugs
-    - make coverage
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-cov"
-    paths:
-      - build/clang8-cov
-    untracked: true
diff --git a/.gitlab-ci/clang8-seq-release.yml b/.gitlab-ci/clang8-seq-release.yml
deleted file mode 100644
index acdc43a3e10be5c8fff911c8298c09327f3d4696..0000000000000000000000000000000000000000
--- a/.gitlab-ci/clang8-seq-release.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-build:clang8-seq-release:
-  image: localhost:5000/ubuntu_clang8
-  stage: build
-  script:
-    - mkdir -p build/clang8-release-seq
-    - cd build/clang8-release-seq
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make pugs
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-release-seq"
-    paths:
-      - build/clang8-release-seq
-    untracked: true
-
-test:clang8-seq-release:
-  image: localhost:5000/ubuntu_clang8
-  stage: test
-  dependencies:
-    - build:clang8-seq-release
-  script:
-    - mkdir -p build/clang8-release-seq
-    - cd build/clang8-release-seq
-    - CXX=clang++-8 CC=clang-8 cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCLANG_FORMAT=/usr/bin/clang-format-8
-    - make run_unit_tests
-  cache:
-    key: "${CI_COMMIT_REF_SLUG}-clang8-release-seq"
-    paths:
-      - build/clang8-release-seq
-    untracked: true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b5a8d153925bbe9c57dd04c817ad25ad67e01c6..73cda5739485b07c04c44c93ae6f4e9533d0f055 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -435,6 +435,7 @@ target_link_libraries(
   ${KOKKOS_CXX_FLAGS}
   ${OPENMP_LINK_FLAGS}
   ${PUGS_STD_LINK_FLAGS}
+  stdc++fs
   )
 
 # ---------------------- Doxygen ----------------------
diff --git a/packages/CLI11/.all-contributorsrc b/packages/CLI11/.all-contributorsrc
index abdeb6b26bb8f4303bce81f432ebe8949d83ad41..b95934e25458f31722995ac160ee685dd0d2c11e 100644
--- a/packages/CLI11/.all-contributorsrc
+++ b/packages/CLI11/.all-contributorsrc
@@ -359,6 +359,24 @@
       "contributions": [
         "platform"
       ]
+    },
+    {
+      "login": "certik",
+      "name": "Ondřej Čertík",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/20568?v=4",
+      "profile": "https://ondrejcertik.com/",
+      "contributions": [
+        "bug"
+      ]
+    },
+    {
+      "login": "samhocevar",
+      "name": "Sam Hocevar",
+      "avatar_url": "https://avatars2.githubusercontent.com/u/245089?v=4",
+      "profile": "http://sam.hocevar.net/",
+      "contributions": [
+        "code"
+      ]
     }
   ],
   "contributorsPerLine": 7,
diff --git a/packages/CLI11/.clang-tidy b/packages/CLI11/.clang-tidy
index c9b6458fc13541c63705403ac53cbb1de865a42f..09875c87a6b7adbc0aa8f5b0ba872493f2c82e63 100644
--- a/packages/CLI11/.clang-tidy
+++ b/packages/CLI11/.clang-tidy
@@ -6,26 +6,16 @@ FormatStyle: file
 Checks: '
 -*,
 google-*,
--google-runtime-int,
 -google-runtime-references,
 llvm-include-order,
 llvm-namespace-comment,
 misc-throw-by-value-catch-by-reference,
 modernize*,
+-modernize-use-trailing-return-type,
 readability-container-size-empty,
 '
 
-WarningsAsErrors: '
--*,
-google-*,
--google-runtime-int,
--google-runtime-references,
-llvm-include-order,
-llvm-namespace-comment,
-misc-throw-by-value-catch-by-reference,
-modernize*,
-readability-container-size-empty,
-'
+WarningsAsErrors: '*'
 
 HeaderFilterRegex: '.*hpp'
 
diff --git a/packages/CLI11/.github/actions/cmake_config/Dockerfile b/packages/CLI11/.github/actions/cmake_config/Dockerfile
index 81eb9b9965f0deb6e4e252d9cd9c5262a4d118a9..63b28a9949de219993f26a48d85db4afe6bce6df 100644
--- a/packages/CLI11/.github/actions/cmake_config/Dockerfile
+++ b/packages/CLI11/.github/actions/cmake_config/Dockerfile
@@ -7,7 +7,7 @@ RUN apt-get update \
         libidn11=1.33-2.1ubuntu1.2 \
         ca-certificates=20180409 \
         make=4.1-9.1ubuntu1 \
-        git=1:2.17.1-1ubuntu0.5 \
+        git=1:2.17.1-1ubuntu0.7 \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*
 
diff --git a/packages/CLI11/.github/workflows/tests.yml b/packages/CLI11/.github/workflows/tests.yml
index c3c832bc6e08e3b057dcb01ef8cc2ea7293c14da..86cc78ec2eca21d575c05154af554d47325e9d09 100644
--- a/packages/CLI11/.github/workflows/tests.yml
+++ b/packages/CLI11/.github/workflows/tests.yml
@@ -13,15 +13,15 @@ jobs:
     name: Formatting
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v1
-    - uses: actions/setup-python@v1
+    - uses: actions/checkout@v2
+    - uses: actions/setup-python@v2
     - name: set PY
-      run: echo "::set-env name=PY::$(python --version --version | sha256sum | cut -d' ' -f1)"
+      run: echo "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
     - uses: actions/cache@v1
       with:
         path: ~/.cache/pre-commit
         key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
-    - uses: pre-commit/action@v1.0.0
+    - uses: pre-commit/action@v1.1.0
 
   cuda-build:
     name: CUDA build only
@@ -107,9 +107,14 @@ jobs:
       with:
         version: 3.15.6
       if: success() || failure()
+    - name: CMake 3.16
+      uses: ./.github/actions/cmake_config
+      with:
+        version: 3.16.8
+      if: success() || failure()
     - name: CMake 3.16 (full)
       uses: ./.github/actions/cmake_config
       with:
-        version: 3.16.2
+        version: 3.17.3
         options: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON
       if: success() || failure()
diff --git a/packages/CLI11/.gitrepo b/packages/CLI11/.gitrepo
index 313778e5c16693281c8db1f9cab797506e10822f..4b4e25a2b1b976c20f3ad37c88290ccfc63e5fc5 100644
--- a/packages/CLI11/.gitrepo
+++ b/packages/CLI11/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:CLIUtils/CLI11.git
 	branch = master
-	commit = b9a2f320b912aae623c4acddea06cba399b98654
-	parent = 73e054c98d4a424c44972eb708495c40dfa0dbac
+	commit = 2b059cbdbe844450e1675a5dda3cb8acb1147631
+	parent = fb9f84797173b01c7277657b883e954800be1fc9
 	cmdver = 0.4.1
 	method = merge
diff --git a/packages/CLI11/CHANGELOG.md b/packages/CLI11/CHANGELOG.md
index f753569eb09fa75e8653be43579fe83fd2cd4977..f9cc853b7f3bf554c2743b98de8f6fe53e610617 100644
--- a/packages/CLI11/CHANGELOG.md
+++ b/packages/CLI11/CHANGELOG.md
@@ -1,3 +1,37 @@
+## Version 2.0: In progress
+
+* Built-in config format is TOML compliant now [#435]
+* Config updates [#442]
+* More powerful containers, `%%` separator [#423]
+* Add a version flag easily [#452]
+
+[#435]: https://github.com/CLIUtils/CLI11/pull/435
+[#443]: https://github.com/CLIUtils/CLI11/pull/443
+[#423]: https://github.com/CLIUtils/CLI11/pull/423
+[#452]: https://github.com/CLIUtils/CLI11/pull/452
+
+
+### Version 1.9.1: Backporting fixes
+
+This is a patch version that backports fixes from the development of 2.0.
+
+* Support relative inclusion [#475][]
+* Fix cases where spaces in paths could break CMake support [#471][]
+* Fix an issue with string conversion [#421][]
+* Cross-compiling improvement for Conan.io [#430][]
+* Fix option group default propagation [#450][]
+* Fix for C++20 [#459][]
+* Support compiling with RTTI off [#461][]
+
+[#421]: https://github.com/CLIUtils/CLI11/pull/421
+[#430]: https://github.com/CLIUtils/CLI11/pull/430
+[#450]: https://github.com/CLIUtils/CLI11/pull/450
+[#459]: https://github.com/CLIUtils/CLI11/pull/459
+[#461]: https://github.com/CLIUtils/CLI11/pull/461
+[#471]: https://github.com/CLIUtils/CLI11/pull/471
+[#475]: https://github.com/CLIUtils/CLI11/pull/475
+
+
 ## Version 1.9: Config files and cleanup
 
 Config file handling was revamped to fix common issues, and now supports reading [TOML](https://github.com/toml-lang/toml).
diff --git a/packages/CLI11/CMakeLists.txt b/packages/CLI11/CMakeLists.txt
index e7c2695e1e3d0311f38abf2aa2768df521cd1012..574ca1ee824c68e165fa9c013afd39db66bd658a 100644
--- a/packages/CLI11/CMakeLists.txt
+++ b/packages/CLI11/CMakeLists.txt
@@ -4,12 +4,12 @@ cmake_minimum_required(VERSION 3.4)
 
 # Make sure users don't get warnings on a tested (3.4 to 3.16) version
 # of CMake. For most of the policies, the new version is better (hence the change).
-# We don't use the 3.4...3.16 syntax because of a bug in an older MSVC's
+# We don't use the 3.4...3.17 syntax because of a bug in an older MSVC's
 # built-in and modified CMake 3.11
-if(${CMAKE_VERSION} VERSION_LESS 3.16)
+if(${CMAKE_VERSION} VERSION_LESS 3.17)
     cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 else()
-    cmake_policy(VERSION 3.16)
+    cmake_policy(VERSION 3.17)
 endif()
 
 set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"")
@@ -46,7 +46,20 @@ list(APPEND force-libcxx "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME")
 list(APPEND build-docs "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME")
 list(APPEND build-docs "NOT CMAKE_VERSION VERSION_LESS 3.11")
 list(APPEND build-docs "Doxygen_FOUND")
-list(APPEND build-docs "EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/docs")
+
+# Necessary to support paths with spaces, see #457
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
+    set(docs_EXIST TRUE)
+else()
+    set(docs_EXIST FALSE)
+endif()
+list(APPEND build-docs "docs_EXIST")
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples")
+    set(examples_EXIST TRUE)
+else()
+    set(examples_EXIST FALSE)
+endif()
 
 option(CLI11_WARNINGS_AS_ERRORS "Turn all warnings into errors (for CI)")
 option(CLI11_SINGLE_FILE "Generate a single header file")
@@ -64,7 +77,7 @@ cmake_dependent_option(CLI11_BUILD_TESTS
 
 cmake_dependent_option(CLI11_BUILD_EXAMPLES
     "Build CLI11 examples" ON
-    "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME;EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/examples" OFF)
+    "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME;${examples_EXIST}" OFF)
 
 cmake_dependent_option(CLI11_BUILD_EXAMPLES_JSON
     "Build CLI11 json example" OFF
@@ -181,8 +194,8 @@ endif()
 
 # This folder should be installed
 if(CLI11_INSTALL)
-    install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
-        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+    install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
+        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
 
     # Make an export target
     install(TARGETS CLI11 EXPORT CLI11Targets)
@@ -198,13 +211,13 @@ if(CLI11_INSTALL)
 
     # Make version available in the install
     install(FILES "${PROJECT_BINARY_DIR}/CLI11ConfigVersion.cmake"
-        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CLI11)
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CLI11")
 
     # Install the export target as a file
     install(EXPORT CLI11Targets
         FILE CLI11Config.cmake
         NAMESPACE CLI11::
-        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CLI11)
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CLI11")
 
     # Use find_package on the installed package
     export(TARGETS CLI11
@@ -239,7 +252,7 @@ if(CLI11_SINGLE_FILE)
     add_custom_target(CLI11-generate-single-file ALL
         DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp")
     set_property(TARGET CLI11-generate-single-file PROPERTY FOLDER "Scripts")
-    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp
+    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
         DESTINATION include)
     add_library(CLI11_SINGLE INTERFACE)
     target_link_libraries(CLI11_SINGLE INTERFACE CLI11)
diff --git a/packages/CLI11/README.md b/packages/CLI11/README.md
index e98f2175a8519bc6b67b31039f6995e72fb8885a..d3552752b3135f5d23213173dc9a276b9cf540b8 100644
--- a/packages/CLI11/README.md
+++ b/packages/CLI11/README.md
@@ -926,6 +926,8 @@ This project was created by [Henry Schreiner](https://github.com/henryiii) and m
   <tr>
     <td align="center"><a href="https://github.com/jsoref"><img src="https://avatars0.githubusercontent.com/u/2119212?v=4" width="100px;" alt=""/><br /><sub><b>Josh Soref</b></sub></a><br /><a href="#tool-jsoref" title="Tools">🔧</a></td>
     <td align="center"><a href="https://github.com/geir-t"><img src="https://avatars3.githubusercontent.com/u/35292136?v=4" width="100px;" alt=""/><br /><sub><b>geir-t</b></sub></a><br /><a href="#platform-geir-t" title="Packaging/porting to new platform">📦</a></td>
+    <td align="center"><a href="https://ondrejcertik.com/"><img src="https://avatars3.githubusercontent.com/u/20568?v=4" width="100px;" alt=""/><br /><sub><b>Ondřej Čertík</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Acertik" title="Bug reports">🐛</a></td>
+    <td align="center"><a href="http://sam.hocevar.net/"><img src="https://avatars2.githubusercontent.com/u/245089?v=4" width="100px;" alt=""/><br /><sub><b>Sam Hocevar</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=samhocevar" title="Code">💻</a></td>
   </tr>
 </table>
 
@@ -945,7 +947,7 @@ CLI11 was developed at the [University of Cincinnati][] to support of the [GooFi
 [doi-badge]: https://zenodo.org/badge/80064252.svg
 [doi-link]: https://zenodo.org/badge/latestdoi/80064252
 [azure-badge]: https://dev.azure.com/CLIUtils/CLI11/_apis/build/status/CLIUtils.CLI11?branchName=master
-[azure]: https://dev.azure.com/CLIUtils/CLI11/_build/latest?definitionId=1&branchName=master
+[azure]: https://dev.azure.com/CLIUtils/CLI11
 [travis-badge]: https://img.shields.io/travis/CLIUtils/CLI11/master.svg?label=Linux/macOS
 [travis]: https://travis-ci.org/CLIUtils/CLI11
 [appveyor-badge]: https://img.shields.io/appveyor/ci/HenrySchreiner/cli11/master.svg?label=AppVeyor
diff --git a/packages/CLI11/azure-pipelines.yml b/packages/CLI11/azure-pipelines.yml
index 7d2d7f400f413001a4660e48e8fe7cdce6b9c24f..90017c62f8f111acfa4eb95c78f07d2c1453fd9c 100644
--- a/packages/CLI11/azure-pipelines.yml
+++ b/packages/CLI11/azure-pipelines.yml
@@ -5,9 +5,11 @@
 
 trigger:
 - master
+- 'v*'
 
 pr:
 - master
+- 'v*'
 
 variables:
   cli11.single: ON
@@ -62,7 +64,12 @@ jobs:
         cli11.std: 11
       Windowslatest:
         vmImage: 'windows-2019'
+        cli11.std: 20
+        cli11.options: -DCMAKE_CXX_FLAGS="/std:c++latest /EHsc"
+      Linux17nortti:
+        vmImage: 'ubuntu-latest'
         cli11.std: 17
+        cli11.options: -DCMAKE_CXX_FLAGS="-fno-rtti"
   pool:
     vmImage: $(vmImage)
   steps:
@@ -113,6 +120,10 @@ jobs:
         containerImage: silkeh/clang:8
         cli11.std: 17
         cli11.options: -DCLI11_FORCE_LIBCXX=ON
+      clang10_20:
+        containerImage: helics/buildenv:clang10-builder
+        cli11.std: 20
+        cli11.options: -DCLI11_FORCE_LIBCXX=ON -DCMAKE_CXX_FLAGS=-std=c++20
   container: $[ variables['containerImage'] ]
   steps:
     - template: .ci/azure-cmake.yml
diff --git a/packages/CLI11/book/chapters/config.md b/packages/CLI11/book/chapters/config.md
index a9edf9aac521d44f522662fd45a3ecb82a063b83..fd2dbd7d95c0c4d29c6d080051641cbc3b7a13a1 100644
--- a/packages/CLI11/book/chapters/config.md
+++ b/packages/CLI11/book/chapters/config.md
@@ -135,7 +135,7 @@ The default configuration file will read INI files, but will write out files in
 ```cpp
 app.config_formatter(std::make_shared<CLI::ConfigINI>());
 ```
-which makes use of a predefined modification of the ConfigBase class which TOML also uses. If a custom formatter is used that is not inheriting from the from ConfigBase class `get_config_formatter_base() will return a nullptr, so some care must be exercised in its us with custom configurations.
+which makes use of a predefined modification of the ConfigBase class which TOML also uses. If a custom formatter is used that is not inheriting from the from ConfigBase class `get_config_formatter_base() will return a nullptr if RTTI is on (usually the default), or garbage if RTTI is off, so some care must be exercised in its use with custom configurations.
 
 ## Custom formats
 
diff --git a/packages/CLI11/examples/CMakeLists.txt b/packages/CLI11/examples/CMakeLists.txt
index 2359d5cd8d64ddf5a8a61524624e73f2403b93af..8cea1581d17b3dd919f1066e0c9a5f07a7eff756 100644
--- a/packages/CLI11/examples/CMakeLists.txt
+++ b/packages/CLI11/examples/CMakeLists.txt
@@ -54,6 +54,9 @@ set_property(TEST simple_all PROPERTY PASS_REGULAR_EXPRESSION
     "Received flag: 2 (2) times"
     "Some value: 1.2")
 
+add_test(NAME simple_version COMMAND simple --version)
+set_property(TEST simple_version PROPERTY PASS_REGULAR_EXPRESSION
+    "${CLI11_VERSION}")
 
 add_cli_exe(subcommands subcommands.cpp)
 add_test(NAME subcommands_none COMMAND subcommands)
diff --git a/packages/CLI11/examples/simple.cpp b/packages/CLI11/examples/simple.cpp
index 2d465cb223575a7d6d7a3ea2049b195c5253e333..c1354eaf38189f5f87c53ad4565d86d048082fef 100644
--- a/packages/CLI11/examples/simple.cpp
+++ b/packages/CLI11/examples/simple.cpp
@@ -11,7 +11,8 @@
 int main(int argc, char **argv) {
 
     CLI::App app("K3Pi goofit fitter");
-
+    // add version output
+    app.set_version_flag("--version", std::string(CLI11_VERSION));
     std::string file;
     CLI::Option *opt = app.add_option("-f,--file,file", file, "File name");
 
diff --git a/packages/CLI11/extern/googletest b/packages/CLI11/extern/googletest
index 703bd9caab50b139428cea1aaff9974ebee5742e..859bfe8981d6724c4ea06e73d29accd8588f3230 160000
--- a/packages/CLI11/extern/googletest
+++ b/packages/CLI11/extern/googletest
@@ -1 +1 @@
-Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e
+Subproject commit 859bfe8981d6724c4ea06e73d29accd8588f3230
diff --git a/packages/CLI11/include/CLI/App.hpp b/packages/CLI11/include/CLI/App.hpp
index 2a2414d13f144299a3276c59a2d132791716c17f..8d47976e56c39aeaf88277ea27a27cf93c4df442 100644
--- a/packages/CLI11/include/CLI/App.hpp
+++ b/packages/CLI11/include/CLI/App.hpp
@@ -20,14 +20,14 @@
 #include <vector>
 
 // CLI Library includes
-#include "CLI/ConfigFwd.hpp"
-#include "CLI/Error.hpp"
-#include "CLI/FormatterFwd.hpp"
-#include "CLI/Macros.hpp"
-#include "CLI/Option.hpp"
-#include "CLI/Split.hpp"
-#include "CLI/StringTools.hpp"
-#include "CLI/TypeTools.hpp"
+#include "ConfigFwd.hpp"
+#include "Error.hpp"
+#include "FormatterFwd.hpp"
+#include "Macros.hpp"
+#include "Option.hpp"
+#include "Split.hpp"
+#include "StringTools.hpp"
+#include "TypeTools.hpp"
 
 namespace CLI {
 
@@ -139,6 +139,9 @@ class App {
     /// A pointer to the help all flag if there is one INHERITABLE
     Option *help_all_ptr_{nullptr};
 
+    /// A pointer to a version flag if there is one
+    Option *version_ptr_{nullptr};
+
     /// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
     std::shared_ptr<FormatterBase> formatter_{new Formatter()};
 
@@ -703,6 +706,45 @@ class App {
         return help_all_ptr_;
     }
 
+    /// Set a version flag and version display string, replace the existing one if present
+    Option *set_version_flag(std::string flag_name = "", const std::string &versionString = "") {
+        // take flag_description by const reference otherwise add_flag tries to assign to version_description
+        if(version_ptr_ != nullptr) {
+            remove_option(version_ptr_);
+            version_ptr_ = nullptr;
+        }
+
+        // Empty name will simply remove the version flag
+        if(!flag_name.empty()) {
+            version_ptr_ = add_flag_callback(
+                flag_name,
+                [versionString]() { throw(CLI::CallForVersion(versionString, 0)); },
+                "Display program version information and exit");
+            version_ptr_->configurable(false);
+        }
+
+        return version_ptr_;
+    }
+    /// Generate the version string through a callback function
+    Option *set_version_flag(std::string flag_name, std::function<std::string()> vfunc) {
+        // take flag_description by const reference otherwise add_flag tries to assign to version_description
+        if(version_ptr_ != nullptr) {
+            remove_option(version_ptr_);
+            version_ptr_ = nullptr;
+        }
+
+        // Empty name will simply remove the version flag
+        if(!flag_name.empty()) {
+            version_ptr_ = add_flag_callback(
+                flag_name,
+                [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); },
+                "Display program version information and exit");
+            version_ptr_->configurable(false);
+        }
+
+        return version_ptr_;
+    }
+
   private:
     /// Internal function for adding a flag
     Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
@@ -993,7 +1035,7 @@ class App {
     /// creates an option group as part of the given app
     template <typename T = Option_group>
     T *add_option_group(std::string group_name, std::string group_description = "") {
-        auto option_group = std::make_shared<T>(std::move(group_description), group_name, nullptr);
+        auto option_group = std::make_shared<T>(std::move(group_description), group_name, this);
         auto ptr = option_group.get();
         // move to App_p for overload resolution on older gcc versions
         App_p app_ptr = std::dynamic_pointer_cast<App>(option_group);
@@ -1332,19 +1374,24 @@ class App {
     int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {
 
         /// Avoid printing anything if this is a CLI::RuntimeError
-        if(dynamic_cast<const CLI::RuntimeError *>(&e) != nullptr)
+        if(e.get_name() == "RuntimeError")
             return e.get_exit_code();
 
-        if(dynamic_cast<const CLI::CallForHelp *>(&e) != nullptr) {
+        if(e.get_name() == "CallForHelp") {
             out << help();
             return e.get_exit_code();
         }
 
-        if(dynamic_cast<const CLI::CallForAllHelp *>(&e) != nullptr) {
+        if(e.get_name() == "CallForAllHelp") {
             out << help("", AppFormatMode::All);
             return e.get_exit_code();
         }
 
+        if(e.get_name() == "CallForVersion") {
+            out << e.what() << std::endl;
+            return e.get_exit_code();
+        }
+
         if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
             if(failure_message_)
                 err << failure_message_(this, e) << std::flush;
@@ -1530,6 +1577,23 @@ class App {
         return formatter_->make_help(this, prev, mode);
     }
 
+    /// Displays a version string
+    std::string version() const {
+        std::string val;
+        if(version_ptr_ != nullptr) {
+            auto rv = version_ptr_->results();
+            version_ptr_->clear();
+            version_ptr_->add_result("true");
+            try {
+                version_ptr_->run_callback();
+            } catch(const CLI::CallForVersion &cfv) {
+                val = cfv.what();
+            }
+            version_ptr_->clear();
+            version_ptr_->add_result(rv);
+        }
+        return val;
+    }
     ///@}
     /// @name Getters
     ///@{
@@ -1542,7 +1606,12 @@ class App {
 
     /// Access the config formatter as a configBase pointer
     std::shared_ptr<ConfigBase> get_config_formatter_base() const {
+        // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase
+#if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0))
         return std::dynamic_pointer_cast<ConfigBase>(config_formatter_);
+#else
+        return std::static_pointer_cast<ConfigBase>(config_formatter_);
+#endif
     }
 
     /// Get the app or subcommand description
@@ -1726,6 +1795,12 @@ class App {
     /// Get a pointer to the config option. (const)
     const Option *get_config_ptr() const { return config_ptr_; }
 
+    /// Get a pointer to the version option.
+    Option *get_version_ptr() { return version_ptr_; }
+
+    /// Get a pointer to the version option. (const)
+    const Option *get_version_ptr() const { return version_ptr_; }
+
     /// Get the parent of this subcommand (or nullptr if master app)
     App *get_parent() { return parent_; }
 
@@ -3086,7 +3161,18 @@ inline std::string help(const App *app, const Error &e) {
 namespace detail {
 /// This class is simply to allow tests access to App's protected functions
 struct AppFriend {
+#ifdef CLI11_CPP14
 
+    /// Wrap _parse_short, perfectly forward arguments and return
+    template <typename... Args> static decltype(auto) parse_arg(App *app, Args &&... args) {
+        return app->_parse_arg(std::forward<Args>(args)...);
+    }
+
+    /// Wrap _parse_subcommand, perfectly forward arguments and return
+    template <typename... Args> static decltype(auto) parse_subcommand(App *app, Args &&... args) {
+        return app->_parse_subcommand(std::forward<Args>(args)...);
+    }
+#else
     /// Wrap _parse_short, perfectly forward arguments and return
     template <typename... Args>
     static auto parse_arg(App *app, Args &&... args) ->
@@ -3100,6 +3186,7 @@ struct AppFriend {
         typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
         return app->_parse_subcommand(std::forward<Args>(args)...);
     }
+#endif
     /// Wrap the fallthrough parent function to make sure that is working correctly
     static App *get_fallthrough_parent(App *app) { return app->_get_fallthrough_parent(); }
 };
diff --git a/packages/CLI11/include/CLI/CLI.hpp b/packages/CLI11/include/CLI/CLI.hpp
index 22e85aed184e7b443927617231f190235e47e41e..98fca54884b17de40198ea6719b90549eb3c9d61 100644
--- a/packages/CLI11/include/CLI/CLI.hpp
+++ b/packages/CLI11/include/CLI/CLI.hpp
@@ -9,28 +9,28 @@
 // CLI Library includes
 // Order is important for combiner script
 
-#include "CLI/Version.hpp"
+#include "Version.hpp"
 
-#include "CLI/Macros.hpp"
+#include "Macros.hpp"
 
-#include "CLI/StringTools.hpp"
+#include "StringTools.hpp"
 
-#include "CLI/Error.hpp"
+#include "Error.hpp"
 
-#include "CLI/TypeTools.hpp"
+#include "TypeTools.hpp"
 
-#include "CLI/Split.hpp"
+#include "Split.hpp"
 
-#include "CLI/ConfigFwd.hpp"
+#include "ConfigFwd.hpp"
 
-#include "CLI/Validators.hpp"
+#include "Validators.hpp"
 
-#include "CLI/FormatterFwd.hpp"
+#include "FormatterFwd.hpp"
 
-#include "CLI/Option.hpp"
+#include "Option.hpp"
 
-#include "CLI/App.hpp"
+#include "App.hpp"
 
-#include "CLI/Config.hpp"
+#include "Config.hpp"
 
-#include "CLI/Formatter.hpp"
+#include "Formatter.hpp"
diff --git a/packages/CLI11/include/CLI/Config.hpp b/packages/CLI11/include/CLI/Config.hpp
index 8ef40552ecd3027e76bee6be19f825c753618318..5a982236cc16aa5bf2cd48c45b42748591cdb334 100644
--- a/packages/CLI11/include/CLI/Config.hpp
+++ b/packages/CLI11/include/CLI/Config.hpp
@@ -13,9 +13,9 @@
 #include <utility>
 #include <vector>
 
-#include "CLI/App.hpp"
-#include "CLI/ConfigFwd.hpp"
-#include "CLI/StringTools.hpp"
+#include "App.hpp"
+#include "ConfigFwd.hpp"
+#include "StringTools.hpp"
 
 namespace CLI {
 
diff --git a/packages/CLI11/include/CLI/ConfigFwd.hpp b/packages/CLI11/include/CLI/ConfigFwd.hpp
index 49ca1b288b9349befbc8757232fd003e96d02c70..2546d1352022147614cdc276acd1cef18ab9fb65 100644
--- a/packages/CLI11/include/CLI/ConfigFwd.hpp
+++ b/packages/CLI11/include/CLI/ConfigFwd.hpp
@@ -12,8 +12,8 @@
 #include <string>
 #include <vector>
 
-#include "CLI/Error.hpp"
-#include "CLI/StringTools.hpp"
+#include "Error.hpp"
+#include "StringTools.hpp"
 
 namespace CLI {
 
diff --git a/packages/CLI11/include/CLI/Error.hpp b/packages/CLI11/include/CLI/Error.hpp
index 0adf15c50454a6188ec8e6897fa14930bb87aa84..11feaedbcdf2d6c13faf8519abd588ac1cde31f0 100644
--- a/packages/CLI11/include/CLI/Error.hpp
+++ b/packages/CLI11/include/CLI/Error.hpp
@@ -13,7 +13,7 @@
 #include <vector>
 
 // CLI library includes
-#include "CLI/StringTools.hpp"
+#include "StringTools.hpp"
 
 namespace CLI {
 
@@ -157,18 +157,25 @@ class Success : public ParseError {
 };
 
 /// -h or --help on command line
-class CallForHelp : public ParseError {
-    CLI11_ERROR_DEF(ParseError, CallForHelp)
+class CallForHelp : public Success {
+    CLI11_ERROR_DEF(Success, CallForHelp)
     CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
 };
 
 /// Usually something like --help-all on command line
-class CallForAllHelp : public ParseError {
-    CLI11_ERROR_DEF(ParseError, CallForAllHelp)
+class CallForAllHelp : public Success {
+    CLI11_ERROR_DEF(Success, CallForAllHelp)
     CallForAllHelp()
         : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
 };
 
+/// -v or --version on command line
+class CallForVersion : public Success {
+    CLI11_ERROR_DEF(Success, CallForVersion)
+    CallForVersion()
+        : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
+};
+
 /// Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error code.
 class RuntimeError : public ParseError {
     CLI11_ERROR_DEF(ParseError, RuntimeError)
diff --git a/packages/CLI11/include/CLI/Formatter.hpp b/packages/CLI11/include/CLI/Formatter.hpp
index 6ac4e4d1a090fbd5d9cafcb9755123929b6c5a90..8a8ba3526e15da81b08c9a3c722c07797f9214d1 100644
--- a/packages/CLI11/include/CLI/Formatter.hpp
+++ b/packages/CLI11/include/CLI/Formatter.hpp
@@ -10,8 +10,8 @@
 #include <string>
 #include <vector>
 
-#include "CLI/App.hpp"
-#include "CLI/FormatterFwd.hpp"
+#include "App.hpp"
+#include "FormatterFwd.hpp"
 
 namespace CLI {
 
diff --git a/packages/CLI11/include/CLI/FormatterFwd.hpp b/packages/CLI11/include/CLI/FormatterFwd.hpp
index 4c4a5de05652373fe54c5e608bd5d7aeecac699c..362219e24e817aa42b682d06a0204ac4ca87b26a 100644
--- a/packages/CLI11/include/CLI/FormatterFwd.hpp
+++ b/packages/CLI11/include/CLI/FormatterFwd.hpp
@@ -11,7 +11,7 @@
 #include <utility>
 #include <vector>
 
-#include "CLI/StringTools.hpp"
+#include "StringTools.hpp"
 
 namespace CLI {
 
diff --git a/packages/CLI11/include/CLI/Option.hpp b/packages/CLI11/include/CLI/Option.hpp
index 911dd64b213536adfa942a293b70d70d5a81aff9..e980002847881b5c7eabe3f8b7573c25351afeec 100644
--- a/packages/CLI11/include/CLI/Option.hpp
+++ b/packages/CLI11/include/CLI/Option.hpp
@@ -15,11 +15,11 @@
 #include <utility>
 #include <vector>
 
-#include "CLI/Error.hpp"
-#include "CLI/Macros.hpp"
-#include "CLI/Split.hpp"
-#include "CLI/StringTools.hpp"
-#include "CLI/Validators.hpp"
+#include "Error.hpp"
+#include "Macros.hpp"
+#include "Split.hpp"
+#include "StringTools.hpp"
+#include "Validators.hpp"
 
 namespace CLI {
 
@@ -508,7 +508,7 @@ class Option : public OptionBase<Option> {
 
     /// Can find a string if needed
     template <typename T = App> Option *needs(std::string opt_name) {
-        auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
+        auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
         if(opt == nullptr) {
             throw IncorrectConstruction::MissingOption(opt_name);
         }
@@ -550,7 +550,7 @@ class Option : public OptionBase<Option> {
 
     /// Can find a string if needed
     template <typename T = App> Option *excludes(std::string opt_name) {
-        auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
+        auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
         if(opt == nullptr) {
             throw IncorrectConstruction::MissingOption(opt_name);
         }
@@ -587,7 +587,7 @@ class Option : public OptionBase<Option> {
     template <typename T = App> Option *ignore_case(bool value = true) {
         if(!ignore_case_ && value) {
             ignore_case_ = value;
-            auto *parent = dynamic_cast<T *>(parent_);
+            auto *parent = static_cast<T *>(parent_);
             for(const Option_p &opt : parent->options_) {
                 if(opt.get() == this) {
                     continue;
@@ -612,7 +612,7 @@ class Option : public OptionBase<Option> {
 
         if(!ignore_underscore_ && value) {
             ignore_underscore_ = value;
-            auto *parent = dynamic_cast<T *>(parent_);
+            auto *parent = static_cast<T *>(parent_);
             for(const Option_p &opt : parent->options_) {
                 if(opt.get() == this) {
                     continue;
diff --git a/packages/CLI11/include/CLI/Split.hpp b/packages/CLI11/include/CLI/Split.hpp
index 7e534732d5a5ac936363454e93e7d17139682d1d..6306404bcf86f8093f36d34ec5898063de3c8518 100644
--- a/packages/CLI11/include/CLI/Split.hpp
+++ b/packages/CLI11/include/CLI/Split.hpp
@@ -11,8 +11,8 @@
 #include <utility>
 #include <vector>
 
-#include "CLI/Error.hpp"
-#include "CLI/StringTools.hpp"
+#include "Error.hpp"
+#include "StringTools.hpp"
 
 namespace CLI {
 namespace detail {
diff --git a/packages/CLI11/include/CLI/StringTools.hpp b/packages/CLI11/include/CLI/StringTools.hpp
index cd861ba2dbb436fa45af03a63d10a810fd1082e8..70f202aa71901720370e7daf4c50115c49e6be48 100644
--- a/packages/CLI11/include/CLI/StringTools.hpp
+++ b/packages/CLI11/include/CLI/StringTools.hpp
@@ -190,7 +190,7 @@ inline bool valid_name_string(const std::string &str) {
     return true;
 }
 
-/// check if a string is a container segment separator (empty or "%%"
+/// check if a string is a container segment separator (empty or "%%")
 inline bool is_separator(const std::string &str) {
     static const std::string sep("%%");
     return (str.empty() || str == sep);
diff --git a/packages/CLI11/include/CLI/TypeTools.hpp b/packages/CLI11/include/CLI/TypeTools.hpp
index a4297b2ff866c21202ad6703a669e941ede8b5f4..4b85f05c51aa8c5b93dba3257e66629403fa6f70 100644
--- a/packages/CLI11/include/CLI/TypeTools.hpp
+++ b/packages/CLI11/include/CLI/TypeTools.hpp
@@ -232,7 +232,7 @@ struct is_mutable_container<
 // check to see if an object is a mutable container (fail by default)
 template <typename T, typename _ = void> struct is_readable_container : std::false_type {};
 
-/// type trait to test if a type is a container meaning it has a value_type, it has an iterator, a clear, and an en end
+/// type trait to test if a type is a container meaning it has a value_type, it has an iterator, a clear, and an end
 /// methods and an insert function.  And for our purposes we exclude std::string and types that can be constructed from
 /// a std::string
 template <typename T>
@@ -244,7 +244,7 @@ struct is_readable_container<
 // check to see if an object is a wrapper (fail by default)
 template <typename T, typename _ = void> struct is_wrapper : std::false_type {};
 
-// check if an object is a is a wrapper (it has a value_type defined)
+// check if an object is a wrapper (it has a value_type defined)
 template <typename T>
 struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> : public std::true_type {};
 
@@ -344,7 +344,7 @@ auto value_string(const T &value) -> decltype(to_string(value)) {
     return to_string(value);
 }
 
-/// temple to get the underlying value type if it exists or use a default
+/// template to get the underlying value type if it exists or use a default
 template <typename T, typename def, typename Enable = void> struct wrapped_type { using type = def; };
 
 /// Type size for regular object types that do not look like a tuple
diff --git a/packages/CLI11/include/CLI/Validators.hpp b/packages/CLI11/include/CLI/Validators.hpp
index 9f47477db301fa9ee691891a38683d19746043d0..bc916f8615fef58ae0b7a6f011dedf6778298ac1 100644
--- a/packages/CLI11/include/CLI/Validators.hpp
+++ b/packages/CLI11/include/CLI/Validators.hpp
@@ -6,9 +6,9 @@
 
 #pragma once
 
-#include "CLI/Macros.hpp"
-#include "CLI/StringTools.hpp"
-#include "CLI/TypeTools.hpp"
+#include "Macros.hpp"
+#include "StringTools.hpp"
+#include "TypeTools.hpp"
 
 #include <cmath>
 #include <cstdint>
diff --git a/packages/CLI11/scripts/MakeSingleHeader.py b/packages/CLI11/scripts/MakeSingleHeader.py
index 1163485a3de63706543f73182681bbc083cd21ba..1c4385826a2413c60ee4f12a8e6fc18bc2a4bfb0 100755
--- a/packages/CLI11/scripts/MakeSingleHeader.py
+++ b/packages/CLI11/scripts/MakeSingleHeader.py
@@ -128,6 +128,7 @@ def MakeHeader(
 
     base_dir = os.path.abspath(os.path.join(DIR, include_dir))
     main_header = os.path.join(base_dir, main_header)
+    header_dir = os.path.dirname(main_header)
     licence_file = os.path.abspath(os.path.join(DIR, "../LICENSE"))
 
     with open(licence_file) as f:
@@ -138,7 +139,7 @@ def MakeHeader(
 
     include_files = includes_local.findall(header)
 
-    headers = [HeaderFile(base_dir, inc) for inc in include_files]
+    headers = [HeaderFile(header_dir, inc) for inc in include_files]
     single_header = reduce(add, headers)
 
     if macro is not None:
diff --git a/packages/CLI11/tests/HelpTest.cpp b/packages/CLI11/tests/HelpTest.cpp
index 68d96d13b5ee87432363b39039719b2d1c959458..161b0b9eea47a1f7b8a1b2635e681b5c7cd70860 100644
--- a/packages/CLI11/tests/HelpTest.cpp
+++ b/packages/CLI11/tests/HelpTest.cpp
@@ -1165,3 +1165,53 @@ TEST(THelp, FunctionDefaultString) {
 
     EXPECT_THAT(help, HasSubstr("INT=Powerful"));
 }
+
+TEST(TVersion, simple_flag) {
+
+    CLI::App app;
+
+    app.set_version_flag("-v,--version", "VERSION " CLI11_VERSION);
+
+    auto vers = app.version();
+    EXPECT_THAT(vers, HasSubstr("VERSION"));
+
+    app.set_version_flag();
+    EXPECT_TRUE(app.version().empty());
+}
+
+TEST(TVersion, callback_flag) {
+
+    CLI::App app;
+
+    app.set_version_flag("-v,--version", []() { return std::string("VERSION " CLI11_VERSION); });
+
+    auto vers = app.version();
+    EXPECT_THAT(vers, HasSubstr("VERSION"));
+
+    app.set_version_flag("-v", []() { return std::string("VERSION2 " CLI11_VERSION); });
+    vers = app.version();
+    EXPECT_THAT(vers, HasSubstr("VERSION"));
+}
+
+TEST(TVersion, parse_throw) {
+
+    CLI::App app;
+
+    app.set_version_flag("--version", CLI11_VERSION);
+
+    EXPECT_THROW(app.parse("--version"), CLI::CallForVersion);
+    EXPECT_THROW(app.parse("--version --arg2 5"), CLI::CallForVersion);
+
+    auto ptr = app.get_version_ptr();
+
+    ptr->ignore_case();
+    try {
+        app.parse("--Version");
+    } catch(const CLI::CallForVersion &v) {
+        EXPECT_STREQ(v.what(), CLI11_VERSION);
+        EXPECT_EQ(v.get_exit_code(), 0);
+        const auto &appc = app;
+        auto cptr = appc.get_version_ptr();
+        EXPECT_EQ(cptr->count(), 1U);
+    }
+}
diff --git a/packages/CLI11/tests/OptionGroupTest.cpp b/packages/CLI11/tests/OptionGroupTest.cpp
index 51bb9fd260cdb1fb11cf760e4bb5b0ba6d6ae353..e510c1a390847b0494e60f7608a9b6a85ab073bd 100644
--- a/packages/CLI11/tests/OptionGroupTest.cpp
+++ b/packages/CLI11/tests/OptionGroupTest.cpp
@@ -374,6 +374,18 @@ TEST_F(TApp, InvalidOptions) {
     EXPECT_THROW(ogroup->add_option(opt), CLI::OptionNotFound);
 }
 
+TEST_F(TApp, OptionGroupInheritedOptionDefaults) {
+    app.option_defaults()->ignore_case();
+    auto ogroup = app.add_option_group("clusters");
+    int res{0};
+    ogroup->add_option("--test1", res);
+
+    args = {"--Test1", "5"};
+    run();
+    EXPECT_EQ(res, 5);
+    EXPECT_EQ(app.count_all(), 1u);
+}
+
 struct ManyGroups : public TApp {
 
     CLI::Option_group *main{nullptr};
diff --git a/packages/Catch2/.clang-format b/packages/Catch2/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..2a82aacfdcf07382b720d7706bf9ad60f4fc8402
--- /dev/null
+++ b/packages/Catch2/.clang-format
@@ -0,0 +1,25 @@
+---
+AccessModifierOffset: '-4'
+AlignEscapedNewlines: Left
+AllowAllConstructorInitializersOnNextLine: 'true'
+BinPackArguments: 'false'
+BinPackParameters: 'false'
+BreakConstructorInitializers: AfterColon
+ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
+DerivePointerAlignment: 'false'
+FixNamespaceComments: 'true'
+IncludeBlocks: Regroup
+IndentCaseLabels: 'false'
+IndentPPDirectives: AfterHash
+IndentWidth: '4'
+Language: Cpp
+NamespaceIndentation: All
+PointerAlignment: Left
+SpaceBeforeCtorInitializerColon: 'false'
+SpaceInEmptyParentheses: 'false'
+SpacesInParentheses: 'true'
+Standard: Cpp11
+TabWidth: '4'
+UseTab: Never
+
+...
diff --git a/packages/Catch2/.conan/build.py b/packages/Catch2/.conan/build.py
index 272986516325e2af1e048f6c15b9f062829fda0e..37975a8a1e1caf2b326641a116cd4635760ac830 100644
--- a/packages/Catch2/.conan/build.py
+++ b/packages/Catch2/.conan/build.py
@@ -31,7 +31,7 @@ class BuilderSettings(object):
             not match the stable pattern. Otherwise it will upload to stable
             channel.
         """
-        return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/Catch2")
+        return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/catch2")
 
     @property
     def upload_only_when_stable(self):
diff --git a/packages/Catch2/.github/FUNDING.yml b/packages/Catch2/.github/FUNDING.yml
index 01d384e8268e6a7e979bb2e73724bb336baf3a09..4d8a0e95ae59d78c522dd3422ed050c5946c8f3e 100644
--- a/packages/Catch2/.github/FUNDING.yml
+++ b/packages/Catch2/.github/FUNDING.yml
@@ -1 +1 @@
-patreon: horenmar
+custom: "https://www.paypal.me/horenmar"
diff --git a/packages/Catch2/.gitignore b/packages/Catch2/.gitignore
index f017e9e09f991ed589a0f3b27b8bc490be28b5c1..dd12a74ba602982fa3cc1134f378b6cf2a69e79b 100644
--- a/packages/Catch2/.gitignore
+++ b/packages/Catch2/.gitignore
@@ -28,3 +28,4 @@ Build
 cmake-build-*
 benchmark-dir
 .conan/test_package/build
+bazel-*
diff --git a/packages/Catch2/.gitrepo b/packages/Catch2/.gitrepo
index eeda199924a84e824ecd08a9d7917712ed180085..1371144f0d2ad5f34cada8849b25859d4a706020 100644
--- a/packages/Catch2/.gitrepo
+++ b/packages/Catch2/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:catchorg/Catch2.git
 	branch = master
-	commit = 38f897c88772d6640196d1bd617ebbcaf44bc05a
-	parent = 2f7310d11077fd2ebdcdc77443bb9560060372c3
+	commit = 2b34b5c7d00ddd379ab62a8d37a7029f04223f45
+	parent = e0c202c86c28b369cbfd00629417affe94cefec0
 	cmdver = 0.4.1
 	method = merge
diff --git a/packages/Catch2/BUILD.bazel b/packages/Catch2/BUILD.bazel
new file mode 100644
index 0000000000000000000000000000000000000000..2a412a8eb8994db6f7bfdcbd517ddf6aa585660c
--- /dev/null
+++ b/packages/Catch2/BUILD.bazel
@@ -0,0 +1,10 @@
+# Load the cc_library rule.
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+# Header-only rule to export catch2/catch.hpp.
+cc_library(
+  name = "catch2",
+  hdrs = ["single_include/catch2/catch.hpp"],
+  visibility = ["//visibility:public"],
+  includes = ["single_include/"],
+)
diff --git a/packages/Catch2/CMakeLists.txt b/packages/Catch2/CMakeLists.txt
index 55bf413d7a696088e1f9dc139b8c6b970b691410..e816058e9437cf5c96f6808d1cc4bad30889f548 100644
--- a/packages/Catch2/CMakeLists.txt
+++ b/packages/Catch2/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5)
 # detect if Catch is being bundled,
 # disable testsuite in that case
 if(NOT DEFINED PROJECT_NAME)
-  set(NOT_SUBPROJECT ON)
+    set(NOT_SUBPROJECT ON)
 endif()
 
 # Catch2's build breaks if done in-tree. You probably should not build
@@ -14,14 +14,12 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
 endif()
 
 
-project(Catch2 LANGUAGES CXX VERSION 2.11.3)
+project(Catch2 LANGUAGES CXX VERSION 2.13.0)
 
 # Provide path for scripts
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
 
 include(GNUInstallDirs)
-include(CMakePackageConfigHelpers)
-include(CTest)
 
 option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
 option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
@@ -33,8 +31,6 @@ option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
 option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
 
 
-set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-
 # define some folders
 set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
@@ -45,12 +41,16 @@ if(USE_WMAIN)
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
 endif()
 
-if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
-    find_package(PythonInterp)
-    if (NOT PYTHONINTERP_FOUND)
-        message(FATAL_ERROR "Python not found, but required for tests")
+if(NOT_SUBPROJECT)
+    include(CTest)
+    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+    if(BUILD_TESTING AND CATCH_BUILD_TESTING)
+        find_package(PythonInterp)
+        if (NOT PYTHONINTERP_FOUND)
+            message(FATAL_ERROR "Python not found, but required for tests")
+        endif()
+        add_subdirectory(projects)
     endif()
-    add_subdirectory(projects)
 endif()
 
 if(CATCH_BUILD_EXAMPLES)
@@ -107,6 +107,7 @@ add_library(Catch2::Catch2 ALIAS Catch2)
 # a subproject via `add_subdirectory`, or the destinations will break,
 # see https://github.com/catchorg/Catch2/issues/1373
 if (NOT_SUBPROJECT)
+    include(CMakePackageConfigHelpers)
     set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
 
     configure_package_config_file(
diff --git a/packages/Catch2/README.md b/packages/Catch2/README.md
index e7469c7459b16a9f6ddf7c4538993810bc3b09ec..82541b54c491376fe269216594d6a28634081730 100644
--- a/packages/Catch2/README.md
+++ b/packages/Catch2/README.md
@@ -5,11 +5,11 @@
 [![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
 [![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
 [![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
-[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/p9Pcgple8QWwgNR0)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/aavJBzemrxUgGV9S)
 [![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
 
 
-<a href="https://github.com/catchorg/Catch2/releases/download/v2.11.3/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
+<a href="https://github.com/catchorg/Catch2/releases/download/v2.13.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
 
 ## Catch2 is released!
 
diff --git a/packages/Catch2/WORKSPACE b/packages/Catch2/WORKSPACE
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/packages/Catch2/conanfile.py b/packages/Catch2/conanfile.py
index 8d407bafd9d70dacf7489727a599ef8dc0cb9e6e..a904ce960f96d6fd09b04e9cae82c97866c689f4 100644
--- a/packages/Catch2/conanfile.py
+++ b/packages/Catch2/conanfile.py
@@ -25,3 +25,6 @@ class CatchConan(ConanFile):
 
     def package_id(self):
         self.info.header_only()
+
+    def package_info(self):
+        self.cpp_info.builddirs.append("lib/cmake/Catch2")
diff --git a/packages/Catch2/contrib/ParseAndAddCatchTests.cmake b/packages/Catch2/contrib/ParseAndAddCatchTests.cmake
index 3c551f07d7841293582d97465661469324a0904c..5e89cb76199691be0f2fe70f304b40ded118b6f4 100644
--- a/packages/Catch2/contrib/ParseAndAddCatchTests.cmake
+++ b/packages/Catch2/contrib/ParseAndAddCatchTests.cmake
@@ -189,24 +189,29 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
             # Escape commas in the test spec
             string(REPLACE "," "\\," Name ${Name})
 
+            # Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary,
+            # only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
+            if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18")
+                set(CTestName "\"${CTestName}\"")
+            endif()
             # Add the test and set its properties
-            add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
+            add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
             # Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
             if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
                 ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
-                set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
+                set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
             else()
-                set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
+                set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
                                                         LABELS "${Labels}")
             endif()
             set_property(
               TARGET ${TestTarget}
               APPEND
-              PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
+              PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
             set_property(
               SOURCE ${SourceFile}
               APPEND
-              PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
+              PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
         endif()
 
 
diff --git a/packages/Catch2/docs/command-line.md b/packages/Catch2/docs/command-line.md
index 2b506f167753b4d825953de78e24093482192740..a99a10726192748f3225f8172375171df38262f0 100644
--- a/packages/Catch2/docs/command-line.md
+++ b/packages/Catch2/docs/command-line.md
@@ -222,6 +222,16 @@ available warnings
 
 When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not.
 
+<pre>-D, --min-duration &lt;value></pre>
+
+> `--min-duration` was [introduced](https://github.com/catchorg/Catch2/pull/1910) in Catch 2.13.0
+
+When set, Catch will report the duration of each test case that took more
+than &lt;value> seconds, in milliseconds. This option is overriden by both
+`-d yes` and `-d no`, so that either all durations are reported, or none
+are.
+
+
 <a id="input-file"></a>
 ## Load test names to run from a file
 <pre>-f, --input-file &lt;filename></pre>
@@ -260,6 +270,8 @@ Randomly sorted. The order is dependent on Catch2's random seed (see
 is that as long as the random seed is fixed, running only some tests
 (e.g. via tag) does not change their relative order.
 
+> The subset stability was introduced in Catch2 v2.12.0
+
 
 <a id="rng-seed"></a>
 ## Specify a seed for the Random Number Generator
diff --git a/packages/Catch2/docs/contributing.md b/packages/Catch2/docs/contributing.md
index 5429bf9dc18f48fdeae1ab2162120b1d23994ef6..5ac0d5585898e15336d89fb7de0422cf3b6d5d1f 100644
--- a/packages/Catch2/docs/contributing.md
+++ b/packages/Catch2/docs/contributing.md
@@ -1,117 +1,119 @@
 <a id="top"></a>
-# Contributing to Catch
+# Contributing to Catch2
 
 **Contents**<br>
-[Branches](#branches)<br>
-[Directory structure](#directory-structure)<br>
+[Using Git(Hub)](#using-github)<br>
 [Testing your changes](#testing-your-changes)<br>
-[Documenting your code](#documenting-your-code)<br>
-[Code constructs to watch out for](#code-constructs-to-watch-out-for)<br>
+[Writing documentation](#writing-documentation)<br>
+[Writing code](#writing-code)<br>
+[CoC](#coc)<br>
 
-So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
-additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
-Of course so are bug reports and other comments and questions.
+So you want to contribute something to Catch2? That's great! Whether it's
+a bug fix, a new feature, support for additional compilers - or just
+a fix to the documentation - all contributions are very welcome and very
+much appreciated. Of course so are bug reports, other comments, and
+questions, but generally it is a better idea to ask questions in our
+[Discord](https://discord.gg/4CWS9zD), than in the issue tracker.
 
-If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to
-help you find your way around. As this is liable to drift out of date please raise an issue or, better still, a pull
-request for this file, if you notice that.
 
-## Branches
+This page covers some guidelines and helpful tips for contributing
+to the codebase itself.
 
-Ongoing development is currently on _master_. At some point an integration branch will be set-up and PRs should target
- that - but for now it's all against master. You may see feature branches come and go from time to time, too.
+## Using Git(Hub)
 
-## Directory structure
+Ongoing development happens in the `master` branch for Catch2 v2, and in
+`dev-v3` for the next major version, v3.
 
-_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
-primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
-`projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
-project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion,
-it can work with the CMake file directly.
+Commits should be small and atomic. A commit is atomic when, after it is
+applied, the codebase, tests and all, still works as expected. Small
+commits are also prefered, as they make later operations with git history,
+whether it is bisecting, reverting, or something else, easier.
 
-As well as the runtime test files you'll also see a `SurrogateCpps` directory under `projects/SelfTest`.
-This contains a set of .cpp files that each `#include` a single header.
-While these files are not essential to compilation they help to keep the implementation headers self-contained.
-At time of writing this set is not complete but has reasonable coverage.
-If you add additional headers please try to remember to add a surrogate cpp for it.
+_When submitting a pull request please do not include changes to the
+single include. This means do not include them in your git commits!_
 
-The other directories are `scripts` which contains a set of python scripts to help in testing Catch as well as
-generating the single include, and `docs`, which contains the documentation as a set of markdown files.
 
-__When submitting a pull request please do not include changes to the single include, or to the version number file
-as these are managed by the scripts!__
+When addressing review comments in a MR, please do not rebase/squash the
+commits immediately. Doing so makes it harder to review the new changes,
+slowing down the process of merging a MR. Instead, when addressing review
+comments, you should append new commits to the branch and only squash
+them into other commits when the MR is ready to be merged. We recommend
+creating new commits with `git commit --fixup` (or `--squash`) and then
+later squashing them with `git rebase --autosquash` to make things easier.
+
 
 
 ## Testing your changes
 
-Obviously all changes to Catch's code should be tested. If you added new
-functionality, you should add tests covering and showcasing it. Even if you have
-only made changes to Catch internals (i.e. you implemented some performance
-improvements), you should still test your changes.
+_Note: Running Catch2's tests requires Python3_
+
+
+Catch2 has multiple layers of tests that are then run as part of our CI.
+The most obvious one are the unit tests compiled into the `SelfTest`
+binary. These are then used in "Approval tests", which run (almost) all
+tests from `SelfTest` through a specific reporter and then compare the
+generated output with a known good output ("Baseline"). By default, new
+tests should be placed here.
+
+However, not all tests can be written as plain unit tests. For example,
+checking that Catch2 orders tests randomly when asked to, and that this
+random ordering is subset-invariant, is better done as an integration
+test using an external check script. Catch2 integration tests are written
+using CTest, either as a direct command invocation + pass/fail regex,
+or by delegating the check to a Python script.
 
-This means 2 things
+There are also two more kinds of tests, examples and "ExtraTests".
+Examples serve as a compilation test on the single-header distribution,
+and present a small and self-contained snippets of using Catch2 for
+writing tests. ExtraTests then are tests that either take a long time
+to run, or require separate compilation, e.g. because of testing compile
+time configuration options, and take a long time because of that.
 
-* Compiling Catch's SelfTest project:
+Both of these are compiled against the single-header distribution of
+Catch2, and thus might require you to regenerate it manually. This is
+done by calling the `generateSingleHeader.py` script in `scripts`.
+
+Examples and ExtraTests are not compiled by default. To compile them,
+add `-DCATCH_BUILD_EXAMPLES=ON` and `-DCATCH_BUILD_EXTRA_TESTS=ON` to
+the invocation of CMake configuration step.
+
+Bringing this all together, the steps below should configure, build,
+and run all tests in the `Debug` compilation.
+
+1. Regenerate the single header distribution
 ```
 $ cd Catch2
-$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug
+$ ./scripts/generateSingleHeader.py
+```
+2. Configure the full test build
+```
+$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON
+```
+3. Run the actual build
+```
 $ cmake --build debug-build
 ```
-because code that does not compile is evidently incorrect. Obviously,
-you are not expected to have access to all the compilers and platforms
-supported by Catch2, but you should at least smoke test your changes
-on your platform. Our CI pipeline will check your PR against most of
-the supported platforms, but it takes an hour to finish -- compiling
-locally takes just a few minutes.
-
-
-* Running the tests via CTest:
+4. Run the tests using CTest
 ```
 $ cd debug-build
-$ ctest -j 2 --output-on-failure
+$ ctest -j 4 --output-on-failure -C Debug
 ```
-__Note:__ When running your tests with multi-configuration generators like
-Visual Studio, you might get errors "Test not available without configuration."
-You then have to pick one configuration (e.g. ` -C Debug`) in the `ctest` call.
-
-If you added new tests, approval tests are very likely to fail. If they
-do not, it means that your changes weren't run as part of them. This
-_might_ be intentional, but usually is not.
-
-The approval tests compare current output of the SelfTest binary in various
-configurations against known good outputs. The reason it fails is,
-_usually_, that you've added new tests but have not yet approved the changes
-they introduce. This is done with the `scripts/approve.py` script, but
-before you do so, you need to check that the introduced changes are indeed
-intentional.
 
 
-## Documenting your code
+## Writing documentation
 
 If you have added new feature to Catch2, it needs documentation, so that
 other people can use it as well. This section collects some technical
 information that you will need for updating Catch2's documentation, and
 possibly some generic advise as well.
 
+### Technicalities 
+
 First, the technicalities:
 
-* We introduced version tags to the documentation, which show users in
-which version a specific feature was introduced. This means that newly
-written documentation should be tagged with a placeholder, that will
-be replaced with the actual version upon release. There are 2 styles
-of placeholders used through the documentation, you should pick one that
-fits your text better (if in doubt, take a look at the existing version
-tags for other features).
-  * `> [Introduced](link-to-issue-or-PR) in Catch X.Y.Z` - this
-  placeholder is usually used after a section heading
-  * `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
-  - this placeholder is used when you need to tag a subpart of something,
-  e.g. list
-* Crosslinks to different pages should target the `top` anchor, like this
-`[link to contributing](contributing.md#top)`.
 * If you have introduced a new document, there is a simple template you
-should use. It provides you with the top anchor mentioned above, and also
-with a backlink to the top of the documentation:
+should use. It provides you with the top anchor mentioned to link to
+(more below), and also with a backlink to the top of the documentation:
 ```markdown
 <a id="top"></a>
 # Cool feature
@@ -123,6 +125,23 @@ Text that explains how to use the cool feature.
 
 [Home](Readme.md#top)
 ```
+
+* Crosslinks to different pages should target the `top` anchor, like this
+`[link to contributing](contributing.md#top)`.
+
+* We introduced version tags to the documentation, which show users in
+which version a specific feature was introduced. This means that newly
+written documentation should be tagged with a placeholder, that will
+be replaced with the actual version upon release. There are 2 styles
+of placeholders used through the documentation, you should pick one that
+fits your text better (if in doubt, take a look at the existing version
+tags for other features).
+  * `> [Introduced](link-to-issue-or-PR) in Catch X.Y.Z` - this
+  placeholder is usually used after a section heading
+  * `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
+  - this placeholder is used when you need to tag a subpart of something,
+  e.g. a list
+
 * For pages with more than 4 subheadings, we provide a table of contents
 (ToC) at the top of the page. Because GitHub markdown does not support
 automatic generation of ToC, it has to be handled semi-manually. Thus,
@@ -130,21 +149,54 @@ if you've added a new subheading to some page, you should add it to the
 ToC. This can be done either manually, or by running the
 `updateDocumentToC.py` script in the `scripts/` folder.
 
+### Contents
+
+Now, for some content tips:
+
+* Usage examples are good. However, having large code snippets inline
+can make the documentation less readable, and so the inline snippets
+should be kept reasonably short. To provide more complex compilable
+examples, consider adding new .cpp file to `examples/`.
+
+* Don't be afraid to introduce new pages. The current documentation
+tends towards long pages, but a lot of that is caused by legacy, and
+we know that some of the pages are overly big and unfocused.
+
+* When adding information to an existing page, please try to keep your
+formatting, style and changes consistent with the rest of the page.
+
+* Any documentation has multiple different audiences, that desire
+different information from the text. The 3 basic user-types to try and
+cover are:
+  * A beginner to Catch2, who requires closer guidance for the usage of Catch2.
+  * Advanced user of Catch2, who want to customize their usage.
+  * Experts, looking for full reference of Catch2's capabilities.
 
-Now, for the generic tips:
-  * Usage examples are good
-  * Don't be afraid to introduce new pages
-  * Try to be reasonably consistent with the surrounding documentation
 
+## Writing code
 
+If want to contribute code, this section contains some simple rules
+and tips on things like code formatting, code constructions to avoid,
+and so on.
 
 
-## Code constructs to watch out for
+### Formatting
+
+To make code formatting simpler for the contributors, Catch2 provides
+its own config for `clang-format`. However, because it is currently
+impossible to replicate existing Catch2's formatting in clang-format,
+using it to reformat a whole file would cause massive diffs. To keep
+the size of your diffs reasonable, you should only use clang-format
+on the newly changed code.
+
+
+### Code constructs to watch out for
 
 This section is a (sadly incomplete) listing of various constructs that
 are problematic and are not always caught by our CI infrastructure.
 
-### Naked exceptions and exceptions-related function
+
+#### Naked exceptions and exceptions-related function
 
 If you are throwing an exception, it should be done via `CATCH_ERROR`
 or `CATCH_RUNTIME_ERROR` in `catch_enforce.h`. These macros will handle
@@ -155,7 +207,8 @@ CI, but luckily there should not be too many reasons to use these.
 However, if you do, they should be kept behind a
 `CATCH_CONFIG_DISABLE_EXCEPTIONS` macro.
 
-### Unqualified usage of functions from C's stdlib
+
+#### Unqualified usage of functions from C's stdlib
 
 If you are using a function from C's stdlib, please include the header
 as `<cfoo>` and call the function qualified. The common knowledge that
@@ -163,7 +216,12 @@ there is no difference is wrong, QNX and VxWorks won't compile if you
 include the header as `<cfoo>` and call the function unqualified.
 
 
-----
+## CoC
+
+This project has a [CoC](../CODE_OF_CONDUCT.md). Please adhere to it
+while contributing to Catch2.
+
+-----------
 
 _This documentation will always be in-progress as new information comes
 up, but we are trying to keep it as up to date as possible._
diff --git a/packages/Catch2/docs/generators.md b/packages/Catch2/docs/generators.md
index 55ff0ba541dfc0665e21b1726754d10e4f7904dd..96e322e6d0b846ac0ae9655c1d4a2c81e2b9107f 100644
--- a/packages/Catch2/docs/generators.md
+++ b/packages/Catch2/docs/generators.md
@@ -12,23 +12,88 @@ are run once per each value in a generator.
 This is best explained with an example:
 ```cpp
 TEST_CASE("Generators") {
-    auto i = GENERATE(1, 2, 3);
-    SECTION("one") {
-        auto j = GENERATE( -3, -2, -1 );
-        REQUIRE(j < i);
-    }
+    auto i = GENERATE(1, 3, 5);
+    REQUIRE(is_odd(i));
 }
 ```
 
-The assertion in this test case will be run 9 times, because there
-are 3 possible values for `i` (1, 2, and 3) and there are 3 possible
-values for `j` (-3, -2, and -1).
+The "Generators" `TEST_CASE` will be entered 3 times, and the value of
+`i` will be 1, 3, and 5 in turn. `GENERATE`s can also be used multiple
+times at the same scope, in which case the result will be a cartesian
+product of all elements in the generators. This means that in the snippet
+below, the test case will be run 6 (2\*3) times.
 
+```cpp
+TEST_CASE("Generators") {
+    auto i = GENERATE(1, 2);
+    auto j = GENERATE(3, 4, 5);
+}
+```
 
 There are 2 parts to generators in Catch2, the `GENERATE` macro together
 with the already provided generators, and the `IGenerator<T>` interface
 that allows users to implement their own generators.
 
+
+## Combining `GENERATE` and `SECTION`.
+
+`GENERATE` can be seen as an implicit `SECTION`, that goes from the place
+`GENERATE` is used, to the end of the scope. This can be used for various
+effects. The simplest usage is shown below, where the `SECTION` "one"
+runs 4 (2\*2) times, and `SECTION` "two" is run 6 times (2\*3).
+
+```
+TEST_CASE("Generators") {
+    auto i = GENERATE(1, 2);
+    SECTION("one") {
+        auto j = GENERATE(-3, -2);
+        REQUIRE(j < i);
+    }
+    SECTION("two") {
+        auto k = GENERATE(4, 5, 6);
+        REQUIRE(j != k);
+    }
+}
+```
+
+The specific order of the `SECTION`s will be "one", "one", "two", "two",
+"two", "one"...
+
+
+The fact that `GENERATE` introduces a virtual `SECTION` can also be used
+to make a generator replay only some `SECTION`s, without having to
+explicitly add a `SECTION`. As an example, the code below reports 3
+assertions, because the "first" section is run once, but the "second"
+section is run twice.
+
+```cpp
+TEST_CASE("GENERATE between SECTIONs") {
+    SECTION("first") { REQUIRE(true); }
+    auto _ = GENERATE(1, 2);
+    SECTION("second") { REQUIRE(true); }
+}
+```
+
+This can lead to surprisingly complex test flows. As an example, the test
+below will report 14 assertions:
+
+```cpp
+TEST_CASE("Complex mix of sections and generates") {
+    auto i = GENERATE(1, 2);
+    SECTION("A") {
+        SUCCEED("A");
+    }
+    auto j = GENERATE(3, 4);
+    SECTION("B") {
+        SUCCEED("B");
+    }
+    auto k = GENERATE(5, 6);
+    SUCCEED();
+}
+```
+
+> The ability to place `GENERATE` between two `SECTION`s was [introduced](https://github.com/catchorg/Catch2/issues/1938) in Catch 2.13.0.
+
 ## Provided generators
 
 Catch2's provided generator functionality consists of three parts,
diff --git a/packages/Catch2/docs/list-of-examples.md b/packages/Catch2/docs/list-of-examples.md
index 95e7bda0ce206f7a21583d61aab43de328cbd2a7..c3514ed5b51702dc43a4bdb146ac40e891aec02b 100644
--- a/packages/Catch2/docs/list-of-examples.md
+++ b/packages/Catch2/docs/list-of-examples.md
@@ -16,6 +16,7 @@
 - Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
 - Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
 - Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
+- Generators: [Run test with a table of input values](../examples/302-Gen-Table.cpp)
 - Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
 - Generators: [Use custom variable capture in generator expressions](../examples/311-Gen-CustomCapture.cpp)
 
diff --git a/packages/Catch2/docs/own-main.md b/packages/Catch2/docs/own-main.md
index 6a9b1aadc7ab31ff3923adbf3ef3daf14d05bdb7..06ea243dab14025034ece1b045cc3c17f48bed46 100644
--- a/packages/Catch2/docs/own-main.md
+++ b/packages/Catch2/docs/own-main.md
@@ -11,9 +11,9 @@ The easiest way to use Catch is to let it supply ```main()``` for you and handle
 
 This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
 
-Sometimes, though, you need to write your own version of main(). You can do this by writing ```#define CATCH_CONFIG_RUNNER``` instead. Now you are free to write ```main()``` as normal and call into Catch yourself manually.
+Sometimes, though, you need to write your own version of main(). You can do this by writing ```#define CATCH_CONFIG_RUNNER``` instead. Now you are free to write ```main()``` as normal and call into Catch yourself manually. You now have a lot of flexibility - but here are three recipes to get your started:
 
-You now have a lot of flexibility - but here are three recipes to get your started:
+**Important note: you can only provide `main` in the same file you defined `CATCH_CONFIG_RUNNER`.**
 
 ## Let Catch take full control of args and config
 
diff --git a/packages/Catch2/docs/release-notes.md b/packages/Catch2/docs/release-notes.md
index b6975b64caae477a2131d22d1ad6f03541d5c3c1..33e3d2558f56a0f7857077f0e8970879a9404145 100644
--- a/packages/Catch2/docs/release-notes.md
+++ b/packages/Catch2/docs/release-notes.md
@@ -2,6 +2,12 @@
 
 # Release notes
 **Contents**<br>
+[2.13.0](#2130)<br>
+[2.12.4](#2124)<br>
+[2.12.3](#2123)<br>
+[2.12.2](#2122)<br>
+[2.12.1](#2121)<br>
+[2.12.0](#2120)<br>
 [2.11.3](#2113)<br>
 [2.11.2](#2112)<br>
 [2.11.1](#2111)<br>
@@ -34,6 +40,89 @@
 [Older versions](#older-versions)<br>
 [Even Older versions](#even-older-versions)<br>
 
+## 2.13.0
+
+### Improvements
+* `GENERATE` can now follow a `SECTION` at the same level of nesting (#1938)
+  * The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will.
+* Added `-D`/`--min-duration` command line flag (#1910)
+  * If a test takes longer to finish than the provided value, its name and duration will be printed.
+  * This flag is overriden by setting `-d`/`--duration`.
+
+### Fixes
+* `TAPReporter` no longer skips successful assertions (#1983)
+
+
+## 2.12.4
+
+### Improvements
+* Added support for MacOS on ARM (#1971)
+
+
+## 2.12.3
+
+### Fixes
+* `GENERATE` nested in a for loop no longer creates multiple generators (#1913)
+* Fixed copy paste error breaking `TEMPLATE_TEST_CASE_SIG` for 6 or more arguments (#1954)
+* Fixed potential UB when handling non-ASCII characters in CLI args (#1943)
+
+### Improvements
+* There can be multiple calls to `GENERATE` on a single line
+* Improved `fno-except` support for platforms that do not provide shims for exception-related std functions (#1950)
+  * E.g. the Green Hills C++ compiler
+* XmlReporter now also reports test-case-level statistics (#1958)
+  * This is done via a new element, `OverallResultsCases`
+
+### Miscellaneous
+* Added `.clang-format` file to the repo (#1182, #1920)
+* Rewrote contributing docs
+  * They should explain the different levels of testing and so on much better
+
+
+## 2.12.2
+
+### Fixes
+* Fixed compilation failure if `is_range` ADL found deleted function (#1929)
+* Fixed potential UB in `CAPTURE` if the expression contained non-ASCII characters (#1925)
+
+### Improvements
+* `std::result_of` is not used if `std::invoke_result` is available (#1934)
+* JUnit reporter writes out `status` attribute for tests (#1899)
+* Suppresed clang-tidy's `hicpp-vararg` warning (#1921)
+  * Catch2 was already suppressing the `cppcoreguidelines-pro-type-vararg` alias of the warning
+
+
+## 2.12.1
+
+### Fixes
+* Vector matchers now support initializer list literals better
+
+### Improvements
+* Added support for `^` (bitwise xor) to `CHECK` and `REQUIRE`
+
+
+## 2.12.0
+
+### Improvements
+* Running tests in random order (`--order rand`) has been reworked significantly (#1908)
+  * Given same seed, all platforms now produce the same order
+  * Given same seed, the relative order of tests does not change if you select only a subset of them
+* Vector matchers support custom allocators (#1909)
+* `|` and `&` (bitwise or and bitwise and) are now supported in `CHECK` and `REQUIRE`
+  * The resulting type must be convertible to `bool`
+
+### Fixes
+* Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886)
+* Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901)
+  * It was a false positive trigered by the new warning support workaround
+* Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905)
+
+### Miscellaneous
+* Worked around IBM XL's codegen bug (#1907)
+  * It would emit code for _destructors_ of temporaries in an unevaluated context
+* Improved detection of stdlib's support for `std::uncaught_exceptions` (#1911)
+
+
 ## 2.11.3
 
 ### Fixes
diff --git a/packages/Catch2/examples/301-Gen-MapTypeConversion.cpp b/packages/Catch2/examples/301-Gen-MapTypeConversion.cpp
index 88772971444e0cdb520139aeef16c224b16bddad..54eab571e2ba95db1bc9461e2df4b4e3bcd7e9c6 100644
--- a/packages/Catch2/examples/301-Gen-MapTypeConversion.cpp
+++ b/packages/Catch2/examples/301-Gen-MapTypeConversion.cpp
@@ -1,7 +1,9 @@
 // 301-Gen-MapTypeConversion.cpp
 // Shows how to use map to modify generator's return type.
 
-// TODO
+// Specifically we wrap a std::string returning generator with a generator
+// that converts the strings using stoi, so the returned type is actually
+// an int.
 
 #include <catch2/catch.hpp>
 
diff --git a/packages/Catch2/examples/302-Gen-Table.cpp b/packages/Catch2/examples/302-Gen-Table.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fe226dc12bd62c7d45ff459260b7d0dc3d6e5a3e
--- /dev/null
+++ b/packages/Catch2/examples/302-Gen-Table.cpp
@@ -0,0 +1,54 @@
+// 302-Gen-Table.cpp
+// Shows how to use table to run a test many times with different inputs. Lifted from examples on
+// issue #850.
+
+#include <catch2/catch.hpp>
+#include <string>
+
+struct TestSubject {
+    // this is the method we are going to test. It returns the length of the
+    // input string.
+    size_t GetLength( const std::string& input ) const { return input.size(); }
+};
+
+
+TEST_CASE("Table allows pre-computed test inputs and outputs", "[example][generator]") {
+    using std::make_tuple;
+    // do setup here as normal
+    TestSubject subj;
+
+    SECTION("This section is run for each row in the table") {
+        std::string test_input;
+        size_t expected_output;
+        std::tie( test_input, expected_output ) =
+            GENERATE( table<std::string, size_t>(
+                { /* In this case one of the parameters to our test case is the
+                   * expected output, but this is not required. There could be
+                   * multiple expected values in the table, which can have any
+                   * (fixed) number of columns.
+                   */
+                  make_tuple( "one", 3 ),
+                  make_tuple( "two", 3 ),
+                  make_tuple( "three", 5 ),
+                  make_tuple( "four", 4 ) } ) );
+
+        // run the test
+        auto result = subj.GetLength(test_input);
+        // capture the input data to go with the outputs.
+        CAPTURE(test_input);
+        // check it matches the pre-calculated data
+        REQUIRE(result == expected_output);
+    }   // end section
+}
+
+/* Possible simplifications where less legacy toolchain support is needed:
+ *
+ * - With libstdc++6 or newer, the make_tuple() calls can be ommitted
+ * (technically C++17 but does not require -std in GCC/Clang). See
+ *   https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
+ *
+ * - In C++17 mode std::tie() and the preceeding variable delcarations can be
+ * replaced by structured bindings: auto [test_input, expected] = GENERATE(
+ * table<std::string, size_t>({ ...
+ */
+// Compiling and running this file will result in 4 successful assertions
diff --git a/packages/Catch2/examples/311-Gen-CustomCapture.cpp b/packages/Catch2/examples/311-Gen-CustomCapture.cpp
index da6d686f95c69a8ea30223927b3e493dfc06185b..970512c2cf96b519cf8ce85c663aa2511717e8ea 100644
--- a/packages/Catch2/examples/311-Gen-CustomCapture.cpp
+++ b/packages/Catch2/examples/311-Gen-CustomCapture.cpp
@@ -23,11 +23,11 @@ TEST_CASE("Generate random doubles across different ranges",
     }));
 
     auto r2(r1);
-    
+
     // This will take r1 by reference and r2 by value.
     // Note that there are no advantages for doing so in this example,
     // it is done only for expository purposes.
-    auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
+    auto number = Catch::Generators::generate( "custom capture generator", CATCH_INTERNAL_LINEINFO,
         [&r1, r2]{
             using namespace Catch::Generators;
             return makeGenerators(take(50, random(std::get<0>(r1), std::get<1>(r2))));
diff --git a/packages/Catch2/examples/CMakeLists.txt b/packages/Catch2/examples/CMakeLists.txt
index 65dc5f54ace8426fef8aebd2097a6417eec0524b..d9842486e7bb3130567228e003d748214eef7300 100644
--- a/packages/Catch2/examples/CMakeLists.txt
+++ b/packages/Catch2/examples/CMakeLists.txt
@@ -46,6 +46,7 @@ set( SOURCES_IDIOMATIC_TESTS
     210-Evt-EventListeners.cpp
     300-Gen-OwnGenerator.cpp
     301-Gen-MapTypeConversion.cpp
+    302-Gen-Table.cpp
     310-Gen-VariablesInGenerators.cpp
     311-Gen-CustomCapture.cpp
 )
diff --git a/packages/Catch2/include/catch.hpp b/packages/Catch2/include/catch.hpp
index d0404a86ffbba9cf179ee5e55c123cdebcc000d5..18509248b4c14ca355f2224bceee7f951ce8c9b4 100644
--- a/packages/Catch2/include/catch.hpp
+++ b/packages/Catch2/include/catch.hpp
@@ -10,8 +10,8 @@
 #define TWOBLUECUBES_CATCH_HPP_INCLUDED
 
 #define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 11
-#define CATCH_VERSION_PATCH 3
+#define CATCH_VERSION_MINOR 13
+#define CATCH_VERSION_PATCH 0
 
 #ifdef __clang__
 #    pragma clang system_header
diff --git a/packages/Catch2/include/external/clara.hpp b/packages/Catch2/include/external/clara.hpp
index c7348bf95bb4e3108de759ff52ea185b2cb71650..a0836487d226ae830cf29ce4ddf20bb7e26d4466 100644
--- a/packages/Catch2/include/external/clara.hpp
+++ b/packages/Catch2/include/external/clara.hpp
@@ -667,7 +667,7 @@ namespace detail {
     }
     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
         std::string srcLC = source;
-        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
         if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
             target = true;
         else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
diff --git a/packages/Catch2/include/internal/benchmark/detail/catch_complete_invoke.hpp b/packages/Catch2/include/internal/benchmark/detail/catch_complete_invoke.hpp
index abeb2ac71d6e6e76368f792ec67a4ccae5832f14..f6a083d486f1943b418cf99d980430b819229da5 100644
--- a/packages/Catch2/include/internal/benchmark/detail/catch_complete_invoke.hpp
+++ b/packages/Catch2/include/internal/benchmark/detail/catch_complete_invoke.hpp
@@ -12,6 +12,7 @@
 #define TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
 
 #include "../../catch_enforce.h"
+#include "../../catch_meta.hpp"
 
 #include <type_traits>
 #include <utility>
@@ -42,20 +43,18 @@ namespace Catch {
                     return {};
                 }
             };
-            template <typename Sig>
-            using ResultOf_t = typename std::result_of<Sig>::type;
 
             // invoke and not return void :(
             template <typename Fun, typename... Args>
-            CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
-                return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+            CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
+                return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
             }
 
             const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
         } // namespace Detail
 
         template <typename Fun>
-        Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
+        Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
             CATCH_TRY{
                 return Detail::complete_invoke(std::forward<Fun>(fun));
             } CATCH_CATCH_ALL{
diff --git a/packages/Catch2/include/internal/benchmark/detail/catch_measure.hpp b/packages/Catch2/include/internal/benchmark/detail/catch_measure.hpp
index 62ed2809633264ea2a6e449a88a46eb78294f5f8..c3bd35fab32fdeaa6ac00b0515f81b5f23304884 100644
--- a/packages/Catch2/include/internal/benchmark/detail/catch_measure.hpp
+++ b/packages/Catch2/include/internal/benchmark/detail/catch_measure.hpp
@@ -21,7 +21,7 @@ namespace Catch {
     namespace Benchmark {
         namespace Detail {
             template <typename Clock, typename Fun, typename... Args>
-            TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
+            TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
                 auto start = Clock::now();
                 auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
                 auto end = Clock::now();
diff --git a/packages/Catch2/include/internal/benchmark/detail/catch_run_for_at_least.hpp b/packages/Catch2/include/internal/benchmark/detail/catch_run_for_at_least.hpp
index a41c6b4611546b0d4d2f4e74fd5814210f800428..339507bac74703652fd4893a419ff9cea1064831 100644
--- a/packages/Catch2/include/internal/benchmark/detail/catch_run_for_at_least.hpp
+++ b/packages/Catch2/include/internal/benchmark/detail/catch_run_for_at_least.hpp
@@ -25,11 +25,11 @@ namespace Catch {
     namespace Benchmark {
         namespace Detail {
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
+            TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
                 return Detail::measure<Clock>(fun, iters);
             }
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
+            TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
                 Detail::ChronometerModel<Clock> meter;
                 auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
 
@@ -46,7 +46,7 @@ namespace Catch {
             };
 
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+            TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
                 auto iters = seed;
                 while (iters < (1 << 30)) {
                     auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
diff --git a/packages/Catch2/include/internal/benchmark/detail/catch_timing.hpp b/packages/Catch2/include/internal/benchmark/detail/catch_timing.hpp
index 073cb74274bf9765d70e29bde279a3a6955d4964..fc24886a08c19a726f860e7f7e647d4fa4ca6895 100644
--- a/packages/Catch2/include/internal/benchmark/detail/catch_timing.hpp
+++ b/packages/Catch2/include/internal/benchmark/detail/catch_timing.hpp
@@ -25,8 +25,8 @@ namespace Catch {
             Result result;
             int iterations;
         };
-        template <typename Clock, typename Sig>
-        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
+        template <typename Clock, typename Func, typename... Args>
+        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
     } // namespace Benchmark
 } // namespace Catch
 
diff --git a/packages/Catch2/include/internal/catch_assertionhandler.cpp b/packages/Catch2/include/internal/catch_assertionhandler.cpp
index 77c3f1d4748db6aa4ad3c388f0c4203639923674..fd14c85a2fbf998c41f9087e884c8df3ebb7e498 100644
--- a/packages/Catch2/include/internal/catch_assertionhandler.cpp
+++ b/packages/Catch2/include/internal/catch_assertionhandler.cpp
@@ -15,6 +15,7 @@
 #include "catch_interfaces_registry_hub.h"
 #include "catch_capture_matchers.h"
 #include "catch_run_context.h"
+#include "catch_enforce.h"
 
 namespace Catch {
 
diff --git a/packages/Catch2/include/internal/catch_commandline.cpp b/packages/Catch2/include/internal/catch_commandline.cpp
index a4010850d0cf7bf914dabfe362ea3ade2f8442f5..673d3b70bc70d6452b8f94bb0d1fe7439d04c02b 100644
--- a/packages/Catch2/include/internal/catch_commandline.cpp
+++ b/packages/Catch2/include/internal/catch_commandline.cpp
@@ -170,6 +170,9 @@ namespace Catch {
             | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
                 ["-d"]["--durations"]
                 ( "show test durations" )
+            | Opt( config.minDuration, "seconds" )
+                ["-D"]["--min-duration"]
+                ( "show test durations for tests taking at least the given number of seconds" )
             | Opt( loadTestNamesFromFile, "filename" )
                 ["-f"]["--input-file"]
                 ( "load test names to run from a file" )
diff --git a/packages/Catch2/include/internal/catch_compiler_capabilities.h b/packages/Catch2/include/internal/catch_compiler_capabilities.h
index 26351c7acbfdcc7a664668080a656aa6c393fe14..52b41aae672376f2ac77caf409b229709658f4f6 100644
--- a/packages/Catch2/include/internal/catch_compiler_capabilities.h
+++ b/packages/Catch2/include/internal/catch_compiler_capabilities.h
@@ -70,7 +70,7 @@
 //
 // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
 #  if !defined(__ibmxl__)
-#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */
+#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
 #  endif
 
 
@@ -240,7 +240,10 @@
 
   // Check if byte is available and usable
   #  if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
-  #    define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+  #    include <cstddef>
+  #    if __cpp_lib_byte > 0
+  #      define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+  #    endif
   #  endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
 
   // Check if variant is available and usable
diff --git a/packages/Catch2/include/internal/catch_config.cpp b/packages/Catch2/include/internal/catch_config.cpp
index 21cd62965ba214fd7b6ed0aa2290c8d0d9b5e29e..252bec62ef1c03b1bda59097f2be931f6f91271d 100644
--- a/packages/Catch2/include/internal/catch_config.cpp
+++ b/packages/Catch2/include/internal/catch_config.cpp
@@ -64,6 +64,7 @@ namespace Catch {
     bool Config::warnAboutMissingAssertions() const    { return !!(m_data.warnings & WarnAbout::NoAssertions); }
     bool Config::warnAboutNoTests() const              { return !!(m_data.warnings & WarnAbout::NoTests); }
     ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+    double Config::minDuration() const                 { return m_data.minDuration; }
     RunTests::InWhatOrder Config::runOrder() const     { return m_data.runOrder; }
     unsigned int Config::rngSeed() const               { return m_data.rngSeed; }
     UseColour::YesOrNo Config::useColour() const       { return m_data.useColour; }
diff --git a/packages/Catch2/include/internal/catch_config.hpp b/packages/Catch2/include/internal/catch_config.hpp
index 64d2c035f9bb80e18fe3bffb8b558ffff9fa3b2c..fd7de5b2d44c9543dc2b39d7728dbf3b1587f162 100644
--- a/packages/Catch2/include/internal/catch_config.hpp
+++ b/packages/Catch2/include/internal/catch_config.hpp
@@ -52,6 +52,7 @@ namespace Catch {
         Verbosity verbosity = Verbosity::Normal;
         WarnAbout::What warnings = WarnAbout::Nothing;
         ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+        double minDuration = -1;
         RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
         UseColour::YesOrNo useColour = UseColour::Auto;
         WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
@@ -103,6 +104,7 @@ namespace Catch {
         bool warnAboutMissingAssertions() const override;
         bool warnAboutNoTests() const override;
         ShowDurations::OrNot showDurations() const override;
+        double minDuration() const override;
         RunTests::InWhatOrder runOrder() const override;
         unsigned int rngSeed() const override;
         UseColour::YesOrNo useColour() const override;
diff --git a/packages/Catch2/include/internal/catch_debugger.h b/packages/Catch2/include/internal/catch_debugger.h
index 77db8aed2fb86c842fa49fa3d446c4201a89c1c8..a0148aa88fa442ecd973dcf0b0d8cd523000ef96 100644
--- a/packages/Catch2/include/internal/catch_debugger.h
+++ b/packages/Catch2/include/internal/catch_debugger.h
@@ -17,7 +17,11 @@ namespace Catch {
 
 #ifdef CATCH_PLATFORM_MAC
 
-    #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+    #if defined(__i386__) || defined(__x86_64__)
+        #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+    #elif defined(__aarch64__)
+        #define CATCH_TRAP()  __asm__(".inst 0xd4200000")
+    #endif
 
 #elif defined(CATCH_PLATFORM_IPHONE)
 
diff --git a/packages/Catch2/include/internal/catch_decomposer.h b/packages/Catch2/include/internal/catch_decomposer.h
index 08075f0e9ef4c7ef442d5948b30ea603dcae234e..9320c4ddf8bebd0b81444bbe1a205324115680ec 100644
--- a/packages/Catch2/include/internal/catch_decomposer.h
+++ b/packages/Catch2/include/internal/catch_decomposer.h
@@ -200,6 +200,18 @@ namespace Catch {
         auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
             return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
         }
+        template <typename RhsT>
+        auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
+        }
+        template <typename RhsT>
+        auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
+        }
+        template <typename RhsT>
+        auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
+        }
 
         template<typename RhsT>
         auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
diff --git a/packages/Catch2/include/internal/catch_generators.cpp b/packages/Catch2/include/internal/catch_generators.cpp
index 5fbe2d2384fc368657b070af9fda16c9e9a685b8..c6d60a70add2883dc2d8666bbc0b2b263986e78c 100644
--- a/packages/Catch2/include/internal/catch_generators.cpp
+++ b/packages/Catch2/include/internal/catch_generators.cpp
@@ -24,8 +24,8 @@ namespace Generators {
 
     GeneratorUntypedBase::~GeneratorUntypedBase() {}
 
-    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
-        return getResultCapture().acquireGeneratorTracker( lineInfo );
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
     }
 
 } // namespace Generators
diff --git a/packages/Catch2/include/internal/catch_generators.hpp b/packages/Catch2/include/internal/catch_generators.hpp
index d0fbe8bf316a829ddd3f6e27b6225f81c032e1c1..e253ea096679a7af14c05452963e677ee728d699 100644
--- a/packages/Catch2/include/internal/catch_generators.hpp
+++ b/packages/Catch2/include/internal/catch_generators.hpp
@@ -10,6 +10,7 @@
 #include "catch_interfaces_generatortracker.h"
 #include "catch_common.h"
 #include "catch_enforce.h"
+#include "catch_stringref.h"
 
 #include <memory>
 #include <vector>
@@ -181,16 +182,16 @@ namespace Generators {
         return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
     }
 
-    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
 
     template<typename L>
     // Note: The type after -> is weird, because VS2015 cannot parse
     //       the expression used in the typedef inside, when it is in
     //       return type. Yeah.
-    auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+    auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
         using UnderlyingType = typename decltype(generatorExpression())::type;
 
-        IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
+        IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
         if (!tracker.hasGenerator()) {
             tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
         }
@@ -203,10 +204,16 @@ namespace Generators {
 } // namespace Catch
 
 #define GENERATE( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 #define GENERATE_COPY( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 #define GENERATE_REF( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 
 #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
diff --git a/packages/Catch2/include/internal/catch_interfaces_capture.h b/packages/Catch2/include/internal/catch_interfaces_capture.h
index 8c25c8cf7659e9ccf326a452412b1728158aba24..ccca73de303f8a3cd6f30ed10307fe927874be08 100644
--- a/packages/Catch2/include/internal/catch_interfaces_capture.h
+++ b/packages/Catch2/include/internal/catch_interfaces_capture.h
@@ -44,7 +44,7 @@ namespace Catch {
         virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
         virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
 
-        virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+        virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
         virtual void benchmarkPreparing( std::string const& name ) = 0;
diff --git a/packages/Catch2/include/internal/catch_interfaces_config.h b/packages/Catch2/include/internal/catch_interfaces_config.h
index 8fb986be467911c037231a5f92e8f1d0d7f16378..e9c2cf9662037731adc873ac41caa316c17a5917 100644
--- a/packages/Catch2/include/internal/catch_interfaces_config.h
+++ b/packages/Catch2/include/internal/catch_interfaces_config.h
@@ -69,6 +69,7 @@ namespace Catch {
         virtual int abortAfter() const = 0;
         virtual bool showInvisibles() const = 0;
         virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual double minDuration() const = 0;
         virtual TestSpec const& testSpec() const = 0;
         virtual bool hasTestFilters() const = 0;
         virtual std::vector<std::string> const& getTestsOrTags() const = 0;
diff --git a/packages/Catch2/include/internal/catch_interfaces_exception.h b/packages/Catch2/include/internal/catch_interfaces_exception.h
index d3254d5f244cda720125d823589556f80c404c91..43840ea090577cd351d539192c733e1e085af65b 100644
--- a/packages/Catch2/include/internal/catch_interfaces_exception.h
+++ b/packages/Catch2/include/internal/catch_interfaces_exception.h
@@ -46,6 +46,9 @@ namespace Catch {
             {}
 
             std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+                return "";
+#else
                 try {
                     if( it == itEnd )
                         std::rethrow_exception(std::current_exception());
@@ -55,6 +58,7 @@ namespace Catch {
                 catch( T& ex ) {
                     return m_translateFunction( ex );
                 }
+#endif
             }
 
         protected:
diff --git a/packages/Catch2/include/internal/catch_matchers_vector.h b/packages/Catch2/include/internal/catch_matchers_vector.h
index 084130f5227d768f49417790c0db44e353927d99..bbe7c784752624cacd846262f124c1e903d96bc2 100644
--- a/packages/Catch2/include/internal/catch_matchers_vector.h
+++ b/packages/Catch2/include/internal/catch_matchers_vector.h
@@ -131,8 +131,6 @@ namespace Matchers {
         struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
             UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
             bool match(std::vector<T, AllocMatch> const& vec) const override {
-                // Note: This is a reimplementation of std::is_permutation,
-                //       because I don't want to include <algorithm> inside the common path
                 if (m_target.size() != vec.size()) {
                     return false;
                 }
@@ -151,7 +149,7 @@ namespace Matchers {
     // The following functions create the actual matcher objects.
     // This allows the types to be inferred
 
-    template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
     Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
         return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
     }
@@ -161,17 +159,17 @@ namespace Matchers {
         return Vector::ContainsElementMatcher<T, Alloc>( comparator );
     }
 
-    template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
     Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
         return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
     }
 
-    template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
     Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
         return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
     }
 
-    template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
     Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
         return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
     }
diff --git a/packages/Catch2/include/internal/catch_message.cpp b/packages/Catch2/include/internal/catch_message.cpp
index 64c817b7005c86fafdc59cc7168f0d5bfa3b15f6..97983a1e8e6d1c179041b86f35050d411d2ed9d4 100644
--- a/packages/Catch2/include/internal/catch_message.cpp
+++ b/packages/Catch2/include/internal/catch_message.cpp
@@ -69,10 +69,10 @@ namespace Catch {
 
     Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
         auto trimmed = [&] (size_t start, size_t end) {
-            while (names[start] == ',' || isspace(names[start])) {
+            while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
                 ++start;
             }
-            while (names[end] == ',' || isspace(names[end])) {
+            while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
                 --end;
             }
             return names.substr(start, end - start + 1);
diff --git a/packages/Catch2/include/internal/catch_meta.hpp b/packages/Catch2/include/internal/catch_meta.hpp
index 4eca7efc2043079d773477c15bfb52b2f2666262..b54cecc20ad7e30ad0e3476342567ea628716ba1 100644
--- a/packages/Catch2/include/internal/catch_meta.hpp
+++ b/packages/Catch2/include/internal/catch_meta.hpp
@@ -32,13 +32,13 @@ namespace Catch {
 
 #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
     // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
-    // replaced with std::invoke_result here. Also *_t format is preferred over
-    // typename *::type format.
-    template <typename Func, typename U>
-    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
+    // replaced with std::invoke_result here.
+    template <typename Func, typename... U>
+    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
 #else
-    template <typename Func, typename U>
-    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
+    // Keep ::type here because we still support C++11
+    template <typename Func, typename... U>
+    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;
 #endif
 
 } // namespace Catch
diff --git a/packages/Catch2/include/internal/catch_preprocessor.hpp b/packages/Catch2/include/internal/catch_preprocessor.hpp
index f1bd0905b05b3911ac94111c899600ac0e62e578..928384eb9915e41df35f39f618f77b0eaccfecf1 100644
--- a/packages/Catch2/include/internal/catch_preprocessor.hpp
+++ b/packages/Catch2/include/internal/catch_preprocessor.hpp
@@ -1,3 +1,4 @@
+
 /*
  *  Created by Jozef on 12/11/2018.
  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
@@ -90,7 +91,7 @@
 #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
 #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
 #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
-#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
 #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
 #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
 #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
diff --git a/packages/Catch2/include/internal/catch_registry_hub.cpp b/packages/Catch2/include/internal/catch_registry_hub.cpp
index 8a3c7a9793843a908ff155ad1064bc7afc9a679f..852b34e08f0ee31f118d2b53af92f39cf0d150a9 100644
--- a/packages/Catch2/include/internal/catch_registry_hub.cpp
+++ b/packages/Catch2/include/internal/catch_registry_hub.cpp
@@ -59,7 +59,11 @@ namespace Catch {
                 m_tagAliasRegistry.add( alias, tag, lineInfo );
             }
             void registerStartupException() noexcept override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
                 m_exceptionRegistry.add(std::current_exception());
+#else
+                CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+#endif
             }
             IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
                 return m_enumValuesRegistry;
diff --git a/packages/Catch2/include/internal/catch_run_context.cpp b/packages/Catch2/include/internal/catch_run_context.cpp
index 2eb84fb9afe0de0f97114bded95e2ddc6979a2db..c7a9f203f097172ce0a6c3a2231ece1be1d8879d 100644
--- a/packages/Catch2/include/internal/catch_run_context.cpp
+++ b/packages/Catch2/include/internal/catch_run_context.cpp
@@ -25,17 +25,32 @@ namespace Catch {
                 std::shared_ptr<GeneratorTracker> tracker;
 
                 ITracker& currentTracker = ctx.currentTracker();
-                if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                // Under specific circumstances, the generator we want
+                // to acquire is also the current tracker. If this is
+                // the case, we have to avoid looking through current
+                // tracker's children, and instead return the current
+                // tracker.
+                // A case where this check is important is e.g.
+                //     for (int i = 0; i < 5; ++i) {
+                //         int n = GENERATE(1, 2);
+                //     }
+                //
+                // without it, the code above creates 5 nested generators.
+                if (currentTracker.nameAndLocation() == nameAndLocation) {
+                    auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
+                    assert(thisTracker);
+                    assert(thisTracker->isGeneratorTracker());
+                    tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
+                } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
                     assert( childTracker );
                     assert( childTracker->isGeneratorTracker() );
                     tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
-                }
-                else {
+                } else {
                     tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
                     currentTracker.addChild( tracker );
                 }
 
-                if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                if( !tracker->isComplete() ) {
                     tracker->open();
                 }
 
@@ -49,8 +64,28 @@ namespace Catch {
             }
             void close() override {
                 TrackerBase::close();
-                // Generator interface only finds out if it has another item on atual move
-                if (m_runState == CompletedSuccessfully && m_generator->next()) {
+                // If a generator has a child (it is followed by a section)
+                // and none of its children have started, then we must wait
+                // until later to start consuming its values.
+                // This catches cases where `GENERATE` is placed between two
+                // `SECTION`s.
+                // **The check for m_children.empty cannot be removed**.
+                // doing so would break `GENERATE` _not_ followed by `SECTION`s.
+                const bool should_wait_for_child =
+                    !m_children.empty() &&
+                    std::find_if( m_children.begin(),
+                                  m_children.end(),
+                                  []( TestCaseTracking::ITrackerPtr tracker ) {
+                                      return tracker->hasStarted();
+                                  } ) == m_children.end();
+
+                // This check is a bit tricky, because m_generator->next()
+                // has a side-effect, where it consumes generator's current
+                // value, but we do not want to invoke the side-effect if
+                // this generator is still waiting for any child to start.
+                if ( should_wait_for_child ||
+                     ( m_runState == CompletedSuccessfully &&
+                       m_generator->next() ) ) {
                     m_children.clear();
                     m_runState = Executing;
                 }
@@ -187,10 +222,10 @@ namespace Catch {
 
         return true;
     }
-    auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+    auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
         using namespace Generators;
-        GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
-        assert( tracker.isOpen() );
+        GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
+                                                              TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
         m_lastAssertionInfo.lineInfo = lineInfo;
         return tracker;
     }
@@ -233,17 +268,17 @@ namespace Catch {
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
     void RunContext::benchmarkPreparing(std::string const& name) {
-		m_reporter->benchmarkPreparing(name);
-	}
+        m_reporter->benchmarkPreparing(name);
+    }
     void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
         m_reporter->benchmarkStarting( info );
     }
     void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
         m_reporter->benchmarkEnded( stats );
     }
-	void RunContext::benchmarkFailed(std::string const & error) {
-		m_reporter->benchmarkFailed(error);
-	}
+    void RunContext::benchmarkFailed(std::string const & error) {
+        m_reporter->benchmarkFailed(error);
+    }
 #endif // CATCH_CONFIG_ENABLE_BENCHMARKING
 
     void RunContext::pushScopedMessage(MessageInfo const & message) {
diff --git a/packages/Catch2/include/internal/catch_run_context.h b/packages/Catch2/include/internal/catch_run_context.h
index 2a8e72dca8773519c8df3376b5e9f0224d8d25c3..044bdd817574b3a2bbed47102458d0a031bacf10 100644
--- a/packages/Catch2/include/internal/catch_run_context.h
+++ b/packages/Catch2/include/internal/catch_run_context.h
@@ -80,7 +80,7 @@ namespace Catch {
         void sectionEnded( SectionEndInfo const& endInfo ) override;
         void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
 
-        auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+        auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
         void benchmarkPreparing( std::string const& name ) override;
diff --git a/packages/Catch2/include/internal/catch_startup_exception_registry.cpp b/packages/Catch2/include/internal/catch_startup_exception_registry.cpp
index 3c5bd22f5f8353fe725bef16c0748a9e1b8230ff..04e46170d57bc5734903b9244459dddddc57d980 100644
--- a/packages/Catch2/include/internal/catch_startup_exception_registry.cpp
+++ b/packages/Catch2/include/internal/catch_startup_exception_registry.cpp
@@ -9,6 +9,7 @@
 #include "catch_startup_exception_registry.h"
 #include "catch_compiler_capabilities.h"
 
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
 namespace Catch {
 void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
         CATCH_TRY {
@@ -24,3 +25,4 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce
     }
 
 } // end namespace Catch
+#endif
diff --git a/packages/Catch2/include/internal/catch_startup_exception_registry.h b/packages/Catch2/include/internal/catch_startup_exception_registry.h
index feb566019e2ba805814766b86cd41368de8ba848..366312adda16e0e5f0bb546e9457ed24be031215 100644
--- a/packages/Catch2/include/internal/catch_startup_exception_registry.h
+++ b/packages/Catch2/include/internal/catch_startup_exception_registry.h
@@ -15,11 +15,13 @@
 namespace Catch {
 
     class StartupExceptionRegistry {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
     public:
         void add(std::exception_ptr const& exception) noexcept;
         std::vector<std::exception_ptr> const& getExceptions() const noexcept;
     private:
         std::vector<std::exception_ptr> m_exceptions;
+#endif
     };
 
 } // end namespace Catch
diff --git a/packages/Catch2/include/internal/catch_string_manip.cpp b/packages/Catch2/include/internal/catch_string_manip.cpp
index 65be34d037c96907943659d87655b45b842cd807..accb3498e20c0a175057a6059e2080c649bc1dca 100644
--- a/packages/Catch2/include/internal/catch_string_manip.cpp
+++ b/packages/Catch2/include/internal/catch_string_manip.cpp
@@ -18,7 +18,7 @@ namespace Catch {
 
     namespace {
         char toLowerCh(char c) {
-            return static_cast<char>( std::tolower( c ) );
+            return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
         }
     }
 
diff --git a/packages/Catch2/include/internal/catch_test_case_tracker.cpp b/packages/Catch2/include/internal/catch_test_case_tracker.cpp
index 1fc820b13ec198da7e668cebdccd44a36fe75e4b..2541a3d17c1a04e81dcaee345b716796aacb972e 100644
--- a/packages/Catch2/include/internal/catch_test_case_tracker.cpp
+++ b/packages/Catch2/include/internal/catch_test_case_tracker.cpp
@@ -65,15 +65,12 @@ namespace TestCaseTracking {
     }
 
 
-    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
-    :   m_nameAndLocation( nameAndLocation ),
+    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
+        ITracker(nameAndLocation),
         m_ctx( ctx ),
         m_parent( parent )
     {}
 
-    NameAndLocation const& TrackerBase::nameAndLocation() const {
-        return m_nameAndLocation;
-    }
     bool TrackerBase::isComplete() const {
         return m_runState == CompletedSuccessfully || m_runState == Failed;
     }
@@ -190,7 +187,8 @@ namespace TestCaseTracking {
     bool SectionTracker::isComplete() const {
         bool complete = true;
 
-        if ((m_filters.empty() || m_filters[0] == "")
+        if (m_filters.empty()
+            || m_filters[0] == ""
             || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
             complete = TrackerBase::isComplete();
         }
diff --git a/packages/Catch2/include/internal/catch_test_case_tracker.h b/packages/Catch2/include/internal/catch_test_case_tracker.h
index 563dbef2c94b7ef9507b9c6f1bc77e99d1e98778..131e2ea04b53d179d03e9644f08b60bbbf14b9d1 100644
--- a/packages/Catch2/include/internal/catch_test_case_tracker.h
+++ b/packages/Catch2/include/internal/catch_test_case_tracker.h
@@ -23,23 +23,39 @@ namespace TestCaseTracking {
         SourceLineInfo location;
 
         NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+        friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
+            return lhs.name == rhs.name
+                && lhs.location == rhs.location;
+        }
     };
 
-    struct ITracker;
+    class ITracker;
 
     using ITrackerPtr = std::shared_ptr<ITracker>;
 
-    struct ITracker {
-        virtual ~ITracker();
+    class  ITracker {
+        NameAndLocation m_nameAndLocation;
+
+    public:
+        ITracker(NameAndLocation const& nameAndLoc) :
+            m_nameAndLocation(nameAndLoc)
+        {}
+
 
         // static queries
-        virtual NameAndLocation const& nameAndLocation() const = 0;
+        NameAndLocation const& nameAndLocation() const {
+            return m_nameAndLocation;
+        }
+
+        virtual ~ITracker();
+
 
         // dynamic queries
         virtual bool isComplete() const = 0; // Successfully completed or failed
         virtual bool isSuccessfullyCompleted() const = 0;
         virtual bool isOpen() const = 0; // Started but not complete
         virtual bool hasChildren() const = 0;
+        virtual bool hasStarted() const = 0;
 
         virtual ITracker& parent() = 0;
 
@@ -94,7 +110,6 @@ namespace TestCaseTracking {
         };
 
         using Children = std::vector<ITrackerPtr>;
-        NameAndLocation m_nameAndLocation;
         TrackerContext& m_ctx;
         ITracker* m_parent;
         Children m_children;
@@ -103,12 +118,13 @@ namespace TestCaseTracking {
     public:
         TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
 
-        NameAndLocation const& nameAndLocation() const override;
         bool isComplete() const override;
         bool isSuccessfullyCompleted() const override;
         bool isOpen() const override;
         bool hasChildren() const override;
-
+        bool hasStarted() const override {
+            return m_runState != NotStarted;
+        }
 
         void addChild( ITrackerPtr const& child ) override;
 
diff --git a/packages/Catch2/include/internal/catch_tostring.h b/packages/Catch2/include/internal/catch_tostring.h
index 640fc8cbd0492672588b59567d6bee77384c5a89..8687c4a644f8cc7df559908f57abda0585b920af 100644
--- a/packages/Catch2/include/internal/catch_tostring.h
+++ b/packages/Catch2/include/internal/catch_tostring.h
@@ -469,20 +469,27 @@ namespace Catch {
 #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
 
 namespace Catch {
-    struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
-
-    // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+    // Import begin/ end from std here
     using std::begin;
     using std::end;
 
-    not_this_one begin( ... );
-    not_this_one end( ... );
+    namespace detail {
+        template <typename...>
+        struct void_type {
+            using type = void;
+        };
+
+        template <typename T, typename = void>
+        struct is_range_impl : std::false_type {
+        };
+
+        template <typename T>
+        struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {
+        };
+    } // namespace detail
 
     template <typename T>
-    struct is_range {
-        static const bool value =
-            !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
-            !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
+    struct is_range : detail::is_range_impl<T> {
     };
 
 #if defined(_MANAGED) // Managed types are never ranges
diff --git a/packages/Catch2/include/internal/catch_uncaught_exceptions.cpp b/packages/Catch2/include/internal/catch_uncaught_exceptions.cpp
index b990ccd8f31202f40ae25926d1cc4918033e33a6..22b1ed43db179b446b0e1af518041dd102f5739b 100644
--- a/packages/Catch2/include/internal/catch_uncaught_exceptions.cpp
+++ b/packages/Catch2/include/internal/catch_uncaught_exceptions.cpp
@@ -12,7 +12,9 @@
 
 namespace Catch {
     bool uncaught_exceptions() {
-#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        return false;
+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
         return std::uncaught_exceptions() > 0;
 #else
         return std::uncaught_exception();
diff --git a/packages/Catch2/include/internal/catch_version.cpp b/packages/Catch2/include/internal/catch_version.cpp
index db6425e803708cc15c106abcc2f93b6da6461a5c..ad3e800e2fb6fe620601706b8430637d9bc08113 100644
--- a/packages/Catch2/include/internal/catch_version.cpp
+++ b/packages/Catch2/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@ namespace Catch {
     }
 
     Version const& libraryVersion() {
-        static Version version( 2, 11, 3, "", 0 );
+        static Version version( 2, 13, 0, "", 0 );
         return version;
     }
 
diff --git a/packages/Catch2/include/reporters/catch_reporter_bases.cpp b/packages/Catch2/include/reporters/catch_reporter_bases.cpp
index fcbafef58b65a6829478181d6c88379e2f5b223f..0578e8abd2f00d6c8b76bea238fa42aa02119232 100644
--- a/packages/Catch2/include/reporters/catch_reporter_bases.cpp
+++ b/packages/Catch2/include/reporters/catch_reporter_bases.cpp
@@ -41,6 +41,17 @@ namespace Catch {
         return std::string(buffer);
     }
 
+    bool shouldShowDuration( IConfig const& config, double duration ) {
+        if ( config.showDurations() == ShowDurations::Always ) {
+            return true;
+        }
+        if ( config.showDurations() == ShowDurations::Never ) {
+            return false;
+        }
+        const double min = config.minDuration();
+        return min >= 0 && duration >= min;
+    }
+
     std::string serializeFilters( std::vector<std::string> const& container ) {
         ReusableStringStream oss;
         bool first = true;
diff --git a/packages/Catch2/include/reporters/catch_reporter_bases.hpp b/packages/Catch2/include/reporters/catch_reporter_bases.hpp
index 66a891ffd4cf56b30f69ba2e915757f221fc83e7..f62e14305f87bb4f2cb133b596bc93585b821d43 100644
--- a/packages/Catch2/include/reporters/catch_reporter_bases.hpp
+++ b/packages/Catch2/include/reporters/catch_reporter_bases.hpp
@@ -25,6 +25,9 @@ namespace Catch {
     // Returns double formatted as %.3f (format expected on output)
     std::string getFormattedDuration( double duration );
 
+    //! Should the reporter show
+    bool shouldShowDuration( IConfig const& config, double duration );
+
     std::string serializeFilters( std::vector<std::string> const& container );
 
     template<typename DerivedT>
@@ -52,7 +55,7 @@ namespace Catch {
         void noMatchingTestCases(std::string const&) override {}
 
         void reportInvalidArguments(std::string const&) override {}
-        
+
         void testRunStarting(TestRunInfo const& _testRunInfo) override {
             currentTestRunInfo = _testRunInfo;
         }
diff --git a/packages/Catch2/include/reporters/catch_reporter_compact.cpp b/packages/Catch2/include/reporters/catch_reporter_compact.cpp
index 017f521f483a10126ca0cc12c8f6718f9e9b3779..74df8d507014a5835e7574e4085cf7e88f4e292c 100644
--- a/packages/Catch2/include/reporters/catch_reporter_compact.cpp
+++ b/packages/Catch2/include/reporters/catch_reporter_compact.cpp
@@ -245,10 +245,6 @@ private:
             return "Reports test results on a single line, suitable for IDEs";
         }
 
-        ReporterPreferences CompactReporter::getPreferences() const {
-            return m_reporterPrefs;
-        }
-
         void CompactReporter::noMatchingTestCases( std::string const& spec ) {
             stream << "No test cases matched '" << spec << '\'' << std::endl;
         }
@@ -275,8 +271,9 @@ private:
         }
 
         void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
-            if (m_config->showDurations() == ShowDurations::Always) {
-                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            double dur = _sectionStats.durationInSeconds;
+            if ( shouldShowDuration( *m_config, dur ) ) {
+                stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
             }
         }
 
diff --git a/packages/Catch2/include/reporters/catch_reporter_compact.h b/packages/Catch2/include/reporters/catch_reporter_compact.h
index 5002df7b1fb41f172eec6c959a557fb8bc18ae32..fe33a2205d35e1ed08c526811cb6e56827e07ed9 100644
--- a/packages/Catch2/include/reporters/catch_reporter_compact.h
+++ b/packages/Catch2/include/reporters/catch_reporter_compact.h
@@ -22,8 +22,6 @@ namespace Catch {
 
         static std::string getDescription();
 
-        ReporterPreferences getPreferences() const override;
-
         void noMatchingTestCases(std::string const& spec) override;
 
         void assertionStarting(AssertionInfo const&) override;
diff --git a/packages/Catch2/include/reporters/catch_reporter_console.cpp b/packages/Catch2/include/reporters/catch_reporter_console.cpp
index 0fa399d586cc567634658844ae17a0e20d0dfdd6..4f74ccb320411ddb1d1dd168e3ea7f98bd15b3d4 100644
--- a/packages/Catch2/include/reporters/catch_reporter_console.cpp
+++ b/packages/Catch2/include/reporters/catch_reporter_console.cpp
@@ -418,8 +418,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
             stream << "\nNo assertions in test case";
         stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
     }
-    if (m_config->showDurations() == ShowDurations::Always) {
-        stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+    double dur = _sectionStats.durationInSeconds;
+    if (shouldShowDuration(*m_config, dur)) {
+        stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
     }
     if (m_headerPrinted) {
         m_headerPrinted = false;
diff --git a/packages/Catch2/include/reporters/catch_reporter_junit.cpp b/packages/Catch2/include/reporters/catch_reporter_junit.cpp
index 7416a523e7112a093cf2634d5910a1a9ffee8e15..31f0802f194c74d16b7d670fc462c8d36b1de102 100644
--- a/packages/Catch2/include/reporters/catch_reporter_junit.cpp
+++ b/packages/Catch2/include/reporters/catch_reporter_junit.cpp
@@ -193,6 +193,11 @@ namespace Catch {
                 xml.writeAttribute( "name", name );
             }
             xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
+            // This is not ideal, but it should be enough to mimic gtest's
+            // junit output.
+            // Ideally the JUnit reporter would also handle `skipTest`
+            // events and write those out appropriately.
+            xml.writeAttribute( "status", "run" );
 
             writeAssertions( sectionNode );
 
diff --git a/packages/Catch2/include/reporters/catch_reporter_tap.hpp b/packages/Catch2/include/reporters/catch_reporter_tap.hpp
index 1bfe4f5e1ca732f9df75e922953ff70dc15df3ec..5ac8524ce7abebdf264a5584c509c71c2a1df2da 100644
--- a/packages/Catch2/include/reporters/catch_reporter_tap.hpp
+++ b/packages/Catch2/include/reporters/catch_reporter_tap.hpp
@@ -23,16 +23,17 @@ namespace Catch {
 
         using StreamingReporterBase::StreamingReporterBase;
 
+        TAPReporter( ReporterConfig const& config ):
+            StreamingReporterBase( config ) {
+            m_reporterPrefs.shouldReportAllAssertions = true;
+        }
+
         ~TAPReporter() override;
 
         static std::string getDescription() {
             return "Reports test results in TAP format, suitable for test harnesses";
         }
 
-        ReporterPreferences getPreferences() const override {
-            return m_reporterPrefs;
-        }
-
         void noMatchingTestCases( std::string const& spec ) override {
             stream << "# No test cases matched '" << spec << "'" << std::endl;
         }
@@ -203,16 +204,15 @@ namespace Catch {
                     return;
                 }
 
-                // using messages.end() directly (or auto) yields compilation error:
-                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
-                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+                const auto itEnd = messages.cend();
+                const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
 
                 {
                     Colour colourGuard( colour );
                     stream << " with " << pluralise( N, "message" ) << ":";
                 }
 
-                for(; itMessage != itEnd; ) {
+                while( itMessage != itEnd ) {
                     // If this assertion is a warning ignore any INFO messages
                     if( printInfoMessages || itMessage->type != ResultWas::Info ) {
                         stream << " '" << itMessage->message << "'";
@@ -220,7 +220,9 @@ namespace Catch {
                             Colour colourGuard( dimColour() );
                             stream << " and";
                         }
+                        continue;
                     }
+                    ++itMessage;
                 }
             }
 
@@ -234,10 +236,9 @@ namespace Catch {
         };
 
         void printTotals( const Totals& totals ) const {
+            stream << "1.." << totals.assertions.total();
             if( totals.testCases.total() == 0 ) {
-                stream << "1..0 # Skipped: No tests ran.";
-            } else {
-                stream << "1.." << counter;
+                stream << " # Skipped: No tests ran.";
             }
         }
     };
diff --git a/packages/Catch2/include/reporters/catch_reporter_xml.cpp b/packages/Catch2/include/reporters/catch_reporter_xml.cpp
index 0fb78be03d472b542e8236224e27d2ee561b1dfd..b58becd8a5a4c3e772d0f015d9ba83fa6427c2de 100644
--- a/packages/Catch2/include/reporters/catch_reporter_xml.cpp
+++ b/packages/Catch2/include/reporters/catch_reporter_xml.cpp
@@ -207,6 +207,10 @@ namespace Catch {
             .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
             .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
             .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testGroupStats.totals.testCases.passed )
+            .writeAttribute( "failures", testGroupStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
         m_xml.endElement();
     }
 
@@ -216,6 +220,10 @@ namespace Catch {
             .writeAttribute( "successes", testRunStats.totals.assertions.passed )
             .writeAttribute( "failures", testRunStats.totals.assertions.failed )
             .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testRunStats.totals.testCases.passed )
+            .writeAttribute( "failures", testRunStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
         m_xml.endElement();
     }
 
diff --git a/packages/Catch2/projects/CMakeLists.txt b/packages/Catch2/projects/CMakeLists.txt
index 08badb809a995f317648e91c9f0b8a5aedcb5ac7..914af8d6b66e345cf029dcbf2b5306aa3a4d0d54 100644
--- a/packages/Catch2/projects/CMakeLists.txt
+++ b/packages/Catch2/projects/CMakeLists.txt
@@ -27,6 +27,7 @@ set(TEST_SOURCES
         ${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
         ${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
         ${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
+        ${SELF_TEST_DIR}/TimingTests/Sleep.tests.cpp
         ${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
         ${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
         ${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
diff --git a/packages/Catch2/projects/ExtraTests/CMakeLists.txt b/packages/Catch2/projects/ExtraTests/CMakeLists.txt
index c8c975c00d65d10e1676b1eaf82bcfd7b9f06dd7..637dc692a6d1fd9f50f3157425049be2875e9741 100644
--- a/packages/Catch2/projects/ExtraTests/CMakeLists.txt
+++ b/packages/Catch2/projects/ExtraTests/CMakeLists.txt
@@ -10,6 +10,40 @@ project( Catch2ExtraTests LANGUAGES CXX )
 
 message( STATUS "Extra tests included" )
 
+# The MinDuration reporting tests do not need separate compilation, but
+# they have non-trivial execution time, so they are categorized as
+# extra tests, so that they are run less.
+add_test(NAME MinDuration::SimpleThreshold COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.22 [min_duration_test])
+set_tests_properties(
+    MinDuration::SimpleThreshold
+  PROPERTIES
+    PASS_REGULAR_EXPRESSION "s: sleep_for_250ms"
+    FAIL_REGULAR_EXPRESSION "sleep_for_100ms"
+    RUN_SERIAL ON  # The test is timing sensitive, so we want to run it
+    # serially to avoid false positives on oversubscribed machines
+)
+
+# -d yes overrides the threshold, so we should see the faster test even
+# with a ridiculous high min duration threshold
+add_test(NAME MinDuration::DurationOverrideYes COMMAND $<TARGET_FILE:SelfTest> --min-duration 1.0 -d yes [min_duration_test])
+set_tests_properties(
+    MinDuration::DurationOverrideYes
+  PROPERTIES
+    PASS_REGULAR_EXPRESSION "s: sleep_for_100ms"
+)
+
+# -d no overrides the threshold, so we should never see any tests even
+# with ridiculously low min duration threshold
+add_test(NAME MinDuration::DurationOverrideNo COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.0001 -d no [min_duration_test])
+set_tests_properties(
+    MinDuration::DurationOverrideNo
+  PROPERTIES
+    FAIL_REGULAR_EXPRESSION "sleep_for_250ms"
+)
+
+
+# ------------ end of duration reporting tests
+
 # define folders used:
 
 set( TESTS_DIR   ${CATCH_DIR}/projects/ExtraTests )
diff --git a/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
index 280f697adbaaed137e65cd260bb2cb7d1a07f8b5..59a909b2f0277d9c8c54712076949caaaa1ac8e1 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
@@ -26,6 +26,61 @@ Compilation.tests.cpp:<line number>: passed: std::is_same<TypeList<int>, TypeLis
 CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("spec . char")) for: true
 CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("spec , char")) for: true
 CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase(R"(spec \, char)"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec {a} char)")) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec [a] char)")) for: true
+CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("differs but has similar tag", "[a]"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec \ char)")) for: true
+Generators.tests.cpp:<line number>: passed: counter < 7 for: 3 < 7
+Generators.tests.cpp:<line number>: passed: counter < 7 for: 6 < 7
+Generators.tests.cpp:<line number>: passed: i != j for: 1 != 3
+Generators.tests.cpp:<line number>: passed: i != j for: 1 != 4
+Generators.tests.cpp:<line number>: passed: i != j for: 2 != 3
+Generators.tests.cpp:<line number>: passed: i != j for: 2 != 4
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
+PartTracker.tests.cpp:<line number>: passed: m for: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: m for: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 3' and 'k := 5'
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 3' and 'k := 6'
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 4' and 'k := 5'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 4' and 'k := 6'
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 3' and 'k := 5'
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 3' and 'k := 6'
+PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 4' and 'k := 5'
+PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 4' and 'k := 6'
+PartTracker.tests.cpp:<line number>: passed: m for: 1
+PartTracker.tests.cpp:<line number>: passed: n for: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 1
+PartTracker.tests.cpp:<line number>: passed: n for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 1
+PartTracker.tests.cpp:<line number>: passed: n for: 3
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: n for: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: n for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 2
+PartTracker.tests.cpp:<line number>: passed: n for: 3
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: n for: 1
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: n for: 2
+PartTracker.tests.cpp:<line number>: passed: m for: 3
+PartTracker.tests.cpp:<line number>: passed: n for: 3
+Misc.tests.cpp:<line number>: passed:
+Misc.tests.cpp:<line number>: passed:
+Misc.tests.cpp:<line number>: passed:
 Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
 Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
 Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
@@ -240,6 +295,11 @@ Matchers.tests.cpp:<line number>: passed: 1, Predicate<int>(alwaysTrue, "always
 Matchers.tests.cpp:<line number>: passed: 1, !Predicate<int>(alwaysFalse, "always false") for: 1 not matches predicate: "always false"
 Matchers.tests.cpp:<line number>: passed: "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal"
 Matchers.tests.cpp:<line number>: passed: "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate
+Compilation.tests.cpp:<line number>: passed: lhs | rhs for: Val: 1 | Val: 2
+Compilation.tests.cpp:<line number>: passed: !(lhs & rhs) for: !(Val: 1 & Val: 2)
+Compilation.tests.cpp:<line number>: passed: HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val: 1
+Compilation.tests.cpp:<line number>: passed: lhs ^ rhs for: Val: 1 ^ Val: 2
+Compilation.tests.cpp:<line number>: passed: !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
 Tricky.tests.cpp:<line number>: passed: true
 Tricky.tests.cpp:<line number>: passed: true
 Tricky.tests.cpp:<line number>: passed: true
@@ -317,6 +377,12 @@ Condition.tests.cpp:<line number>: passed: 6 == uc for: 6 == 6
 Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4
 Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), !composed1 for: "some completely different text that contains one common word" not ( contains: "string" or contains: "random" )
 Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), composed2 for: "some completely different text that contains one common word" ( contains: "string" or contains: "random" or contains: "different" )
+Matchers.tests.cpp:<line number>: passed: 1, !(first && second) for: 1 not ( CheckedTestingMatcher set to fail and CheckedTestingMatcher set to fail )
+Matchers.tests.cpp:<line number>: passed: first.matchCalled for: true
+Matchers.tests.cpp:<line number>: passed: !second.matchCalled for: true
+Matchers.tests.cpp:<line number>: passed: 1, first || second for: 1 ( CheckedTestingMatcher set to succeed or CheckedTestingMatcher set to fail )
+Matchers.tests.cpp:<line number>: passed: first.matchCalled for: true
+Matchers.tests.cpp:<line number>: passed: !second.matchCalled for: true
 Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
 Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING"
 Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
@@ -1522,6 +1588,7 @@ Approx.tests.cpp:<line number>: passed: approx( d ) != 1.25 for: Approx( 1.23 )
 VariadicMacros.tests.cpp:<line number>: passed: with 1 message: 'no assertions'
 Matchers.tests.cpp:<line number>: passed: empty, Approx(empty) for: {  } is approx: {  }
 Matchers.tests.cpp:<line number>: passed: v1, Approx(v1) for: { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
+Matchers.tests.cpp:<line number>: passed: v1, Approx<double>({ 1., 2., 3. }) for: { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
 Matchers.tests.cpp:<line number>: passed: v1, !Approx(temp) for: { 1.0, 2.0, 3.0 } not is approx: { 1.0, 2.0, 3.0, 4.0 }
 Matchers.tests.cpp:<line number>: passed: v1, !Approx(v2) for: { 1.0, 2.0, 3.0 } not is approx: { 1.5, 2.5, 3.5 }
 Matchers.tests.cpp:<line number>: passed: v1, Approx(v2).margin(0.5) for: { 1.0, 2.0, 3.0 } is approx: { 1.5, 2.5, 3.5 }
@@ -1533,6 +1600,7 @@ Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) for: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v, VectorContains(2) for: { 1, 2, 3 } Contains: 2
 Matchers.tests.cpp:<line number>: passed: v5, (VectorContains<int, CustomAllocator<int>>(2)) for: { 1, 2, 3 } Contains: 2
 Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2 }
+Matchers.tests.cpp:<line number>: passed: v, Contains<int>({ 1, 2 }) for: { 1, 2, 3 } Contains: { 1, 2 }
 Matchers.tests.cpp:<line number>: passed: v5, (Contains<int, std::allocator<int>, CustomAllocator<int>>(v2)) for: { 1, 2, 3 } Contains: { 1, 2 }
 Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v, Contains(empty) for: { 1, 2, 3 } Contains: {  }
@@ -1542,10 +1610,12 @@ Matchers.tests.cpp:<line number>: passed: v5, Contains(v6) for: { 1, 2, 3 } Cont
 Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) && VectorContains(2) for: { 1, 2, 3 } ( Contains: 1 and Contains: 2 )
 Matchers.tests.cpp:<line number>: passed: v, Equals(v) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: empty, Equals(empty) for: {  } Equals: {  }
+Matchers.tests.cpp:<line number>: passed: v, Equals<int>({ 1, 2, 3 }) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v, Equals(v2) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v5, (Equals<int, std::allocator<int>, CustomAllocator<int>>(v2)) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v5, Equals(v6) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: v, UnorderedEquals(v) for: { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>: passed: v, UnorderedEquals<int>({ 3, 2, 1 }) for: { 1, 2, 3 } UnorderedEquals: { 3, 2, 1 }
 Matchers.tests.cpp:<line number>: passed: empty, UnorderedEquals(empty) for: {  } UnorderedEquals: {  }
 Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 }
 Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 }
diff --git a/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
index 6b29a98ca99fb8b15bc81bd0f2524d99fb0c8c8b..c1600545cbc77d06e75c2759a6e2c71ff97d160c 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
@@ -1380,6 +1380,6 @@ due to unexpected exception with message:
   Why would you throw a std::string?
 
 ===============================================================================
-test cases:  308 |  234 passed |  70 failed |  4 failed as expected
-assertions: 1688 | 1536 passed | 131 failed | 21 failed as expected
+test cases:  321 |  247 passed |  70 failed |  4 failed as expected
+assertions: 1758 | 1606 passed | 131 failed | 21 failed as expected
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
index fcb7a802dc7be5a9754550ae4d9b9701fde5f55a..3603215f9fd239cc59584811f8d90f67a24c7f2b 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
@@ -209,6 +209,548 @@ CmdLine.tests.cpp:<line number>: PASSED:
 with expansion:
   !false
 
+-------------------------------------------------------------------------------
+#1912 -- test spec parser handles escaping
+  Various parentheses
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec {a} char)")) )
+with expansion:
+  true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec [a] char)")) )
+with expansion:
+  true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE_FALSE( spec.matches(fakeTestCase("differs but has similar tag", "[a]")) )
+with expansion:
+  !false
+
+-------------------------------------------------------------------------------
+#1912 -- test spec parser handles escaping
+  backslash in test name
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec \ char)")) )
+with expansion:
+  true
+
+-------------------------------------------------------------------------------
+#1913 - GENERATE inside a for loop should not keep recreating the generator
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( counter < 7 )
+with expansion:
+  3 < 7
+
+-------------------------------------------------------------------------------
+#1913 - GENERATE inside a for loop should not keep recreating the generator
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( counter < 7 )
+with expansion:
+  6 < 7
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  1 != 3
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  1 != 4
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  2 != 3
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  2 != 4
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( 1 )
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 3
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 3
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 4
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 4
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 3
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 3
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 4
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 4
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
 -------------------------------------------------------------------------------
 #748 - captures with unexpected exceptions
   outside assertions
@@ -1900,6 +2442,37 @@ Matchers.tests.cpp:<line number>: PASSED:
 with expansion:
   "This wouldn't pass" not matches undescribed predicate
 
+-------------------------------------------------------------------------------
+Assertion macros support bit operators and bool conversions
+-------------------------------------------------------------------------------
+Compilation.tests.cpp:<line number>
+...............................................................................
+
+Compilation.tests.cpp:<line number>: PASSED:
+  REQUIRE( lhs | rhs )
+with expansion:
+  Val: 1 | Val: 2
+
+Compilation.tests.cpp:<line number>: PASSED:
+  REQUIRE_FALSE( lhs & rhs )
+with expansion:
+  !(Val: 1 & Val: 2)
+
+Compilation.tests.cpp:<line number>: PASSED:
+  REQUIRE( HasBitOperators{ 1 } & HasBitOperators{ 1 } )
+with expansion:
+  Val: 1 & Val: 1
+
+Compilation.tests.cpp:<line number>: PASSED:
+  REQUIRE( lhs ^ rhs )
+with expansion:
+  Val: 1 ^ Val: 2
+
+Compilation.tests.cpp:<line number>: PASSED:
+  REQUIRE_FALSE( lhs ^ lhs )
+with expansion:
+  !(Val: 1 ^ Val: 1)
+
 -------------------------------------------------------------------------------
 Assertions then sections
 -------------------------------------------------------------------------------
@@ -2429,6 +3002,52 @@ with expansion:
   "some completely different text that contains one common word" ( contains:
   "string" or contains: "random" or contains: "different" )
 
+-------------------------------------------------------------------------------
+Composed matchers shortcircuit
+  &&
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+  CHECK_THAT( 1, !(first && second) )
+with expansion:
+  1 not ( CheckedTestingMatcher set to fail and CheckedTestingMatcher set to
+  fail )
+
+Matchers.tests.cpp:<line number>: PASSED:
+  REQUIRE( first.matchCalled )
+with expansion:
+  true
+
+Matchers.tests.cpp:<line number>: PASSED:
+  REQUIRE( !second.matchCalled )
+with expansion:
+  true
+
+-------------------------------------------------------------------------------
+Composed matchers shortcircuit
+  ||
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+  CHECK_THAT( 1, first || second )
+with expansion:
+  1 ( CheckedTestingMatcher set to succeed or CheckedTestingMatcher set to fail
+  )
+
+Matchers.tests.cpp:<line number>: PASSED:
+  REQUIRE( first.matchCalled )
+with expansion:
+  true
+
+Matchers.tests.cpp:<line number>: PASSED:
+  REQUIRE( !second.matchCalled )
+with expansion:
+  true
+
 -------------------------------------------------------------------------------
 Contains string matcher
 -------------------------------------------------------------------------------
@@ -11122,6 +11741,11 @@ Matchers.tests.cpp:<line number>: PASSED:
 with expansion:
   { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
 
+Matchers.tests.cpp:<line number>: PASSED:
+  REQUIRE_THAT( v1, Approx<double>({ 1., 2., 3. }) )
+with expansion:
+  { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
+
 -------------------------------------------------------------------------------
 Vector Approx matcher
   Vectors with elements
@@ -11221,6 +11845,11 @@ Matchers.tests.cpp:<line number>: PASSED:
 with expansion:
   { 1, 2, 3 } Contains: { 1, 2 }
 
+Matchers.tests.cpp:<line number>: PASSED:
+  CHECK_THAT( v, Contains<int>({ 1, 2 }) )
+with expansion:
+  { 1, 2, 3 } Contains: { 1, 2 }
+
 Matchers.tests.cpp:<line number>: PASSED:
   CHECK_THAT( v5, (Contains<int, std::allocator<int>, CustomAllocator<int>>(v2)) )
 with expansion:
@@ -11280,6 +11909,11 @@ Matchers.tests.cpp:<line number>: PASSED:
 with expansion:
   {  } Equals: {  }
 
+Matchers.tests.cpp:<line number>: PASSED:
+  CHECK_THAT( v, Equals<int>({ 1, 2, 3 }) )
+with expansion:
+  { 1, 2, 3 } Equals: { 1, 2, 3 }
+
 Matchers.tests.cpp:<line number>: PASSED:
   CHECK_THAT( v, Equals(v2) )
 with expansion:
@@ -11307,6 +11941,11 @@ Matchers.tests.cpp:<line number>: PASSED:
 with expansion:
   { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 }
 
+Matchers.tests.cpp:<line number>: PASSED:
+  CHECK_THAT( v, UnorderedEquals<int>({ 3, 2, 1 }) )
+with expansion:
+  { 1, 2, 3 } UnorderedEquals: { 3, 2, 1 }
+
 Matchers.tests.cpp:<line number>: PASSED:
   CHECK_THAT( empty, UnorderedEquals(empty) )
 with expansion:
@@ -13488,6 +14127,6 @@ Misc.tests.cpp:<line number>
 Misc.tests.cpp:<line number>: PASSED:
 
 ===============================================================================
-test cases:  308 |  218 passed |  86 failed |  4 failed as expected
-assertions: 1705 | 1536 passed | 148 failed | 21 failed as expected
+test cases:  321 |  231 passed |  86 failed |  4 failed as expected
+assertions: 1775 | 1606 passed | 148 failed | 21 failed as expected
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/console.swa4.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/console.swa4.approved.txt
index e32fd88f425033e017773cc22799420740249562..599382255e988fca4e83ff8aff72ce71515eb5a2 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/console.swa4.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/console.swa4.approved.txt
@@ -209,6 +209,548 @@ CmdLine.tests.cpp:<line number>: PASSED:
 with expansion:
   !false
 
+-------------------------------------------------------------------------------
+#1912 -- test spec parser handles escaping
+  Various parentheses
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec {a} char)")) )
+with expansion:
+  true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec [a] char)")) )
+with expansion:
+  true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE_FALSE( spec.matches(fakeTestCase("differs but has similar tag", "[a]")) )
+with expansion:
+  !false
+
+-------------------------------------------------------------------------------
+#1912 -- test spec parser handles escaping
+  backslash in test name
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+  REQUIRE( spec.matches(fakeTestCase(R"(spec \ char)")) )
+with expansion:
+  true
+
+-------------------------------------------------------------------------------
+#1913 - GENERATE inside a for loop should not keep recreating the generator
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( counter < 7 )
+with expansion:
+  3 < 7
+
+-------------------------------------------------------------------------------
+#1913 - GENERATE inside a for loop should not keep recreating the generator
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( counter < 7 )
+with expansion:
+  6 < 7
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  1 != 3
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  1 != 4
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  2 != 3
+
+-------------------------------------------------------------------------------
+#1913 - GENERATEs can share a line
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+  REQUIRE( i != j )
+with expansion:
+  2 != 4
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - GENERATE after a section
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( 1 )
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - Section followed by flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - flat generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 3
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 3
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 4
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 1
+  j := 4
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  A
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  A
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 3
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 3
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+  B
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with message:
+  B
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 4
+  k := 5
+
+-------------------------------------------------------------------------------
+#1938 - mixed sections and generates
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+with messages:
+  i := 2
+  j := 4
+  k := 6
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  1
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  2
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  1
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  2
+
+-------------------------------------------------------------------------------
+#1938 - nested generate
+-------------------------------------------------------------------------------
+PartTracker.tests.cpp:<line number>
+...............................................................................
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( m )
+with expansion:
+  3
+
+PartTracker.tests.cpp:<line number>: PASSED:
+  REQUIRE( n )
+with expansion:
+  3
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
+-------------------------------------------------------------------------------
+#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+
 -------------------------------------------------------------------------------
 #748 - captures with unexpected exceptions
   outside assertions
@@ -389,6 +931,6 @@ Condition.tests.cpp:<line number>: FAILED:
   CHECK( true != true )
 
 ===============================================================================
-test cases: 20 | 15 passed | 3 failed | 2 failed as expected
-assertions: 45 | 38 passed | 4 failed | 3 failed as expected
+test cases:  31 | 26 passed | 3 failed | 2 failed as expected
+assertions: 100 | 93 passed | 4 failed | 3 failed as expected
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
index 76284a2fba97b31bfed2bc87e48ecc4371b2f2cc..9c8505340c7e1dded90a28dd3c901b1a32de1c4c 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
@@ -1,22 +1,22 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <testsuitesloose text artifact
 >
-  <testsuite name="<exe-name>" errors="17" failures="132" tests="1706" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
+  <testsuite name="<exe-name>" errors="17" failures="132" tests="1776" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
     <properties>
       <property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
       <property name="random-seed" value="1"/>
     </properties>
-    <testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1027: Bitfields can be captured" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1147" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
-    <testcase classname="<exe-name>.(Fixture_1245&lt;int, int>)" name="#1245" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1403" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1455 - INFO and WARN can start with a linebreak" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}">
+    <testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1027" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1027: Bitfields can be captured" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1147" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1238" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.(Fixture_1245&lt;int, int>)" name="#1245" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1403" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1455 - INFO and WARN can start with a linebreak" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 1514
@@ -29,9 +29,25 @@ This would not be caught previously
 Nor would this
       </system-err>
     </testcase>
-    <testcase classname="<exe-name>.global" name="#1548" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#1905 -- test spec parser properly clears internal state between compound tests" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
+    <testcase classname="<exe-name>.global" name="#1548" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1905 -- test spec parser properly clears internal state between compound tests" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1912 -- test spec parser handles escaping/Various parentheses" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1912 -- test spec parser handles escaping/backslash in test name" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1913 - GENERATE inside a for loop should not keep recreating the generator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1913 - GENERATEs can share a line" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - GENERATE after a section/A" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - GENERATE after a section/B" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - Section followed by flat generate" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - Section followed by flat generate/A" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - flat generate" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - mixed sections and generates" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - mixed sections and generates/A" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - mixed sections and generates/B" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1938 - nested generate" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 expected exception
@@ -39,7 +55,7 @@ answer := 42
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/inside REQUIRE_NOTHROW" time="{duration}">
+    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/inside REQUIRE_NOTHROW" time="{duration}" status="run">
       <error message="thisThrows()" type="REQUIRE_NOTHROW">
 FAILED:
   REQUIRE_NOTHROW( thisThrows() )
@@ -48,10 +64,10 @@ answer := 42
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/inside REQUIRE_THROWS" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#809" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#833" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#835 -- errno should not be touched by Catch" time="{duration}">
+    <testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/inside REQUIRE_THROWS" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#809" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#833" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#835 -- errno should not be touched by Catch" time="{duration}" status="run">
       <failure message="f() == 0" type="CHECK">
 FAILED:
   CHECK( f() == 0 )
@@ -60,13 +76,13 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="#872" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 0" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 3" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 4" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="'Not' checks that should fail" time="{duration}">
+    <testcase classname="<exe-name>.global" name="#872" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 3" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 4" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="'Not' checks that should fail" time="{duration}" status="run">
       <failure message="false != false" type="CHECK">
 FAILED:
   CHECK( false != false )
@@ -118,14 +134,14 @@ FAILED:
 Condition.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="'Not' checks that should succeed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/compare to true" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/compare to false" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}"/>
-    <testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
+    <testcase classname="<exe-name>.global" name="'Not' checks that should succeed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/compare to true" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/compare to false" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}" status="run">
       <failure message="s == &quot;world&quot;" type="REQUIRE">
 FAILED:
   REQUIRE( s == "world" )
@@ -134,8 +150,8 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that succeeds" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" time="{duration}">
+    <testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that succeeds" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
@@ -144,7 +160,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
@@ -153,7 +169,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
@@ -162,7 +178,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
@@ -171,11 +187,11 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;float>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;float>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;float, 6>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;float, 6>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
@@ -184,7 +200,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;int, 2>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;int, 2>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
@@ -193,7 +209,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;float, 6>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;float, 6>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
@@ -202,7 +218,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;int, 2>" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;int, 2>" time="{duration}" status="run">
       <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
@@ -211,11 +227,11 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;float,6>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;int,2>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;float,6>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;int,2>" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;float,6>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;int,2>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;float,6>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;int,2>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}" status="run">
       <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
@@ -224,7 +240,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" time="{duration}" status="run">
       <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
@@ -233,7 +249,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" time="{duration}" status="run">
       <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
 FAILED:
   REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
@@ -242,10 +258,10 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int" time="{duration}"/>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1" time="{duration}">
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1" time="{duration}" status="run">
       <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
 FAILED:
   REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
@@ -254,7 +270,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3" time="{duration}">
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3" time="{duration}" status="run">
       <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
 FAILED:
   REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
@@ -263,7 +279,7 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6" time="{duration}">
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6" time="{duration}" status="run">
       <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
 FAILED:
   REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
@@ -272,10 +288,10 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1" time="{duration}"/>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3" time="{duration}"/>
-    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6" time="{duration}"/>
-    <testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that fails" time="{duration}">
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that fails" time="{duration}" status="run">
       <failure message="m_a == 2" type="REQUIRE">
 FAILED:
   REQUIRE( m_a == 2 )
@@ -284,25 +300,25 @@ with expansion:
 Class.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that succeeds" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;float>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;float>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;float, 42>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;int, 9>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;float, 42>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;int, 9>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}">
+    <testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that succeeds" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;float, 42>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;int, 9>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;float, 42>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;int, 9>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 to infinity and beyond
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure/Outer/Inner" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="A failing expression with a non streamable type is still captured" time="{duration}">
+    <testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure/Outer/Inner" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="A failing expression with a non streamable type is still captured" time="{duration}" status="run">
       <failure message="&amp;o1 == &amp;o2" type="CHECK">
 FAILED:
   CHECK( &amp;o1 == &amp;o2 )
@@ -318,9 +334,9 @@ with expansion:
 Tricky.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Absolute margin" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="An expression with side-effects should only be evaluated once" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="An unchecked exception reports the line of the last assertion" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Absolute margin" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="An expression with side-effects should only be evaluated once" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="An unchecked exception reports the line of the last assertion" time="{duration}" status="run">
       <error message="{Unknown expression after the reported line}">
 FAILED:
   {Unknown expression after the reported line}
@@ -328,37 +344,40 @@ unexpected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Anonymous test case 1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approx setters validate their arguments" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approx with exactly-representable margin" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approximate PI" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approximate comparisons with different epsilons" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approximate comparisons with floats" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approximate comparisons with ints" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Approximate comparisons with mixed numeric types" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Function pointer" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Lambdas + different type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Assertions then sections" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another other section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Capture and info messages/Capture should stringify like assertions" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Capture and info messages/Info should NOT stringify the way assertions do" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Character pretty printing/Specifically escaped" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Character pretty printing/General chars" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Character pretty printing/Low ASCII" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparison with explicitly convertible types" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparisons between ints where one side is computed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Comparisons with int literals don't warn when mixing signed/ unsigned" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Composed matchers are distinct" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Contains string matcher" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Anonymous test case 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approx setters validate their arguments" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approx with exactly-representable margin" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approximate PI" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approximate comparisons with different epsilons" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approximate comparisons with floats" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approximate comparisons with ints" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Approximate comparisons with mixed numeric types" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Function pointer" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Lambdas + different type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Assertion macros support bit operators and bool conversions" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Assertions then sections" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another other section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Capture and info messages/Capture should stringify like assertions" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Capture and info messages/Info should NOT stringify the way assertions do" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Character pretty printing/Specifically escaped" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Character pretty printing/General chars" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Character pretty printing/Low ASCII" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparison with explicitly convertible types" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparisons between ints where one side is computed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Comparisons with int literals don't warn when mixing signed/ unsigned" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Composed matchers are distinct" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Composed matchers shortcircuit/&amp;&amp;" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Composed matchers shortcircuit/||" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Contains string matcher" time="{duration}" status="run">
       <failure message="testStringForMatching(), Contains(&quot;not there&quot;, Catch::CaseSensitive::No)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) )
@@ -375,10 +394,10 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Copy and then generate a range/from var and iterators" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Copy and then generate a range/From a temporary container" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Copy and then generate a range/Final validation" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for nothrow" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Copy and then generate a range/from var and iterators" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Copy and then generate a range/From a temporary container" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Copy and then generate a range/Final validation" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for nothrow" time="{duration}" status="run">
       <error message="throwCustom()" type="REQUIRE_NOTHROW">
 FAILED:
   REQUIRE_NOTHROW( throwCustom() )
@@ -386,7 +405,7 @@ custom exception - not std
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for throwing as something else" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for throwing as something else" time="{duration}" status="run">
       <error message="throwCustom(), std::exception" type="REQUIRE_THROWS_AS">
 FAILED:
   REQUIRE_THROWS_AS( throwCustom(), std::exception )
@@ -394,16 +413,16 @@ custom exception - not std
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Custom std-exceptions can be custom translated" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Custom std-exceptions can be custom translated" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 custom std exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Default scale is invisible to comparison" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Directly creating an EnumInfo" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="EndsWith string matcher" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Default scale is invisible to comparison" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Directly creating an EnumInfo" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="EndsWith string matcher" time="{duration}" status="run">
       <failure message="testStringForMatching(), EndsWith(&quot;Substring&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), EndsWith("Substring") )
@@ -420,10 +439,10 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Enums can quickly have stringification enabled using REGISTER_ENUM" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Epsilon only applies to Approx's value" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Equality checks that should fail" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Enums can quickly have stringification enabled using REGISTER_ENUM" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Epsilon only applies to Approx's value" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Equality checks that should fail" time="{duration}" status="run">
       <failure message="data.int_seven == 6" type="CHECK">
 FAILED:
   CHECK( data.int_seven == 6 )
@@ -516,9 +535,9 @@ with expansion:
 Condition.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Equality checks that should succeed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Equals" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Equals string matcher" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Equality checks that should succeed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Equals" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Equals string matcher" time="{duration}" status="run">
       <failure message="testStringForMatching(), Equals(&quot;this string contains 'ABC' as a substring&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), Equals("this string contains 'ABC' as a substring") )
@@ -536,8 +555,8 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Exception matchers that fail/No exception" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Exception matchers that fail/No exception" time="{duration}" status="run">
       <failure message="doesNotThrow(), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
 FAILED:
   CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{1} )
@@ -549,7 +568,7 @@ FAILED:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Exception matchers that fail/Type mismatch" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Exception matchers that fail/Type mismatch" time="{duration}" status="run">
       <error message="throwsAsInt(1), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
 FAILED:
   CHECK_THROWS_MATCHES( throwsAsInt(1), SpecialException, ExceptionMatcher{1} )
@@ -563,7 +582,7 @@ Unknown exception
 Matchers.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Exception matchers that fail/Contents are wrong" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Exception matchers that fail/Contents are wrong" time="{duration}" status="run">
       <failure message="throwsSpecialException(3), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
 FAILED:
   CHECK_THROWS_MATCHES( throwsSpecialException(3), SpecialException, ExceptionMatcher{1} )
@@ -579,12 +598,12 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Exception matchers that succeed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/exact match" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/different case" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/wildcarded" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Exceptions matchers" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Expected exceptions that don't throw or unexpected exceptions fail the test" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Exception matchers that succeed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/exact match" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/different case" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Exception messages can be tested for/wildcarded" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Exceptions matchers" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Expected exceptions that don't throw or unexpected exceptions fail the test" time="{duration}" status="run">
       <error message="thisThrows(), std::string" type="CHECK_THROWS_AS">
 FAILED:
   CHECK_THROWS_AS( thisThrows(), std::string )
@@ -603,77 +622,77 @@ expected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="FAIL aborts the test" time="{duration}">
+    <testcase classname="<exe-name>.global" name="FAIL aborts the test" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 This is a failure
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="FAIL does not require an argument" time="{duration}">
+    <testcase classname="<exe-name>.global" name="FAIL does not require an argument" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="FAIL_CHECK does not abort the test" time="{duration}">
+    <testcase classname="<exe-name>.global" name="FAIL_CHECK does not abort the test" time="{duration}" status="run">
       <failure type="FAIL_CHECK">
 FAILED:
 This is a failure
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Factorials are computed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative/Some subnormal values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Margin" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different deduced type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Chunk size of zero" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Preset values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Generator combinator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Explicitly typed generator sequence" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Filter generator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take less" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take more" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Map with explicit return type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Map with deduced return type" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Repeat/Singular repeat" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Repeat/Actual repeat" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive auto step/Integer" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative auto step/Integer" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Exact" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly over end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly under end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Exact" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly over end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly under end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Exact" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly over end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly under end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Factorials are computed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative/Some subnormal values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Margin" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different deduced type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Chunk size of zero" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Preset values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Generator combinator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Explicitly typed generator sequence" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Filter generator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take less" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take more" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Map with explicit return type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Map with deduced return type" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Repeat/Singular repeat" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Repeat/Actual repeat" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive auto step/Integer" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative auto step/Integer" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Exact" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly over end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly under end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Exact" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly over end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly under end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Exact" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly over end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly under end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}" status="run">
       <failure message="a == 1" type="REQUIRE">
 FAILED:
   REQUIRE( a == 1 )
@@ -684,7 +703,7 @@ so should this
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="INFO gets logged on failure, even if captured before successful assertions" time="{duration}">
+    <testcase classname="<exe-name>.global" name="INFO gets logged on failure, even if captured before successful assertions" time="{duration}" status="run">
       <failure message="a == 1" type="CHECK">
 FAILED:
   CHECK( a == 1 )
@@ -705,7 +724,7 @@ and this, but later
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="INFO is reset for each loop" time="{duration}">
+    <testcase classname="<exe-name>.global" name="INFO is reset for each loop" time="{duration}" status="run">
       <failure message="i &lt; 10" type="REQUIRE">
 FAILED:
   REQUIRE( i &lt; 10 )
@@ -716,7 +735,7 @@ i := 10
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Inequality checks that should fail" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Inequality checks that should fail" time="{duration}" status="run">
       <failure message="data.int_seven != 7" type="CHECK">
 FAILED:
   CHECK( data.int_seven != 7 )
@@ -753,14 +772,14 @@ with expansion:
 Condition.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Inequality checks that should succeed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Lambdas in assertions" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Less-than inequalities with different epsilons" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="ManuallyRegistered" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Matchers can be (AllOf) composed with the &amp;&amp; operator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Matchers can be (AnyOf) composed with the || operator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and ||" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and || - failing" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Inequality checks that should succeed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Lambdas in assertions" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Less-than inequalities with different epsilons" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="ManuallyRegistered" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Matchers can be (AllOf) composed with the &amp;&amp; operator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Matchers can be (AnyOf) composed with the || operator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and ||" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and || - failing" time="{duration}" status="run">
       <failure message="testStringForMatching(), (Contains(&quot;string&quot;) || Contains(&quot;different&quot;)) &amp;&amp; Contains(&quot;random&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), (Contains("string") || Contains("different")) &amp;&amp; Contains("random") )
@@ -770,8 +789,8 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator - failing" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator - failing" time="{duration}" status="run">
       <failure message="testStringForMatching(), !Contains(&quot;substring&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), !Contains("substring") )
@@ -780,7 +799,7 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Mismatching exception messages failing the test" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Mismatching exception messages failing the test" time="{duration}" status="run">
       <failure message="thisThrows(), &quot;should fail&quot;" type="REQUIRE_THROWS_WITH">
 FAILED:
   REQUIRE_THROWS_WITH( thisThrows(), "should fail" )
@@ -789,18 +808,18 @@ with expansion:
 Exception.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Nested generators and captured variables" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Nice descriptive name" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Non-std exceptions can be translated" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Nested generators and captured variables" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Nice descriptive name" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Non-std exceptions can be translated" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 custom exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Objects that evaluated in boolean contexts can be checked" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Optionally static assertions" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Ordering comparison checks that should fail" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Objects that evaluated in boolean contexts can be checked" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Optionally static assertions" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Ordering comparison checks that should fail" time="{duration}" status="run">
       <failure message="data.int_seven > 7" type="CHECK">
 FAILED:
   CHECK( data.int_seven > 7 )
@@ -935,98 +954,98 @@ with expansion:
 Condition.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Ordering comparison checks that should succeed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Default seeded" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Specific seed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Output from all sections is reported/one" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Ordering comparison checks that should succeed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Default seeded" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Specific seed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Output from all sections is reported/one" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 Message from section one
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Output from all sections is reported/two" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Output from all sections is reported/two" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 Message from section two
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Empty test spec should have no filters" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from empty string should have no filters" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from just a comma should have no filters" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from name should have one filter" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from quoted name should have one filter" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from name should have one filter" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at the start" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at the end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at both ends" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at the start" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at the end" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at both ends" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at both ends, redundant at start" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Just wildcard" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag, two matches" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Two tags" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Two tags, spare separated" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcarded name and tag" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag exclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion and one tag inclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion and one wldcarded name inclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion, using exclude:, and one wldcarded name inclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/name exclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion with tag inclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion, using exclude:, with tag inclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/two wildcarded names" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/empty tag" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/empty quoted name" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags are split apart when parsing" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags also properly handle exclusion" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Predicate matcher can accept const char*" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/empty args don't cause a crash" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/default - no arguments" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case using" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case exclusion using exclude:" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case exclusion using ~" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/-r/console" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/-r/xml" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/--reporter/junit" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/Only one reporter is accepted" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/must match one of the available ones" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/-b" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/--break" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-a aborts after first failure" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x 2 aborts after two failures" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x must be numeric" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/Accepted options" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/invalid options are reported" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/-e" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/--nothrow" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/output filename/-o filename" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/output filename/--out" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/combinations/Single character flags can be combined" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/without option" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/auto" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/samples" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/resamples" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/confidence-interval" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/no-analysis" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/warmup-time" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double, float>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Empty test spec should have no filters" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from empty string should have no filters" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from just a comma should have no filters" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from name should have one filter" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from quoted name should have one filter" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from name should have one filter" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at the start" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at the end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at both ends" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at the start" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at the end" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Redundant wildcard at both ends" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcard at both ends, redundant at start" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Just wildcard" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag, two matches" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Two tags" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Two tags, spare separated" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Wildcarded name and tag" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Single tag exclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion and one tag inclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion and one wldcarded name inclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/One tag exclusion, using exclude:, and one wldcarded name inclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/name exclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion with tag inclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/wildcarded name exclusion, using exclude:, with tag inclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/two wildcarded names" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/empty tag" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/empty quoted name" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags are split apart when parsing" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags also properly handle exclusion" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Predicate matcher can accept const char*" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/empty args don't cause a crash" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/default - no arguments" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case using" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case exclusion using exclude:" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/test lists/Specify one test case exclusion using ~" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/-r/console" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/-r/xml" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/--reporter/junit" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/Only one reporter is accepted" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/must match one of the available ones" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/-b" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/--break" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-a aborts after first failure" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x 2 aborts after two failures" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x must be numeric" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/Accepted options" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/invalid options are reported" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/-e" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/--nothrow" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/output filename/-o filename" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/output filename/--out" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/combinations/Single character flags can be combined" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/without option" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/auto" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/samples" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/resamples" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/confidence-interval" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/no-analysis" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/warmup-time" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double, float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}" status="run">
       <failure message="truthy(false)" type="CHECK">
 FAILED:
   CHECK( truthy(false) )
@@ -1035,7 +1054,7 @@ with expansion:
 Decomposition.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Regex string matcher" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Regex string matcher" time="{duration}" status="run">
       <failure message="testStringForMatching(), Matches(&quot;this STRING contains 'abc' as a substring&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), Matches("this STRING contains 'abc' as a substring") )
@@ -1061,19 +1080,19 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Regression test #1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="SUCCEED counts as a test pass" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="SUCCEED does not require an argument" time="{duration}"/>
-    <testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" time="{duration}"/>
-    <testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this/And: do that" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: This is a really long scenario name to see how the list command deals with wrapping/Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up/And when: it is made smaller again/Then: the size goes down but the capacity stays the same" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: we reserve more space/Then: The capacity is increased but the size remains the same" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Sends stuff to stdout and stderr" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Regression test #1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="SUCCEED counts as a test pass" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="SUCCEED does not require an argument" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this/And: do that" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: This is a really long scenario name to see how the list command deals with wrapping/Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up/And when: it is made smaller again/Then: the size goes down but the capacity stays the same" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: we reserve more space/Then: The capacity is increased but the size remains the same" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Sends stuff to stdout and stderr" time="{duration}" status="run">
       <system-out>
 A string sent directly to stdout
       </system-out>
@@ -1082,14 +1101,14 @@ A string sent directly to stderr
 A string sent to stderr via clog
       </system-err>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Some simple comparisons between doubles" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Standard output from all sections is reported/two" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Some simple comparisons between doubles" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Standard output from all sections is reported/two" time="{duration}" status="run">
       <system-out>
 Message from section one
 Message from section two
       </system-out>
     </testcase>
-    <testcase classname="<exe-name>.global" name="StartsWith string matcher" time="{duration}">
+    <testcase classname="<exe-name>.global" name="StartsWith string matcher" time="{duration}" status="run">
       <failure message="testStringForMatching(), StartsWith(&quot;This String&quot;)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( testStringForMatching(), StartsWith("This String") )
@@ -1106,31 +1125,31 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Single item" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Multiple" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Non-trivial inner items" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="String matchers" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Empty string" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/From string literal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/From sub-string" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/zero-based substring" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/non-zero-based substring" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of full refs should match" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/from std::string/assigned" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/to std::string/explicitly constructed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef/to std::string/assigned" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef at compilation time/Simple constructors" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="StringRef at compilation time/UDL construction" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration helpers" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration with weird ratios" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::time_point&lt;system_clock>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tabs and newlines show in output" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Single item" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Multiple" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Non-trivial inner items" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="String matchers" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Empty string" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/From string literal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/From sub-string" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/zero-based substring" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/non-zero-based substring" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of full refs should match" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/from std::string/assigned" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/to std::string/explicitly constructed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef/to std::string/assigned" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef at compilation time/Simple constructors" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="StringRef at compilation time/UDL construction" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration helpers" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration with weird ratios" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Stringifying std::chrono::time_point&lt;system_clock>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tabs and newlines show in output" time="{duration}" status="run">
       <failure message="s1 == s2" type="CHECK">
 FAILED:
   CHECK( s1 == s2 )
@@ -1146,103 +1165,103 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/The same tag alias can only be registered once" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/Tag aliases must be of the form [@name]" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
-    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Test case with one argument" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Test enum bit values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Test with special, characters &quot;in name" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="The NO_FAIL macro reports a failure but does not fail the test" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="This test 'should' fail but doesn't" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Thrown string literals are translated" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/The same tag alias can only be registered once" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/Tag aliases must be of the form [@name]" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 0" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 1" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - int/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::string/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Test case with one argument" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Test enum bit values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Test with special, characters &quot;in name" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="The NO_FAIL macro reports a failure but does not fail the test" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="This test 'should' fail but doesn't" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Thrown string literals are translated" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 For some reason someone is throwing a string literal!
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Tracker" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/fail one section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/fail one section/re-enter after failed section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/fail one section/re-enter after failed section and find next section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Tracker/open a nested section" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Trim strings" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Unexpected exceptions can be translated" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Tracker" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/fail one section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/fail one section/re-enter after failed section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/fail one section/re-enter after failed section and find next section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Tracker/open a nested section" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Trim strings" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Unexpected exceptions can be translated" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 3.14
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Use a custom approx" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Variadic macros/Section with one argument" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Empty vector is roughly equal to an empty vector" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/A vector is approx equal to itself" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Different length" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Same length, different elements" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Empty and non empty vectors are not approx equal" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Use a custom approx" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Variadic macros/Section with one argument" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Empty vector is roughly equal to an empty vector" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/A vector is approx equal to itself" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Different length" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Same length, different elements" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Empty and non empty vectors are not approx equal" time="{duration}" status="run">
       <failure message="empty, Approx(t1)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( empty, Approx(t1) )
@@ -1251,7 +1270,7 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Just different vectors" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Just different vectors" time="{duration}" status="run">
       <failure message="v1, Approx(v2)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( v1, Approx(v2) )
@@ -1260,12 +1279,12 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (element)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (vector)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (element), composed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector matchers/Equals" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector matchers/UnorderedEquals" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (element)" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (element)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (vector)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector matchers/Contains (element), composed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector matchers/Equals" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector matchers/UnorderedEquals" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (element)" time="{duration}" status="run">
       <failure message="v, VectorContains(-1)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( v, VectorContains(-1) )
@@ -1281,7 +1300,7 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (vector)" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (vector)" time="{duration}" status="run">
       <failure message="empty, Contains(v)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( empty, Contains(v) )
@@ -1297,7 +1316,7 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Equals" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Vector matchers that fail/Equals" time="{duration}" status="run">
       <failure message="v, Equals(v2)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( v, Equals(v2) )
@@ -1327,7 +1346,7 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Vector matchers that fail/UnorderedEquals" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Vector matchers that fail/UnorderedEquals" time="{duration}" status="run">
       <failure message="v, UnorderedEquals(empty)" type="CHECK_THAT">
 FAILED:
   CHECK_THAT( v, UnorderedEquals(empty) )
@@ -1357,15 +1376,15 @@ with expansion:
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="When checked exceptions are thrown they can be expected or unexpected" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown directly they are always failures" time="{duration}">
+    <testcase classname="<exe-name>.global" name="When checked exceptions are thrown they can be expected or unexpected" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown directly they are always failures" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 unexpected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a CHECK the test should continue" time="{duration}">
+    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a CHECK the test should continue" time="{duration}" status="run">
       <error message="thisThrows() == 0" type="CHECK">
 FAILED:
   CHECK( thisThrows() == 0 )
@@ -1373,7 +1392,7 @@ expected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" time="{duration}">
+    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" time="{duration}" status="run">
       <error message="thisThrows() == 0" type="REQUIRE">
 FAILED:
   REQUIRE( thisThrows() == 0 )
@@ -1381,7 +1400,7 @@ expected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from functions they are always failures" time="{duration}">
+    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from functions they are always failures" time="{duration}" status="run">
       <error message="thisThrows() == 0" type="CHECK">
 FAILED:
   CHECK( thisThrows() == 0 )
@@ -1389,33 +1408,33 @@ expected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from sections they are always failures/section name" time="{duration}">
+    <testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from sections they are always failures/section name" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 unexpected exception
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="Where the LHS is not a simple value" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="Where there is more to the expression after the RHS" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="X/level/0/a" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="X/level/0/b" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="X/level/1/a" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="X/level/1/b" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/normal string" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/empty string" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with ampersand" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with less-than" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with greater-than" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with quotes" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with control char (1)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="XmlEncode/string with control char (x7F)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="adding a hide tag implicitly enables all others" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="array&lt;int, N> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="atomic if" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="boolean member" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="checkedElse" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="checkedElse, failing" time="{duration}">
+    <testcase classname="<exe-name>.global" name="Where the LHS is not a simple value" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="Where there is more to the expression after the RHS" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="X/level/0/a" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="X/level/0/b" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="X/level/1/a" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="X/level/1/b" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/normal string" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/empty string" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with ampersand" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with less-than" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with greater-than" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with quotes" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with control char (1)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="XmlEncode/string with control char (x7F)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="adding a hide tag implicitly enables all others" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="array&lt;int, N> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="atomic if" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="boolean member" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="checkedElse" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="checkedElse, failing" time="{duration}" status="run">
       <failure message="flag" type="CHECKED_ELSE">
 FAILED:
   CHECKED_ELSE( flag )
@@ -1431,8 +1450,8 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="checkedIf" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="checkedIf, failing" time="{duration}">
+    <testcase classname="<exe-name>.global" name="checkedIf" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="checkedIf, failing" time="{duration}" status="run">
       <failure message="flag" type="CHECKED_IF">
 FAILED:
   CHECKED_IF( flag )
@@ -1448,27 +1467,27 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="comparisons between const int variables" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="comparisons between int variables" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/d (leaf)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/e (leaf)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/f (leaf)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="just failure" time="{duration}">
+    <testcase classname="<exe-name>.global" name="comparisons between const int variables" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="comparisons between int variables" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/d (leaf)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/e (leaf)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="even more nested SECTION tests/f (leaf)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="just failure" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 Previous info should not be seen
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="just failure after unscoped info" time="{duration}">
+    <testcase classname="<exe-name>.global" name="just failure after unscoped info" time="{duration}" status="run">
       <failure type="FAIL">
 FAILED:
 previous unscoped info SHOULD not be seen
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="long long" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 0" time="{duration}">
+    <testcase classname="<exe-name>.global" name="long long" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 0" time="{duration}" status="run">
       <failure message="b > a" type="CHECK">
 FAILED:
   CHECK( b > a )
@@ -1477,7 +1496,7 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 1" time="{duration}">
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 1" time="{duration}" status="run">
       <failure message="b > a" type="CHECK">
 FAILED:
   CHECK( b > a )
@@ -1486,15 +1505,15 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 2" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 3" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 4" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 5" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 6" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 7" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 8" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 9" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="looped tests" time="{duration}">
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 2" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 3" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 4" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 5" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 6" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 7" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 8" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 9" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="looped tests" time="{duration}" status="run">
       <failure message="( fib[i] % 2 ) == 0" type="CHECK">
 FAILED:
   CHECK( ( fib[i] % 2 ) == 0 )
@@ -1544,8 +1563,8 @@ Testing if fib[7] (21) is even
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="mix info, unscoped info and warning" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="more nested SECTION tests/equal/doesn't equal" time="{duration}">
+    <testcase classname="<exe-name>.global" name="mix info, unscoped info and warning" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="more nested SECTION tests/equal/doesn't equal" time="{duration}" status="run">
       <failure message="a == b" type="REQUIRE">
 FAILED:
   REQUIRE( a == b )
@@ -1554,14 +1573,14 @@ with expansion:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="more nested SECTION tests/doesn't equal/not equal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="more nested SECTION tests/doesn't equal/less than" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="nested SECTION tests/doesn't equal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="nested SECTION tests/doesn't equal/not equal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="non streamable - with conv. op" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="non-copyable objects" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="not allowed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}">
+    <testcase classname="<exe-name>.global" name="more nested SECTION tests/doesn't equal/not equal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="more nested SECTION tests/doesn't equal/less than" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="nested SECTION tests/doesn't equal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="nested SECTION tests/doesn't equal/not equal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="non streamable - with conv. op" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="non-copyable objects" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="not allowed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}" status="run">
       <failure message="false" type="REQUIRE">
 FAILED:
   REQUIRE( false )
@@ -1569,15 +1588,15 @@ this SHOULD be seen
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="null strings" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="null_ptr" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="pair&lt;pair&lt;int,const char *,pair&lt;std::string,int> > -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="parseEnums/No enums" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="parseEnums/One enum value" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="parseEnums/Multiple enum values" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="pointer to class" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}">
+    <testcase classname="<exe-name>.global" name="null strings" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="null_ptr" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="pair&lt;pair&lt;int,const char *,pair&lt;std::string,int> > -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="parseEnums/No enums" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="parseEnums/One enum value" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="parseEnums/Multiple enum values" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="pointer to class" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}" status="run">
       <failure message="false" type="REQUIRE">
 FAILED:
   REQUIRE( false )
@@ -1586,7 +1605,7 @@ this SHOULD also be seen
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}">
+    <testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}" status="run">
       <failure message="false" type="CHECK">
 FAILED:
   CHECK( false )
@@ -1594,16 +1613,16 @@ this SHOULD be seen only ONCE
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="random SECTION tests/doesn't equal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="random SECTION tests/not equal" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace single char" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace two chars" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace first char" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace last char" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace all chars" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/replace no chars" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="replaceInPlace/escape '" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="send a single char to INFO" time="{duration}">
+    <testcase classname="<exe-name>.global" name="random SECTION tests/doesn't equal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="random SECTION tests/not equal" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace single char" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace two chars" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace first char" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace last char" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace all chars" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/replace no chars" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="replaceInPlace/escape '" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="send a single char to INFO" time="{duration}" status="run">
       <failure message="false" type="REQUIRE">
 FAILED:
   REQUIRE( false )
@@ -1611,7 +1630,7 @@ FAILED:
 Misc.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="sends information to INFO" time="{duration}">
+    <testcase classname="<exe-name>.global" name="sends information to INFO" time="{duration}" status="run">
       <failure message="false" type="REQUIRE">
 FAILED:
   REQUIRE( false )
@@ -1620,9 +1639,9 @@ i := 7
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="shortened hide tags are split apart" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="splitString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stacks unscoped info in loops" time="{duration}">
+    <testcase classname="<exe-name>.global" name="shortened hide tags are split apart" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="splitString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stacks unscoped info in loops" time="{duration}" status="run">
       <failure message="false" type="CHECK">
 FAILED:
   CHECK( false )
@@ -1642,16 +1661,16 @@ Count 4 to 6...
 Message.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="std::map is convertible string/empty" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::map is convertible string/single item" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::map is convertible string/several items" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::pair&lt;int,const std::string> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::pair&lt;int,std::string> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::set is convertible string/empty" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::set is convertible string/single item" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::set is convertible string/several items" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="string literals of different sizes can be compared" time="{duration}">
+    <testcase classname="<exe-name>.global" name="std::map is convertible string/empty" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::map is convertible string/single item" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::map is convertible string/several items" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::pair&lt;int,const std::string> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::pair&lt;int,std::string> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::set is convertible string/empty" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::set is convertible string/single item" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::set is convertible string/several items" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="string literals of different sizes can be compared" time="{duration}" status="run">
       <failure message="std::string( &quot;first&quot; ) == &quot;second&quot;" type="REQUIRE">
 FAILED:
   REQUIRE( std::string( "first" ) == "second" )
@@ -1660,51 +1679,51 @@ with expansion:
 Tricky.tests.cpp:<line number>
       </failure>
     </testcase>
-    <testcase classname="<exe-name>.global" name="stringify ranges" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( has_maker )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( has_template_operator )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="strlen3" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tables" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
+    <testcase classname="<exe-name>.global" name="stringify ranges" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_maker )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_template_operator )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="strlen3" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tables" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}" status="run">
       <error type="TEST_CASE">
 FAILED:
 Why would you throw a std::string?
 Exception.tests.cpp:<line number>
       </error>
     </testcase>
-    <testcase classname="<exe-name>.global" name="toString on const wchar_t const pointer returns the string contents" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString on wchar_t returns the string contents" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString(enum class w/operator&lt;&lt;)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString(enum class)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="toString(enum)" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;float,int>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;int>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;0,int,const char *>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;string,string>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="tuple&lt;tuple&lt;int>,tuple&lt;>,float>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vec&lt;vec&lt;string,alloc>> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vector&lt;bool> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vector&lt;int,allocator> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vector&lt;int> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vector&lt;string> -> toString" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing bigger changes size and capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing smaller changes size but not capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/reserving bigger changes capacity but not size" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/reserving smaller does not change size or capacity" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="xmlentitycheck/embedded xml: &lt;test>it should be possible to embed xml characters, such as &lt;, &quot; or &amp;, or even whole &lt;xml>documents&lt;/xml> within an attribute&lt;/test>" time="{duration}"/>
-    <testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &amp;&amp;&amp;&quot;&quot;&quot;&lt;&lt;&lt;&amp;&quot;&lt;&lt;&amp;&quot;" time="{duration}"/>
+    <testcase classname="<exe-name>.global" name="toString on const wchar_t const pointer returns the string contents" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString on const wchar_t pointer returns the string contents" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString on wchar_t const pointer returns the string contents" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString on wchar_t returns the string contents" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString(enum class w/operator&lt;&lt;)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString(enum class)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString(enum w/operator&lt;&lt;)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="toString(enum)" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;float,int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;int>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;0,int,const char *>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;string,string>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="tuple&lt;tuple&lt;int>,tuple&lt;>,float>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vec&lt;vec&lt;string,alloc>> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vector&lt;bool> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vector&lt;int,allocator> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vector&lt;int> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vector&lt;string> -> toString" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing bigger changes size and capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing smaller changes size but not capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/reserving bigger changes capacity but not size" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="vectors can be sized and resized/reserving smaller does not change size or capacity" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="xmlentitycheck/embedded xml: &lt;test>it should be possible to embed xml characters, such as &lt;, &quot; or &amp;, or even whole &lt;xml>documents&lt;/xml> within an attribute&lt;/test>" time="{duration}" status="run"/>
+    <testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &amp;&amp;&amp;&quot;&quot;&quot;&lt;&lt;&lt;&amp;&quot;&lt;&lt;&amp;&quot;" time="{duration}" status="run"/>
     <system-out>
 This would not be caught previously
 A string sent directly to stdout
diff --git a/packages/Catch2/projects/SelfTest/Baselines/sonarqube.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/sonarqube.sw.approved.txt
index 72fdd780190ff3caa016fa9bc5cf172ea1566e03..35360ebcaca76e2109cfc776c198c4b39c0d922c 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/sonarqube.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/sonarqube.sw.approved.txt
@@ -3,6 +3,8 @@
 >
   <file path="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp">
     <testCase name="#1905 -- test spec parser properly clears internal state between compound tests" duration="{duration}"/>
+    <testCase name="#1912 -- test spec parser handles escaping/Various parentheses" duration="{duration}"/>
+    <testCase name="#1912 -- test spec parser handles escaping/backslash in test name" duration="{duration}"/>
     <testCase name="Parse test names and tags/Empty test spec should have no filters" duration="{duration}"/>
     <testCase name="Parse test names and tags/Test spec from empty string should have no filters" duration="{duration}"/>
     <testCase name="Parse test names and tags/Test spec from just a comma should have no filters" duration="{duration}"/>
@@ -97,6 +99,15 @@
     <testCase name="Generators internals/Range/Negative manual step/Integer/Slightly under end" duration="{duration}"/>
   </file>
   <file path="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp">
+    <testCase name="#1938 - GENERATE after a section/A" duration="{duration}"/>
+    <testCase name="#1938 - GENERATE after a section/B" duration="{duration}"/>
+    <testCase name="#1938 - Section followed by flat generate" duration="{duration}"/>
+    <testCase name="#1938 - Section followed by flat generate/A" duration="{duration}"/>
+    <testCase name="#1938 - flat generate" duration="{duration}"/>
+    <testCase name="#1938 - mixed sections and generates" duration="{duration}"/>
+    <testCase name="#1938 - mixed sections and generates/A" duration="{duration}"/>
+    <testCase name="#1938 - mixed sections and generates/B" duration="{duration}"/>
+    <testCase name="#1938 - nested generate" duration="{duration}"/>
     <testCase name="Tracker" duration="{duration}"/>
     <testCase name="Tracker/successfully close one section" duration="{duration}"/>
     <testCase name="Tracker/fail one section" duration="{duration}"/>
@@ -370,6 +381,7 @@ Class.tests.cpp:<line number>
     <testCase name="#809" duration="{duration}"/>
     <testCase name="#833" duration="{duration}"/>
     <testCase name="#872" duration="{duration}"/>
+    <testCase name="Assertion macros support bit operators and bool conversions" duration="{duration}"/>
     <testCase name="Lambdas in assertions" duration="{duration}"/>
     <testCase name="Optionally static assertions" duration="{duration}"/>
   </file>
@@ -872,6 +884,8 @@ Exception.tests.cpp:<line number>
     </testCase>
   </file>
   <file path="projects/<exe-name>/UsageTests/Generators.tests.cpp">
+    <testCase name="#1913 - GENERATE inside a for loop should not keep recreating the generator" duration="{duration}"/>
+    <testCase name="#1913 - GENERATEs can share a line" duration="{duration}"/>
     <testCase name="3x3x3 ints" duration="{duration}"/>
     <testCase name="Copy and then generate a range/from var and iterators" duration="{duration}"/>
     <testCase name="Copy and then generate a range/From a temporary container" duration="{duration}"/>
@@ -897,6 +911,8 @@ Exception.tests.cpp:<line number>
     <testCase name="Arbitrary predicate matcher/Function pointer" duration="{duration}"/>
     <testCase name="Arbitrary predicate matcher/Lambdas + different type" duration="{duration}"/>
     <testCase name="Composed matchers are distinct" duration="{duration}"/>
+    <testCase name="Composed matchers shortcircuit/&amp;&amp;" duration="{duration}"/>
+    <testCase name="Composed matchers shortcircuit/||" duration="{duration}"/>
     <testCase name="Contains string matcher" duration="{duration}">
       <failure message="CHECK_THAT(testStringForMatching(), Contains(&quot;not there&quot;, Catch::CaseSensitive::No))">
 FAILED:
@@ -1347,6 +1363,9 @@ Message.tests.cpp:<line number>
   <file path="projects/<exe-name>/UsageTests/Misc.tests.cpp">
     <testCase name="# A test name that starts with a #" duration="{duration}"/>
     <testCase name="#1175 - Hidden Test" duration="{duration}"/>
+    <testCase name="#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0" duration="{duration}"/>
+    <testCase name="#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0" duration="{duration}"/>
+    <testCase name="#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0" duration="{duration}"/>
     <testCase name="#835 -- errno should not be touched by Catch" duration="{duration}">
       <skipped message="CHECK(f() == 0)">
 FAILED:
diff --git a/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
index 807a946e68e1da07a5710f2bf2580145cbb82426..30d113efe1a61d36ac262267043605dde5d08bfc 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
@@ -223,6 +223,446 @@ Nor would this
       </Expression>
       <OverallResult success="true"/>
     </TestCase>
+    <TestCase name="#1912 -- test spec parser handles escaping" tags="[command-line][test-spec]" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+      <Section name="Various parentheses" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+          <Original>
+            spec.matches(fakeTestCase(R"(spec {a} char)"))
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+          <Original>
+            spec.matches(fakeTestCase(R"(spec [a] char)"))
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+          <Original>
+            !(spec.matches(fakeTestCase("differs but has similar tag", "[a]")))
+          </Original>
+          <Expanded>
+            !false
+          </Expanded>
+        </Expression>
+        <OverallResults successes="3" failures="0" expectedFailures="0"/>
+      </Section>
+      <Section name="backslash in test name" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+          <Original>
+            spec.matches(fakeTestCase(R"(spec \ char)"))
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1913 - GENERATE inside a for loop should not keep recreating the generator" tags="[generators][regression]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          counter &lt; 7
+        </Original>
+        <Expanded>
+          3 &lt; 7
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          counter &lt; 7
+        </Original>
+        <Expanded>
+          6 &lt; 7
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1913 - GENERATEs can share a line" tags="[generators][regression]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          i != j
+        </Original>
+        <Expanded>
+          1 != 3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          i != j
+        </Original>
+        <Expanded>
+          1 != 4
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          i != j
+        </Original>
+        <Expanded>
+          2 != 3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+        <Original>
+          i != j
+        </Original>
+        <Expanded>
+          2 != 4
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1938 - GENERATE after a section" tags="[!hide][.][generators][regression]" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+      <Section name="A" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+          <Original>
+            m
+          </Original>
+          <Expanded>
+            1
+          </Expanded>
+        </Expression>
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+          <Original>
+            m
+          </Original>
+          <Expanded>
+            2
+          </Expanded>
+        </Expression>
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+          <Original>
+            m
+          </Original>
+          <Expanded>
+            3
+          </Expanded>
+        </Expression>
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1938 - Section followed by flat generate" tags="[!hide][.][generators][regression]" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+      <Section name="A" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+          <Original>
+            1
+          </Original>
+          <Expanded>
+            1
+          </Expanded>
+        </Expression>
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1938 - flat generate" tags="[!hide][.][generators][regression]" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1938 - mixed sections and generates" tags="[!hide][.][generators][regression]" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+      <Section name="A" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 1
+      </Info>
+      <Info>
+        j := 3
+      </Info>
+      <Info>
+        k := 5
+      </Info>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 1
+      </Info>
+      <Info>
+        j := 3
+      </Info>
+      <Info>
+        k := 6
+      </Info>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 1
+      </Info>
+      <Info>
+        j := 4
+      </Info>
+      <Info>
+        k := 5
+      </Info>
+      <Info>
+        i := 1
+      </Info>
+      <Info>
+        j := 4
+      </Info>
+      <Info>
+        k := 6
+      </Info>
+      <Section name="A" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 2
+      </Info>
+      <Info>
+        j := 3
+      </Info>
+      <Info>
+        k := 5
+      </Info>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 2
+      </Info>
+      <Info>
+        j := 3
+      </Info>
+      <Info>
+        k := 6
+      </Info>
+      <Section name="B" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+      </Section>
+      <Info>
+        i := 2
+      </Info>
+      <Info>
+        j := 4
+      </Info>
+      <Info>
+        k := 5
+      </Info>
+      <Info>
+        i := 2
+      </Info>
+      <Info>
+        j := 4
+      </Info>
+      <Info>
+        k := 6
+      </Info>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1938 - nested generate" tags="[!hide][.][generators][regression]" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          m
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
+        <Original>
+          n
+        </Original>
+        <Expanded>
+          3
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0" tags="[!hide][.][compilation][regression]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0" tags="[!hide][.][compilation][regression]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+      <OverallResult success="true"/>
+    </TestCase>
+    <TestCase name="#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0" tags="[!hide][.][compilation][regression]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+      <OverallResult success="true"/>
+    </TestCase>
     <TestCase name="#748 - captures with unexpected exceptions" tags="[!hide][!shouldfail][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
       <Section name="outside assertions" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
         <Info>
@@ -2136,6 +2576,49 @@ Nor would this
       </Section>
       <OverallResult success="true"/>
     </TestCase>
+    <TestCase name="Assertion macros support bit operators and bool conversions" tags="[bitops][compilation]" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+        <Original>
+          lhs | rhs
+        </Original>
+        <Expanded>
+          Val: 1 | Val: 2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+        <Original>
+          !(lhs &amp; rhs)
+        </Original>
+        <Expanded>
+          !(Val: 1 &amp; Val: 2)
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+        <Original>
+          HasBitOperators{ 1 } &amp; HasBitOperators{ 1 }
+        </Original>
+        <Expanded>
+          Val: 1 &amp; Val: 1
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+        <Original>
+          lhs ^ rhs
+        </Original>
+        <Expanded>
+          Val: 1 ^ Val: 2
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+        <Original>
+          !(lhs ^ lhs)
+        </Original>
+        <Expanded>
+          !(Val: 1 ^ Val: 1)
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
     <TestCase name="Assertions then sections" tags="[Tricky]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
       <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
         <Original>
@@ -2878,6 +3361,63 @@ Nor would this
       </Expression>
       <OverallResult success="true"/>
     </TestCase>
+    <TestCase name="Composed matchers shortcircuit" tags="[composed][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+      <Section name="&amp;&amp;" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+        <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            1, !(first &amp;&amp; second)
+          </Original>
+          <Expanded>
+            1 not ( CheckedTestingMatcher set to fail and CheckedTestingMatcher set to fail )
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            first.matchCalled
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            !second.matchCalled
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <OverallResults successes="3" failures="0" expectedFailures="0"/>
+      </Section>
+      <Section name="||" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+        <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            1, first || second
+          </Original>
+          <Expanded>
+            1 ( CheckedTestingMatcher set to succeed or CheckedTestingMatcher set to fail )
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            first.matchCalled
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            !second.matchCalled
+          </Original>
+          <Expanded>
+            true
+          </Expanded>
+        </Expression>
+        <OverallResults successes="3" failures="0" expectedFailures="0"/>
+      </Section>
+      <OverallResult success="true"/>
+    </TestCase>
     <TestCase name="Contains string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
       <Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
         <Original>
@@ -13556,9 +14096,17 @@ There is no extra whitespace here
               { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
             </Expanded>
           </Expression>
-          <OverallResults successes="1" failures="0" expectedFailures="0"/>
+          <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+            <Original>
+              v1, Approx&lt;double>({ 1., 2., 3. })
+            </Original>
+            <Expanded>
+              { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
+            </Expanded>
+          </Expression>
+          <OverallResults successes="2" failures="0" expectedFailures="0"/>
         </Section>
-        <OverallResults successes="1" failures="0" expectedFailures="0"/>
+        <OverallResults successes="2" failures="0" expectedFailures="0"/>
       </Section>
       <Section name="Vectors with elements" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
         <Section name="Different length" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -13676,6 +14224,14 @@ There is no extra whitespace here
             { 1, 2, 3 } Contains: { 1, 2 }
           </Expanded>
         </Expression>
+        <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            v, Contains&lt;int>({ 1, 2 })
+          </Original>
+          <Expanded>
+            { 1, 2, 3 } Contains: { 1, 2 }
+          </Expanded>
+        </Expression>
         <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
           <Original>
             v5, (Contains&lt;int, std::allocator&lt;int>, CustomAllocator&lt;int>>(v2))
@@ -13724,7 +14280,7 @@ There is no extra whitespace here
             { 1, 2, 3 } Contains: { 1, 2 }
           </Expanded>
         </Expression>
-        <OverallResults successes="7" failures="0" expectedFailures="0"/>
+        <OverallResults successes="8" failures="0" expectedFailures="0"/>
       </Section>
       <Section name="Contains (element), composed" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
         <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -13754,6 +14310,14 @@ There is no extra whitespace here
             {  } Equals: {  }
           </Expanded>
         </Expression>
+        <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            v, Equals&lt;int>({ 1, 2, 3 })
+          </Original>
+          <Expanded>
+            { 1, 2, 3 } Equals: { 1, 2, 3 }
+          </Expanded>
+        </Expression>
         <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
           <Original>
             v, Equals(v2)
@@ -13778,7 +14342,7 @@ There is no extra whitespace here
             { 1, 2, 3 } Equals: { 1, 2, 3 }
           </Expanded>
         </Expression>
-        <OverallResults successes="5" failures="0" expectedFailures="0"/>
+        <OverallResults successes="6" failures="0" expectedFailures="0"/>
       </Section>
       <Section name="UnorderedEquals" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
         <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -13789,6 +14353,14 @@ There is no extra whitespace here
             { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 }
           </Expanded>
         </Expression>
+        <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+          <Original>
+            v, UnorderedEquals&lt;int>({ 3, 2, 1 })
+          </Original>
+          <Expanded>
+            { 1, 2, 3 } UnorderedEquals: { 3, 2, 1 }
+          </Expanded>
+        </Expression>
         <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
           <Original>
             empty, UnorderedEquals(empty)
@@ -13829,7 +14401,7 @@ There is no extra whitespace here
             { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 }
           </Expanded>
         </Expression>
-        <OverallResults successes="6" failures="0" expectedFailures="0"/>
+        <OverallResults successes="7" failures="0" expectedFailures="0"/>
       </Section>
       <OverallResult success="true"/>
     </TestCase>
@@ -16139,7 +16711,9 @@ loose text artifact
       </Section>
       <OverallResult success="true"/>
     </TestCase>
-    <OverallResults successes="1536" failures="149" expectedFailures="21"/>
+    <OverallResults successes="1606" failures="149" expectedFailures="21"/>
+    <OverallResultsCases successes="231" failures="86" expectedFailures="4"/>
   </Group>
-  <OverallResults successes="1536" failures="148" expectedFailures="21"/>
+  <OverallResults successes="1606" failures="148" expectedFailures="21"/>
+  <OverallResultsCases successes="231" failures="86" expectedFailures="4"/>
 </Catch>
diff --git a/packages/Catch2/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/packages/Catch2/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
index 0d8232e0a11c507a349d6f005e9e46bfca16ec3e..488957178e2411b945d70fead10fd1ef308d1609 100644
--- a/packages/Catch2/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
@@ -303,6 +303,24 @@ TEST_CASE("#1905 -- test spec parser properly clears internal state between comp
     REQUIRE_FALSE(spec.matches(fakeTestCase(R"(spec \, char)")));
 }
 
+TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spec]") {
+    using Catch::parseTestSpec;
+    using Catch::TestSpec;
+
+    SECTION("Various parentheses") {
+        TestSpec spec = parseTestSpec(R"(spec {a} char,spec \[a] char)");
+
+        REQUIRE(spec.matches(fakeTestCase(R"(spec {a} char)")));
+        REQUIRE(spec.matches(fakeTestCase(R"(spec [a] char)")));
+        REQUIRE_FALSE(spec.matches(fakeTestCase("differs but has similar tag", "[a]")));
+    }
+    SECTION("backslash in test name") {
+        TestSpec spec = parseTestSpec(R"(spec \\ char)");
+
+        REQUIRE(spec.matches(fakeTestCase(R"(spec \ char)")));
+    }
+}
+
 TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
 
 #ifndef CATCH_CONFIG_DISABLE_MATCHERS
diff --git a/packages/Catch2/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp b/packages/Catch2/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
index 837d3661b1be400ff7342ffd188e40e83058c968..41a7bc0a89ffd7fd1488255cca45de83c8878ed5 100644
--- a/packages/Catch2/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
@@ -204,3 +204,50 @@ TEST_CASE("#1670 regression check", "[.approvals][tracker]") {
         SECTION("2") SUCCEED();
     }
 }
+
+// #1938 required a rework on how generator tracking works, so that `GENERATE`
+// supports being sandwiched between two `SECTION`s. The following tests check
+// various other scenarios through checking output in approval tests.
+TEST_CASE("#1938 - GENERATE after a section", "[.][regression][generators]") {
+    SECTION("A") {
+        SUCCEED("A");
+    }
+    auto m = GENERATE(1, 2, 3);
+    SECTION("B") {
+        REQUIRE(m);
+    }
+}
+
+TEST_CASE("#1938 - flat generate", "[.][regression][generators]") {
+    auto m = GENERATE(1, 2, 3);
+    REQUIRE(m);
+}
+
+TEST_CASE("#1938 - nested generate", "[.][regression][generators]") {
+    auto m = GENERATE(1, 2, 3);
+    auto n = GENERATE(1, 2, 3);
+    REQUIRE(m);
+    REQUIRE(n);
+}
+
+TEST_CASE("#1938 - mixed sections and generates", "[.][regression][generators]") {
+    auto i = GENERATE(1, 2);
+    SECTION("A") {
+        SUCCEED("A");
+    }
+    auto j = GENERATE(3, 4);
+    SECTION("B") {
+        SUCCEED("B");
+    }
+    auto k = GENERATE(5, 6);
+    CAPTURE(i, j, k);
+    SUCCEED();
+}
+
+TEST_CASE("#1938 - Section followed by flat generate", "[.][regression][generators]") {
+    SECTION("A") {
+        REQUIRE(1);
+    }
+    auto m = GENERATE(2, 3);
+    REQUIRE(m);
+}
diff --git a/packages/Catch2/projects/SelfTest/TimingTests/Sleep.tests.cpp b/packages/Catch2/projects/SelfTest/TimingTests/Sleep.tests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..672d9efb7c9a1f9d9e4fb8d9e10ed50e8059b935
--- /dev/null
+++ b/packages/Catch2/projects/SelfTest/TimingTests/Sleep.tests.cpp
@@ -0,0 +1,23 @@
+/*
+ *  Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "catch.hpp"
+
+#include <chrono>
+#include <thread>
+
+TEST_CASE( "sleep_for_100ms", "[.min_duration_test][approvals]" )
+{
+  std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
+  CHECK( true );
+}
+
+TEST_CASE( "sleep_for_250ms", "[.min_duration_test][approvals]" )
+{
+  std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) );
+  CHECK( true );
+}
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/Compilation.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/Compilation.tests.cpp
index 0baf2842ba4de01494b6f8628d2c3fad3bf4c6de..850d5f9b1a2f8b76a975b205d60d6120c15c1a49 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/Compilation.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/Compilation.tests.cpp
@@ -234,3 +234,36 @@ namespace { namespace CompilationTests {
 
 }} // namespace CompilationTests
 
+namespace {
+    struct HasBitOperators {
+        int value;
+
+        friend HasBitOperators operator| (HasBitOperators lhs, HasBitOperators rhs) {
+            return { lhs.value | rhs.value };
+        }
+        friend HasBitOperators operator& (HasBitOperators lhs, HasBitOperators rhs) {
+            return { lhs.value & rhs.value };
+        }
+        friend HasBitOperators operator^ (HasBitOperators lhs, HasBitOperators rhs) {
+            return { lhs.value ^ rhs.value };
+        }
+        explicit operator bool() const {
+            return !!value;
+        }
+
+        friend std::ostream& operator<<(std::ostream& out, HasBitOperators val) {
+            out << "Val: " << val.value;
+            return out;
+        }
+    };
+}
+
+TEST_CASE("Assertion macros support bit operators and bool conversions", "[compilation][bitops]") {
+    HasBitOperators lhs{ 1 }, rhs{ 2 };
+    REQUIRE(lhs | rhs);
+    REQUIRE_FALSE(lhs & rhs);
+    REQUIRE(HasBitOperators{ 1 } & HasBitOperators{ 1 });
+    REQUIRE(lhs ^ rhs);
+    REQUIRE_FALSE(lhs ^ lhs);
+}
+
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/Generators.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/Generators.tests.cpp
index 0e39bd5cbfce337ead5e17e7604e1ceb7297a069..f2906dbf505a937f276b3a027e8fc87ff99050e4 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/Generators.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/Generators.tests.cpp
@@ -251,6 +251,23 @@ TEST_CASE("Copy and then generate a range", "[generators]") {
     }
 }
 
+TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") {
+    static int counter = 0;
+    for (int i = 0; i < 3; ++i) {
+        int _ = GENERATE(1, 2);
+        (void)_;
+        ++counter;
+    }
+    // There should be at most 6 (3 * 2) counter increments
+    REQUIRE(counter < 7);
+}
+
+TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") {
+    int i = GENERATE(1, 2); int j = GENERATE(3, 4);
+    REQUIRE(i != j);
+}
+
+
 #if defined(__clang__)
 #pragma clang diagnostic pop
 #endif
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
index e7a1d5424f3956bd84604ff8470fae610ab445fe..1797d4a1c832350a5cfb642f4b7d3d768c1eb379 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
@@ -288,6 +288,7 @@ namespace { namespace MatchersTests {
             }
             SECTION("Contains (vector)") {
                 CHECK_THAT(v, Contains(v2));
+                CHECK_THAT(v, Contains<int>({ 1, 2 }));
                 CHECK_THAT(v5, (Contains<int, std::allocator<int>, CustomAllocator<int>>(v2)));
 
                 v2.push_back(3); // now exactly matches
@@ -307,10 +308,10 @@ namespace { namespace MatchersTests {
 
                 // Same vector
                 CHECK_THAT(v, Equals(v));
-
                 CHECK_THAT(empty, Equals(empty));
 
                 // Different vector with same elements
+                CHECK_THAT(v, Equals<int>({ 1, 2, 3 }));
                 v2.push_back(3);
                 CHECK_THAT(v, Equals(v2));
 
@@ -321,6 +322,7 @@ namespace { namespace MatchersTests {
             }
             SECTION("UnorderedEquals") {
                 CHECK_THAT(v, UnorderedEquals(v));
+                CHECK_THAT(v, UnorderedEquals<int>({ 3, 2, 1 }));
                 CHECK_THAT(empty, UnorderedEquals(empty));
 
                 auto permuted = v;
@@ -580,6 +582,7 @@ namespace { namespace MatchersTests {
                 std::vector<double> v1({1., 2., 3.});
                 SECTION("A vector is approx equal to itself") {
                     REQUIRE_THAT(v1, Approx(v1));
+                    REQUIRE_THAT(v1, Approx<double>({ 1., 2., 3. }));
                 }
                 std::vector<double> v2({1.5, 2.5, 3.5});
                 SECTION("Different length") {
@@ -614,7 +617,7 @@ namespace { namespace MatchersTests {
             REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, !Message("DerivedException::what"));
             REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException,  Message("SpecialException::what"));
         }
-        
+
         TEST_CASE("Composed matchers are distinct", "[matchers][composed]") {
             auto m1 = Contains("string");
             auto m2 = Contains("random");
@@ -625,6 +628,45 @@ namespace { namespace MatchersTests {
             REQUIRE_THAT(testStringForMatching2(), composed2);
         }
 
+        struct CheckedTestingMatcher : Catch::MatcherBase<int> {
+            mutable bool matchCalled = false;
+            bool matchSucceeds = false;
+
+            bool match(int const&) const override {
+                matchCalled = true;
+                return matchSucceeds;
+            }
+            std::string describe() const override {
+                return "CheckedTestingMatcher set to " + (matchSucceeds ? std::string("succeed") : std::string("fail"));
+            }
+        };
+
+        TEST_CASE("Composed matchers shortcircuit", "[matchers][composed]") {
+            // Check that if first returns false, second is not touched
+            CheckedTestingMatcher first, second;
+            SECTION("&&") {
+                first.matchSucceeds = false;
+                // This assertion doesn't actually test anything, we just
+                // want the composed matcher's `match` being called.
+                CHECK_THAT(1, !(first && second));
+
+                // These two assertions are the important ones
+                REQUIRE(first.matchCalled);
+                REQUIRE(!second.matchCalled);
+            }
+            // Check that if first returns true, second is not touched
+            SECTION("||") {
+                first.matchSucceeds = true;
+                // This assertion doesn't actually test anything, we just
+                // want the composed matcher's `match` being called.
+                CHECK_THAT(1, first || second);
+
+                // These two assertions are the important ones
+                REQUIRE(first.matchCalled);
+                REQUIRE(!second.matchCalled);
+            }
+        }
+
 } } // namespace MatchersTests
 
 #endif // CATCH_CONFIG_DISABLE_MATCHERS
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/Misc.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/Misc.tests.cpp
index 808d1d0af13c2e52070d92ee628cd75fa9237c9b..dcd9fc8a8af8710dd2c6e2691243c50b772eedfc 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/Misc.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/Misc.tests.cpp
@@ -484,4 +484,10 @@ TEST_CASE( "#1175 - Hidden Test", "[.]" ) {
   SUCCEED();
 }
 
+TEMPLATE_TEST_CASE_SIG("#1954 - 7 arg template test case sig compiles", "[regression][.compilation]",
+                       ((int Tnx, int Tnu, int Tny, int Tph, int Tch, int Tineq, int Teq), Tnx, Tnu, Tny, Tph, Tch, Tineq, Teq),
+                       (1, 1, 1, 1, 1, 0, 0), (5, 1, 1, 1, 1, 0, 0), (5, 3, 1, 1, 1, 0, 0)) {
+    SUCCEED();
+}
+
 }} // namespace MiscTests
diff --git a/packages/Catch2/projects/TestScripts/testRandomOrder.py b/packages/Catch2/projects/TestScripts/testRandomOrder.py
index a6ffb996d778be666ad3e8a1dfec3a1b0d459e00..fc245b85f39288721f0c04ec383c2c0f5649f616 100755
--- a/packages/Catch2/projects/TestScripts/testRandomOrder.py
+++ b/packages/Catch2/projects/TestScripts/testRandomOrder.py
@@ -15,9 +15,9 @@ import random
 def list_tests(self_test_exe, tags, rng_seed):
     cmd = [self_test_exe, '--list-test-names-only', '--order', 'rand',
             '--rng-seed', str(rng_seed)]
-    tags_arg = ','.join('[{}]'.format(t) for t in tags)
+    tags_arg = ','.join('[{}]~[.]'.format(t) for t in tags)
     if tags_arg:
-        cmd.append(tags_arg + '~[.]')
+        cmd.append(tags_arg)
     process = subprocess.Popen(
             cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     stdout, stderr = process.communicate()
diff --git a/packages/Catch2/scripts/updateDocumentToC.py b/packages/Catch2/scripts/updateDocumentToC.py
old mode 100644
new mode 100755
diff --git a/packages/Catch2/single_include/catch2/catch.hpp b/packages/Catch2/single_include/catch2/catch.hpp
index 51618b38e9e4706602c2ce267b12b419987730d9..cf1fae15aace281f5ca3a764e8a619878bd5790b 100644
--- a/packages/Catch2/single_include/catch2/catch.hpp
+++ b/packages/Catch2/single_include/catch2/catch.hpp
@@ -1,6 +1,6 @@
 /*
- *  Catch v2.11.3
- *  Generated: 2020-03-19 13:44:21.042491
+ *  Catch v2.13.0
+ *  Generated: 2020-07-12 20:07:49.015950
  *  ----------------------------------------------------------
  *  This file has been merged from multiple headers. Please don't edit it directly
  *  Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
@@ -14,8 +14,8 @@
 
 
 #define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 11
-#define CATCH_VERSION_PATCH 3
+#define CATCH_VERSION_MINOR 13
+#define CATCH_VERSION_PATCH 0
 
 #ifdef __clang__
 #    pragma clang system_header
@@ -132,7 +132,7 @@ namespace Catch {
 
 #endif
 
-#if defined(CATCH_CPP17_OR_GREATER)
+#if defined(__cpp_lib_uncaught_exceptions)
 #  define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
 #endif
 
@@ -151,7 +151,20 @@ namespace Catch {
 #    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
 #    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  _Pragma( "clang diagnostic pop" )
 
-#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
+// which results in calls to destructors being emitted for each temporary,
+// without a matching initialization. In practice, this can result in something
+// like `std::string::~string` being called on an uninitialized value.
+//
+// For example, this code will likely segfault under IBM XL:
+// ```
+// REQUIRE(std::string("12") + "34" == "1234")
+// ```
+//
+// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
+#  if !defined(__ibmxl__)
+#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
+#  endif
 
 #    define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
@@ -762,7 +775,7 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n
 #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
 #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
 #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
-#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
 #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
 #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
 #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
@@ -931,13 +944,13 @@ namespace Catch {
 
 #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
     // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
-    // replaced with std::invoke_result here. Also *_t format is preferred over
-    // typename *::type format.
-    template <typename Func, typename U>
-    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
+    // replaced with std::invoke_result here.
+    template <typename Func, typename... U>
+    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
 #else
-    template <typename Func, typename U>
-    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
+    // Keep ::type here because we still support C++11
+    template <typename Func, typename... U>
+    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;
 #endif
 
 } // namespace Catch
@@ -1975,20 +1988,27 @@ namespace Catch {
 #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
 
 namespace Catch {
-    struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
-
-    // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+    // Import begin/ end from std here
     using std::begin;
     using std::end;
 
-    not_this_one begin( ... );
-    not_this_one end( ... );
+    namespace detail {
+        template <typename...>
+        struct void_type {
+            using type = void;
+        };
+
+        template <typename T, typename = void>
+        struct is_range_impl : std::false_type {
+        };
+
+        template <typename T>
+        struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {
+        };
+    } // namespace detail
 
     template <typename T>
-    struct is_range {
-        static const bool value =
-            !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
-            !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
+    struct is_range : detail::is_range_impl<T> {
     };
 
 #if defined(_MANAGED) // Managed types are never ranges
@@ -2356,6 +2376,18 @@ namespace Catch {
         auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
             return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
         }
+        template <typename RhsT>
+        auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
+        }
+        template <typename RhsT>
+        auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
+        }
+        template <typename RhsT>
+        auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
+        }
 
         template<typename RhsT>
         auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
@@ -2436,7 +2468,7 @@ namespace Catch {
         virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
         virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
 
-        virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+        virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
         virtual void benchmarkPreparing( std::string const& name ) = 0;
@@ -3000,6 +3032,9 @@ namespace Catch {
             {}
 
             std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+                return "";
+#else
                 try {
                     if( it == itEnd )
                         std::rethrow_exception(std::current_exception());
@@ -3009,6 +3044,7 @@ namespace Catch {
                 catch( T& ex ) {
                     return m_translateFunction( ex );
                 }
+#endif
             }
 
         protected:
@@ -3571,12 +3607,12 @@ namespace Catch {
 namespace Matchers {
 
     namespace Vector {
-        template<typename T>
-        struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
+        template<typename T, typename Alloc>
+        struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
 
             ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
 
-            bool match(std::vector<T> const &v) const override {
+            bool match(std::vector<T, Alloc> const &v) const override {
                 for (auto const& el : v) {
                     if (el == m_comparator) {
                         return true;
@@ -3592,12 +3628,12 @@ namespace Matchers {
             T const& m_comparator;
         };
 
-        template<typename T>
-        struct ContainsMatcher : MatcherBase<std::vector<T>> {
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
 
-            ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+            ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
 
-            bool match(std::vector<T> const &v) const override {
+            bool match(std::vector<T, AllocMatch> const &v) const override {
                 // !TBD: see note in EqualsMatcher
                 if (m_comparator.size() > v.size())
                     return false;
@@ -3619,18 +3655,18 @@ namespace Matchers {
                 return "Contains: " + ::Catch::Detail::stringify( m_comparator );
             }
 
-            std::vector<T> const& m_comparator;
+            std::vector<T, AllocComp> const& m_comparator;
         };
 
-        template<typename T>
-        struct EqualsMatcher : MatcherBase<std::vector<T>> {
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
 
-            EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+            EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
 
-            bool match(std::vector<T> const &v) const override {
+            bool match(std::vector<T, AllocMatch> const &v) const override {
                 // !TBD: This currently works if all elements can be compared using !=
                 // - a more general approach would be via a compare template that defaults
-                // to using !=. but could be specialised for, e.g. std::vector<T> etc
+                // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
                 // - then just call that directly
                 if (m_comparator.size() != v.size())
                     return false;
@@ -3642,15 +3678,15 @@ namespace Matchers {
             std::string describe() const override {
                 return "Equals: " + ::Catch::Detail::stringify( m_comparator );
             }
-            std::vector<T> const& m_comparator;
+            std::vector<T, AllocComp> const& m_comparator;
         };
 
-        template<typename T>
-        struct ApproxMatcher : MatcherBase<std::vector<T>> {
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
 
-            ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}
+            ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
 
-            bool match(std::vector<T> const &v) const override {
+            bool match(std::vector<T, AllocMatch> const &v) const override {
                 if (m_comparator.size() != v.size())
                     return false;
                 for (std::size_t i = 0; i < v.size(); ++i)
@@ -3677,16 +3713,14 @@ namespace Matchers {
                 return *this;
             }
 
-            std::vector<T> const& m_comparator;
+            std::vector<T, AllocComp> const& m_comparator;
             mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
         };
 
-        template<typename T>
-        struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
-            UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
-            bool match(std::vector<T> const& vec) const override {
-                // Note: This is a reimplementation of std::is_permutation,
-                //       because I don't want to include <algorithm> inside the common path
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+            UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
+            bool match(std::vector<T, AllocMatch> const& vec) const override {
                 if (m_target.size() != vec.size()) {
                     return false;
                 }
@@ -3697,7 +3731,7 @@ namespace Matchers {
                 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
             }
         private:
-            std::vector<T> const& m_target;
+            std::vector<T, AllocComp> const& m_target;
         };
 
     } // namespace Vector
@@ -3705,29 +3739,29 @@ namespace Matchers {
     // The following functions create the actual matcher objects.
     // This allows the types to be inferred
 
-    template<typename T>
-    Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
-        return Vector::ContainsMatcher<T>( comparator );
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
     }
 
-    template<typename T>
-    Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
-        return Vector::ContainsElementMatcher<T>( comparator );
+    template<typename T, typename Alloc = std::allocator<T>>
+    Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
+        return Vector::ContainsElementMatcher<T, Alloc>( comparator );
     }
 
-    template<typename T>
-    Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
-        return Vector::EqualsMatcher<T>( comparator );
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
     }
 
-    template<typename T>
-    Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) {
-        return Vector::ApproxMatcher<T>( comparator );
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
     }
 
-    template<typename T>
-    Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
-        return Vector::UnorderedEqualsMatcher<T>(target);
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
+        return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
     }
 
 } // namespace Matchers
@@ -4046,16 +4080,16 @@ namespace Generators {
         return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
     }
 
-    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
 
     template<typename L>
     // Note: The type after -> is weird, because VS2015 cannot parse
     //       the expression used in the typedef inside, when it is in
     //       return type. Yeah.
-    auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+    auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
         using UnderlyingType = typename decltype(generatorExpression())::type;
 
-        IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
+        IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
         if (!tracker.hasGenerator()) {
             tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
         }
@@ -4068,11 +4102,17 @@ namespace Generators {
 } // namespace Catch
 
 #define GENERATE( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 #define GENERATE_COPY( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 #define GENERATE_REF( ... ) \
-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 
 // end catch_generators.hpp
 // start catch_generators_generic.hpp
@@ -4482,6 +4522,7 @@ namespace Catch {
         virtual int abortAfter() const = 0;
         virtual bool showInvisibles() const = 0;
         virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual double minDuration() const = 0;
         virtual TestSpec const& testSpec() const = 0;
         virtual bool hasTestFilters() const = 0;
         virtual std::vector<std::string> const& getTestsOrTags() const = 0;
@@ -5254,6 +5295,7 @@ namespace Catch {
         Verbosity verbosity = Verbosity::Normal;
         WarnAbout::What warnings = WarnAbout::Nothing;
         ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+        double minDuration = -1;
         RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
         UseColour::YesOrNo useColour = UseColour::Auto;
         WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
@@ -5304,6 +5346,7 @@ namespace Catch {
         bool warnAboutMissingAssertions() const override;
         bool warnAboutNoTests() const override;
         ShowDurations::OrNot showDurations() const override;
+        double minDuration() const override;
         RunTests::InWhatOrder runOrder() const override;
         unsigned int rngSeed() const override;
         UseColour::YesOrNo useColour() const override;
@@ -5681,6 +5724,9 @@ namespace Catch {
     // Returns double formatted as %.3f (format expected on output)
     std::string getFormattedDuration( double duration );
 
+    //! Should the reporter show
+    bool shouldShowDuration( IConfig const& config, double duration );
+
     std::string serializeFilters( std::vector<std::string> const& container );
 
     template<typename DerivedT>
@@ -6074,8 +6120,6 @@ namespace Catch {
 
         static std::string getDescription();
 
-        ReporterPreferences getPreferences() const override;
-
         void noMatchingTestCases(std::string const& spec) override;
 
         void assertionStarting(AssertionInfo const&) override;
@@ -6523,20 +6567,18 @@ namespace Catch {
                     return {};
                 }
             };
-            template <typename Sig>
-            using ResultOf_t = typename std::result_of<Sig>::type;
 
             // invoke and not return void :(
             template <typename Fun, typename... Args>
-            CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
-                return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+            CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
+                return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
             }
 
             const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
         } // namespace Detail
 
         template <typename Fun>
-        Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
+        Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
             CATCH_TRY{
                 return Detail::complete_invoke(std::forward<Fun>(fun));
             } CATCH_CATCH_ALL{
@@ -6781,8 +6823,8 @@ namespace Catch {
             Result result;
             int iterations;
         };
-        template <typename Clock, typename Sig>
-        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
+        template <typename Clock, typename Func, typename... Args>
+        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
     } // namespace Benchmark
 } // namespace Catch
 
@@ -6793,7 +6835,7 @@ namespace Catch {
     namespace Benchmark {
         namespace Detail {
             template <typename Clock, typename Fun, typename... Args>
-            TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
+            TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
                 auto start = Clock::now();
                 auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
                 auto end = Clock::now();
@@ -6812,11 +6854,11 @@ namespace Catch {
     namespace Benchmark {
         namespace Detail {
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
+            TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
                 return Detail::measure<Clock>(fun, iters);
             }
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
+            TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
                 Detail::ChronometerModel<Clock> meter;
                 auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
 
@@ -6833,7 +6875,7 @@ namespace Catch {
             };
 
             template <typename Clock, typename Fun>
-            TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+            TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
                 auto iters = seed;
                 while (iters < (1 << 30)) {
                     auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
@@ -7431,23 +7473,37 @@ namespace TestCaseTracking {
         SourceLineInfo location;
 
         NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+        friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
+            return lhs.name == rhs.name
+                && lhs.location == rhs.location;
+        }
     };
 
-    struct ITracker;
+    class ITracker;
 
     using ITrackerPtr = std::shared_ptr<ITracker>;
 
-    struct ITracker {
-        virtual ~ITracker();
+    class  ITracker {
+        NameAndLocation m_nameAndLocation;
+
+    public:
+        ITracker(NameAndLocation const& nameAndLoc) :
+            m_nameAndLocation(nameAndLoc)
+        {}
 
         // static queries
-        virtual NameAndLocation const& nameAndLocation() const = 0;
+        NameAndLocation const& nameAndLocation() const {
+            return m_nameAndLocation;
+        }
+
+        virtual ~ITracker();
 
         // dynamic queries
         virtual bool isComplete() const = 0; // Successfully completed or failed
         virtual bool isSuccessfullyCompleted() const = 0;
         virtual bool isOpen() const = 0; // Started but not complete
         virtual bool hasChildren() const = 0;
+        virtual bool hasStarted() const = 0;
 
         virtual ITracker& parent() = 0;
 
@@ -7502,7 +7558,6 @@ namespace TestCaseTracking {
         };
 
         using Children = std::vector<ITrackerPtr>;
-        NameAndLocation m_nameAndLocation;
         TrackerContext& m_ctx;
         ITracker* m_parent;
         Children m_children;
@@ -7511,11 +7566,13 @@ namespace TestCaseTracking {
     public:
         TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
 
-        NameAndLocation const& nameAndLocation() const override;
         bool isComplete() const override;
         bool isSuccessfullyCompleted() const override;
         bool isOpen() const override;
         bool hasChildren() const override;
+        bool hasStarted() const override {
+            return m_runState != NotStarted;
+        }
 
         void addChild( ITrackerPtr const& child ) override;
 
@@ -7878,7 +7935,11 @@ namespace Catch {
 
 #ifdef CATCH_PLATFORM_MAC
 
-    #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+    #if defined(__i386__) || defined(__x86_64__)
+        #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+    #elif defined(__aarch64__)
+        #define CATCH_TRAP()  __asm__(".inst 0xd4200000")
+    #endif
 
 #elif defined(CATCH_PLATFORM_IPHONE)
 
@@ -8063,7 +8124,7 @@ namespace Catch {
         void sectionEnded( SectionEndInfo const& endInfo ) override;
         void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
 
-        auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+        auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
         void benchmarkPreparing( std::string const& name ) override;
@@ -9039,7 +9100,7 @@ namespace detail {
     }
     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
         std::string srcLC = source;
-        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
         if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
             target = true;
         else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
@@ -9808,6 +9869,9 @@ namespace Catch {
             | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
                 ["-d"]["--durations"]
                 ( "show test durations" )
+            | Opt( config.minDuration, "seconds" )
+                ["-D"]["--min-duration"]
+                ( "show test durations for tests taking at least the given number of seconds" )
             | Opt( loadTestNamesFromFile, "filename" )
                 ["-f"]["--input-file"]
                 ( "load test names to run from a file" )
@@ -9955,6 +10019,7 @@ namespace Catch {
     bool Config::warnAboutMissingAssertions() const    { return !!(m_data.warnings & WarnAbout::NoAssertions); }
     bool Config::warnAboutNoTests() const              { return !!(m_data.warnings & WarnAbout::NoTests); }
     ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+    double Config::minDuration() const                 { return m_data.minDuration; }
     RunTests::InWhatOrder Config::runOrder() const     { return m_data.runOrder; }
     unsigned int Config::rngSeed() const               { return m_data.rngSeed; }
     UseColour::YesOrNo Config::useColour() const       { return m_data.useColour; }
@@ -10319,8 +10384,7 @@ namespace Catch {
 
 #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
 
-#  include <assert.h>
-#  include <stdbool.h>
+#  include <cassert>
 #  include <sys/types.h>
 #  include <unistd.h>
 #  include <cstddef>
@@ -10852,8 +10916,8 @@ namespace Generators {
 
     GeneratorUntypedBase::~GeneratorUntypedBase() {}
 
-    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
-        return getResultCapture().acquireGeneratorTracker( lineInfo );
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
     }
 
 } // namespace Generators
@@ -11740,10 +11804,10 @@ namespace Catch {
 
     Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
         auto trimmed = [&] (size_t start, size_t end) {
-            while (names[start] == ',' || isspace(names[start])) {
+            while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
                 ++start;
             }
-            while (names[end] == ',' || isspace(names[end])) {
+            while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
                 --end;
             }
             return names.substr(start, end - start + 1);
@@ -12273,11 +12337,13 @@ namespace Catch {
 namespace Catch {
 
     class StartupExceptionRegistry {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
     public:
         void add(std::exception_ptr const& exception) noexcept;
         std::vector<std::exception_ptr> const& getExceptions() const noexcept;
     private:
         std::vector<std::exception_ptr> m_exceptions;
+#endif
     };
 
 } // end namespace Catch
@@ -12360,7 +12426,11 @@ namespace Catch {
                 m_tagAliasRegistry.add( alias, tag, lineInfo );
             }
             void registerStartupException() noexcept override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
                 m_exceptionRegistry.add(std::current_exception());
+#else
+                CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+#endif
             }
             IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
                 return m_enumValuesRegistry;
@@ -12464,17 +12534,32 @@ namespace Catch {
                 std::shared_ptr<GeneratorTracker> tracker;
 
                 ITracker& currentTracker = ctx.currentTracker();
-                if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                // Under specific circumstances, the generator we want
+                // to acquire is also the current tracker. If this is
+                // the case, we have to avoid looking through current
+                // tracker's children, and instead return the current
+                // tracker.
+                // A case where this check is important is e.g.
+                //     for (int i = 0; i < 5; ++i) {
+                //         int n = GENERATE(1, 2);
+                //     }
+                //
+                // without it, the code above creates 5 nested generators.
+                if (currentTracker.nameAndLocation() == nameAndLocation) {
+                    auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
+                    assert(thisTracker);
+                    assert(thisTracker->isGeneratorTracker());
+                    tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
+                } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
                     assert( childTracker );
                     assert( childTracker->isGeneratorTracker() );
                     tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
-                }
-                else {
+                } else {
                     tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
                     currentTracker.addChild( tracker );
                 }
 
-                if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                if( !tracker->isComplete() ) {
                     tracker->open();
                 }
 
@@ -12488,8 +12573,28 @@ namespace Catch {
             }
             void close() override {
                 TrackerBase::close();
-                // Generator interface only finds out if it has another item on atual move
-                if (m_runState == CompletedSuccessfully && m_generator->next()) {
+                // If a generator has a child (it is followed by a section)
+                // and none of its children have started, then we must wait
+                // until later to start consuming its values.
+                // This catches cases where `GENERATE` is placed between two
+                // `SECTION`s.
+                // **The check for m_children.empty cannot be removed**.
+                // doing so would break `GENERATE` _not_ followed by `SECTION`s.
+                const bool should_wait_for_child =
+                    !m_children.empty() &&
+                    std::find_if( m_children.begin(),
+                                  m_children.end(),
+                                  []( TestCaseTracking::ITrackerPtr tracker ) {
+                                      return tracker->hasStarted();
+                                  } ) == m_children.end();
+
+                // This check is a bit tricky, because m_generator->next()
+                // has a side-effect, where it consumes generator's current
+                // value, but we do not want to invoke the side-effect if
+                // this generator is still waiting for any child to start.
+                if ( should_wait_for_child ||
+                     ( m_runState == CompletedSuccessfully &&
+                       m_generator->next() ) ) {
                     m_children.clear();
                     m_runState = Executing;
                 }
@@ -12625,10 +12730,10 @@ namespace Catch {
 
         return true;
     }
-    auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+    auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
         using namespace Generators;
-        GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
-        assert( tracker.isOpen() );
+        GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
+                                                              TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
         m_lastAssertionInfo.lineInfo = lineInfo;
         return tracker;
     }
@@ -12671,17 +12776,17 @@ namespace Catch {
 
 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
     void RunContext::benchmarkPreparing(std::string const& name) {
-		m_reporter->benchmarkPreparing(name);
-	}
+        m_reporter->benchmarkPreparing(name);
+    }
     void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
         m_reporter->benchmarkStarting( info );
     }
     void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
         m_reporter->benchmarkEnded( stats );
     }
-	void RunContext::benchmarkFailed(std::string const & error) {
-		m_reporter->benchmarkFailed(error);
-	}
+    void RunContext::benchmarkFailed(std::string const & error) {
+        m_reporter->benchmarkFailed(error);
+    }
 #endif // CATCH_CONFIG_ENABLE_BENCHMARKING
 
     void RunContext::pushScopedMessage(MessageInfo const & message) {
@@ -13402,6 +13507,7 @@ namespace Catch {
 // end catch_singletons.cpp
 // start catch_startup_exception_registry.cpp
 
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
 namespace Catch {
 void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
         CATCH_TRY {
@@ -13417,6 +13523,7 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce
     }
 
 } // end namespace Catch
+#endif
 // end catch_startup_exception_registry.cpp
 // start catch_stream.cpp
 
@@ -13601,7 +13708,7 @@ namespace Catch {
 
     namespace {
         char toLowerCh(char c) {
-            return static_cast<char>( std::tolower( c ) );
+            return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
         }
     }
 
@@ -13977,27 +14084,77 @@ namespace Catch {
 // end catch_test_case_info.cpp
 // start catch_test_case_registry_impl.cpp
 
+#include <algorithm>
 #include <sstream>
 
 namespace Catch {
 
-    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+    namespace {
+        struct TestHasher {
+            explicit TestHasher(Catch::SimplePcg32& rng) {
+                basis = rng();
+                basis <<= 32;
+                basis |= rng();
+            }
 
-        std::vector<TestCase> sorted = unsortedTestCases;
+            uint64_t basis;
 
+            uint64_t operator()(TestCase const& t) const {
+                // Modified FNV-1a hash
+                static constexpr uint64_t prime = 1099511628211;
+                uint64_t hash = basis;
+                for (const char c : t.name) {
+                    hash ^= c;
+                    hash *= prime;
+                }
+                return hash;
+            }
+        };
+    } // end unnamed namespace
+
+    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
         switch( config.runOrder() ) {
-            case RunTests::InLexicographicalOrder:
-                std::sort( sorted.begin(), sorted.end() );
-                break;
-            case RunTests::InRandomOrder:
-                seedRng( config );
-                std::shuffle( sorted.begin(), sorted.end(), rng() );
-                break;
             case RunTests::InDeclarationOrder:
                 // already in declaration order
                 break;
+
+            case RunTests::InLexicographicalOrder: {
+                std::vector<TestCase> sorted = unsortedTestCases;
+                std::sort( sorted.begin(), sorted.end() );
+                return sorted;
+            }
+
+            case RunTests::InRandomOrder: {
+                seedRng( config );
+                TestHasher h( rng() );
+
+                using hashedTest = std::pair<uint64_t, TestCase const*>;
+                std::vector<hashedTest> indexed_tests;
+                indexed_tests.reserve( unsortedTestCases.size() );
+
+                for (auto const& testCase : unsortedTestCases) {
+                    indexed_tests.emplace_back(h(testCase), &testCase);
+                }
+
+                std::sort(indexed_tests.begin(), indexed_tests.end(),
+                          [](hashedTest const& lhs, hashedTest const& rhs) {
+                          if (lhs.first == rhs.first) {
+                              return lhs.second->name < rhs.second->name;
+                          }
+                          return lhs.first < rhs.first;
+                });
+
+                std::vector<TestCase> sorted;
+                sorted.reserve( indexed_tests.size() );
+
+                for (auto const& hashed : indexed_tests) {
+                    sorted.emplace_back(*hashed.second);
+                }
+
+                return sorted;
+            }
         }
-        return sorted;
+        return unsortedTestCases;
     }
 
     bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
@@ -14134,15 +14291,12 @@ namespace TestCaseTracking {
         m_currentTracker = tracker;
     }
 
-    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
-    :   m_nameAndLocation( nameAndLocation ),
+    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
+        ITracker(nameAndLocation),
         m_ctx( ctx ),
         m_parent( parent )
     {}
 
-    NameAndLocation const& TrackerBase::nameAndLocation() const {
-        return m_nameAndLocation;
-    }
     bool TrackerBase::isComplete() const {
         return m_runState == CompletedSuccessfully || m_runState == Failed;
     }
@@ -14258,7 +14412,8 @@ namespace TestCaseTracking {
     bool SectionTracker::isComplete() const {
         bool complete = true;
 
-        if ((m_filters.empty() || m_filters[0] == "")
+        if (m_filters.empty()
+            || m_filters[0] == ""
             || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
             complete = TrackerBase::isComplete();
         }
@@ -14591,6 +14746,7 @@ namespace Catch {
          m_pos = m_arg.size();
          m_substring.clear();
          m_patternName.clear();
+         m_realPatternPos = 0;
          return false;
       }
       endMode();
@@ -14609,6 +14765,7 @@ namespace Catch {
         }
 
         m_patternName.clear();
+        m_realPatternPos = 0;
 
         return token;
     }
@@ -15039,7 +15196,9 @@ namespace Catch {
 
 namespace Catch {
     bool uncaught_exceptions() {
-#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        return false;
+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
         return std::uncaught_exceptions() > 0;
 #else
         return std::uncaught_exception();
@@ -15079,7 +15238,7 @@ namespace Catch {
     }
 
     Version const& libraryVersion() {
-        static Version version( 2, 11, 3, "", 0 );
+        static Version version( 2, 13, 0, "", 0 );
         return version;
     }
 
@@ -15481,6 +15640,17 @@ namespace Catch {
         return std::string(buffer);
     }
 
+    bool shouldShowDuration( IConfig const& config, double duration ) {
+        if ( config.showDurations() == ShowDurations::Always ) {
+            return true;
+        }
+        if ( config.showDurations() == ShowDurations::Never ) {
+            return false;
+        }
+        const double min = config.minDuration();
+        return min >= 0 && duration >= min;
+    }
+
     std::string serializeFilters( std::vector<std::string> const& container ) {
         ReusableStringStream oss;
         bool first = true;
@@ -15747,10 +15917,6 @@ private:
             return "Reports test results on a single line, suitable for IDEs";
         }
 
-        ReporterPreferences CompactReporter::getPreferences() const {
-            return m_reporterPrefs;
-        }
-
         void CompactReporter::noMatchingTestCases( std::string const& spec ) {
             stream << "No test cases matched '" << spec << '\'' << std::endl;
         }
@@ -15777,8 +15943,9 @@ private:
         }
 
         void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
-            if (m_config->showDurations() == ShowDurations::Always) {
-                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            double dur = _sectionStats.durationInSeconds;
+            if ( shouldShowDuration( *m_config, dur ) ) {
+                stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
             }
         }
 
@@ -16142,7 +16309,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
         else
         {
             return{
-                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
+                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
                 { "samples      mean       std dev", 14, ColumnInfo::Right },
                 { "iterations   low mean   low std dev", 14, ColumnInfo::Right },
                 { "estimated    high mean  high std dev", 14, ColumnInfo::Right }
@@ -16198,8 +16365,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
             stream << "\nNo assertions in test case";
         stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
     }
-    if (m_config->showDurations() == ShowDurations::Always) {
-        stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+    double dur = _sectionStats.durationInSeconds;
+    if (shouldShowDuration(*m_config, dur)) {
+        stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
     }
     if (m_headerPrinted) {
         m_headerPrinted = false;
@@ -16658,6 +16826,11 @@ namespace Catch {
                 xml.writeAttribute( "name", name );
             }
             xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
+            // This is not ideal, but it should be enough to mimic gtest's
+            // junit output.
+            // Ideally the JUnit reporter would also handle `skipTest`
+            // events and write those out appropriately.
+            xml.writeAttribute( "status", "run" );
 
             writeAssertions( sectionNode );
 
@@ -17092,6 +17265,10 @@ namespace Catch {
             .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
             .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
             .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testGroupStats.totals.testCases.passed )
+            .writeAttribute( "failures", testGroupStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
         m_xml.endElement();
     }
 
@@ -17101,6 +17278,10 @@ namespace Catch {
             .writeAttribute( "successes", testRunStats.totals.assertions.passed )
             .writeAttribute( "failures", testRunStats.totals.assertions.failed )
             .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testRunStats.totals.testCases.passed )
+            .writeAttribute( "failures", testRunStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
         m_xml.endElement();
     }
 
diff --git a/packages/Catch2/single_include/catch2/catch_reporter_tap.hpp b/packages/Catch2/single_include/catch2/catch_reporter_tap.hpp
index 1bfe4f5e1ca732f9df75e922953ff70dc15df3ec..5ac8524ce7abebdf264a5584c509c71c2a1df2da 100644
--- a/packages/Catch2/single_include/catch2/catch_reporter_tap.hpp
+++ b/packages/Catch2/single_include/catch2/catch_reporter_tap.hpp
@@ -23,16 +23,17 @@ namespace Catch {
 
         using StreamingReporterBase::StreamingReporterBase;
 
+        TAPReporter( ReporterConfig const& config ):
+            StreamingReporterBase( config ) {
+            m_reporterPrefs.shouldReportAllAssertions = true;
+        }
+
         ~TAPReporter() override;
 
         static std::string getDescription() {
             return "Reports test results in TAP format, suitable for test harnesses";
         }
 
-        ReporterPreferences getPreferences() const override {
-            return m_reporterPrefs;
-        }
-
         void noMatchingTestCases( std::string const& spec ) override {
             stream << "# No test cases matched '" << spec << "'" << std::endl;
         }
@@ -203,16 +204,15 @@ namespace Catch {
                     return;
                 }
 
-                // using messages.end() directly (or auto) yields compilation error:
-                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
-                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+                const auto itEnd = messages.cend();
+                const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
 
                 {
                     Colour colourGuard( colour );
                     stream << " with " << pluralise( N, "message" ) << ":";
                 }
 
-                for(; itMessage != itEnd; ) {
+                while( itMessage != itEnd ) {
                     // If this assertion is a warning ignore any INFO messages
                     if( printInfoMessages || itMessage->type != ResultWas::Info ) {
                         stream << " '" << itMessage->message << "'";
@@ -220,7 +220,9 @@ namespace Catch {
                             Colour colourGuard( dimColour() );
                             stream << " and";
                         }
+                        continue;
                     }
+                    ++itMessage;
                 }
             }
 
@@ -234,10 +236,9 @@ namespace Catch {
         };
 
         void printTotals( const Totals& totals ) const {
+            stream << "1.." << totals.assertions.total();
             if( totals.testCases.total() == 0 ) {
-                stream << "1..0 # Skipped: No tests ran.";
-            } else {
-                stream << "1.." << counter;
+                stream << " # Skipped: No tests ran.";
             }
         }
     };
diff --git a/packages/Catch2/third_party/clara.hpp b/packages/Catch2/third_party/clara.hpp
index 9f4f1b2c317c9ded1d86ae5bca01c5edc19d794f..eb4c7275b103eb0638ad40c204766d445f1f175f 100644
--- a/packages/Catch2/third_party/clara.hpp
+++ b/packages/Catch2/third_party/clara.hpp
@@ -667,7 +667,7 @@ namespace detail {
     }
     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
         std::string srcLC = source;
-        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( ::tolower( c ) ); } );
         if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
             target = true;
         else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
diff --git a/packages/PEGTL/.appveyor.yml b/packages/PEGTL/.appveyor.yml
index 716434a3043a74f22d63bcb374dac3b7a9c7766d..02289836c6090f6ceccf750a79ed6a2e875082c5 100644
--- a/packages/PEGTL/.appveyor.yml
+++ b/packages/PEGTL/.appveyor.yml
@@ -1,65 +1,29 @@
 version: '{branch}-{build}'
 
-os:
-  - Visual Studio 2017
-
 skip_commits:
   files:
+    - README.md
     - doc/**/*
 
-environment:
-  matrix:
-    - GENERATOR: Visual Studio 15 2017
-      platform: x86
-      configuration: Debug
+os:
+  - Visual Studio 2017
 
-    - GENERATOR: Visual Studio 15 2017
-      platform: x86
-      configuration: Release
+platform:
+  - x86
+  - x64
 
-    - GENERATOR: Visual Studio 15 2017
-      platform: x64
-      configuration: Debug
+configuration:
+  - Debug
+  - Release
 
+environment:
+  matrix:
     - GENERATOR: Visual Studio 15 2017
-      platform: x64
-      configuration: Release
-
-    - GENERATOR: Visual Studio 15 2017 Win64
-      platform: x86
-      configuration: Debug
 
     - GENERATOR: Visual Studio 15 2017 Win64
-      platform: x86
-      configuration: Release
-
-    - GENERATOR: Visual Studio 15 2017 Win64
-      platform: x64
-      configuration: Debug
-
-    - GENERATOR: Visual Studio 15 2017 Win64
-      platform: x64
-      configuration: Release
-
-    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-      GENERATOR: Visual Studio 16 2019
-      platform: x86
-      configuration: Debug
 
     - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
       GENERATOR: Visual Studio 16 2019
-      platform: x86
-      configuration: Release
-
-    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-      GENERATOR: Visual Studio 16 2019
-      platform: x64
-      configuration: Debug
-
-    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-      GENERATOR: Visual Studio 16 2019
-      platform: x64
-      configuration: Release
 
 init: []
 
@@ -74,4 +38,3 @@ build_script:
 
 test_script:
 - ctest -C "%CONFIGURATION%" --output-on-failure
-
diff --git a/packages/PEGTL/.clang-format b/packages/PEGTL/.clang-format
index 729f882aad10760bbc2afa0fe571376390a19bdb..c423ca2749e808e112ba69db6d6f33ee76ca955f 100644
--- a/packages/PEGTL/.clang-format
+++ b/packages/PEGTL/.clang-format
@@ -3,7 +3,7 @@
 # clang-format -i -style=file $(find . -name '[^.]*.[hc]pp')
 
 Language: Cpp
-Standard: Cpp11
+Standard: Latest
 
 AccessModifierOffset: -3
 AlignAfterOpenBracket: Align
diff --git a/packages/PEGTL/.clang-tidy b/packages/PEGTL/.clang-tidy
index 14eb1216c414dfe3269d2b3195855173b18299f1..2af75f8edbfac208c7fef1dfcbbcb1da1093f367 100644
--- a/packages/PEGTL/.clang-tidy
+++ b/packages/PEGTL/.clang-tidy
@@ -21,6 +21,7 @@ Checks: >-
   readability-*,
   -readability-avoid-const-params-in-decls,
   -readability-magic-numbers,
+  -readability-static-accessed-through-instance,
 
 CheckOptions:
   - { key: readability-identifier-naming.ClassCase,     value: lower_case }
diff --git a/packages/PEGTL/.gitrepo b/packages/PEGTL/.gitrepo
index 7eea19117c858927ae7c942b0fe1631d3c411044..00b4dcf367034ec66b746e464a2f7bb9ffdcf080 100644
--- a/packages/PEGTL/.gitrepo
+++ b/packages/PEGTL/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:taocpp/PEGTL.git
 	branch = master
-	commit = 1a4a2d0df43f773893e0e4102d56d85e6b3fb7fc
-	parent = 28dff7b443629a23205fd32909491e7e5de495a3
+	commit = 3d4fee2837decb5ecff9543276c4aa922b280972
+	parent = 0a259f7e3e4fe2364b8d45b641c7f48ff3bc7341
 	cmdver = 0.4.1
 	method = merge
diff --git a/packages/PEGTL/.travis.yml b/packages/PEGTL/.travis.yml
index 95e20d5032f8e6f5e3cd3adb8f7d200153d039a8..8d81bb3ce3272882de4fc246274b13ea56acfb72 100644
--- a/packages/PEGTL/.travis.yml
+++ b/packages/PEGTL/.travis.yml
@@ -4,43 +4,48 @@ dist: xenial
 
 jobs:
   include:
-    - &gcc-7
-      compiler: gcc
+    - compiler: gcc
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test ]
-          packages: [ g++-7 ]
+          packages: [ g++-8 ]
       env:
-        - CXX=g++-7
+        - CXX=g++-8
+        - LDFLAGS="-lstdc++fs"
 
-    - &gcc-8
-      compiler: gcc
+    - compiler: gcc
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test ]
-          packages: [ g++-8 ]
-      env:
-        - CXX=g++-8
-
-    - <<: *gcc-8
+          packages: [ g++-9 ]
       env:
-        - CXX=g++-8
-        - CPPFLAGS="-fno-rtti"
+        - CXX=g++-9
 
-    - &gcc-9
+    - &gcc-10
+      dist: bionic
       compiler: gcc
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test ]
-          packages: [ g++-9 ]
+          packages: [ g++-10 ]
       env:
-        - CXX=g++-9
+        - CXX=g++-10
+
+    - <<: *gcc-10
+      env:
+        - CXX=g++-10
+        - CXXSTD="-std=c++20"
+
+    - <<: *gcc-10
+      env:
+        - CXX=g++-10
+        - CPPFLAGS="-fno-rtti"
 
     - compiler: clang
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-5 ]
-          packages: [ clang-5.0, g++-7 ]
+          packages: [ clang-5.0, g++-9 ]
       env:
         - CXX=clang++-5.0
 
@@ -48,7 +53,7 @@ jobs:
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-6 ]
-          packages: [ clang-6.0, g++-7 ]
+          packages: [ clang-6.0, g++-9 ]
       env:
         - CXX=clang++-6.0
 
@@ -56,7 +61,7 @@ jobs:
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-7 ]
-          packages: [ clang-7, g++-7 ]
+          packages: [ clang-7, g++-9 ]
       env:
         - CXX=clang++-7
 
@@ -64,14 +69,14 @@ jobs:
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test, llvm-toolchain-xenial-8 ]
-          packages: [ clang-8, g++-8 ]
+          packages: [ clang-8, g++-9 ]
       env:
         - CXX=clang++-8
 
     - compiler: clang
       addons:
         apt:
-          sources: &clang-9-sources
+          sources:
             - ubuntu-toolchain-r-test
             - sourceline: deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main
               key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
@@ -80,17 +85,23 @@ jobs:
         - CXX=clang++-9
 
     - &clang-10
+      dist: bionic
       compiler: clang
       addons:
         apt:
           sources: &clang-10-sources
             - ubuntu-toolchain-r-test
-            - sourceline: deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main
+            - sourceline: deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main
               key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
-          packages: [ clang-10, g++-9 ]
+          packages: [ clang-10, g++-10 ]
       env:
         - CXX=clang++-10
 
+    - <<: *clang-10
+      env:
+        - CXX=clang++-10
+        - CXXSTD="-std=c++20"
+
     - <<: *clang-10
       env:
         - CXX=clang++-10
@@ -101,19 +112,12 @@ jobs:
         - CXX=clang++-10
         - CPPFLAGS="-fno-rtti"
 
-    - &osx
-      os: osx
-      osx_image: xcode9.4
+    - os: osx
+      osx_image: xcode11.4
       compiler: clang
       env:
         - CXX=clang++
 
-    - <<: *osx
-      osx_image: xcode10.3
-
-    - <<: *osx
-      osx_image: xcode11.4
-
     - &android
       compiler: clang
       addons:
@@ -153,14 +157,14 @@ jobs:
         - ANDROID_ABI=arm64-v8a
         - ANDROID_PLATFORM=android-24
 
-    - <<: *gcc-9
+    - <<: *gcc-10
       env:
-        - CXX=g++-9
+        - CXX=g++-10
         - CPPFLAGS="-fsanitize=undefined -fuse-ld=gold"
 
-    - <<: *gcc-9
+    - <<: *gcc-10
       env:
-        - CXX=g++-9
+        - CXX=g++-10
         - CPPFLAGS="-fsanitize=address -fuse-ld=gold"
 
     - <<: *clang-10
@@ -173,53 +177,57 @@ jobs:
         - CXX=clang++-10
         - CPPFLAGS="-fsanitize=address"
 
-    - compiler: clang
+    - dist: bionic
+      compiler: clang
       addons:
         apt:
           sources: *clang-10-sources
-          packages: [ clang-10, clang-tidy-10, g++-9 ]
+          packages: [ clang-10, clang-tidy-10, g++-10 ]
       env:
         - CXX=clang++-10
         - CLANG_TIDY=clang-tidy-10
       script:
         - make -kj3 clang-tidy
 
-    - compiler: clang
+    - dist: bionic
+      compiler: clang
       addons:
         apt:
           sources: *clang-10-sources
-          packages: [ clang-tools-10, g++-9 ]
+          packages: [ clang-tools-10, g++-10 ]
       script:
         - scan-build-10 --use-c++=clang++-10 --status-bugs make -kj3
 
-    - compiler: gcc
+    - dist: bionic
+      compiler: gcc
       addons:
         apt:
           sources: [ ubuntu-toolchain-r-test ]
-          packages: [ g++-9, valgrind ]
+          packages: [ g++-10, valgrind ]
       env:
-        - CXX=g++-9
+        - CXX=g++-10
         - SPECIAL=valgrind
       script:
         - make -kj3 valgrind
 
-    - <<: *gcc-7
+    - <<: *gcc-10
       env:
-        - CXX=g++-7
+        - CXX=g++-10
         - CXXFLAGS="-O0 --coverage"
       before_script:
         - pip install --user cpp-coveralls
       script:
         - make -kj3 check
-        - coveralls --gcov gcov-7 --gcov-options '\-lp' --exclude src
+        - coveralls --gcov gcov-10 --gcov-options '\-lp' --exclude src
 
-    - compiler: clang
+    - dist: bionic
+      compiler: clang
       addons:
         apt:
-          sources: *clang-9-sources
-          packages: [ clang-format-9, g++-9 ]
+          sources: *clang-10-sources
+          packages: [ clang-format-10, g++-10 ]
       script:
-        - clang-format-9 -i -style=file $(find . -name '[^.]*.[hc]pp')
+        - clang-format-10 -i -style=file $(find . -name '[^.]*.[hc]pp')
         - git diff --exit-code
 
 script:
diff --git a/packages/PEGTL/Makefile b/packages/PEGTL/Makefile
index 9ff538aff11cec39c905b5d76871e6338af76b73..3f47845535131816144829cf7cbecf1724fbe640 100644
--- a/packages/PEGTL/Makefile
+++ b/packages/PEGTL/Makefile
@@ -62,7 +62,7 @@ valgrind: $(UNIT_TESTS:%=%.valgrind)
 	@echo "All $(words $(UNIT_TESTS)) valgrind tests passed."
 
 build/%.clang-tidy: % .clang-tidy
-	$(CLANG_TIDY) -quiet $< -- $(CXXSTD) -Iinclude $(CPPFLAGS) $(CXXFLAGS) 2>/dev/null
+	$(CLANG_TIDY) -quiet $< -- $(CXXSTD) -Iinclude $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) 2>/dev/null
 	@mkdir -p $(@D)
 	@touch $@
 
@@ -80,7 +80,7 @@ build/%.d: %.cpp Makefile
 	$(CXX) $(CXXSTD) -Iinclude $(CPPFLAGS) -MM -MQ $@ $< -o $@
 
 build/%: %.cpp build/%.d
-	$(CXX) $(CXXSTD) -Iinclude $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+	$(CXX) $(CXXSTD) -Iinclude $(CPPFLAGS) $(CXXFLAGS) $< $(LDFLAGS) -o $@
 
 .PHONY: amalgamate
 amalgamate: build/amalgamated/pegtl.hpp
@@ -94,7 +94,6 @@ build/amalgamated/pegtl.hpp: $(HEADERS)
 	@sed -i -e 's%^//#include "%#include "%g' $$(find build/include -name '*.hpp')
 	@for i in $$(find build/include -name '*.hpp'); do echo "#pragma once" >tmp.out; echo "#line 1" >>tmp.out; cat $$i >>tmp.out; mv tmp.out $$i; done
 	@echo '#include "tao/pegtl.hpp"' >build/include/amalgamated.hpp
-	@echo '#include "tao/pegtl/analyze.hpp"' >>build/include/amalgamated.hpp
 	@( cd build/include ; for i in tao/pegtl/contrib/*.hpp; do echo "#include \"$$i\""; done ) >>build/include/amalgamated.hpp
 	@echo -e "/*\n\nWelcome to the Parsing Expression Grammar Template Library (PEGTL)." >$@
 	@echo -e "See https://github.com/taocpp/PEGTL/ for more information, documentation, etc.\n" >>$@
diff --git a/packages/PEGTL/README.md b/packages/PEGTL/README.md
index 2b57955028ddacc5d5418558f98a2589c1fa6680..c11b0c8822e7f67f8280f0a17529ed6344b6b498 100644
--- a/packages/PEGTL/README.md
+++ b/packages/PEGTL/README.md
@@ -1,12 +1,5 @@
 # Welcome to the PEGTL
 
-[![Release](https://img.shields.io/github/release/taocpp/PEGTL.svg)](https://github.com/taocpp/PEGTL/releases/latest)
-[![Download](https://api.bintray.com/packages/conan/conan-center/taocpp-pegtl%3A_/images/download.svg)](https://bintray.com/conan/conan-center/taocpp-pegtl%3A_/_latestVersion)
-[![TravisCI](https://travis-ci.org/taocpp/PEGTL.svg?branch=master)](https://travis-ci.org/taocpp/PEGTL)
-[![AppVeyor](https://ci.appveyor.com/api/projects/status/pa5sbnw68tu650aq/branch/master?svg=true)](https://ci.appveyor.com/project/taocpp/PEGTL)
-[![Coverage](https://coveralls.io/repos/github/taocpp/PEGTL/badge.svg?branch=master)](https://coveralls.io/github/taocpp/PEGTL)
-[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/taocpp/PEGTL.svg)](https://lgtm.com/projects/g/taocpp/PEGTL/context:cpp)
-
 The Parsing Expression Grammar Template Library (PEGTL) is a zero-dependency C++ header-only parser combinator library for creating parsers according to a [Parsing Expression Grammar](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (PEG).
 
 ## Documentation
@@ -56,6 +49,9 @@ The rules are expressed in C++ as template instantiations, and it is the compile
 
 ## Status
 
+[![TravisCI](https://travis-ci.org/taocpp/PEGTL.svg?branch=master)](https://travis-ci.org/taocpp/PEGTL)
+[![AppVeyor](https://ci.appveyor.com/api/projects/status/pa5sbnw68tu650aq/branch/master?svg=true)](https://ci.appveyor.com/project/taocpp/PEGTL)
+
 Each commit is automatically tested with multiple architectures, operating systems, compilers, and versions thereof.
 
 * Windows
@@ -65,17 +61,36 @@ Each commit is automatically tested with multiple architectures, operating syste
 
 * macOS (using libc++)
 
-  * macOS 10.13, Xcode 9.4
-  * macOS 10.14, Xcode 10.3
-  * macOS 10.14, Xcode 11.4
+  * macOS 10.15, Xcode 11.4
 
 * Ubuntu 16.04 LTS (using libstdc++)
 
-  * GCC 7.x, 8.x, 9.x
-  * Clang 5.x, 6.x, 7.x, 8.x, 9.x, 10.x
+  * GCC 8.x, 9.x
+  * Clang 5.x, 6.x, 7.x, 8.x, 9.x
+
+* Ubuntu 18.04 LTS (using libstdc++)
+
+  * GCC 10.x
+  * Clang 10.x
+
+### Code Quality
+
+[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/taocpp/PEGTL.svg)](https://lgtm.com/projects/g/taocpp/PEGTL/context:cpp)
+
+Each commit is checked with Clang's [Static Analyzer](https://clang-analyzer.llvm.org/), GCC's and Clang's [sanitizers](https://github.com/google/sanitizers), [`clang-tidy`](http://clang.llvm.org/extra/clang-tidy/), and [`valgrind`](http://valgrind.org/).
+Additionally, we use [LGTM](https://lgtm.com/) to scan for (security) issues.
+Note that [LGTM](https://lgtm.com/) sometimes generate false positives, hence the above badge may not show an accurate grade.
+
+### Code Coverage
+
+[![Coverage](https://coveralls.io/repos/github/taocpp/PEGTL/badge.svg?branch=master)](https://coveralls.io/github/taocpp/PEGTL)
 
-Additionally, each commit is checked with Clang's [Static Analyzer](https://clang-analyzer.llvm.org/), GCC's and Clang's [sanitizers](https://github.com/google/sanitizers), [`clang-tidy`](http://clang.llvm.org/extra/clang-tidy/), and [`valgrind`](http://valgrind.org/).
 Code coverage is automatically measured and the unit tests cover 100% of the core library code (for releases).
+Note that the infrastructure is partially broken, hence the above badge may not show 100%.
+
+### Versioning
+
+[![Release](https://img.shields.io/github/release/taocpp/PEGTL.svg)](https://github.com/taocpp/PEGTL/releases/latest)
 
 [Releases](https://github.com/taocpp/PEGTL/releases) are done in accordance with [Semantic Versioning](http://semver.org/).
 Incompatible API changes are *only* allowed to occur between major versions.
@@ -85,47 +100,48 @@ For details see the [changelog](doc/Changelog.md).
 
 In appreciation of all contributions here are the people that have [directly contributed](https://github.com/taocpp/PEGTL/graphs/contributors) to the PEGTL and/or its development.
 
-[<img alt="andoma" src="https://avatars.githubusercontent.com/u/216384?s=117" width="117">](https://github.com/andoma)
-[<img alt="bjoe" src="https://avatars.githubusercontent.com/u/727911?s=117" width="117">](https://github.com/bjoe)
-[<img alt="bwagner" src="https://avatars.githubusercontent.com/u/447049?s=117" width="117">](https://github.com/bwagner)
-[<img alt="cdiggins" src="https://avatars.githubusercontent.com/u/1759994?s=460&v=4?s=117" width="117">](https://github.com/cdiggins)
-[<img alt="delpinux" src="https://avatars.githubusercontent.com/u/35096584?s=117" width="117">](https://github.com/delpinux)
-[<img alt="dkopecek" src="https://avatars.githubusercontent.com/u/1353140?s=117" width="117">](https://github.com/dkopecek)
-[<img alt="irrequietus" src="https://avatars.githubusercontent.com/u/231192?s=117" width="117">](https://github.com/irrequietus)
-[<img alt="jedelbo" src="https://avatars.githubusercontent.com/u/572755?s=117" width="117">](https://github.com/jedelbo)
-[<img alt="joelfrederico" src="https://avatars.githubusercontent.com/u/458871?s=117" width="117">](https://github.com/joelfrederico)
-[<img alt="johelegp" src="https://avatars.githubusercontent.com/u/21071787?s=117" width="117">](https://github.com/johelegp)
-[<img alt="jovermann" src="https://avatars.githubusercontent.com/u/6087443?s=117" width="117">](https://github.com/jovermann)
-[<img alt="kneth" src="https://avatars.githubusercontent.com/u/1225363?s=117" width="117">](https://github.com/kneth)
-[<img alt="kuzmas" src="https://avatars.githubusercontent.com/u/1858553?s=117" width="117">](https://github.com/kuzmas)
-[<img alt="lambdafu" src="https://avatars.githubusercontent.com/u/1138455?s=117" width="117">](https://github.com/lambdafu)
-[<img alt="lichray" src="https://avatars.githubusercontent.com/u/433009?s=117" width="117">](https://github.com/lichray)
-[<img alt="michael-brade" src="https://avatars.githubusercontent.com/u/8768950?s=117" width="117">](https://github.com/michael-brade)
-[<img alt="mkrupcale" src="https://avatars.githubusercontent.com/u/13936020?s=117" width="117">](https://github.com/mkrupcale)
-[<img alt="newproggie" src="https://avatars.githubusercontent.com/u/162319?s=460&v=4?s=117" width="117">](https://github.com/newproggie)
-[<img alt="obiwahn" src="https://avatars.githubusercontent.com/u/741109?s=117" width="117">](https://github.com/obiwahn)
-[<img alt="ohanar" src="https://avatars.githubusercontent.com/u/1442822?s=117" width="117">](https://github.com/ohanar)
-[<img alt="pauloscustodio" src="https://avatars.githubusercontent.com/u/70773?s=117" width="117">](https://github.com/pauloscustodio)
-[<img alt="pleroux0" src="https://avatars.githubusercontent.com/u/39619854?s=117" width="117">](https://github.com/pleroux0)
-[<img alt="quadfault" src="https://avatars.githubusercontent.com/u/30195320?s=117" width="117">](https://github.com/quadfault)
-[<img alt="robertcampion" src="https://avatars.githubusercontent.com/u/4220569?s=117" width="117">](https://github.com/robertcampion)
-[<img alt="samhocevar" src="https://avatars.githubusercontent.com/u/245089?s=117" width="117">](https://github.com/samhocevar)
-[<img alt="sanssecours" src="https://avatars.githubusercontent.com/u/691989?s=117" width="117">](https://github.com/sanssecours)
-[<img alt="sgbeal" src="https://avatars.githubusercontent.com/u/235303?s=117" width="117">](https://github.com/sgbeal)
-[<img alt="skyrich62" src="https://avatars.githubusercontent.com/u/23705081?s=117" width="117">](https://github.com/skyrich62)
-[<img alt="studoot" src="https://avatars.githubusercontent.com/u/799344?s=117" width="117">](https://github.com/studoot)
-[<img alt="svenjo" src="https://avatars.githubusercontent.com/u/1538181?s=460&v=4?s=117" width="117">](https://github.com/svenjo)
-[<img alt="wickedmic" src="https://avatars.githubusercontent.com/u/12001183?s=117" width="117">](https://github.com/wickedmic)
-[<img alt="wravery" src="https://avatars.githubusercontent.com/u/6502881?s=117" width="117">](https://github.com/wravery)
-[<img alt="zhihaoy" src="https://avatars.githubusercontent.com/u/43971430?s=117" width="117">](https://github.com/zhihaoy)
+[<img alt="andoma" src="https://avatars.githubusercontent.com/u/216384" width="120">](https://github.com/andoma)
+[<img alt="bjoe" src="https://avatars.githubusercontent.com/u/727911" width="120">](https://github.com/bjoe)
+[<img alt="bwagner" src="https://avatars.githubusercontent.com/u/447049" width="120">](https://github.com/bwagner)
+[<img alt="cdiggins" src="https://avatars.githubusercontent.com/u/1759994" width="120">](https://github.com/cdiggins)
+[<img alt="delpinux" src="https://avatars.githubusercontent.com/u/35096584" width="120">](https://github.com/delpinux)
+[<img alt="dkopecek" src="https://avatars.githubusercontent.com/u/1353140" width="120">](https://github.com/dkopecek)
+[<img alt="gene-hightower" src="https://avatars.githubusercontent.com/u/3957811" width="120">](https://github.com/gene-hightower)
+[<img alt="irrequietus" src="https://avatars.githubusercontent.com/u/231192" width="120">](https://github.com/irrequietus)
+[<img alt="jedelbo" src="https://avatars.githubusercontent.com/u/572755" width="120">](https://github.com/jedelbo)
+[<img alt="joelfrederico" src="https://avatars.githubusercontent.com/u/458871" width="120">](https://github.com/joelfrederico)
+[<img alt="johelegp" src="https://avatars.githubusercontent.com/u/21071787" width="120">](https://github.com/johelegp)
+[<img alt="jovermann" src="https://avatars.githubusercontent.com/u/6087443" width="120">](https://github.com/jovermann)
+[<img alt="kneth" src="https://avatars.githubusercontent.com/u/1225363" width="120">](https://github.com/kneth)
+[<img alt="kuzmas" src="https://avatars.githubusercontent.com/u/1858553" width="120">](https://github.com/kuzmas)
+[<img alt="lambdafu" src="https://avatars.githubusercontent.com/u/1138455" width="120">](https://github.com/lambdafu)
+[<img alt="lichray" src="https://avatars.githubusercontent.com/u/433009" width="120">](https://github.com/lichray)
+[<img alt="michael-brade" src="https://avatars.githubusercontent.com/u/8768950" width="120">](https://github.com/michael-brade)
+[<img alt="mkrupcale" src="https://avatars.githubusercontent.com/u/13936020" width="120">](https://github.com/mkrupcale)
+[<img alt="newproggie" src="https://avatars.githubusercontent.com/u/162319" width="120">](https://github.com/newproggie)
+[<img alt="obiwahn" src="https://avatars.githubusercontent.com/u/741109" width="120">](https://github.com/obiwahn)
+[<img alt="ohanar" src="https://avatars.githubusercontent.com/u/1442822" width="120">](https://github.com/ohanar)
+[<img alt="pauloscustodio" src="https://avatars.githubusercontent.com/u/70773" width="120">](https://github.com/pauloscustodio)
+[<img alt="pleroux0" src="https://avatars.githubusercontent.com/u/39619854" width="120">](https://github.com/pleroux0)
+[<img alt="quadfault" src="https://avatars.githubusercontent.com/u/30195320" width="120">](https://github.com/quadfault)
+[<img alt="robertcampion" src="https://avatars.githubusercontent.com/u/4220569" width="120">](https://github.com/robertcampion)
+[<img alt="samhocevar" src="https://avatars.githubusercontent.com/u/245089" width="120">](https://github.com/samhocevar)
+[<img alt="sanssecours" src="https://avatars.githubusercontent.com/u/691989" width="120">](https://github.com/sanssecours)
+[<img alt="sgbeal" src="https://avatars.githubusercontent.com/u/235303" width="120">](https://github.com/sgbeal)
+[<img alt="skyrich62" src="https://avatars.githubusercontent.com/u/23705081" width="120">](https://github.com/skyrich62)
+[<img alt="studoot" src="https://avatars.githubusercontent.com/u/799344" width="120">](https://github.com/studoot)
+[<img alt="svenjo" src="https://avatars.githubusercontent.com/u/1538181" width="120">](https://github.com/svenjo)
+[<img alt="wickedmic" src="https://avatars.githubusercontent.com/u/12001183" width="120">](https://github.com/wickedmic)
+[<img alt="wravery" src="https://avatars.githubusercontent.com/u/6502881" width="120">](https://github.com/wravery)
+[<img alt="zhihaoy" src="https://avatars.githubusercontent.com/u/43971430" width="120">](https://github.com/zhihaoy)
 
 ## The Art of C++
 
 The PEGTL is part of [The Art of C++](https://taocpp.github.io/).
 
-[<img alt="colinh" src="https://avatars.githubusercontent.com/u/113184?s=117" width="117">](https://github.com/colinh)
-[<img alt="d-frey" src="https://avatars.githubusercontent.com/u/3956325?s=117" width="117">](https://github.com/d-frey)
-[<img alt="uilianries" src="https://avatars.githubusercontent.com/u/4870173?s=117" width="117">](https://github.com/uilianries)
+[<img alt="colinh" src="https://avatars.githubusercontent.com/u/113184" width="120">](https://github.com/colinh)
+[<img alt="d-frey" src="https://avatars.githubusercontent.com/u/3956325" width="120">](https://github.com/d-frey)
+[<img alt="uilianries" src="https://avatars.githubusercontent.com/u/4870173" width="120">](https://github.com/uilianries)
 
 ## Contact
 
diff --git a/packages/PEGTL/doc/Actions-and-States.md b/packages/PEGTL/doc/Actions-and-States.md
index ae234dc28007583c315f81b06205a7198dfb8dc1..480df8140fae8188ddad1c9f2271b99ce21225f0 100644
--- a/packages/PEGTL/doc/Actions-and-States.md
+++ b/packages/PEGTL/doc/Actions-and-States.md
@@ -198,7 +198,7 @@ Conversely `iterator()` returns a pointer or iterator to the beginning of the ac
 More importantly the `action_input` does **not** own the data it points to, it belongs to the original input used in the parsing run.
 Therefore **the validity of the pointed-to data might not extend (much) beyond the call to `apply()`**!
 
-When the original input has tracking mode `eager`, the `iterator_t` returned by `action_input::iterator()` will contain the `byte`, `line` and `byte_in_line` counters corresponding to the beginning of the matched input represented by the `action_input`.
+When the original input has tracking mode `eager`, the `iterator_t` returned by `action_input::iterator()` will contain the `byte`, `line` and `column` counters corresponding to the beginning of the matched input represented by the `action_input`.
 
 When the original input has tracking mode `lazy`, then `action_input::position()` is not efficient because it calculates the line number etc. by scanning the complete original input from the beginning
 
diff --git a/packages/PEGTL/doc/Changelog.md b/packages/PEGTL/doc/Changelog.md
index 3198b38dfad39a10d59ff81600ee256c3b0ded67..a6290b6b79212f37de6db731df3879cf0646d58e 100644
--- a/packages/PEGTL/doc/Changelog.md
+++ b/packages/PEGTL/doc/Changelog.md
@@ -5,36 +5,51 @@
 **Not yet released**
 
 * Use the [**migration guide**](Migration-Guide.md#version-300) when updating.
-* Updated required C++ standard to C++17.
-* Updated required [CMake](https://cmake.org/) version to 3.8.
-* The macro `TAO_PEGTL_NAMESPACE` now contains the fully qualified namespace, e.g. `tao::pegtl`.
-* Replaced `tao::pegtl::input_error` with `std::system_error`.
-* Moved the analysis function and header to contrib.
-* Replaced `analysis_t` with more general and complete `rule_t` and `subs_t`.
-* Added functions to visit all rules of a grammar.
-* Added infrastructure and functions to measure rule coverage of a parsing run.
-* Added [`must_if<>`](Errors-and-Exceptions.md#custom-exception-messages)
-  * Allows to define custom error messages for global errors.
-  * As a non-intrusive way to define global parse errors for a grammar retroactively.
-* Moved rule `eolf` from inline namespace `tao::pegtl::ascii` to `tao::pegtl`.
-* Changed message of `tao::pegtl::parse_error` to no longer contain the position redundantly.
-* Changed rules in `tao/pegtl/contrib/integer.hpp` to not accept redundant leading zeros.
-* Added rules to `tao/pegtl/contrib/integer.hpp` that test unsigned values against a maximum.
-* Removed option of [state](Rule-Reference.md#state-s-r-)'s `S::success()` to have an extended signature to get access to the current `apply_mode`, `rewind_mode`, *action*- and *control* class (template).
-* Added `[[nodiscard]]` or `[[noreturn]]` to most non-void functions.
-* Removed compatibility macros starting with `TAOCPP_PEGTL_`.
-* Removed compatibility uppercase enumerators.
-* Removed compatibility `peek_byte()` member functions.
-* Removed compatibility header `changes.hpp` from contrib.
-* Demoted UTF-16 and UTF-32 support to contrib.
-* Demoted UINT-8, UINT-16, UINT-32 and UINT-64 support to contrib.
-* Folded `contrib/counter.hpp` into `json_count.cpp`, count is superceded by coverage.
-* Refactored demangling.
-  * Improves generated code to be shorter and more efficient.
-  * Removes the need for RTTI.
-  * Some broken/unknown compilers will use RTTI as a fallback, without demangling.
-* Refactored parse tree type storage/handling.
-  * Removes the need for RTTI.
+* Infrastructure
+  * Updated required C++ standard to C++17.
+  * Updated required [CMake](https://cmake.org/) version to 3.8.
+  * The macro `TAO_PEGTL_NAMESPACE` now contains the fully qualified namespace, e.g. `tao::pegtl`.
+  * Added `[[nodiscard]]` or `[[noreturn]]` to most non-void functions.
+* Meta-Data Layer
+  * Replaced `analysis_t` with more general and complete `rule_t` and `subs_t`.
+  * Added functions to visit all rules of a grammar.
+  * Added functions to measure rule coverage of a parsing run.
+  * Moved the analysis function and header to contrib.
+* Error Handling
+  * Replaced `tao::pegtl::input_error` with `std::system_error` and `std::filesystem::filesystem_error`.
+  * Added [`must_if<>`](Errors-and-Exceptions.md#custom-exception-messages)
+    * Allows to define custom error messages for global errors.
+    * Adds a non-intrusive way to define global parse errors for a grammar retroactively.
+* Demangling
+  * Removed the need for RTTI.
+    * Some broken/unknown compilers will use RTTI as a fallback, without demangling.
+  * Moved `tao::pegtl::internal::demangle<T>()` to `tao::demangle<T>()`.
+  * Improved generated code to be shorter and more efficient.
+* Parse Tree
+  * Removed the need for RTTI.
+* Other
+  * Changed `std::string` to `std::filesystem::path` for filename parameters.
+  * Renamed `byte_in_line` to `column` and use 1-based counting.
+  * Moved rule `eolf` from inline namespace `tao::pegtl::ascii` to `tao::pegtl`.
+  * Changed rules in `tao/pegtl/contrib/integer.hpp` to not accept redundant leading zeros.
+  * Added rules to `tao/pegtl/contrib/integer.hpp` that test unsigned values against a maximum.
+  * Demoted UTF-16 and UTF-32 support to contrib.
+  * Demoted UINT-8, UINT-16, UINT-32 and UINT-64 support to contrib.
+  * Folded `contrib/counter.hpp` into `json_count.cpp`, count is superceded by coverage.
+* Cleanup
+  * Removed option of [state](Rule-Reference.md#state-s-r-)'s `S::success()` to have an extended signature to get access to the current `apply_mode`, `rewind_mode`, *action*- and *control* class (template).
+  * Removed compatibility macros starting with `TAOCPP_PEGTL_`.
+  * Removed compatibility uppercase enumerators.
+  * Removed compatibility `peek_byte()` member functions.
+  * Removed compatibility header `changes.hpp` from contrib.
+
+## 2.8.3
+
+Released 2020-04-22
+
+* Fixed excessive read-ahead with incremental inputs.
+* Added state manipulators `remove_first_state`, `remove_last_states`, `rotate_states_right`, `rotate_states_left`, and `reverse_states` to contrib.
+* Reduced the number of intermediate parse tree nodes.
 
 ## 2.8.2
 
diff --git a/packages/PEGTL/doc/Control-and-Debug.md b/packages/PEGTL/doc/Control-and-Debug.md
index c8817e611e8a84e2c7894da571b74798bf6edf7c..7d801ef358f8822937251303bf3991abdac4b9ee 100644
--- a/packages/PEGTL/doc/Control-and-Debug.md
+++ b/packages/PEGTL/doc/Control-and-Debug.md
@@ -71,6 +71,13 @@ struct normal
 
 The static member functions `start()`, `success()` and `failure()` can be used to debug a grammar by using them to provide insight into what exactly is going on during a parsing run, or to construct a parse tree, etc.
 
+There is one more, *optional* hook function: `unwind()`.
+It is called when a rule throws an exception, e.g. on global error.
+It's signature is identical to `start()`/`success()`/`failure()`.
+It is not included in the default control template `normal`, as the existence of an `unwind()` method requires an additional `try`/`catch` block.
+This might potentially have an impact on the binary size and therefore, one should only add an `unwind()` method if necessary.
+Several other control classes utilize the `unwind()` method to track the execution even in the presence of global errors.
+
 The static member function `raise()` is used to create a global error, and any replacement should again throw an exception, or abort the application.
 
 The static member functions `apply()` and `apply0()` can customise how actions with, and without, receiving the matched input are called, respectively.
@@ -89,17 +96,13 @@ Before attempting to match a rule `R`, the PEGTL calls `C< R >::start()` where `
 Depending on what happens during the attempt to match `R`, one of the other three functions might be called.
 
 - If `R` succeeds, then `C< R >::success()` is called; compared to the call to `C< R >::start()`, the input will have consumed whatever the successful match of `R` consumed.
-
-- If `R` finishes with a failure, i.e. a return value of `false` from `match()`, then `C< R >::failure()` is called; a failed match **must not** consume input.
-
+- If `R` finishes with a local failure, i.e. a return value of `false` from `match()`, then `C< R >::failure()` is called; a failed match **must not** consume input.
+- If `R` finishes with a global failure, i.e. an exception being thrown from `match()`, then, if present, `C< R >::unwind()` is called.
 - If `R` is wrapped in `must< R >`, a global failure is generated by calling `C< R >::raise()` to throw some exception as is expected by the PEGTL in this case.
 
-- If a sub-rule of `R` finishes with a global failure, and the exception is not caught by a `try_catch` or similar combinator, then no other function of `C< R >` is called after `C< R >::start()`.
-
 Additionally, if matching `R` was successful and actions are enabled:
 
 - If `C< R >::apply()` exists, then `C< R >::apply()` is called with the matched input and the current state arguments.
-
 - If `C< R >::apply0()` exists, then `C< R >::apply0()` is called with the current state arguments.
 
 It is an error when both `C< R >::apply()` and `C< R >::apply0()` exist.
@@ -112,7 +115,6 @@ If either produce a (local) failure then `C< R >::failure()` is called.
 In all cases where an action is called, the success or failure hooks are invoked after the action returns.
 
 The included class `tao::pegtl::tracer` in `<tao/pegtl/contrib/tracer.hpp>` gives a practical example that can be used as control class to debug grammars.
-When an instance of class `tao::pegtl::trace_state` is used as single state in a parsing run with the tracer-control then the debug output contains a line number and rule number as additional information.
 
 ## Exception Throwing
 
diff --git a/packages/PEGTL/doc/Errors-and-Exceptions.md b/packages/PEGTL/doc/Errors-and-Exceptions.md
index 7cd752ef7eb009d7489070f9286d447613113e58..10408129978e2abd86bfced826725a9e9a519714 100644
--- a/packages/PEGTL/doc/Errors-and-Exceptions.md
+++ b/packages/PEGTL/doc/Errors-and-Exceptions.md
@@ -6,11 +6,12 @@ A parsing run, a call to one of the `parse()` functions as explained in [Inputs
 * A return value of `false` is called a *local failure* (even when propagated to the top).
 * An exception indicating a *global failure* is thrown.
 
-The PEGTL parsing rules throw exceptions of type `tao::pegtl::parse_error`, some of the inputs throw exceptions of type `tao::pegtl::input_error`.
+The PEGTL parsing rules throw exceptions of type `tao::pegtl::parse_error`, some of the inputs throw additional exceptions like `std::system_error` or `std::filesystem_error`.
 Other exception classes can be used freely from actions and custom parsing rules.
 
 ## Contents
 
+* [Global Failure](#global-failure)
 * [Local to Global Failure](#local-to-global-failure)
   * [Intrusive Local to Global Failure](#intrusive-local-to-global-failure)
   * [Non-Intrusive Local to Global Failure](#non-intrusive-local-to-global-failure)
@@ -18,6 +19,52 @@ Other exception classes can be used freely from actions and custom parsing rules
 * [Examples for Must Rules](#examples-for-must-rules)
 * [Custom Exception Messages](#custom-exception-messages)
 
+## Global Failure
+
+By default, global failure means that an exception of type `tao::pegtl::parse_error` is thrown.
+
+Synposis:
+
+```c++
+namespace tao::pegtl
+{
+   class parse_error
+      : public std::runtime_error
+   {
+      parse_error( const char* msg, position p );
+
+      parse_error( const std::string& msg, position p )
+         : parse_error( msg.c_str(), std::move( p ) )
+      {}
+
+      template< typename ParseInput >
+      parse_error( const char* msg, const ParseInput& in )
+         : parse_error( msg, in.position() )
+      {}
+
+      template< typename ParseInput >
+      parse_error( const std::string& msg, const ParseInput& in )
+         : parse_error( msg, in.position() )
+      {}
+
+      const char* what() const noexcept override;
+
+      std::string_view message() const noexcept;
+      const std::vector< position >& positions() const noexcept;
+
+      void add_position( position&& p );
+   };
+}
+```
+
+The `what()` message will contain all positions as well as the original `msg`.
+This allows retrieval of all information if the exception is handled as a `std::runtime_error` in a generic way.
+
+The `message()` function will return the original `msg`, while `positions()` allows access to the stored positions.
+This is useful to decompose the exception and provide more helpful errors to the user.
+
+The constructors can be used by custom rules to signal global failure, while `add_position()` is often used when you are parsing nested data, so you can append the position in the original file which includes the nested file.
+
 ## Local to Global Failure
 
 ### Intrusive Local to Global Failure
@@ -144,14 +191,25 @@ struct error { template< typename Rule > static constexpr auto message = error_m
 template< typename Rule > using control = tao::pegtl::must_if< error >::control< Rule >;
 ```
 
+`must_if<>` expects a wrapper for the error message as its first template parameter.
+There is a second parameter for the base control class, which defaults to `tao::pegtl::normal`, and which can combine `must_if`'s control class with other control classes.
+
 Since `raise()` is only instantiated for those rules for which `must<>` could trigger an exception, it is sufficient to provide specialisations of the error message string for those rules.
 Furthermore, there will be a compile-time error (i.e. a `static_assert`) for all rules for which the specialisation was forgotten although `raise()` could be called.
 
-The [control class](Control-and-Debug.md) provided by `must_if<>` also turns local failures into global failure if an error message is provided, i.e. if the error message is not `nullptr`.
+The [control class](Control-and-Debug.md) provided by `must_if<>` also turns, by default, local failures into global failure if an error message is provided, i.e. if the error message is not `nullptr`.
 This means that one can provide additional points in the grammar where a global failure is triggered, even when the grammar contains no `must<>` error points.
 
-`must_if<>` expects a wrapper for the error message as its first template parameter.
-There is a second parameter for the base control class, which defaults to `tao::pegtl::normal`, and which can combine `must_if`'s control class with other control classes.
+The above feature also means that a rule which is used both with and without `must<>`, one would not only provide a custom error message for the location where the rule is failing within a `must<>`-context, but local errors in other contexts are implicitly turned into global error.
+If this behaviour is not intended, one can disable the "turn local to global failure" feature by setting `raise_on_failure` to `false` in the wrapper class:
+
+```c++
+struct error
+{
+   template< typename Rule > static constexpr bool raise_on_failure = false;
+   template< typename Rule > static constexpr auto message = error_message< Rule >;
+};
+```
 
 It is advisable to choose the error points in the grammar with prudence.
 This choice becoming particularly cumbersome and/or resulting in a large number of error points might be an indication of the grammar needing some kind of simplification or restructuring.
diff --git a/packages/PEGTL/doc/Getting-Started.md b/packages/PEGTL/doc/Getting-Started.md
index d2ef73f544ed8e824f94101b2c967c789e9227bc..50674bd2af263fd471050316fc5f84dbc31f25d1 100644
--- a/packages/PEGTL/doc/Getting-Started.md
+++ b/packages/PEGTL/doc/Getting-Started.md
@@ -4,9 +4,6 @@ Since the PEGTL is a parser library, here is an "inverse hello world" example th
 rather than prints, the string `Hello, foo!` for any sequence of alphabetic ASCII characters `foo`.
 
 ```c++
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
 #include <string>
 #include <iostream>
 
@@ -98,7 +95,174 @@ terminate called after throwing an instance of 'tao::pegtl::parse_error'
 Aborted (core dumped)
 ```
 
-Frequently an application will include a top-level `try-catch` block to handle
-the exception.
+The PEGTL provides multiple facilities that help to get started and develop your grammar.
+In the following paragraphs we will show several small programs to showcase the capabilities of the PEGTL.
+
+Note, however, that all examples shown in this document will lack proper error handling.
+Frequently an application will include `try-catch` blocks to handle the exceptions.
+The correct way of handling errors is shown at the last paragraph of this page.
+
+## Grammar Analysis
+
+Every grammar must be free of cycles that make no progress, i.e. the cycle does not consume any input.
+This is a common problem in parsing called [left recursion](https://en.wikipedia.org/wiki/Left_recursion).
+Especially with the PEG formalism, it results in an infinite loop and, eventually, in a stack overflow.
+
+The PEGTL provides a [grammar analysis](Grammar-Analysis.md) with which a grammar can be verified.
+Note that this is done at runtime as a pure compile-time analysis would lead to insupportable compile-times.
+The analysis, however, is only based on the grammar itself and not on a specific input.
+Additionally, the analysis is typically written as a separate program to keep any overhead from your normal applications.
+
+```c++
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
+
+// This example uses the included JSON grammar
+#include <tao/pegtl/contrib/json.hpp>
+
+namespace pegtl = tao::pegtl;
+
+using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+int main()
+{
+   if( pegtl::analyze< grammar >() != 0 ) {
+      std::cerr << "cycles without progress detected!\n";
+      return 1;
+   }
+
+   return 0;
+}
+```
+
+## Tracer
+
+One of the most basic tools when developing a grammar is a tracer that prints every step of a parsing run.
+The PEGTL provides a tracer that will print to stderr, as well as allowing users to write their own tracers to output other formats.
+
+```c++
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
+
+// This example uses the included JSON grammar
+#include <tao/pegtl/contrib/json.hpp>
+
+namespace pegtl = tao::pegtl;
+
+using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+int main( int argc, char** argv )
+{
+   if( argc != 2 ) return 1;
+
+   pegtl::argv_input in( argv, i );
+   pegtl::standard_tracer tr( in );
+   tr.parse< grammar >( in );
+
+   return 0;
+}
+```
+
+In the above each command line parameter is parsed as a JSON string.
+As the output gets long quickly, we will not show it here, please have a look at the [Tracer](Tracer.md) documentation.
+
+TODO: Write `Tracer.md`.
+
+## Parse Tree / AST
+
+When developing grammars, a common goal is to generate a [parse tree](https://en.wikipedia.org/wiki/Parse_tree) or an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree).
+
+The PEGTL provides a [Parse Tree](Parse-Tree.md) builder that can filter and/or transform tree nodes on-the-fly.
+Additionally, a helper is provided to print out the resulting data structure in the [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) format, suitable for creating a graphical representation of the parse tree.
+
+The following example uses a selector to filter the parse tree nodes, as otherwise the graphical representation may become confusing quite quickly.
+
+```c++
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/parse_tree.hpp>
+#include <tao/pegtl/contrib/parse_tree_to_dot.hpp>
+
+// This example uses the included JSON grammar
+#include <tao/pegtl/contrib/json.hpp>
+
+namespace pegtl = tao::pegtl;
+
+using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+template< typename Rule >
+using selector = pegtl::parse_tree::selector<
+   Rule,
+   pegtl::parse_tree::store_content::on<
+      pegtl::json::null,
+      pegtl::json::true_,
+      pegtl::json::false_,
+      pegtl::json::number,
+      pegtl::json::string,
+      pegtl::json::key,
+      pegtl::json::array,
+      pegtl::json::object,
+      pegtl::json::member > >;
+
+int main( int argc, char** argv )
+{
+   if( argc != 2 ) return 1;
+
+   pegtl::argv_input in( argv, i );
+   const auto root = parse_tree::parse< grammar, selector >( in );
+   if( root ) {
+      parse_tree::print_dot( std::cout, *root );
+   }
+
+   return 0;
+}
+```
+
+Running the above program with some example input:
+
+```sh
+$ build/src/example/pegtl/json_parse_tree '{"foo":[true,{}],"bar":[42,null]}' | dot -Tsvg -o json_parse_tree.svg
+```
+
+The above will generate an SVG file with a graphical representation of the parse tree.
+
+![JSON Parse Tree](Json-Parse-Tree.svg)
+
+## Error Handling
+
+Although the PEGTL could be used without exceptions, most programs will use input classes or grammars that might throw exceptions.
+Typically, the following pattern helps to print the exceptions properly:
+
+```c++
+   // The surrounding try/catch for normal exceptions.
+   // These might occur if a file can not be opened, etc.
+   try {
+      tao::pegtl::file_input in( filename );
+
+      // The inner try/catch block, see below...
+      try {
+
+         // The actual parser, tracer, parse tree, ...
+         pegtl::parse< grammar >( in );
+
+      }
+      catch( const pegtl::parse_error& e ) {
+
+         // This catch block needs access to the input
+         const auto p = e.positions().front();
+         std::cerr << e.what() << '\n'
+                   << in.line_at( p ) << '\n'
+                   << std::setw( p.column ) << '^' << std::endl;
+
+      }
+   }
+   catch( const std::exception& e ) {
+
+      // Generic catch block for other exceptions
+      std::cerr << e.what() << std::endl;
+
+   }
+```
+
+For more information see [Errors and Exceptions](Errors-and-Exceptions.md).
 
 Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
diff --git a/packages/PEGTL/doc/Inputs-and-Parsing.md b/packages/PEGTL/doc/Inputs-and-Parsing.md
index 689f0938c74c7c99f6dec5555dd554839524b925..2f00c8661cb61e5cdbbbb96f1446d2b7d9899d7d 100644
--- a/packages/PEGTL/doc/Inputs-and-Parsing.md
+++ b/packages/PEGTL/doc/Inputs-and-Parsing.md
@@ -51,7 +51,7 @@ All classes and functions on this page are in namespace `tao::pegtl`.
 
 ## Tracking Mode
 
-Some input classes allow a choice of tracking mode, or whether the `byte`, `line` and `byte_in_line` counters are continuously updated during a parsing run with `tracking_mode::eager`, or only calculated on-demand in `position()` by scanning the complete input again with `tracking_mode::lazy`.
+Some input classes allow a choice of tracking mode, or whether the `byte`, `line` and `column` counters are continuously updated during a parsing run with `tracking_mode::eager`, or only calculated on-demand in `position()` by scanning the complete input again with `tracking_mode::lazy`.
 
 Lazy tracking is recommended when the position is used very infrequently, for example only in the case of throwing a `parse_error`.
 
@@ -78,7 +78,6 @@ The classes `file_input<>`, `read_input<>` and, on supported platforms, `mmap_in
 * `mmap_input<>` uses `mmap(2)` on POSIX compliant systems or `MapViewOfFile()` on Windows.
 * `file_input<>` is derived from `mmap_input<>` when available, and `read_input<>` otherwise, inheriting the respective constructors.
 
-Most file input classes take a single argument, the filename, which can be supplied as `std::string` or `const char*`.
 They immediately make available the complete contents of the file; `read_input<>` reads the entire file upon construction.
 
 The constructors that take a `FILE*` argument take ownership of the file pointer, i.e. they `fclose()` it in the destructor.
@@ -87,27 +86,24 @@ The constructors that take a `FILE*` argument take ownership of the file pointer
 template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf >
 struct read_input
 {
-   explicit read_input( const char* filename );
-   explicit read_input( const std::string& filename );
+   explicit read_input( const std::filesystem::path& path );
+   read_input( const std::filesystem::path& path, const std::string& source );
 
-   read_input( FILE* file, const char* filename );
-   read_input( FILE* file, const std::string& filename );
+   read_input( FILE* file, const std::filesystem::path& path );
+   read_input( FILE* file, const std::filesystem::path& path, const std::string& source );
 };
 
 template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf >
 struct mmap_input
 {
-   explicit mmap_input( const char* filename );
-   explicit mmap_input( const std::string& filename );
+   explicit mmap_input( const std::filesystem::path& path );
+   mmap_input( const std::filesystem::path& path, const std::string& source );
 };
 
 template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf >
 using file_input = mmap_input< P, Eol >;  // Or read_input when no mmap_input available.
 ```
 
-Note that the implementation of the constructors is different than shown.
-They should be used "as if" this was the actual signature.
-
 ## Memory Input
 
 The class `memory_input<>` can be used to parse existing contiguous blocks of memory like the contents of a `std::string`.
@@ -119,7 +115,7 @@ If you don't want to specify a source just use the empty string (`""`).
 The constructors that only takes a `const char* begin` for the data uses `std::strlen()` to determine the length.
 It will therefore *only* work correctly with data that is terminated with a 0-byte (and does not contain embedded 0-bytes, which are otherwise fine).
 
-The constructors that take additional `byte`, `line` and `byte_in_line` arguments initialise the internal counters with the supplied values, rather than the defaults of `0`, `1` and `0`.
+The constructors that take additional `byte`, `line` and `column` arguments initialise the internal counters with the supplied values, rather than the defaults of `0`, `1` and `1`.
 
 ```c++
 template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf, typename Source = std::string >
@@ -142,7 +138,7 @@ class memory_input
 
    template< typename T >
    memory_input( const char* begin, const char* end, T&& source,
-                 const std::size_t byte, const std::size_t line, const std::size_t byte_in_line ) noexcept(...);
+                 const std::size_t byte, const std::size_t line, const std::size_t column ) noexcept(...);
 };
 ```
 
@@ -207,7 +203,7 @@ class string_input
 
    template< typename V, typename T >
    string_input( V&& data, T&& source,
-                 const std::size_t byte, const std::size_t line, const std::size_t byte_in_line ) noexcept(...);
+                 const std::size_t byte, const std::size_t line, const std::size_t column ) noexcept(...);
 };
 ```
 
@@ -532,10 +528,10 @@ try {
   // call parse on the input 'in' here...
 }
 catch( const parse_error& e ) {
-   const auto p = e.positions.front();
+   const auto p = e.positions().front();
    std::cerr << e.what() << std::endl
-             << in.line_at( p ) << std::endl
-             << std::string( p.byte_in_line, ' ' ) << '^' << std::endl;
+             << in.line_at( p ) << '\n'
+             << std::setw( p.column ) << '^' << std::endl;
 }
 ```
 
diff --git a/packages/PEGTL/doc/Installing-and-Using.md b/packages/PEGTL/doc/Installing-and-Using.md
index ec4302e1314688def828e3c9f9737b5f0202c3bc..91fc2efec9a772708ab72d1c8aaa3b27193016a1 100644
--- a/packages/PEGTL/doc/Installing-and-Using.md
+++ b/packages/PEGTL/doc/Installing-and-Using.md
@@ -21,10 +21,15 @@
 
 The PEGTL requires a C++17-capable compiler, e.g. one of
 
-* GCC 7
+* GCC 8
 * Clang 5
 * Visual Studio 2017
 
+with (on Unix)
+
+* libstdc++ 8
+* libc++ 7
+
 on either
 
 * Linux
@@ -34,6 +39,8 @@ on either
 It requires C++17, e.g. using the `--std=c++17` compiler switch.
 Using newer versions of the C++ standard is supported.
 
+Note that using libstdc++ 8 requires linking with `-lstdc++fs`.
+
 Larger projects will frequently require the `/bigobj` option when compiling with Visual Studio on Windows.
 
 It should also work with other C++17 compilers on other Unix systems (or any sufficiently compatible platform).
@@ -50,6 +57,8 @@ Note that some of the listed packages are not updated regularly.
 
 ## Using Conan
 
+[![Download](https://api.bintray.com/packages/conan/conan-center/taocpp-pegtl%3A_/images/download.svg)](https://bintray.com/conan/conan-center/taocpp-pegtl%3A_/_latestVersion)
+
 You can download and install the PEGTL using the [Conan] package manager:
 
 ```bash
@@ -246,9 +255,8 @@ $ make amalgamate
 ```
 
 The above will generate a `build/amalgamated/pegtl.hpp` which will consist of
-the headers `tao/pegtl.hpp`, `tao/pegtl/analyze.hpp`, their dependencies,
-and all headers in `tao/pegtl/contrib/` except for the headers in
-`tao/pegtl/contrib/icu/`.
+the headers `tao/pegtl.hpp`, their dependencies, and all headers in
+`tao/pegtl/contrib/` except for the headers in `tao/pegtl/contrib/icu/`.
 
 Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 
diff --git a/packages/PEGTL/doc/Json-Parse-Tree.svg b/packages/PEGTL/doc/Json-Parse-Tree.svg
new file mode 100644
index 0000000000000000000000000000000000000000..27d62db25f61291e3298077f1f0f2d3b9929ade2
--- /dev/null
+++ b/packages/PEGTL/doc/Json-Parse-Tree.svg
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.40.1 (0)
+ -->
+<!-- Title: parse_tree Pages: 1 -->
+<svg width="1205pt" height="403pt"
+ viewBox="0.00 0.00 1205.45 402.96" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 398.9605)">
+<title>parse_tree</title>
+<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-398.9605 1201.4457,-398.9605 1201.4457,4 -4,4"/>
+<!-- x0x1690eb0 -->
+<g id="node1" class="node">
+<title>x0x1690eb0</title>
+<ellipse fill="none" stroke="#000000" cx="485.0158" cy="-376.9605" rx="38.1938" ry="18"/>
+<text text-anchor="middle" x="485.0158" y="-373.2605" font-family="Times,serif" font-size="14.00" fill="#000000">ROOT</text>
+</g>
+<!-- x0x1691240 -->
+<g id="node2" class="node">
+<title>x0x1691240</title>
+<ellipse fill="none" stroke="#000000" cx="485.0158" cy="-296.0904" rx="194.4087" ry="26.7407"/>
+<text text-anchor="middle" x="485.0158" y="-299.8904" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::object</text>
+<text text-anchor="middle" x="485.0158" y="-284.8904" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;{\&quot;foo\&quot;:[true,{}],\&quot;bar\&quot;:[42,null]}&quot;</text>
+</g>
+<!-- x0x1690eb0&#45;&gt;x0x1691240 -->
+<g id="edge1" class="edge">
+<title>x0x1690eb0&#45;&gt;x0x1691240</title>
+<path fill="none" stroke="#000000" d="M485.0158,-358.6098C485.0158,-351.0399 485.0158,-341.9805 485.0158,-333.1385"/>
+<polygon fill="#000000" stroke="#000000" points="488.5159,-332.961 485.0158,-322.961 481.5159,-332.9611 488.5159,-332.961"/>
+</g>
+<!-- x0x16913f0 -->
+<g id="node3" class="node">
+<title>x0x16913f0</title>
+<ellipse fill="none" stroke="#000000" cx="341.0158" cy="-206.3503" rx="135.1148" ry="26.7407"/>
+<text text-anchor="middle" x="341.0158" y="-210.1503" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::member</text>
+<text text-anchor="middle" x="341.0158" y="-195.1503" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;\&quot;foo\&quot;:[true,{}]&quot;</text>
+</g>
+<!-- x0x1691240&#45;&gt;x0x16913f0 -->
+<g id="edge2" class="edge">
+<title>x0x1691240&#45;&gt;x0x16913f0</title>
+<path fill="none" stroke="#000000" d="M442.5899,-269.6508C426.341,-259.5246 407.6599,-247.8826 390.7852,-237.3663"/>
+<polygon fill="#000000" stroke="#000000" points="392.4859,-234.3022 382.1479,-231.9836 388.7836,-240.243 392.4859,-234.3022"/>
+</g>
+<!-- x0x1691870 -->
+<g id="node4" class="node">
+<title>x0x1691870</title>
+<ellipse fill="none" stroke="#000000" cx="629.0158" cy="-206.3503" rx="135.1148" ry="26.7407"/>
+<text text-anchor="middle" x="629.0158" y="-210.1503" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::member</text>
+<text text-anchor="middle" x="629.0158" y="-195.1503" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;\&quot;bar\&quot;:[42,null]&quot;</text>
+</g>
+<!-- x0x1691240&#45;&gt;x0x1691870 -->
+<g id="edge3" class="edge">
+<title>x0x1691240&#45;&gt;x0x1691870</title>
+<path fill="none" stroke="#000000" d="M527.4417,-269.6508C543.6905,-259.5246 562.3716,-247.8826 579.2464,-237.3663"/>
+<polygon fill="#000000" stroke="#000000" points="581.2479,-240.243 587.8837,-231.9836 577.5456,-234.3022 581.2479,-240.243"/>
+</g>
+<!-- x0x1691510 -->
+<g id="node5" class="node">
+<title>x0x1691510</title>
+<ellipse fill="none" stroke="#000000" cx="111.0158" cy="-116.6102" rx="111.0315" ry="26.7407"/>
+<text text-anchor="middle" x="111.0158" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::key</text>
+<text text-anchor="middle" x="111.0158" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;\&quot;foo\&quot;&quot;</text>
+</g>
+<!-- x0x16913f0&#45;&gt;x0x1691510 -->
+<g id="edge4" class="edge">
+<title>x0x16913f0&#45;&gt;x0x1691510</title>
+<path fill="none" stroke="#000000" d="M279.38,-182.3016C248.5091,-170.2566 211.0461,-155.6394 179.3035,-143.2543"/>
+<polygon fill="#000000" stroke="#000000" points="180.2378,-139.8619 169.6496,-139.4876 177.6934,-146.3831 180.2378,-139.8619"/>
+</g>
+<!-- x0x16916c0 -->
+<g id="node6" class="node">
+<title>x0x16916c0</title>
+<ellipse fill="none" stroke="#000000" cx="360.0158" cy="-116.6102" rx="120.4167" ry="26.7407"/>
+<text text-anchor="middle" x="360.0158" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::array</text>
+<text text-anchor="middle" x="360.0158" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;[true,{}]&quot;</text>
+</g>
+<!-- x0x16913f0&#45;&gt;x0x16916c0 -->
+<g id="edge5" class="edge">
+<title>x0x16913f0&#45;&gt;x0x16916c0</title>
+<path fill="none" stroke="#000000" d="M346.7164,-179.4253C348.4448,-171.2616 350.3742,-162.1491 352.2154,-153.4525"/>
+<polygon fill="#000000" stroke="#000000" points="355.6719,-154.0243 354.3192,-143.5162 348.8237,-152.5743 355.6719,-154.0243"/>
+</g>
+<!-- x0x1691900 -->
+<g id="node9" class="node">
+<title>x0x1691900</title>
+<ellipse fill="none" stroke="#000000" cx="619.0158" cy="-116.6102" rx="111.0315" ry="26.7407"/>
+<text text-anchor="middle" x="619.0158" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::key</text>
+<text text-anchor="middle" x="619.0158" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;\&quot;bar\&quot;&quot;</text>
+</g>
+<!-- x0x1691870&#45;&gt;x0x1691900 -->
+<g id="edge8" class="edge">
+<title>x0x1691870&#45;&gt;x0x1691900</title>
+<path fill="none" stroke="#000000" d="M626.0154,-179.4253C625.1156,-171.3504 624.1124,-162.3471 623.1528,-153.7362"/>
+<polygon fill="#000000" stroke="#000000" points="626.6,-153.067 622.014,-143.5162 619.6431,-153.8423 626.6,-153.067"/>
+</g>
+<!-- x0x1691c70 -->
+<g id="node10" class="node">
+<title>x0x1691c70</title>
+<ellipse fill="none" stroke="#000000" cx="868.0158" cy="-116.6102" rx="120.4167" ry="26.7407"/>
+<text text-anchor="middle" x="868.0158" y="-120.4102" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::array</text>
+<text text-anchor="middle" x="868.0158" y="-105.4102" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;[42,null]&quot;</text>
+</g>
+<!-- x0x1691870&#45;&gt;x0x1691c70 -->
+<g id="edge9" class="edge">
+<title>x0x1691870&#45;&gt;x0x1691c70</title>
+<path fill="none" stroke="#000000" d="M692.4359,-182.5372C724.5318,-170.4858 763.6079,-155.8134 796.7409,-143.3726"/>
+<polygon fill="#000000" stroke="#000000" points="798.2351,-146.5502 806.3666,-139.7583 795.7745,-139.9969 798.2351,-146.5502"/>
+</g>
+<!-- x0x1691480 -->
+<g id="node7" class="node">
+<title>x0x1691480</title>
+<ellipse fill="none" stroke="#000000" cx="154.0158" cy="-26.8701" rx="119.5021" ry="26.7407"/>
+<text text-anchor="middle" x="154.0158" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::true_</text>
+<text text-anchor="middle" x="154.0158" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;true&quot;</text>
+</g>
+<!-- x0x16916c0&#45;&gt;x0x1691480 -->
+<g id="edge6" class="edge">
+<title>x0x16916c0&#45;&gt;x0x1691480</title>
+<path fill="none" stroke="#000000" d="M305.0822,-92.6794C278.4184,-81.0638 246.2148,-67.0349 218.403,-54.9192"/>
+<polygon fill="#000000" stroke="#000000" points="219.7196,-51.6751 209.1539,-50.89 216.9239,-58.0926 219.7196,-51.6751"/>
+</g>
+<!-- x0x1691b50 -->
+<g id="node8" class="node">
+<title>x0x1691b50</title>
+<ellipse fill="none" stroke="#000000" cx="416.0158" cy="-26.8701" rx="124.4016" ry="26.7407"/>
+<text text-anchor="middle" x="416.0158" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::object</text>
+<text text-anchor="middle" x="416.0158" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;{}&quot;</text>
+</g>
+<!-- x0x16916c0&#45;&gt;x0x1691b50 -->
+<g id="edge7" class="edge">
+<title>x0x16916c0&#45;&gt;x0x1691b50</title>
+<path fill="none" stroke="#000000" d="M376.8176,-89.6852C382.1888,-81.0778 388.2182,-71.4157 393.9077,-62.2983"/>
+<polygon fill="#000000" stroke="#000000" points="396.901,-64.1127 399.2258,-53.776 390.9624,-60.4068 396.901,-64.1127"/>
+</g>
+<!-- x0x1691630 -->
+<g id="node11" class="node">
+<title>x0x1691630</title>
+<ellipse fill="none" stroke="#000000" cx="822.0158" cy="-26.8701" rx="132.8722" ry="26.7407"/>
+<text text-anchor="middle" x="822.0158" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::number</text>
+<text text-anchor="middle" x="822.0158" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;42&quot;</text>
+</g>
+<!-- x0x1691c70&#45;&gt;x0x1691630 -->
+<g id="edge10" class="edge">
+<title>x0x1691c70&#45;&gt;x0x1691630</title>
+<path fill="none" stroke="#000000" d="M854.2142,-89.6852C849.8932,-81.2553 845.0535,-71.8137 840.4654,-62.863"/>
+<polygon fill="#000000" stroke="#000000" points="843.4838,-61.0785 835.8075,-53.776 837.2545,-64.2716 843.4838,-61.0785"/>
+</g>
+<!-- x0x1691e80 -->
+<g id="node12" class="node">
+<title>x0x1691e80</title>
+<ellipse fill="none" stroke="#000000" cx="1085.0158" cy="-26.8701" rx="112.36" ry="26.7407"/>
+<text text-anchor="middle" x="1085.0158" y="-30.6701" font-family="Times,serif" font-size="14.00" fill="#000000">tao::pegtl::json::null</text>
+<text text-anchor="middle" x="1085.0158" y="-15.6701" font-family="Times,serif" font-size="14.00" fill="#000000">&quot;null&quot;</text>
+</g>
+<!-- x0x1691c70&#45;&gt;x0x1691e80 -->
+<g id="edge11" class="edge">
+<title>x0x1691c70&#45;&gt;x0x1691e80</title>
+<path fill="none" stroke="#000000" d="M925.3138,-92.9146C954.0934,-81.0129 989.1091,-66.5322 1019.0107,-54.1664"/>
+<polygon fill="#000000" stroke="#000000" points="1020.6216,-57.2878 1028.525,-50.2318 1017.9464,-50.8191 1020.6216,-57.2878"/>
+</g>
+</g>
+</svg>
diff --git a/packages/PEGTL/doc/Meta-Data-and-Visit.md b/packages/PEGTL/doc/Meta-Data-and-Visit.md
index e8c5f5223abe862508dab87112698284c40851a4..3f8207553087b91920fc06f03f7fe54b15da718e 100644
--- a/packages/PEGTL/doc/Meta-Data-and-Visit.md
+++ b/packages/PEGTL/doc/Meta-Data-and-Visit.md
@@ -83,10 +83,68 @@ Unlike `visit()`, `visit_rt()` returns the number of rules visited.
 
 ## Grammar Print
 
-TODO.
+The functions `print_rules()` and `print_sub_rules()` from `include/tao/pegtl/contrib/print.hpp` combine the `visit()` function with visitors that print some information about all (sub-)rules of the supplied grammar to the supplied `std::ostream`.
+
+See `src/example/pegtl/json_print_rules.cpp` and `src/example/pegtl/json_print_sub_rules.cpp` for how to use these functions, and what the output looks like.
+As expected, the `internal` sub-rules are printed, too.
 
 ## Rule Coverage
 
-TODO.
+The function `coverage()` from `include/tao/pegtl/contrib/coverage.hpp` is very similar to the `parse()` function.
+It is called like `parse()`, with the some of the same template parameters and all of the same function arguments, however it returns an object of type `coverage_result` instead of a `bool`.
+
+```c++
+template< typename Rule,
+          template< typename... > class Action = nothing,
+          template< typename... > class Control = normal,
+          typename ParseInput,
+          typename... States >
+coverage_result coverage( ParseInput& in,
+                          States&&... st );
+```
+
+After a parsing run, the `coverage_result` indicates whether the run was a success or a failure, and contains "rule coverage" and "branch coverage" information.
+
+The "rule coverage" shows how often each rule was attempted to match, and how many of these attempts were a success or a -- local or global -- failure.
+
+The "branch coverage" consists in the matching information also being recorded for each immediate sub-rule of every rule; in the case of an `sor<>` this shows how often each sub-rule was taken, hence the name.
+
+The coverage information in the `coverage_result` can either be inspected and processed or printed manually, or the `ostream` output `operator<<` from `include/tao/pegtl/contrib/print_coverage.hpp` can be used.
+The operator formats the output as JSON.
+
+```c++
+std::ostream operator<<( std::ostream&, const coverage_result& );
+```
+
+The coverage information in the `coverage_result` is defined as follows.
+The `coverage_info` is used in two places, as part of the `coverage_entry` for each rule, and as value in the `branches` map for each immediate sub-rule.
+
+```c++
+struct coverage_info
+{
+   std::size_t start = 0;  // How often a rule was attempted to match.
+   std::size_t success = 0;  // How many attempts were a success (true).
+   std::size_t failure = 0;  // How many attempts were a local failure (false).
+   std::size_t unwind = 0;  // How many attempts were aborted due to an exception (thrown here or elsewhere).
+   std::size_t raise = 0;  // How many attempts were a global failure (exception thrown at this rule).
+};
+
+struct coverage_entry
+   : coverage_info  // The coverage_info for each rule.
+{
+   std::map< std::string_view, coverage_info > branches;  // The coverage_info for each immediate sub-rule.
+};
+
+struct coverage_result
+{
+   std::string_view grammar;  // Name of the top-level grammar rule.
+   std::string source;  // From the input.
+
+   std::map< std::string_view, coverage_entry > map;  // The coverage_entry for each rule.
+   bool result;  // Whether the parsing run was a success.
+};
+```
+
+As usual, unless otherwise indicated, all functions and data structure are in the namespace `tao::pegtl`.
 
 Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
diff --git a/packages/PEGTL/doc/Migration-Guide.md b/packages/PEGTL/doc/Migration-Guide.md
index ccbe64dad09a56632149765e2995260aa8574c18..2ef77f806dae469b588eb033c3b01e8671ee849a 100644
--- a/packages/PEGTL/doc/Migration-Guide.md
+++ b/packages/PEGTL/doc/Migration-Guide.md
@@ -4,13 +4,15 @@
 
 * The build system needs to be configured for C++17 or later.
 * The macro `TAO_PEGTL_NAMESPACE` now defines the fully qualified namespace and was changed from `pegtl` to `tao::pegtl`. When setting `TAO_PEGTL_NAMESPACE`, adapt as needed; in case of doubt, add `tao::` as prefix.
+* The 0-based `byte_in_line` was replaced with the 1-based `column`.
 * The control class template's `apply()` and `apply0()` must only be visible (e.g. via SFINAE) when an action class template function with the appropriate signature exists. See `tao::pegtl::normal` as example.
-* The error message from `tao::pegtl::parse_error` no longer contains the position as a prefix. The positions are available from the `positions` member variable.
 * If you have a use-case for [state](Rule-Reference.md#state-s-r-)'s `S::success()` to have an extended signature to get access to the current `apply_mode`, `rewind_mode`, *action*- and *control* class (template), please let us know and we'll re-add this feature.
 * The compatibility macros starting with `TAOCPP_PEGTL_` were removed, the corresponding `TAO_PEGTL_`-prefixed macros must be used.
 * The compatibility uppercase enumerators were removed, the corresponding lowercase enumerators must be used.
 * The compatibility `peek_byte()` member functions were removed, the `peek_uint8()` member functions must be used.
 * The compatibility header `changes.hpp` was removed, use the action-based `change_*.hpp` headers.
+* The parse tree nodes provide `node->type` (a `std::string_view`) instead of `node->name()`.
+* The parse tree nodes provide `node->string_view()` and `node->string()` instead of `node->content()`.
 
 ## Version 2.8.0
 
diff --git a/packages/PEGTL/doc/Parse-Tree.md b/packages/PEGTL/doc/Parse-Tree.md
index 59d5e6ec3f46da0f75f2375f0b15aadd052d1d91..f4a7f7c971296d87d00d18fde2ca18a1c46a4428 100644
--- a/packages/PEGTL/doc/Parse-Tree.md
+++ b/packages/PEGTL/doc/Parse-Tree.md
@@ -10,8 +10,6 @@ It provides the basic infrastructure to build a parse tree that
   * but can also be used with a custom tree node class that adheres to certain rules;
 * and supports on-the-fly tree transformations; some of the more common ones are included.
 
-> The parse tree / AST part of the PEGTL is currently in active development and serves as a prove-of-concept, expect changes at any time. Try it out, experiment with it, and most importantly let us know what you think of it. We need **your** feedback!
-
 ## Content
 
 * [Full Parse Tree](#full-parse-tree)
@@ -34,7 +32,7 @@ auto root = tao::pegtl::parse_tree::parse< my_grammar >( in );
 The result is a `std::unique_ptr< tao::pegtl::parse_tree::node >`.
 The pointer is empty when the input did not match the grammar, otherwise it contains the root node of the resulting parse tree.
 
-The tree nodes have a `name()` member function that returns the name of the grammar rule of which it represents a successful match, `begin()` and `end()` member functions to access the position of the matched portion of the input, `string()` and `string_view()` to actually access said matched input, and a vector called `children` with unique pointers to the child nodes.
+The tree nodes have a `type` member that contains the name of the grammar rule of which it represents a successful match, `begin()` and `end()` member functions to access the position of the matched portion of the input, `string()` and `string_view()` to actually access said matched input, and a vector called `children` with unique pointers to the child nodes.
 
 Note that the included tree node class **points** to the matched data, rather than copying it into the node, wherefore the input **must** still be "alive" when accessing the matched data!
 
diff --git a/packages/PEGTL/doc/README.md b/packages/PEGTL/doc/README.md
index 435f23193261a357715b02597dfa93a6c3148a3f..2fb1681fc3020828f0158ab0390b1c03415f77ba 100644
--- a/packages/PEGTL/doc/README.md
+++ b/packages/PEGTL/doc/README.md
@@ -45,6 +45,7 @@
     * [State Mismatch](Actions-and-States.md#state-mismatch)
   * [Legacy Actions](Actions-and-States.md#legacy-actions)
 * [Errors and Exceptions](Errors-and-Exceptions.md)
+  * [Global Failure]((Errors-and-Exceptions.md#global-failure)
   * [Local to Global Failure](Errors-and-Exceptions.md#local-to-global-failure)
     * [Intrusive Local to Global Failure](Errors-and-Exceptions.md#intrusive-local-to-global-failure)
     * [Non-Intrusive Local to Global Failure](Errors-and-Exceptions.md#non-intrusive-local-to-global-failure)
diff --git a/packages/PEGTL/doc/Rule-Reference.md b/packages/PEGTL/doc/Rule-Reference.md
index 8464355a5ed3125ce0bf02a2300cd52818e8eb1b..4072fd94462affe39a677fb2358ff49470b9b2f7 100644
--- a/packages/PEGTL/doc/Rule-Reference.md
+++ b/packages/PEGTL/doc/Rule-Reference.md
@@ -473,7 +473,7 @@ Note that the `true` template parameter to `internal::if_must` corresponds to th
 ###### `until< R, S... >`
 
 * Matches `seq< S... >` as long as `at< R >` does not match and succeeds when `R` matches.
-* [Equivalent] to `seq< star< not_at< R >, not_at< eof >, S... >, R >`.
+* [Equivalent] to `seq< star< not_at< R >, S... >, R >`.
 * Does not apply if `S` is an empty rule pack, see the previous entry for the semantics of `until< R >`.
 * [Meta data] and [implementation] mapping:
   - `until< R, S >::rule_t` is `internal::until< R, S >`
@@ -530,9 +530,9 @@ Atomic rules do not rely on other rules.
 
 ###### `bol`
 
-* Succeeds at "beginning-of-line", i.e. when the input's `byte_in_line()` member function returns zero.
+* Succeeds at "beginning-of-line", i.e. when the input's `column()` member function returns one.
 * Does not consume input.
-* Does **not** work with inputs that don't have a `byte_in_line()` member function.
+* Does **not** work with inputs that don't have a `column()` member function.
 * [Meta data] and [implementation] mapping:
   - `bol::rule_t` is `internal::bol`
 
diff --git a/packages/PEGTL/doc/Rules-and-Grammars.md b/packages/PEGTL/doc/Rules-and-Grammars.md
index 0fd0caa4c0a206832cc5baa886629277f686dec2..ece2da2dfc8269b4d95571f674c6957cf999dadf 100644
--- a/packages/PEGTL/doc/Rules-and-Grammars.md
+++ b/packages/PEGTL/doc/Rules-and-Grammars.md
@@ -71,44 +71,45 @@ Numbers are non-empty sequences of ASCII digits.
 The rule named `file` is the intended top-level rule of the grammar, i.e. the rule that is supplied as template argument to [the `parse()` function](Inputs-and-Parsing.md#parse-function) in order to start a parsing run with this grammar.
 
 ```c++
-using namespace tao::pegtl;
-
-struct line_comment
-   : until< eolf > {};
+struct hash_comment
+   : tao::pegtl::until< tao::pegtl::eolf > {};
 
 struct list;
 
 struct list_comment
-   : if_must< at< one< '(' > >, disable< list > > {};
+   : tao::pegtl::if_must< tao::pegtl::at< tao::pegtl::one< '(' > >, tao::pegtl::disable< list > > {};
 
-struct comment
-   : if_must< one< '#' >, sor< list_comment, line_comment > > {};
+struct read_include
+   : tao::pegtl::seq< tao::pegtl::one< ' ' >, tao::pegtl::one< '"' >, tao::pegtl::plus< tao::pegtl::not_one< '"' > >, tao::pegtl::one< '"' > > {};
 
-struct nothing
-   : sor< space, comment > {};
+struct hash_include
+   : tao::pegtl::if_must< tao::pegtl::string< 'i', 'n', 'c', 'l', 'u', 'd', 'e' >, read_include > {};
+
+struct hashed
+   : tao::pegtl::if_must< tao::pegtl::one< '#' >, tao::pegtl::sor< hash_include, list_comment, hash_comment > > {};
 
 struct number
-   : plus< digit > {};
+   : tao::pegtl::plus< tao::pegtl::digit > {};
 
 struct symbol
-   : identifier {};
+   : tao::pegtl::identifier {};
 
 struct atom
-   : sor< number, symbol > {};
+   : tao::pegtl::sor< number, symbol > {};
 
 struct anything;
 
 struct list
-   : if_must< one< '(' >, until< one< ')' >, anything > > {};
+   : tao::pegtl::if_must< tao::pegtl::one< '(' >, tao::pegtl::until< tao::pegtl::one< ')' >, anything > > {};
 
-struct something
-   : sor< atom, list > {};
+struct normal
+   : tao::pegtl::sor< atom, list > {};
 
 struct anything
-   : sor< nothing, something > {};
+   : tao::pegtl::sor< tao::pegtl::space, hashed, normal > {};
 
-struct file
-   : until< eof, anything > {};
+struct main
+   : tao::pegtl::until< tao::pegtl::eof, tao::pegtl::must< anything > > {};
 ```
 
 In order to let a parsing run do more than verify whether an input conforms to the grammar, it is necessary to attach user-defined *actions* to some grammar rules, as explained in [Actions and States](Actions-and-States.md).
diff --git a/packages/PEGTL/include/tao/pegtl/argv_input.hpp b/packages/PEGTL/include/tao/pegtl/argv_input.hpp
index 741a3574ddf2ab2de83afd677237f19382826512..311965e7f7bcdd24ede6d6fac5ab2084fd9e302d 100644
--- a/packages/PEGTL/include/tao/pegtl/argv_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/argv_input.hpp
@@ -42,7 +42,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   argv_input( Ts&&... )->argv_input<>;
+   argv_input( Ts&&... ) -> argv_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/ascii.hpp b/packages/PEGTL/include/tao/pegtl/ascii.hpp
index 1e4f1032f4287f4aac2c711c5659086c7666ad1d..e7948367c3a7ae6ff2272d51fd6390987c7a267d 100644
--- a/packages/PEGTL/include/tao/pegtl/ascii.hpp
+++ b/packages/PEGTL/include/tao/pegtl/ascii.hpp
@@ -15,8 +15,8 @@ namespace TAO_PEGTL_NAMESPACE
    inline namespace ascii
    {
       // clang-format off
-      struct alnum : internal::alnum {};
-      struct alpha : internal::alpha {};
+      struct alnum : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9' > {};
+      struct alpha : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z' > {};
       struct any : internal::any< internal::peek_char > {};
       struct blank : internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\t' > {};
       struct digit : internal::range< internal::result_on_found::success, internal::peek_char, '0', '9' > {};
diff --git a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
index f964787769d7f9ae5146ee3a29d99293ca1c556b..35637d145d05d996daeeff71d8ecbf320f44edc9 100644
--- a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
@@ -96,9 +96,9 @@ namespace TAO_PEGTL_NAMESPACE
          return m_current.line;
       }
 
-      [[nodiscard]] std::size_t byte_in_line() const noexcept
+      [[nodiscard]] std::size_t column() const noexcept
       {
-         return m_current.byte_in_line;
+         return m_current.column;
       }
 
       [[nodiscard]] const Source& source() const noexcept
@@ -149,7 +149,7 @@ namespace TAO_PEGTL_NAMESPACE
          if( m_current.data + amount > m_buffer.get() + m_maximum ) {
             throw std::overflow_error( "require beyond end of buffer" );
          }
-         if( const auto r = m_reader( m_end, ( std::min )( buffer_free_after_end(), ( std::max )( amount, Chunk ) ) ) ) {
+         if( const auto r = m_reader( m_end, ( std::min )( buffer_free_after_end(), ( std::max )( amount - buffer_occupied(), Chunk ) ) ) ) {
             m_end += r;
          }
       }
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp b/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp
index 91747dd90a37d0b9cf402c8992bd3d6d8b5efeff..4c8f39d201747eed92511b757d46e9bfdec15eec 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/alphabet.hpp
@@ -8,59 +8,59 @@
 
 namespace TAO_PEGTL_NAMESPACE::alphabet
 {
-   static const int a = 'a';
-   static const int b = 'b';
-   static const int c = 'c';
-   static const int d = 'd';
-   static const int e = 'e';
-   static const int f = 'f';
-   static const int g = 'g';
-   static const int h = 'h';
-   static const int i = 'i';
-   static const int j = 'j';
-   static const int k = 'k';
-   static const int l = 'l';
-   static const int m = 'm';
-   static const int n = 'n';
-   static const int o = 'o';
-   static const int p = 'p';
-   static const int q = 'q';
-   static const int r = 'r';
-   static const int s = 's';
-   static const int t = 't';
-   static const int u = 'u';
-   static const int v = 'v';
-   static const int w = 'w';
-   static const int x = 'x';
-   static const int y = 'y';
-   static const int z = 'z';
+   static const char a = 'a';
+   static const char b = 'b';
+   static const char c = 'c';
+   static const char d = 'd';
+   static const char e = 'e';
+   static const char f = 'f';
+   static const char g = 'g';
+   static const char h = 'h';
+   static const char i = 'i';
+   static const char j = 'j';
+   static const char k = 'k';
+   static const char l = 'l';
+   static const char m = 'm';
+   static const char n = 'n';
+   static const char o = 'o';
+   static const char p = 'p';
+   static const char q = 'q';
+   static const char r = 'r';
+   static const char s = 's';
+   static const char t = 't';
+   static const char u = 'u';
+   static const char v = 'v';
+   static const char w = 'w';
+   static const char x = 'x';
+   static const char y = 'y';
+   static const char z = 'z';
 
-   static const int A = 'A';  // NOLINT(readability-identifier-naming)
-   static const int B = 'B';  // NOLINT(readability-identifier-naming)
-   static const int C = 'C';  // NOLINT(readability-identifier-naming)
-   static const int D = 'D';  // NOLINT(readability-identifier-naming)
-   static const int E = 'E';  // NOLINT(readability-identifier-naming)
-   static const int F = 'F';  // NOLINT(readability-identifier-naming)
-   static const int G = 'G';  // NOLINT(readability-identifier-naming)
-   static const int H = 'H';  // NOLINT(readability-identifier-naming)
-   static const int I = 'I';  // NOLINT(readability-identifier-naming)
-   static const int J = 'J';  // NOLINT(readability-identifier-naming)
-   static const int K = 'K';  // NOLINT(readability-identifier-naming)
-   static const int L = 'L';  // NOLINT(readability-identifier-naming)
-   static const int M = 'M';  // NOLINT(readability-identifier-naming)
-   static const int N = 'N';  // NOLINT(readability-identifier-naming)
-   static const int O = 'O';  // NOLINT(readability-identifier-naming)
-   static const int P = 'P';  // NOLINT(readability-identifier-naming)
-   static const int Q = 'Q';  // NOLINT(readability-identifier-naming)
-   static const int R = 'R';  // NOLINT(readability-identifier-naming)
-   static const int S = 'S';  // NOLINT(readability-identifier-naming)
-   static const int T = 'T';  // NOLINT(readability-identifier-naming)
-   static const int U = 'U';  // NOLINT(readability-identifier-naming)
-   static const int V = 'V';  // NOLINT(readability-identifier-naming)
-   static const int W = 'W';  // NOLINT(readability-identifier-naming)
-   static const int X = 'X';  // NOLINT(readability-identifier-naming)
-   static const int Y = 'Y';  // NOLINT(readability-identifier-naming)
-   static const int Z = 'Z';  // NOLINT(readability-identifier-naming)
+   static const char A = 'A';  // NOLINT(readability-identifier-naming)
+   static const char B = 'B';  // NOLINT(readability-identifier-naming)
+   static const char C = 'C';  // NOLINT(readability-identifier-naming)
+   static const char D = 'D';  // NOLINT(readability-identifier-naming)
+   static const char E = 'E';  // NOLINT(readability-identifier-naming)
+   static const char F = 'F';  // NOLINT(readability-identifier-naming)
+   static const char G = 'G';  // NOLINT(readability-identifier-naming)
+   static const char H = 'H';  // NOLINT(readability-identifier-naming)
+   static const char I = 'I';  // NOLINT(readability-identifier-naming)
+   static const char J = 'J';  // NOLINT(readability-identifier-naming)
+   static const char K = 'K';  // NOLINT(readability-identifier-naming)
+   static const char L = 'L';  // NOLINT(readability-identifier-naming)
+   static const char M = 'M';  // NOLINT(readability-identifier-naming)
+   static const char N = 'N';  // NOLINT(readability-identifier-naming)
+   static const char O = 'O';  // NOLINT(readability-identifier-naming)
+   static const char P = 'P';  // NOLINT(readability-identifier-naming)
+   static const char Q = 'Q';  // NOLINT(readability-identifier-naming)
+   static const char R = 'R';  // NOLINT(readability-identifier-naming)
+   static const char S = 'S';  // NOLINT(readability-identifier-naming)
+   static const char T = 'T';  // NOLINT(readability-identifier-naming)
+   static const char U = 'U';  // NOLINT(readability-identifier-naming)
+   static const char V = 'V';  // NOLINT(readability-identifier-naming)
+   static const char W = 'W';  // NOLINT(readability-identifier-naming)
+   static const char X = 'X';  // NOLINT(readability-identifier-naming)
+   static const char Y = 'Y';  // NOLINT(readability-identifier-naming)
+   static const char Z = 'Z';  // NOLINT(readability-identifier-naming)
 
 }  // namespace TAO_PEGTL_NAMESPACE::alphabet
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp
index 128017d0f9397aa2b0c29f32398d102b9787fcfb..b777c02bc86961c27e4f80da06d9bc9028187e84 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp
@@ -15,10 +15,12 @@
 #include <vector>
 
 #include "../config.hpp"
+#include "../demangle.hpp"
 
 #include "analyze_traits.hpp"
 
-#include "../internal/demangle.hpp"
+#include "internal/set_stack_guard.hpp"
+
 #include "../internal/dependent_false.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
@@ -35,41 +37,6 @@ namespace TAO_PEGTL_NAMESPACE
          std::vector< std::string_view > subs;
       };
 
-      template< typename C >
-      class analyze_guard
-      {
-      public:
-         analyze_guard( C& container, const typename C::value_type& value )
-            : m_i( container.insert( value ) ),
-              m_c( container )
-         {}
-
-         analyze_guard( analyze_guard&& ) = delete;
-         analyze_guard( const analyze_guard& ) = delete;
-
-         void operator=( analyze_guard&& ) = delete;
-         void operator=( const analyze_guard& ) = delete;
-
-         ~analyze_guard()
-         {
-            if( m_i.second ) {
-               m_c.erase( m_i.first );
-            }
-         }
-
-         explicit operator bool() const noexcept
-         {
-            return m_i.second;
-         }
-
-      private:
-         const std::pair< typename C::iterator, bool > m_i;
-         C& m_c;
-      };
-
-      template< typename C >
-      analyze_guard( C&, const typename C::value_type& )->analyze_guard< C >;
-
       class analyze_cycles_impl
       {
       public:
@@ -114,7 +81,7 @@ namespace TAO_PEGTL_NAMESPACE
             if( const auto j = m_cache.find( start->first ); j != m_cache.end() ) {
                return j->second;
             }
-            if( const auto g = analyze_guard( m_stack, start->first ) ) {
+            if( const auto g = set_stack_guard( m_stack, start->first ) ) {
                switch( start->second.type ) {
                   case analyze_type::any: {
                      bool a = false;
@@ -150,7 +117,7 @@ namespace TAO_PEGTL_NAMESPACE
             if( !accum ) {
                ++m_problems;
                if( m_verbose ) {
-                  std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
+                  std::cerr << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
                }
             }
             return m_cache[ start->first ] = accum;
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/control_action.hpp b/packages/PEGTL/include/tao/pegtl/contrib/control_action.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c716c66d69c2f1f75ad01bedadfd0073a43c196d
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/control_action.hpp
@@ -0,0 +1,77 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_CONTROL_ACTION_HPP
+#define TAO_PEGTL_CONTRIB_CONTROL_ACTION_HPP
+
+#include <utility>
+
+#include "../config.hpp"
+#include "../match.hpp"
+#include "../nothing.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< typename, typename Rule, template< typename... > class Action, typename ParseInput, typename... States >
+      inline constexpr bool action_has_unwind = false;
+
+      template< typename Rule, template< typename... > class Action, typename ParseInput, typename... States >
+      inline constexpr bool action_has_unwind< decltype( (void)Action< Rule >::unwind( std::declval< const ParseInput& >(), std::declval< States&& >()... ) ), Rule, Action, ParseInput, States... > = true;
+
+   }  // namespace internal
+
+   struct control_action
+      : maybe_nothing
+   {
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
+      {
+         if constexpr( internal::action_has_unwind< void, Rule, Action, ParseInput, States... > ) {
+            try {
+               return control_action::match_impl< Rule, A, M, Action, Control >( in, st... );
+            }
+            catch( ... ) {
+               Action< Rule >::unwind( const_cast< const ParseInput& >( in ), st... );
+               throw;
+            }
+         }
+         else {
+            return control_action::match_impl< Rule, A, M, Action, Control >( in, st... );
+         }
+      }
+
+   private:
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static bool match_impl( ParseInput& in, States&&... st )
+      {
+         Action< Rule >::start( const_cast< const ParseInput& >( in ), st... );
+         if( TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... ) ) {
+            Action< Rule >::success( const_cast< const ParseInput& >( in ), st... );
+            return true;
+         }
+         Action< Rule >::failure( const_cast< const ParseInput& >( in ), st... );
+         return false;
+      }
+   };
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp
index 582813a8c6de1a450eeb3cb5770fab60d1bd05c1..78e9c64d167258337a3c039c85f051f8c11bd7ce 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp
@@ -4,33 +4,31 @@
 #ifndef TAO_PEGTL_CONTRIB_COVERAGE_HPP
 #define TAO_PEGTL_CONTRIB_COVERAGE_HPP
 
-#include <cassert>
 #include <cstddef>
 #include <map>
-#include <string>
 #include <string_view>
 #include <vector>
 
-#include "remove_first_state.hpp"
-#include "shuffle_states.hpp"
+#include "state_control.hpp"
 
+#include "../apply_mode.hpp"
 #include "../config.hpp"
+#include "../demangle.hpp"
 #include "../normal.hpp"
 #include "../nothing.hpp"
 #include "../parse.hpp"
+#include "../rewind_mode.hpp"
 #include "../type_list.hpp"
 #include "../visit.hpp"
 
-#include "../internal/demangle.hpp"
-
 namespace TAO_PEGTL_NAMESPACE
 {
    struct coverage_info
    {
       std::size_t start = 0;
       std::size_t success = 0;
-      std::size_t local_failure = 0;
-      std::size_t global_failure = 0;
+      std::size_t failure = 0;
+      std::size_t unwind = 0;
       std::size_t raise = 0;
    };
 
@@ -40,94 +38,98 @@ namespace TAO_PEGTL_NAMESPACE
       std::map< std::string_view, coverage_info > branches;
    };
 
-   struct coverage_state
-   {
-      std::string_view grammar;
-      std::string source;
-
-      std::map< std::string_view, coverage_entry > map;
-      bool result;
-
-      std::vector< std::string_view > stack;
-   };
+   using coverage_result = std::map< std::string_view, coverage_entry >;
 
    namespace internal
    {
       template< typename Rule >
       struct coverage_insert
       {
-         static void visit( coverage_state& state )
+         static void visit( std::map< std::string_view, coverage_entry >& map )
          {
-            visit_branches( state.map.try_emplace( internal::demangle< Rule >() ).first->second.branches, typename Rule::subs_t() );
+            visit_branches( map.try_emplace( demangle< Rule >() ).first->second.branches, typename Rule::subs_t() );
          }
 
          template< typename... Ts >
          static void visit_branches( std::map< std::string_view, coverage_info >& branches, type_list< Ts... > /*unused*/ )
          {
-            ( branches.try_emplace( internal::demangle< Ts >() ), ... );
+            ( branches.try_emplace( demangle< Ts >() ), ... );
          }
       };
 
-      template< template< typename... > class Control = normal >
-      struct make_coverage_control
+      struct coverage_state
       {
          template< typename Rule >
-         struct control
-            : remove_first_state< Control< Rule > >
+         static constexpr bool enable = true;
+
+         explicit coverage_state( coverage_result& in_result )
+            : result( in_result )
+         {}
+
+         coverage_result& result;
+         std::vector< std::string_view > stack;
+
+         template< typename Rule, typename ParseInput, typename... States >
+         void start( const ParseInput& /*unused*/, States&&... /*unused*/ )
          {
-            template< typename ParseInput, typename... States >
-            [[noreturn]] static void raise( const ParseInput& in, coverage_state& state, States&&... st )
-            {
-               const auto name = internal::demangle< Rule >();
-               ++state.map.at( name ).raise;
-               if( state.stack.size() > 1 ) {
-                  ++state.map.at( state.stack.at( state.stack.size() - 2 ) ).branches.at( name ).raise;
-               }
-               Control< Rule >::raise( in, st... );
+            const auto name = demangle< Rule >();
+            ++result.at( name ).start;
+            if( !stack.empty() ) {
+               ++result.at( stack.back() ).branches.at( name ).start;
             }
+            stack.push_back( name );
+         }
 
-            template< apply_mode A,
-                      rewind_mode M,
-                      template< typename... >
-                      class Action,
-                      template< typename... >
-                      class Control2,
-                      typename ParseInput,
-                      typename... States >
-            [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-            {
-               coverage_entry dummy;
-               auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) );
-               const auto name = internal::demangle< Rule >();
-               auto& entry = state.map.at( name );
-               auto& previous = state.stack.empty() ? dummy : state.map.at( state.stack.back() ).branches.at( name );
-               ++entry.start;
-               ++previous.start;
-               state.stack.push_back( name );
-               try {
-                  const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... );
-                  state.stack.pop_back();
-                  if( result ) {
-                     ++entry.success;
-                     ++previous.success;
-                  }
-                  else {
-                     ++entry.local_failure;
-                     ++previous.local_failure;
-                  }
-                  return result;
-               }
-               catch( ... ) {
-                  state.stack.pop_back();
-                  ++entry.global_failure;
-                  ++previous.global_failure;
-                  throw;
-               }
+         template< typename Rule, typename ParseInput, typename... States >
+         void success( const ParseInput& /*unused*/, States&&... /*unused*/ )
+         {
+            stack.pop_back();
+            const auto name = demangle< Rule >();
+            ++result.at( name ).success;
+            if( !stack.empty() ) {
+               ++result.at( stack.back() ).branches.at( name ).success;
             }
-         };
+         }
 
-         template< typename Rule >
-         using type = rotate_states_right< control< Rule > >;
+         template< typename Rule, typename ParseInput, typename... States >
+         void failure( const ParseInput& /*unused*/, States&&... /*unused*/ )
+         {
+            stack.pop_back();
+            const auto name = demangle< Rule >();
+            ++result.at( name ).failure;
+            if( !stack.empty() ) {
+               ++result.at( stack.back() ).branches.at( name ).failure;
+            }
+         }
+
+         template< typename Rule, typename ParseInput, typename... States >
+         void raise( const ParseInput& /*unused*/, States&&... /*unused*/ )
+         {
+            const auto name = demangle< Rule >();
+            ++result.at( name ).raise;
+            if( !stack.empty() ) {
+               ++result.at( stack.back() ).branches.at( name ).raise;
+            }
+         }
+
+         template< typename Rule, typename ParseInput, typename... States >
+         void unwind( const ParseInput& /*unused*/, States&&... /*unused*/ )
+         {
+            stack.pop_back();
+            const auto name = demangle< Rule >();
+            ++result.at( name ).unwind;
+            if( !stack.empty() ) {
+               ++result.at( stack.back() ).branches.at( name ).unwind;
+            }
+         }
+
+         template< typename Rule, typename ParseInput, typename... States >
+         void apply( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
+         {}
+
+         template< typename Rule, typename ParseInput, typename... States >
+         void apply0( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
+         {}
       };
 
    }  // namespace internal
@@ -137,21 +139,11 @@ namespace TAO_PEGTL_NAMESPACE
              template< typename... > class Control = normal,
              typename ParseInput,
              typename... States >
-   coverage_state coverage( ParseInput&& in, States&&... st )
+   bool coverage( ParseInput&& in, coverage_result& result, States&&... st )
    {
-      coverage_state state;
-
-      state.grammar = internal::demangle< Rule >();
-      state.source = in.source();
-
-      // populate state
-      visit< Rule, internal::coverage_insert >( state );
-
-      // parse
-      state.result = parse< Rule, Action, internal::make_coverage_control<>::template type >( in, st..., state );
-      assert( state.stack.empty() );
-
-      return state;
+      internal::coverage_state state( result );
+      visit< Rule, internal::coverage_insert >( state.result );  // Fill map with all sub-rules of the grammar.
+      return parse< Rule, Action, state_control< Control >::template type >( in, st..., state );
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
index 9bbbf9977be4e39782f869ee288758fe33b34157..30ba5464faa0961f5c94e78680960b4eac891a5c 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
@@ -7,6 +7,8 @@
 #include <cstdint>
 #include <cstdlib>
 
+#include <limits>
+#include <string_view>
 #include <type_traits>
 
 #include "../ascii.hpp"
@@ -148,7 +150,7 @@ namespace TAO_PEGTL_NAMESPACE
             if( is_digit( c ) ) {
                in.bump_in_this_line();
                if( c == '0' ) {
-                  return in.empty() || ( !is_digit( in.peek_char() ) );  // TODO: Throw exception on digit?
+                  return in.empty() || ( !is_digit( in.peek_char() ) );
                }
                while( ( !in.empty() ) && is_digit( in.peek_char() ) ) {
                   in.bump_in_this_line();
@@ -171,11 +173,11 @@ namespace TAO_PEGTL_NAMESPACE
             if( is_digit( c ) ) {
                if( c == '0' ) {
                   in.bump_in_this_line();
-                  return in.empty() || ( !is_digit( in.peek_char() ) );  // TODO: Throw exception on digit?
+                  return in.empty() || ( !is_digit( in.peek_char() ) );
                }
                do {
                   if( !accumulate_digit< Unsigned, Maximum >( st, c ) ) {
-                     throw parse_error( "integer overflow", in );  // Consistent with "as if" an action was doing the conversion.
+                     throw TAO_PEGTL_NAMESPACE::parse_error( "integer overflow", in );  // Consistent with "as if" an action was doing the conversion.
                   }
                   in.bump_in_this_line();
                } while( ( !in.empty() ) && is_digit( c = in.peek_char() ) );
@@ -192,7 +194,7 @@ namespace TAO_PEGTL_NAMESPACE
       // Assumes that 'in' contains a non-empty sequence of ASCII digits.
 
       template< typename ActionInput, typename Unsigned >
-      static auto apply( const ActionInput& in, Unsigned& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
+      static void apply( const ActionInput& in, Unsigned& st )
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -200,20 +202,6 @@ namespace TAO_PEGTL_NAMESPACE
             throw parse_error( "unsigned integer overflow", in );
          }
       }
-
-      template< typename ActionInput, typename State >
-      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
-      {
-         apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
-      }
-
-      template< typename ActionInput, typename Unsigned, typename... Ts >
-      static auto apply( const ActionInput& in, std::vector< Unsigned, Ts... >& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
-      {
-         Unsigned u = 0;
-         apply( in, u );
-         st.emplace_back( u );
-      }
    };
 
    struct unsigned_rule
@@ -260,9 +248,6 @@ namespace TAO_PEGTL_NAMESPACE
          st = 0;
          return internal::match_and_convert_unsigned_with_maximum( in, st );  // Throws on overflow.
       }
-
-      // TODO: Overload for st.converted?
-      // TODO: Overload for std::vector< Unsigned >?
    };
 
    template< typename Unsigned, Unsigned Maximum >
@@ -273,7 +258,7 @@ namespace TAO_PEGTL_NAMESPACE
       static_assert( std::is_unsigned_v< Unsigned > );
 
       template< typename ActionInput, typename Unsigned2 >
-      static auto apply( const ActionInput& in, Unsigned2& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
+      static void apply( const ActionInput& in, Unsigned2& st )
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -281,20 +266,6 @@ namespace TAO_PEGTL_NAMESPACE
             throw parse_error( "unsigned integer overflow", in );
          }
       }
-
-      template< typename ActionInput, typename State >
-      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
-      {
-         apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
-      }
-
-      template< typename ActionInput, typename Unsigned2, typename... Ts >
-      static auto apply( const ActionInput& in, std::vector< Unsigned2, Ts... >& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
-      {
-         Unsigned u = 0;
-         apply( in, u );
-         st.emplace_back( u );
-      }
    };
 
    template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() >
@@ -349,9 +320,6 @@ namespace TAO_PEGTL_NAMESPACE
          st = 0;
          return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st );  // Throws on overflow.
       }
-
-      // TODO: Overload for st.converted?
-      // TODO: Overload for std::vector< Unsigned >?
    };
 
    struct signed_action
@@ -360,7 +328,7 @@ namespace TAO_PEGTL_NAMESPACE
       // with optional leading sign; with sign, in.size() must be >= 2.
 
       template< typename ActionInput, typename Signed >
-      static auto apply( const ActionInput& in, Signed& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
+      static void apply( const ActionInput& in, Signed& st )
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -368,20 +336,6 @@ namespace TAO_PEGTL_NAMESPACE
             throw parse_error( "signed integer overflow", in );
          }
       }
-
-      template< typename ActionInput, typename State >
-      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
-      {
-         apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
-      }
-
-      template< typename ActionInput, typename Signed, typename... Ts >
-      static auto apply( const ActionInput& in, std::vector< Signed, Ts... >& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
-      {
-         Signed s = 0;
-         apply( in, s );
-         st.emplace_back( s );
-      }
    };
 
    struct signed_rule
@@ -440,9 +394,6 @@ namespace TAO_PEGTL_NAMESPACE
       {
          return TAO_PEGTL_NAMESPACE::parse< signed_rule_new, internal::signed_action_action >( in, st );  // Throws on overflow.
       }
-
-      // TODO: Overload for st.converted?
-      // TODO: Overload for std::vector< Signed >?
    };
 
    template< typename Name >
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/internal/set_stack_guard.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/set_stack_guard.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..99870f9b04d70fceb0a7785f1344d3b4d5555cf1
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/set_stack_guard.hpp
@@ -0,0 +1,52 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_SET_STACK_GUARD_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_SET_STACK_GUARD_HPP
+
+#include <set>
+#include <utility>
+
+#include "../../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   template< typename... Cs >
+   class set_stack_guard
+   {
+   public:
+      template< typename... Ts >
+      set_stack_guard( std::set< Cs... >& set, Ts&&... ts )
+         : m_i( set.emplace( std::forward< Ts >( ts )... ) ),
+           m_s( set )
+      {}
+
+      set_stack_guard( set_stack_guard&& ) = delete;
+      set_stack_guard( const set_stack_guard& ) = delete;
+
+      void operator=( set_stack_guard&& ) = delete;
+      void operator=( const set_stack_guard& ) = delete;
+
+      ~set_stack_guard()
+      {
+         if( m_i.second ) {
+            m_s.erase( m_i.first );
+         }
+      }
+
+      explicit operator bool() const noexcept
+      {
+         return m_i.second;
+      }
+
+   private:
+      const std::pair< typename std::set< Cs... >::iterator, bool > m_i;
+      std::set< Cs... >& m_s;
+   };
+
+   template< typename... Cs >
+   set_stack_guard( std::set< Cs... >&, const typename std::set< Cs... >::value_type& ) -> set_stack_guard< Cs... >;
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
index 964fdf6f0ec8ef74e98c58cc29d87d69c44eb4ee..25742807037cd2fb5cc1288da7c7b7ce45de8f0b 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
@@ -19,16 +19,16 @@
 
 #include "../apply_mode.hpp"
 #include "../config.hpp"
+#include "../demangle.hpp"
 #include "../memory_input.hpp"
 #include "../normal.hpp"
 #include "../nothing.hpp"
 #include "../parse.hpp"
 #include "../rewind_mode.hpp"
 
-#include "../internal/demangle.hpp"
 #include "../internal/enable_control.hpp"
+#include "../internal/has_unwind.hpp"
 #include "../internal/iterator.hpp"
-#include "../internal/try_catch_type.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::parse_tree
 {
@@ -67,13 +67,13 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       template< typename U >
       [[nodiscard]] bool is_type() const noexcept
       {
-         return type == TAO_PEGTL_NAMESPACE::internal::demangle< U >();
+         return type == demangle< U >();
       }
 
       template< typename U >
       void set_type() noexcept
       {
-         type = TAO_PEGTL_NAMESPACE::internal::demangle< U >();
+         type = demangle< U >();
       }
 
       [[nodiscard]] position begin() const
@@ -107,13 +107,13 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       [[nodiscard]] memory_input< P, Eol > as_memory_input() const
       {
          assert( has_content() );
-         return { m_begin.data, m_end.data, source, m_begin.byte, m_begin.line, m_begin.byte_in_line };
+         return { m_begin.data, m_end.data, source, m_begin.byte, m_begin.line, m_begin.column };
       }
 
       template< typename... States >
       void remove_content( States&&... /*unused*/ ) noexcept
       {
-         m_end.reset();
+         m_end = TAO_PEGTL_NAMESPACE::internal::iterator();
       }
 
       // all non-root nodes are initialized by calling this method
@@ -137,6 +137,11 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       void failure( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
       {}
 
+      // if parsing of the rule failed with an exception, this method is called
+      template< typename Rule, typename ParseInput, typename... States >
+      void unwind( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
+      {}
+
       // if parsing succeeded and the (optional) transform call
       // did not discard the node, it is appended to its parent.
       // note that "child" is the node whose Rule just succeeded
@@ -155,12 +160,6 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
 
    namespace internal
    {
-      template< typename >
-      inline constexpr bool is_try_catch_type = false;
-
-      template< typename Exception, typename... Rules >
-      inline constexpr bool is_try_catch_type< TAO_PEGTL_NAMESPACE::internal::try_catch_type< Exception, Rules... > > = true;
-
       template< typename Node >
       struct state
       {
@@ -195,14 +194,14 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
 
       template< typename Selector, typename ParseInput, typename Node, typename... States >
       auto transform( const ParseInput& in, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( in, n, st... ) ) )
-         -> decltype( Selector::transform( in, n, st... ), void() )
+         -> decltype( (void)Selector::transform( in, n, st... ) )
       {
          Selector::transform( in, n, st... );
       }
 
       template< typename Selector, typename ParseInput, typename Node, typename... States >
       auto transform( const ParseInput& /*unused*/, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) )
-         -> decltype( Selector::transform( n, st... ), void() )
+         -> decltype( (void)Selector::transform( n, st... ) )
       {
          Selector::transform( n, st... );
       }
@@ -243,46 +242,33 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       struct make_control< Node, Selector, Control >::state_handler< Rule, false, false >
          : remove_first_state< Control< Rule > >
       {
-         template< apply_mode A,
-                   rewind_mode M,
-                   template< typename... >
-                   class Action,
-                   template< typename... >
-                   class Control2,
-                   typename ParseInput,
-                   typename... States >
-         [[nodiscard]] static bool match( ParseInput& in, States&&... st )
+         template< typename ParseInput, typename... States >
+         static void start( const ParseInput& /*unused*/, state< Node >& state, States&&... /*unused*/ )
          {
-            auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) );
-            if constexpr( is_try_catch_type< Rule > ) {
-               internal::state< Node > tmp;
-               tmp.emplace_back();
-               tmp.stack.swap( state.stack );
-               const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... );
-               tmp.stack.swap( state.stack );
-               if( result ) {
-                  for( auto& c : tmp.back()->children ) {
-                     state.back()->children.emplace_back( std::move( c ) );
-                  }
-               }
-               return result;
-            }
-            else {
-               state.emplace_back();
-               const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... );
-               if( result ) {
-                  auto n = std::move( state.back() );
-                  state.pop_back();
-                  for( auto& c : n->children ) {
-                     state.back()->children.emplace_back( std::move( c ) );
-                  }
-               }
-               else {
-                  state.pop_back();
-               }
-               return result;
+            state.emplace_back();
+         }
+
+         template< typename ParseInput, typename... States >
+         static void success( const ParseInput& /*unused*/, state< Node >& state, States&&... /*unused*/ )
+         {
+            auto n = std::move( state.back() );
+            state.pop_back();
+            for( auto& c : n->children ) {
+               state.back()->children.emplace_back( std::move( c ) );
             }
          }
+
+         template< typename ParseInput, typename... States >
+         static void failure( const ParseInput& /*unused*/, state< Node >& state, States&&... /*unused*/ )
+         {
+            state.pop_back();
+         }
+
+         template< typename ParseInput, typename... States >
+         static void unwind( const ParseInput& /*unused*/, state< Node >& state, States&&... /*unused*/ )
+         {
+            state.pop_back();
+         }
       };
 
       template< typename Node, template< typename... > class Selector, template< typename... > class Control >
@@ -301,7 +287,6 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
          template< typename ParseInput, typename... States >
          static void success( const ParseInput& in, state< Node >& state, States&&... st )
          {
-            Control< Rule >::success( in, st... );
             auto n = std::move( state.back() );
             state.pop_back();
             n->template success< Rule >( in, st... );
@@ -309,14 +294,25 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
             if( n ) {
                state.back()->emplace_back( std::move( n ), st... );
             }
+            Control< Rule >::success( in, st... );
          }
 
          template< typename ParseInput, typename... States >
-         static void failure( const ParseInput& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< Node& >().template failure< Rule >( in, st... ) ) )
+         static void failure( const ParseInput& in, state< Node >& state, States&&... st )
          {
-            Control< Rule >::failure( in, st... );
             state.back()->template failure< Rule >( in, st... );
             state.pop_back();
+            Control< Rule >::failure( in, st... );
+         }
+
+         template< typename ParseInput, typename... States >
+         static void unwind( const ParseInput& in, state< Node >& state, States&&... st )
+         {
+            state.back()->template unwind< Rule >( in, st... );
+            state.pop_back();
+            if constexpr( TAO_PEGTL_NAMESPACE::internal::has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
+               Control< Rule >::unwind( in, st... );
+            }
          }
       };
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp
index 96c1792fe91d6798ea9b2ed267c3ccdc33c7d57c..cc4ce4857460945ebb382e4722cb61b29f62933b 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/print.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp
@@ -7,16 +7,16 @@
 #include <ostream>
 
 #include "../config.hpp"
+#include "../demangle.hpp"
+#include "../type_list.hpp"
 #include "../visit.hpp"
 
-#include "../internal/demangle.hpp"
-
 namespace TAO_PEGTL_NAMESPACE
 {
    namespace internal
    {
       template< typename Name >
-      struct print_rules
+      struct print_names
       {
          static void visit( std::ostream& os )
          {
@@ -25,7 +25,7 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template< typename Name >
-      struct print_sub_rules
+      struct print_debug
       {
          static void visit( std::ostream& os )
          {
@@ -59,15 +59,15 @@ namespace TAO_PEGTL_NAMESPACE
    }  // namespace internal
 
    template< typename Grammar >
-   void print_rules( std::ostream& os )
+   void print_names( std::ostream& os )
    {
-      visit< Grammar, internal::print_rules >( os );
+      visit< Grammar, internal::print_names >( os );
    }
 
    template< typename Grammar >
-   void print_sub_rules( std::ostream& os )
+   void print_debug( std::ostream& os )
    {
-      visit< Grammar, internal::print_sub_rules >( os );
+      visit< Grammar, internal::print_debug >( os );
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp
index 0c49af45e70214c29d2fd7d1b48f489d96d3e9c7..f3ab737e8f1084e8f1920a5b78a9c048ce0e5dea 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp
@@ -10,31 +10,25 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   // output is JSON
-   inline void print_coverage( std::ostream& os, const coverage_state& state )
+   inline std::ostream& operator<<( std::ostream& os, const coverage_result& result )
    {
-      os << "{\n"
-         << "  \"grammar\": \"" << state.grammar << "\",\n"
-         << "  \"source\": \"" << state.source << "\",\n"
-         << "  \"result\": " << ( state.result ? "true" : "false" ) << ",\n"
-         << "  \"coverage\":\n"
-         << "  [\n";
+      os << "[\n";
       bool f = true;
-      for( const auto& [ k, v ] : state.map ) {
+      for( const auto& [ k, v ] : result ) {
          if( f ) {
             f = false;
          }
          else {
             os << ",\n";
          }
-         os << "    {\n"
-            << "      \"rule\": \"" << k << "\",\n"
-            << "      \"start\": " << v.start << ", \"success\": " << v.success << ", \"local_failure\": " << v.local_failure << ", \"global_failure\": " << v.global_failure << ", \"raise\": " << v.raise << ",\n";
+         os << "  {\n"
+            << "    \"rule\": \"" << k << "\",\n"
+            << "    \"start\": " << v.start << ", \"success\": " << v.success << ", \"failure\": " << v.failure << ", \"unwind\": " << v.unwind << ", \"raise\": " << v.raise << ",\n";
          if( v.branches.empty() ) {
-            os << "      \"branches\": []\n";
+            os << "    \"branches\": []\n";
          }
          else {
-            os << "      \"branches\": [\n";
+            os << "    \"branches\": [\n";
             bool f2 = true;
             for( const auto& [ k2, v2 ] : v.branches ) {
                if( f2 ) {
@@ -43,15 +37,15 @@ namespace TAO_PEGTL_NAMESPACE
                else {
                   os << ",\n";
                }
-               os << "        { \"branch\": \"" << k2 << "\", \"start\": " << v2.start << ", \"success\": " << v2.success << ", \"local_failure\": " << v2.local_failure << ", \"global_failure\": " << v2.global_failure << ", \"raise\": " << v2.raise << " }";
+               os << "      { \"branch\": \"" << k2 << "\", \"start\": " << v2.start << ", \"success\": " << v2.success << ", \"failure\": " << v2.failure << ", \"unwind\": " << v2.unwind << ", \"raise\": " << v2.raise << " }";
             }
-            os << "\n      ]\n";
+            os << "\n    ]\n";
          }
-         os << "    }";
+         os << "  }";
       }
-      os << "\n"
-         << "  ]\n"
-         << "}\n";
+      os << "\n";
+      os << "]\n";
+      return os;
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
index 7fc2e049bd994aa7ceb44a2e7bccb775c3d48331..3e4a6a7f4b561d25e1640879402738bc107f7a1e 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
@@ -11,15 +11,7 @@
 #include "../ascii.hpp"
 #include "../config.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../internal/bytes.hpp"
-#include "../internal/enable_control.hpp"
-#include "../internal/eof.hpp"
-#include "../internal/eol.hpp"
-#include "../internal/must.hpp"
-#include "../internal/not_at.hpp"
-#include "../internal/seq.hpp"
-#include "../internal/star.hpp"
+#include "../rules.hpp"
 
 #include "analyze_traits.hpp"
 
@@ -204,7 +196,7 @@ namespace TAO_PEGTL_NAMESPACE
       {};
 
       using rule_t = raw_string;
-      using subs_t = type_list< internal::raw_string_open< Open, Marker >, internal::must< content > >;
+      using subs_t = empty_list;  // type_list< internal::raw_string_open< Open, Marker >, internal::must< content > >;
 
       template< apply_mode A,
                 rewind_mode M,
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
index 48030def2e9bb687e86783ce0558029fd43ad96c..755b913498edbc776be1f85699cc7765e26ec7e0 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
@@ -4,8 +4,12 @@
 #ifndef TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP
 #define TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP
 
+#include <type_traits>
+
 #include "../config.hpp"
 
+#include "../internal/has_unwind.hpp"
+
 namespace TAO_PEGTL_NAMESPACE
 {
    // Applies to start(), success(), failure(), raise(), apply(), and apply0():
@@ -38,6 +42,13 @@ namespace TAO_PEGTL_NAMESPACE
          Base::raise( in, st... );
       }
 
+      template< typename ParseInput, typename State, typename... States >
+      static auto unwind( const ParseInput& in, State&& /*unused*/, States&&... st )
+         -> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, States... > >
+      {
+         Base::unwind( in, st... );
+      }
+
       template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State, typename... States >
       static auto apply( const Iterator& begin, const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::template apply< Action >( begin, in, st... ) ) )
          -> decltype( Base::template apply< Action >( begin, in, st... ) )
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp
index 5fb778b7dbb4d45c29107e987697bc5393b75658..a9006fe1d13e25d4d7535b94f9e8a4b00c19dc71 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp
@@ -9,6 +9,8 @@
 
 #include "../config.hpp"
 
+#include "../internal/has_unwind.hpp"
+
 namespace TAO_PEGTL_NAMESPACE
 {
    // Remove the last N states of start(), success(), failure(), raise(), apply(), and apply0()
@@ -64,6 +66,20 @@ namespace TAO_PEGTL_NAMESPACE
          raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
       }
 
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto unwind_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
+         -> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, std::tuple_element_t< Is, Tuple >... > >
+      {
+         Base::unwind( in, std::get< Is >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static auto unwind( const ParseInput& in, States&&... st )
+         -> decltype( unwind_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) )
+      {
+         unwind_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
       template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is >
       static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) ) )
          -> decltype( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) )
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
index 7ec4639ef68c435f13d585b87a41fa8a5c7784e1..ee0a37820b2af3e548d61449383c246fd99cf2cf 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
@@ -48,6 +48,28 @@ namespace TAO_PEGTL_NAMESPACE
          }
       };
 
+      template< unsigned Max, char C >
+      struct rep_one_min_max< 0, Max, C >
+      {
+         using rule_t = rep_one_min_max;
+         using subs_t = empty_list;
+
+         template< typename ParseInput >
+         [[nodiscard]] static bool match( ParseInput& in )
+         {
+            const auto size = in.size( Max + 1 );
+            std::size_t i = 0;
+            while( ( i < size ) && ( in.peek_char( i ) == C ) ) {
+               ++i;
+            }
+            if( i <= Max ) {
+               bump_help< result_on_found::success, ParseInput, char, C >( in, i );
+               return true;
+            }
+            return false;
+         }
+      };
+
       template< unsigned Min, unsigned Max, char C >
       inline constexpr bool enable_control< rep_one_min_max< Min, Max, C > > = false;
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp
index e081051405ad231b944c5b2a14e5ddbfb25bef04..43912c4f26631b008cc9e4f1f029fcabfed9da6b 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp
@@ -5,10 +5,13 @@
 #define TAO_PEGTL_CONTRIB_SHUFFLE_STATES_HPP
 
 #include <tuple>
+#include <type_traits>
 #include <utility>
 
 #include "../config.hpp"
 
+#include "../internal/has_unwind.hpp"
+
 namespace TAO_PEGTL_NAMESPACE
 {
    namespace internal
@@ -112,6 +115,27 @@ namespace TAO_PEGTL_NAMESPACE
          Base::raise( in, st );
       }
 
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto unwind_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
+         -> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, std::tuple_element_t< Shuffle::template value< Is, sizeof...( Is ) >, Tuple >... > >
+      {
+         Base::unwind( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static auto unwind( const ParseInput& in, States&&... st )
+         -> decltype( unwind_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) )
+      {
+         unwind_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< typename ParseInput, typename State >
+      static auto unwind( const ParseInput& in, State&& st )
+         -> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, State > >
+      {
+         Base::unwind( in, st );
+      }
+
       template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is >
       static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
          -> decltype( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) )
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/state_control.hpp b/packages/PEGTL/include/tao/pegtl/contrib/state_control.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..28b105e913ae7a366d3cfa7c83bf3205e51a0b15
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/state_control.hpp
@@ -0,0 +1,118 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_STATE_CONTROL_HPP
+#define TAO_PEGTL_CONTRIB_STATE_CONTROL_HPP
+
+#include <type_traits>
+
+#include "shuffle_states.hpp"
+
+#include "../config.hpp"
+#include "../internal/has_unwind.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< template< typename... > class Control >
+   struct state_control
+   {
+      template< typename Rule >
+      struct control
+         : Control< Rule >
+      {
+         static constexpr bool enable = true;
+
+         template< typename ParseInput, typename State, typename... States >
+         static void start( [[maybe_unused]] const ParseInput& in, [[maybe_unused]] State& state, [[maybe_unused]] States&&... st )
+         {
+            if constexpr( Control< Rule >::enable ) {
+               Control< Rule >::start( in, st... );
+            }
+            if constexpr( State::template enable< Rule > ) {
+               state.template start< Rule >( in, st... );
+            }
+#if defined( _MSC_VER )
+            ( (void)st, ... );
+#endif
+         }
+
+         template< typename ParseInput, typename State, typename... States >
+         static void success( [[maybe_unused]] const ParseInput& in, [[maybe_unused]] State& state, [[maybe_unused]] States&&... st )
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template success< Rule >( in, st... );
+            }
+            if constexpr( Control< Rule >::enable ) {
+               Control< Rule >::success( in, st... );
+            }
+#if defined( _MSC_VER )
+            ( (void)st, ... );
+#endif
+         }
+
+         template< typename ParseInput, typename State, typename... States >
+         static void failure( [[maybe_unused]] const ParseInput& in, [[maybe_unused]] State& state, [[maybe_unused]] States&&... st )
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template failure< Rule >( in, st... );
+            }
+            if constexpr( Control< Rule >::enable ) {
+               Control< Rule >::failure( in, st... );
+            }
+#if defined( _MSC_VER )
+            ( (void)st, ... );
+#endif
+         }
+
+         template< typename ParseInput, typename State, typename... States >
+         [[noreturn]] static void raise( const ParseInput& in, [[maybe_unused]] State& state, States&&... st )
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template raise< Rule >( in, st... );
+            }
+            Control< Rule >::raise( in, st... );
+         }
+
+         template< typename ParseInput, typename State, typename... States >
+         static auto unwind( [[maybe_unused]] const ParseInput& in, [[maybe_unused]] State& state, [[maybe_unused]] States&&... st )
+            -> std::enable_if_t< State::template enable< Rule > || ( Control< Rule >::enable && internal::has_unwind< Control< Rule >, void, const ParseInput&, States... > ) >
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template unwind< Rule >( in, st... );
+            }
+            if constexpr( Control< Rule >::enable && internal::has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
+               Control< Rule >::unwind( in, st... );
+            }
+#if defined( _MSC_VER )
+            ( (void)st, ... );
+#endif
+         }
+
+         template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State, typename... States >
+         static auto apply( const Iterator& begin, const ParseInput& in, [[maybe_unused]] State& state, States&&... st )
+            -> decltype( Control< Rule >::template apply< Action >( begin, in, st... ) )
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template apply< Rule >( in, st... );
+            }
+            return Control< Rule >::template apply< Action >( begin, in, st... );
+         }
+
+         template< template< typename... > class Action, typename ParseInput, typename State, typename... States >
+         static auto apply0( const ParseInput& in, [[maybe_unused]] State& state, States&&... st )
+            -> decltype( Control< Rule >::template apply0< Action >( in, st... ) )
+         {
+            if constexpr( State::template enable< Rule > ) {
+               state.template apply0< Rule >( in, st... );
+            }
+            return Control< Rule >::template apply0< Action >( in, st... );
+         }
+      };
+
+      template< typename Rule >
+      using type = rotate_states_right< control< Rule > >;
+   };
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp
index 798c951e6ab9cb518ab10622b2c4482ca326e537..9bc5976ac71a391c73bdc2657fca934e9bd9cbcc 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp
@@ -1,153 +1,226 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #ifndef TAO_PEGTL_CONTRIB_TRACE_HPP
 #define TAO_PEGTL_CONTRIB_TRACE_HPP
 
-#include <cassert>
+#include <cstddef>
 #include <iomanip>
 #include <iostream>
-#include <utility>
-#include <vector>
+#include <string_view>
+#include <tuple>
 
+#include "state_control.hpp"
+
+#include "../apply_mode.hpp"
 #include "../config.hpp"
+#include "../demangle.hpp"
 #include "../normal.hpp"
-
-#include "../internal/demangle.hpp"
+#include "../nothing.hpp"
+#include "../parse.hpp"
+#include "../rewind_mode.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   namespace internal
+   template< bool HideInternal = false, bool UseColor = true, std::size_t IndentIncrement = 2, std::size_t InitialIndent = 8 >
+   struct tracer_traits
    {
+      template< typename Rule >
+      static constexpr bool enable = ( HideInternal ? normal< Rule >::enable : true );
+
+      static constexpr std::size_t initial_indent = InitialIndent;
+      static constexpr std::size_t indent_increment = IndentIncrement;
+
+      static constexpr std::string_view ansi_reset = UseColor ? "\033[m" : "";
+      static constexpr std::string_view ansi_rule = UseColor ? "\033[36m" : "";
+      static constexpr std::string_view ansi_hide = UseColor ? "\033[37m" : "";
+
+      static constexpr std::string_view ansi_position = UseColor ? "\033[1;34m" : "";
+      static constexpr std::string_view ansi_success = UseColor ? "\033[32m" : "";
+      static constexpr std::string_view ansi_failure = UseColor ? "\033[31m" : "";
+      static constexpr std::string_view ansi_raise = UseColor ? "\033[1;31m" : "";
+      static constexpr std::string_view ansi_unwind = UseColor ? "\033[31m" : "";
+      static constexpr std::string_view ansi_apply = UseColor ? "\033[1;36m" : "";
+   };
+
+   using standard_tracer_traits = tracer_traits< true >;
+   using complete_tracer_traits = tracer_traits< false >;
+
+   template< typename TracerTraits >
+   struct tracer
+   {
+      const std::ios_base::fmtflags m_flags;
+      std::size_t m_count = 0;
+      std::vector< std::size_t > m_stack;
+      position m_position;
+
+      template< typename Rule >
+      static constexpr bool enable = TracerTraits::template enable< Rule >;
+
       template< typename ParseInput >
-      void print_current( const ParseInput& in )
+      explicit tracer( const ParseInput& in )
+         : m_flags( std::cerr.flags() ),
+           m_position( in.position() )
       {
-         if( in.empty() ) {
-            std::cerr << "<eof>";
-         }
-         else {
-            const auto c = in.peek_uint8();
-            switch( c ) {
-               case 0:
-                  std::cerr << "<nul> = ";
-                  break;
-               case 9:
-                  std::cerr << "<ht> = ";
-                  break;
-               case 10:
-                  std::cerr << "<lf> = ";
-                  break;
-               case 13:
-                  std::cerr << "<cr> = ";
-                  break;
-               default:
-                  if( isprint( c ) ) {
-                     std::cerr << '\'' << c << "' = ";
-                  }
-            }
-            std::cerr << "(char)" << unsigned( c );
-         }
+         std::cerr << std::left;
+         print_position();
       }
 
-   }  // namespace internal
+      tracer( const tracer& ) = delete;
+      tracer( tracer&& ) = delete;
 
-   struct trace_state
-   {
-      unsigned rule = 0;
-      unsigned line = 0;
-      std::vector< unsigned > stack;
-   };
+      ~tracer()
+      {
+         std::cerr.flags( m_flags );
+      }
 
-   template< typename Rule, template< typename... > class Control >
-   struct basic_trace_control
-      : Control< Rule >
-   {
-      template< typename ParseInput, typename... States >
-      static void start( const ParseInput& in, States&&... st )
+      tracer& operator=( const tracer& ) = delete;
+      tracer& operator=( tracer&& ) = delete;
+
+      [[nodiscard]] std::size_t indent() const noexcept
+      {
+         return TracerTraits::initial_indent + TracerTraits::indent_increment * m_stack.size();
+      }
+
+      void print_position() const
       {
-         std::cerr << in.position() << "  start  " << internal::demangle< Rule >() << "; current ";
-         print_current( in );
-         std::cerr << std::endl;
-         Control< Rule >::start( in, st... );
+         std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_position << "position" << TracerTraits::ansi_reset << ' ' << m_position << '\n';
       }
 
-      template< typename ParseInput, typename... States >
-      static void start( const ParseInput& in, trace_state& ts, States&&... st )
+      void update_position( const position& p )
       {
-         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " ";
-         start( in, st... );
-         ts.stack.push_back( ts.rule );
+         if( m_position != p ) {
+            m_position = p;
+            print_position();
+         }
       }
 
-      template< typename ParseInput, typename... States >
-      static void success( const ParseInput& in, States&&... st )
+      template< typename Rule, typename ParseInput, typename... States >
+      void start( const ParseInput& /*unused*/, States&&... /*unused*/ )
       {
-         std::cerr << in.position() << " success " << internal::demangle< Rule >() << "; next ";
-         print_current( in );
-         std::cerr << std::endl;
-         Control< Rule >::success( in, st... );
+         std::cerr << '#' << std::setw( indent() - 1 ) << ++m_count << TracerTraits::ansi_rule << demangle< Rule >() << TracerTraits::ansi_reset << '\n';
+         m_stack.push_back( m_count );
       }
 
-      template< typename ParseInput, typename... States >
-      static void success( const ParseInput& in, trace_state& ts, States&&... st )
+      template< typename Rule, typename ParseInput, typename... States >
+      void success( const ParseInput& in, States&&... /*unused*/ )
       {
-         assert( !ts.stack.empty() );
-         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
-         success( in, st... );
-         ts.stack.pop_back();
+         const auto prev = m_stack.back();
+         m_stack.pop_back();
+         std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_success << "success" << TracerTraits::ansi_reset;
+         if( m_count != prev ) {
+            std::cerr << " #" << prev << ' ' << TracerTraits::ansi_hide << demangle< Rule >() << TracerTraits::ansi_reset;
+         }
+         std::cerr << '\n';
+         update_position( in.position() );
       }
 
-      template< typename ParseInput, typename... States >
-      static void failure( const ParseInput& in, States&&... st )
+      template< typename Rule, typename ParseInput, typename... States >
+      void failure( const ParseInput& in, States&&... /*unused*/ )
       {
-         std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl;
-         Control< Rule >::failure( in, st... );
+         const auto prev = m_stack.back();
+         m_stack.pop_back();
+         std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_failure << "failure" << TracerTraits::ansi_reset;
+         if( m_count != prev ) {
+            std::cerr << " #" << prev << ' ' << TracerTraits::ansi_hide << demangle< Rule >() << TracerTraits::ansi_reset;
+         }
+         std::cerr << '\n';
+         update_position( in.position() );
       }
 
-      template< typename ParseInput, typename... States >
-      static void failure( const ParseInput& in, trace_state& ts, States&&... st )
+      template< typename Rule, typename ParseInput, typename... States >
+      void raise( const ParseInput& /*unused*/, States&&... /*unused*/ )
       {
-         assert( !ts.stack.empty() );
-         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
-         failure( in, st... );
-         ts.stack.pop_back();
+         std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_raise << "raise" << TracerTraits::ansi_reset << ' ' << TracerTraits::ansi_rule << demangle< Rule >() << TracerTraits::ansi_reset << '\n';
+      }
+
+      template< typename Rule, typename ParseInput, typename... States >
+      void unwind( const ParseInput& in, States&&... /*unused*/ )
+      {
+         const auto prev = m_stack.back();
+         m_stack.pop_back();
+         std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_unwind << "unwind" << TracerTraits::ansi_reset;
+         if( m_count != prev ) {
+            std::cerr << " #" << prev << ' ' << TracerTraits::ansi_hide << demangle< Rule >() << TracerTraits::ansi_reset;
+         }
+         std::cerr << '\n';
+         update_position( in.position() );
       }
 
-      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
-      static auto apply( const Iterator& begin, const ParseInput& in, States&&... st )
-         -> decltype( Control< Rule >::template apply< Action >( begin, in, st... ) )
+      template< typename Rule, typename ParseInput, typename... States >
+      void apply( const ParseInput& /*unused*/, States&&... /*unused*/ )
       {
-         std::cerr << in.position() << "  apply  " << internal::demangle< Rule >() << std::endl;
-         return Control< Rule >::template apply< Action >( begin, in, st... );
+         std::cerr << std::setw( static_cast< int >( indent() - TracerTraits::indent_increment ) ) << ' ' << TracerTraits::ansi_apply << "apply" << TracerTraits::ansi_reset << '\n';
       }
 
-      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
-      static auto apply( const Iterator& begin, const ParseInput& in, trace_state& ts, States&&... st )
-         -> decltype( apply< Action >( begin, in, st... ) )
+      template< typename Rule, typename ParseInput, typename... States >
+      void apply0( const ParseInput& /*unused*/, States&&... /*unused*/ )
       {
-         std::cerr << std::setw( 6 ) << ++ts.line << "        ";
-         return apply< Action >( begin, in, st... );
+         std::cerr << std::setw( static_cast< int >( indent() - TracerTraits::indent_increment ) ) << ' ' << TracerTraits::ansi_apply << "apply0" << TracerTraits::ansi_reset << '\n';
       }
 
-      template< template< typename... > class Action, typename ParseInput, typename... States >
-      static auto apply0( const ParseInput& in, States&&... st )
-         -> decltype( Control< Rule >::template apply0< Action >( in, st... ) )
+      template< typename Rule,
+                template< typename... > class Action = nothing,
+                template< typename... > class Control = normal,
+                typename ParseInput,
+                typename... States >
+      bool parse( ParseInput&& in, States&&... st )
       {
-         std::cerr << in.position() << "  apply0 " << internal::demangle< Rule >() << std::endl;
-         return Control< Rule >::template apply0< Action >( in, st... );
+         return TAO_PEGTL_NAMESPACE::parse< Rule, Action, state_control< Control >::template type >( in, st..., *this );
       }
+   };
 
-      template< template< typename... > class Action, typename ParseInput, typename... States >
-      static auto apply0( const ParseInput& in, trace_state& ts, States&&... st )
-         -> decltype( apply0< Action >( in, st... ) )
+   template< typename Rule,
+             template< typename... > class Action = nothing,
+             template< typename... > class Control = normal,
+             typename ParseInput,
+             typename... States >
+   bool standard_trace( ParseInput&& in, States&&... st )
+   {
+      tracer< standard_tracer_traits > tr( in );
+      return tr.parse< Rule, Action, Control >( in, st... );
+   }
+
+   template< typename Rule,
+             template< typename... > class Action = nothing,
+             template< typename... > class Control = normal,
+             typename ParseInput,
+             typename... States >
+   bool complete_trace( ParseInput&& in, States&&... st )
+   {
+      tracer< complete_tracer_traits > tr( in );
+      return tr.parse< Rule, Action, Control >( in, st... );
+   }
+
+   template< typename Tracer >
+   struct trace
+      : maybe_nothing
+   {
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         std::cerr << std::setw( 6 ) << ++ts.line << "        ";
-         return apply0< Action >( in, st... );
+         if constexpr( sizeof...( st ) == 0 ) {
+            return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, state_control< Control >::template type >( in, st..., Tracer( in ) );
+         }
+         else if constexpr( !std::is_same_v< std::tuple_element_t< sizeof...( st ) - 1, std::tuple< States... > >, Tracer& > ) {
+            return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, state_control< Control >::template type >( in, st..., Tracer( in ) );
+         }
+         else {
+            return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... );
+         }
       }
    };
 
-   template< typename Rule >
-   using trace_control = basic_trace_control< Rule, normal >;
+   using trace_standard = trace< tracer< standard_tracer_traits > >;
+   using trace_complete = trace< tracer< complete_tracer_traits > >;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp b/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp
deleted file mode 100644
index b4958e84399f2af15b0da7b940a2472fe52b16e2..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_CONTRIB_VISIT_RT_HPP
-#define TAO_PEGTL_CONTRIB_VISIT_RT_HPP
-
-#include <set>
-#include <string_view>
-
-#include "../config.hpp"
-#include "../type_list.hpp"
-
-#include "../internal/demangle.hpp"
-
-namespace TAO_PEGTL_NAMESPACE
-{
-   namespace internal
-   {
-      template< template< typename... > class Func, typename... Rules >
-      struct visitor_rt
-      {
-         template< typename... Args >
-         static void visit( std::set< std::string_view >& done, Args&&... args )
-         {
-            ( visit_rule< Rules >( typename Rules::subs_t(), done, args... ), ... );
-         }
-
-      private:
-         template< typename Rule, typename... Subs, typename... Args >
-         static void visit_rule( type_list< Subs... > /*unused*/, std::set< std::string_view >& done, Args&&... args )
-         {
-            if( done.emplace( demangle< Rule >() ).second ) {
-               Func< Rule >::visit( args... );
-               visitor_rt< Func, Subs... >::visit( done, args... );
-            }
-         }
-      };
-
-   }  // namespace internal
-
-   template< typename Rule, template< typename... > class Func, typename... Args >
-   std::size_t visit_rt( Args&&... args )
-   {
-      std::set< std::string_view > done;
-      internal::visitor_rt< Func, Rule >::visit( done, args... );
-      return done.size();
-   }
-
-}  // namespace TAO_PEGTL_NAMESPACE
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/cstream_input.hpp b/packages/PEGTL/include/tao/pegtl/cstream_input.hpp
index cebc6f7aa6201b877991cd73bb0b5804092848b8..ad50942faf93da27efaebb8a15bf6b050ea51169 100644
--- a/packages/PEGTL/include/tao/pegtl/cstream_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/cstream_input.hpp
@@ -25,7 +25,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   cstream_input( Ts&&... )->cstream_input<>;
+   cstream_input( Ts&&... ) -> cstream_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp b/packages/PEGTL/include/tao/pegtl/demangle.hpp
similarity index 94%
rename from packages/PEGTL/include/tao/pegtl/internal/demangle.hpp
rename to packages/PEGTL/include/tao/pegtl/demangle.hpp
index 183134309bda8bd43843fb10f3db68880fc5788e..4122ce4afcee169ae4fbcb549704bc135dc81425 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/demangle.hpp
+++ b/packages/PEGTL/include/tao/pegtl/demangle.hpp
@@ -1,15 +1,13 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL
 
-#ifndef TAO_PEGTL_INTERNAL_DEMANGLE_HPP
-#define TAO_PEGTL_INTERNAL_DEMANGLE_HPP
+#ifndef TAO_PEGTL_DEMANGLE_HPP
+#define TAO_PEGTL_DEMANGLE_HPP
 
 #include <ciso646>
 #include <string_view>
 
-#include "../config.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
+namespace tao
 {
 #if defined( __clang__ )
 
@@ -135,6 +133,6 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
 #endif
 
-}  // namespace TAO_PEGTL_NAMESPACE::internal
+}  // namespace tao
 
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/file_input.hpp b/packages/PEGTL/include/tao/pegtl/file_input.hpp
index d54db990fb4bbba59e483a5e5831ff09f9289881..1fba74bb583d95d15deea4076919de820c00e559 100644
--- a/packages/PEGTL/include/tao/pegtl/file_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/file_input.hpp
@@ -37,7 +37,7 @@ namespace TAO_PEGTL_NAMESPACE
 #endif
 
    template< typename... Ts >
-   explicit file_input( Ts&&... )->file_input<>;
+   explicit file_input( Ts&&... ) -> file_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp b/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp
deleted file mode 100644
index 45704b90475acfcc19196b1452416d5d843f2a2f..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/alnum.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_ALNUM_HPP
-#define TAO_PEGTL_INTERNAL_ALNUM_HPP
-
-#include "../config.hpp"
-
-#include "peek_char.hpp"
-#include "ranges.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   using alnum = ranges< peek_char, 'a', 'z', 'A', 'Z', '0', '9' >;
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp b/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp
deleted file mode 100644
index b1591d92b58c847655ee292149b47e135dd54fb4..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/alpha.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_ALPHA_HPP
-#define TAO_PEGTL_INTERNAL_ALPHA_HPP
-
-#include "../config.hpp"
-
-#include "peek_char.hpp"
-#include "ranges.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   using alpha = ranges< peek_char, 'a', 'z', 'A', 'Z' >;
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
index 92e24ef26b528eb3a8370ff88ff577b45529e461..7dac482bffd3cbf166e0f9c5dc48714fb89bf201 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
@@ -29,7 +29,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Control,
                 typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
+      [[nodiscard]] static bool match( [[maybe_unused]] ParseInput& in, [[maybe_unused]] States&&... st )
       {
          if constexpr( ( A == apply_mode::action ) && ( sizeof...( Actions ) > 0 ) ) {
             using action_t = typename ParseInput::action_t;
@@ -38,8 +38,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
          }
          else {
 #if defined( _MSC_VER )
-            (void)in;
-            (void)( (void)st, ... );
+            ( (void)st, ... );
 #endif
             return true;
          }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
index 3ad4b3c2a2800ca4d5e5cc047dc7fcfb469ae417..7c3b92c626b83d630856fd07ae7aaeffdf100e9c 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
@@ -29,14 +29,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Control,
                 typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( ParseInput& /*unused*/, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& /*unused*/, [[maybe_unused]] States&&... st )
       {
          if constexpr( A == apply_mode::action ) {
             return ( apply0_single< Actions >::match( st... ) && ... );
          }
          else {
 #if defined( _MSC_VER )
-            (void)( (void)st, ... );
+            ( (void)st, ... );
 #endif
             return true;
          }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
index 3304cc5d4ff47005570e420c66ed86cc1bb3ce52..20f029e54204ad9ae0f21946de63a357d90e1b81 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
@@ -5,11 +5,10 @@
 #define TAO_PEGTL_INTERNAL_BOL_HPP
 
 #include "../config.hpp"
+#include "../type_list.hpp"
 
 #include "enable_control.hpp"
 
-#include "../type_list.hpp"
-
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct bol
@@ -20,7 +19,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
       template< typename ParseInput >
       [[nodiscard]] static bool match( ParseInput& in ) noexcept
       {
-         return in.byte_in_line() == 0;
+         return in.column() == 1;
       }
    };
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bump.hpp b/packages/PEGTL/include/tao/pegtl/internal/bump.hpp
index 74a1a7d7c749d12c55d570d762d590a5aa8aa554..fded8cc2e2315b25c5dbf170bddfe5729fdf3285 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bump.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bump.hpp
@@ -15,10 +15,10 @@ namespace TAO_PEGTL_NAMESPACE::internal
       for( std::size_t i = 0; i < count; ++i ) {
          if( iter.data[ i ] == ch ) {
             ++iter.line;
-            iter.byte_in_line = 0;
+            iter.column = 1;
          }
          else {
-            ++iter.byte_in_line;
+            ++iter.column;
          }
       }
       iter.byte += count;
@@ -29,14 +29,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       iter.data += count;
       iter.byte += count;
-      iter.byte_in_line += count;
+      iter.column += count;
    }
 
    inline void bump_to_next_line( iterator& iter, const std::size_t count ) noexcept
    {
       ++iter.line;
       iter.byte += count;
-      iter.byte_in_line = 0;
+      iter.column = 1;
       iter.data += count;
    }
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp b/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp
deleted file mode 100644
index dadba26303728559424379934ab53eef38d4a3c1..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/dusel_mode.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_DUSEL_MODE_HPP
-#define TAO_PEGTL_INTERNAL_DUSEL_MODE_HPP
-
-#include "../config.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   enum class dusel_mode : char
-   {
-      nothing = 0,
-      control = 1,
-      control_and_apply_void = 2,
-      control_and_apply_bool = 3,
-      control_and_apply0_void = 4,
-      control_and_apply0_bool = 5
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp b/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp
deleted file mode 100644
index 53555e9faf04b63311c39eb15234fb35a9518db2..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_DUSELTRONIK_HPP
-#define TAO_PEGTL_INTERNAL_DUSELTRONIK_HPP
-
-#include "../apply_mode.hpp"
-#include "../config.hpp"
-#include "../rewind_mode.hpp"
-
-#include "dusel_mode.hpp"
-
-#ifdef _MSC_VER
-#pragma warning( push )
-#pragma warning( disable : 4702 )
-#endif
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control,
-             dusel_mode = dusel_mode::nothing >
-   struct duseltronik;
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static auto match( ParseInput& in, States&&... st )
-         -> decltype( Rule::template match< A, M, Action, Control >( in, st... ) )
-      {
-         return Rule::template match< A, M, Action, Control >( in, st... );
-      }
-
-      template< typename ParseInput, typename... States, int = 1 >
-      [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ )
-         -> decltype( Rule::match( in ) )
-      {
-         return Rule::match( in );
-      }
-   };
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-      {
-         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
-
-         if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
-            return true;
-         }
-         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
-         return false;
-      }
-   };
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_void >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-      {
-         auto m = in.template mark< rewind_mode::required >();
-
-         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
-
-         if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
-            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
-            return m( true );
-         }
-         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
-         return false;
-      }
-   };
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_bool >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-      {
-         auto m = in.template mark< rewind_mode::required >();
-
-         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
-
-         if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            if( Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... ) ) {
-               Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
-               return m( true );
-            }
-         }
-         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
-         return false;
-      }
-   };
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_void >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-      {
-         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
-
-         if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
-            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
-            return true;
-         }
-         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
-         return false;
-      }
-   };
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control >
-   struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_bool >
-   {
-      template< typename ParseInput, typename... States >
-      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
-      {
-         auto m = in.template mark< rewind_mode::required >();
-
-         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
-
-         if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            if( Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... ) ) {
-               Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
-               return m( true );
-            }
-         }
-         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
-         return false;
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp
index cd4b5663e1c14c479835f1d2f7bfa88d48844bb5..86791340031f4f89b8aca1b90c5e807ec21e04eb 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_posix.hpp
@@ -4,22 +4,74 @@
 #ifndef TAO_PEGTL_INTERNAL_FILE_MAPPER_POSIX_HPP
 #define TAO_PEGTL_INTERNAL_FILE_MAPPER_POSIX_HPP
 
+#include <fcntl.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include <system_error>
+#include <filesystem>
+#include <utility>
 
 #include "../config.hpp"
 
-#include "file_opener.hpp"
-
 namespace TAO_PEGTL_NAMESPACE::internal
 {
+   struct file_opener
+   {
+      explicit file_opener( const std::filesystem::path& path )  // NOLINT(modernize-pass-by-value)
+         : m_path( path ),
+           m_fd( open() )
+      {}
+
+      file_opener( const file_opener& ) = delete;
+      file_opener( file_opener&& ) = delete;
+
+      ~file_opener()
+      {
+         ::close( m_fd );
+      }
+
+      void operator=( const file_opener& ) = delete;
+      void operator=( file_opener&& ) = delete;
+
+      [[nodiscard]] std::size_t size() const
+      {
+         struct stat st;
+         errno = 0;
+         if( ::fstat( m_fd, &st ) < 0 ) {
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "fstat() failed", m_path, ec );
+         }
+         return std::size_t( st.st_size );
+      }
+
+      const std::filesystem::path m_path;
+      const int m_fd;
+
+   private:
+      [[nodiscard]] int open() const
+      {
+         errno = 0;
+         const int fd = ::open( m_path.c_str(),
+                                O_RDONLY
+#if defined( O_CLOEXEC )
+                                   | O_CLOEXEC
+#endif
+         );
+         if( fd >= 0 ) {
+            return fd;
+         }
+         const std::error_code ec( errno, std::system_category() );
+         throw std::filesystem::filesystem_error( "open() failed", m_path, ec );
+      }
+   };
+
    class file_mapper
    {
    public:
-      explicit file_mapper( const char* filename )
-         : file_mapper( file_opener( filename ) )
+      explicit file_mapper( const std::filesystem::path& path )
+         : file_mapper( file_opener( path ) )
       {}
 
       explicit file_mapper( const file_opener& reader )
@@ -27,15 +79,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
            m_data( static_cast< const char* >( ::mmap( nullptr, m_size, PROT_READ, MAP_PRIVATE, reader.m_fd, 0 ) ) )
       {
          if( ( m_size != 0 ) && ( intptr_t( m_data ) == -1 ) ) {
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), reader.m_source );
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "mmap() failed", reader.m_path, ec );
          }
       }
 
       file_mapper( const file_mapper& ) = delete;
       file_mapper( file_mapper&& ) = delete;
 
-      ~file_mapper() noexcept
+      ~file_mapper()
       {
          // Legacy C interface requires pointer-to-mutable but does not write through the pointer.
          ::munmap( const_cast< char* >( m_data ), m_size );
diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
index 27f9eaf955f141de0c02478d93d02a518af1bade..e8dab183317686ab86d49a511493892e20c90018 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
@@ -26,7 +26,7 @@
 #undef TAO_PEGTL_WIN32_LEAN_AND_MEAN_WAS_DEFINED
 #endif
 
-#include <system_error>
+#include <filesystem>
 
 #include "../config.hpp"
 
@@ -34,15 +34,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct win32_file_opener
    {
-      explicit win32_file_opener( const char* filename )
-         : m_source( filename ),
+      explicit win32_file_opener( const std::filesystem::path& path )
+         : m_path( path ),
            m_handle( open() )
       {}
 
       win32_file_opener( const win32_file_opener& ) = delete;
       win32_file_opener( win32_file_opener&& ) = delete;
 
-      ~win32_file_opener() noexcept
+      ~win32_file_opener()
       {
          ::CloseHandle( m_handle );
       }
@@ -54,23 +54,21 @@ namespace TAO_PEGTL_NAMESPACE::internal
       {
          LARGE_INTEGER size;
          if( !::GetFileSizeEx( m_handle, &size ) ) {
-            const auto ec = ::GetLastError();
-            throw std::system_error( ec, std::system_category(), std::string( "GetFileSizeEx(): " ) + m_source );
+            const std::error_code ec( ::GetLastError(), std::system_category() );
+            throw std::filesystem::filesystem_error( "GetFileSizeEx() failed", m_path, ec );
          }
          return std::size_t( size.QuadPart );
       }
 
-      const char* const m_source;
+      const std::filesystem::path m_path;
       const HANDLE m_handle;
 
    private:
       [[nodiscard]] HANDLE open() const
       {
          SetLastError( 0 );
-         std::wstring ws( m_source, m_source + strlen( m_source ) );
-
 #if( _WIN32_WINNT >= 0x0602 )
-         const HANDLE handle = ::CreateFile2( ws.c_str(),
+         const HANDLE handle = ::CreateFile2( m_path.c_str(),
                                               GENERIC_READ,
                                               FILE_SHARE_READ,
                                               OPEN_EXISTING,
@@ -78,10 +76,10 @@ namespace TAO_PEGTL_NAMESPACE::internal
          if( handle != INVALID_HANDLE_VALUE ) {
             return handle;
          }
-         const auto ec = ::GetLastError();
-         throw std::system_error( ec, std::system_category(), std::string( "CreateFile2(): " ) + m_source );
+         const std::error_code ec( ::GetLastError(), std::system_category() );
+         throw std::filesystem::filesystem_error( "CreateFile2() failed", m_path, ec );
 #else
-         const HANDLE handle = ::CreateFileW( ws.c_str(),
+         const HANDLE handle = ::CreateFileW( m_path.c_str(),
                                               GENERIC_READ,
                                               FILE_SHARE_READ,
                                               nullptr,
@@ -91,16 +89,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
          if( handle != INVALID_HANDLE_VALUE ) {
             return handle;
          }
-         const auto ec = ::GetLastError();
-         throw std::system_error( ec, std::system_category(), std::string( "CreateFileW(): " ) + m_source );
+         const std::error_code ec( ::GetLastError(), std::system_category() );
+         throw std::filesystem::filesystem_error( "CreateFileW()", m_path, ec );
 #endif
       }
    };
 
    struct win32_file_mapper
    {
-      explicit win32_file_mapper( const char* filename )
-         : win32_file_mapper( win32_file_opener( filename ) )
+      explicit win32_file_mapper( const std::filesystem::path& path )
+         : win32_file_mapper( win32_file_opener( path ) )
       {}
 
       explicit win32_file_mapper( const win32_file_opener& reader )
@@ -111,7 +109,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
       win32_file_mapper( const win32_file_mapper& ) = delete;
       win32_file_mapper( win32_file_mapper&& ) = delete;
 
-      ~win32_file_mapper() noexcept
+      ~win32_file_mapper()
       {
          ::CloseHandle( m_handle );
       }
@@ -140,16 +138,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
          if( handle != NULL || file_size == 0 ) {
             return handle;
          }
-         const auto ec = ::GetLastError();
-         throw std::system_error( ec, std::system_category(), std::string( "CreateFileMappingW(): " ) + reader.m_source );
+         const std::error_code ec( ::GetLastError(), std::system_category() );
+         throw std::filesystem::filesystem_error( "CreateFileMappingW() failed", reader.m_path, ec );
       }
    };
 
    class file_mapper
    {
    public:
-      explicit file_mapper( const char* filename )
-         : file_mapper( win32_file_mapper( filename ) )
+      explicit file_mapper( const std::filesystem::path& path )
+         : file_mapper( win32_file_mapper( path ) )
       {}
 
       explicit file_mapper( const win32_file_mapper& mapper )
@@ -161,15 +159,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
                                                                 0 ) ) )
       {
          if( ( m_size != 0 ) && ( intptr_t( m_data ) == 0 ) ) {
-            const auto ec = ::GetLastError();
-            throw std::system_error( ec, std::system_category(), "MapViewOfFile()" );
+            const std::error_code ec( ::GetLastError(), std::system_category() );
+            throw std::filesystem::filesystem_error( "MapViewOfFile() failed", ec );
          }
       }
 
       file_mapper( const file_mapper& ) = delete;
       file_mapper( file_mapper&& ) = delete;
 
-      ~file_mapper() noexcept
+      ~file_mapper()
       {
          ::UnmapViewOfFile( LPCVOID( m_data ) );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp
deleted file mode 100644
index 5f2521b6b1e3eafc4a7b294e8ce65f0dc2426c21..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/file_opener.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_FILE_OPENER_HPP
-#define TAO_PEGTL_INTERNAL_FILE_OPENER_HPP
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <system_error>
-#include <utility>
-
-#include "../config.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   struct file_opener
-   {
-      explicit file_opener( const char* filename )
-         : m_source( filename ),
-           m_fd( open() )
-      {}
-
-      file_opener( const file_opener& ) = delete;
-      file_opener( file_opener&& ) = delete;
-
-      ~file_opener() noexcept
-      {
-         ::close( m_fd );
-      }
-
-      void operator=( const file_opener& ) = delete;
-      void operator=( file_opener&& ) = delete;
-
-      [[nodiscard]] std::size_t size() const
-      {
-         struct stat st;
-         errno = 0;
-         if( ::fstat( m_fd, &st ) < 0 ) {
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), m_source );
-         }
-         return std::size_t( st.st_size );
-      }
-
-      const char* const m_source;
-      const int m_fd;
-
-   private:
-      [[nodiscard]] int open() const
-      {
-         errno = 0;
-         const int fd = ::open( m_source,
-                                O_RDONLY
-#if defined( O_CLOEXEC )
-                                   | O_CLOEXEC
-#endif
-         );
-         if( fd >= 0 ) {
-            return fd;
-         }
-         const auto ec = errno;
-         throw std::system_error( ec, std::system_category(), m_source );
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp
index ac098e5921edae0d14f0ed7efe7e298670b95c9a..d2812abfc8fc62726ee55c93679beb91e07aa4ed 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/file_reader.hpp
@@ -5,31 +5,37 @@
 #define TAO_PEGTL_INTERNAL_FILE_READER_HPP
 
 #include <cstdio>
+#include <filesystem>
 #include <memory>
 #include <string>
-#include <system_error>
 #include <utility>
 
 #include "../config.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
-   [[nodiscard]] inline std::FILE* file_open( const char* filename )
+   [[nodiscard]] inline std::FILE* file_open( const std::filesystem::path& path )
    {
       errno = 0;
 #if defined( _MSC_VER )
       std::FILE* file;
-      if( ::fopen_s( &file, filename, "rb" ) == 0 )
-#elif defined( __MINGW32__ )
-      if( auto* file = std::fopen( filename, "rb" ) )
+      if( ::_wfopen_s( &file, path.c_str(), L"rb" ) == 0 ) {
+         return file;
+      }
+      const std::error_code ec( errno, std::system_category() );
+      throw std::filesystem::filesystem_error( "_wfopen_s() failed", path, ec );
 #else
-      if( auto* file = std::fopen( filename, "rbe" ) )
+#if defined( __MINGW32__ )
+      if( auto* file = std::fopen( path.c_str(), "rb" ) )
+#else
+      if( auto* file = std::fopen( path.c_str(), "rbe" ) )
 #endif
       {
          return file;
       }
-      const auto ec = errno;
-      throw std::system_error( ec, std::system_category(), filename );
+      const std::error_code ec( errno, std::system_category() );
+      throw std::filesystem::filesystem_error( "std::fopen() failed", path, ec );
+#endif
    }
 
    struct file_close
@@ -43,13 +49,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
    class file_reader
    {
    public:
-      explicit file_reader( const char* filename )
-         : m_source( filename ),
-           m_file( file_open( m_source ) )
+      explicit file_reader( const std::filesystem::path& path )
+         : file_reader( file_open( path ), path )
       {}
 
-      file_reader( FILE* file, const char* filename ) noexcept
-         : m_source( filename ),
+      file_reader( FILE* file, const std::filesystem::path& path )  // NOLINT(modernize-pass-by-value)
+         : m_path( path ),
            m_file( file )
       {}
 
@@ -66,23 +71,23 @@ namespace TAO_PEGTL_NAMESPACE::internal
          errno = 0;
          if( std::fseek( m_file.get(), 0, SEEK_END ) != 0 ) {
             // LCOV_EXCL_START
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), m_source );
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "std::fseek() failed [SEEK_END]", m_path, ec );
             // LCOV_EXCL_STOP
          }
          errno = 0;
          const auto s = std::ftell( m_file.get() );
          if( s < 0 ) {
             // LCOV_EXCL_START
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), m_source );
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "std::ftell() failed", m_path, ec );
             // LCOV_EXCL_STOP
          }
          errno = 0;
          if( std::fseek( m_file.get(), 0, SEEK_SET ) != 0 ) {
             // LCOV_EXCL_START
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), m_source );
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "std::fseek() failed [SEEK_SET]", m_path, ec );
             // LCOV_EXCL_STOP
          }
          return std::size_t( s );
@@ -95,15 +100,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
          errno = 0;
          if( !nrv.empty() && ( std::fread( &nrv[ 0 ], nrv.size(), 1, m_file.get() ) != 1 ) ) {
             // LCOV_EXCL_START
-            const auto ec = errno;
-            throw std::system_error( ec, std::system_category(), m_source );
+            const std::error_code ec( errno, std::system_category() );
+            throw std::filesystem::filesystem_error( "std::fread() failed", m_path, ec );
             // LCOV_EXCL_STOP
          }
          return nrv;
       }
 
    private:
-      const char* const m_source;
+      const std::filesystem::path m_path;
       const std::unique_ptr< std::FILE, file_close > m_file;
    };
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_unwind.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_unwind.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..20bd953f5b35b75f78588449507ae2234e0c899d
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/has_unwind.hpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_HAS_UNWIND_HPP
+#define TAO_PEGTL_INTERNAL_HAS_UNWIND_HPP
+
+#include <utility>
+
+#include "../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   template< typename, typename... >
+   inline constexpr bool has_unwind = false;
+
+   template< typename C, typename... S >
+   inline constexpr bool has_unwind< C, decltype( C::unwind( std::declval< S >()... ) ), S... > = true;
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp b/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp
index 416b53d006beb875cf725d25649ceaf8014f26b1..ae2cca18d962d44aa7eb53ea62918fd2a64644d7 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/iterator.hpp
@@ -4,6 +4,7 @@
 #ifndef TAO_PEGTL_INTERNAL_ITERATOR_HPP
 #define TAO_PEGTL_INTERNAL_ITERATOR_HPP
 
+#include <cassert>
 #include <cstdlib>
 
 #include "../config.hpp"
@@ -18,12 +19,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
          : data( in_data )
       {}
 
-      iterator( const char* in_data, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line ) noexcept
+      iterator( const char* in_data, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_column ) noexcept
          : data( in_data ),
            byte( in_byte ),
            line( in_line ),
-           byte_in_line( in_byte_in_line )
-      {}
+           column( in_column )
+      {
+         assert( in_line != 0 );
+         assert( in_column != 0 );
+      }
 
       iterator( const iterator& ) = default;
       iterator( iterator&& ) = default;
@@ -33,16 +37,11 @@ namespace TAO_PEGTL_NAMESPACE::internal
       iterator& operator=( const iterator& ) = default;
       iterator& operator=( iterator&& ) = default;
 
-      void reset() noexcept
-      {
-         *this = iterator();
-      }
-
       const char* data = nullptr;
 
       std::size_t byte = 0;
       std::size_t line = 1;
-      std::size_t byte_in_line = 0;
+      std::size_t column = 1;
    };
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
diff --git a/packages/PEGTL/include/tao/pegtl/internal/marker.hpp b/packages/PEGTL/include/tao/pegtl/internal/marker.hpp
index 27d4c0cf08e42cccac3502b93685251ce2556fa1..6cec4aa8f6122ff05e1180da6ef8fdcd16e272ac 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/marker.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/marker.hpp
@@ -46,7 +46,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
       marker( const marker& ) = delete;
       marker( marker&& ) = delete;
 
-      ~marker() noexcept
+      ~marker()
       {
          if( m_input != nullptr ) {
             ( *m_input ) = m_saved;
diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
index 0e3e51127f48a7ef7e6162b3bcb9ed2ec051193a..d1e8f76837a68acff767962ca7c1ef9c9eb92acc 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
@@ -16,8 +16,11 @@ namespace TAO_PEGTL_NAMESPACE::internal
              typename... States >
    void missing_apply( ParseInput& in, States&&... st )
    {
+      // This function only exists for better error messages, which means that it is only called when we know that it won't compile.
+      // LCOV_EXCL_START
       auto m = in.template mark< rewind_mode::required >();
       (void)Control::template apply< Action >( m.iterator(), in, st... );
+      // LCOV_EXCL_STOP
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
index 345e50f6e9ec3dce59f0fec4fc0340c48d9aeb86..a7b65f8c925c0b2c174cd406d7edc027dd2257c5 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
@@ -15,7 +15,10 @@ namespace TAO_PEGTL_NAMESPACE::internal
              typename... States >
    void missing_apply0( ParseInput& in, States&&... st )
    {
+      // This function only exists for better error messages, which means that it is only called when we know that it won't compile.
+      // LCOV_EXCL_START
       (void)Control::template apply0< Action >( in, st... );
+      // LCOV_EXCL_STOP
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
diff --git a/packages/PEGTL/include/tao/pegtl/internal/path_to_string.hpp b/packages/PEGTL/include/tao/pegtl/internal/path_to_string.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..04b0774e069b45472b47cce1e4d5d275e19b69ed
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/path_to_string.hpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_PATH_TO_STRING_HPP
+#define TAO_PEGTL_INTERNAL_PATH_TO_STRING_HPP
+
+#include <filesystem>
+#include <string>
+
+#include "../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   [[nodiscard]] inline std::string path_to_string( const std::filesystem::path& path )
+   {
+#if defined( __cpp_char8_t )
+      const auto s = path.u8string();
+      return { reinterpret_cast< const char* >( s.data() ), s.size() };
+#else
+      return path.u8string();
+#endif
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
index 2e9554a70ff1b1818043035f29e944f695ddcb6d..de13adfbe8ff8c967b1d990b62c3ddbf87aa8268 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
@@ -5,8 +5,6 @@
 #define TAO_PEGTL_INTERNAL_RULES_HPP
 
 #include "action.hpp"
-#include "alnum.hpp"
-#include "alpha.hpp"
 #include "any.hpp"
 #include "apply.hpp"
 #include "apply0.hpp"
diff --git a/packages/PEGTL/include/tao/pegtl/istream_input.hpp b/packages/PEGTL/include/tao/pegtl/istream_input.hpp
index d9a967ef91f71a5c9e26b61de282db57bb129b31..68a484000fa372b915646e4d7089c85baa35ffa5 100644
--- a/packages/PEGTL/include/tao/pegtl/istream_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/istream_input.hpp
@@ -25,7 +25,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   istream_input( Ts&&... )->istream_input<>;
+   istream_input( Ts&&... ) -> istream_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/match.hpp b/packages/PEGTL/include/tao/pegtl/match.hpp
index 77f596b94c23954b5eb294bfe103686d0aae3434..6bb87565b83dbe01472890412e2861cc0af31bce 100644
--- a/packages/PEGTL/include/tao/pegtl/match.hpp
+++ b/packages/PEGTL/include/tao/pegtl/match.hpp
@@ -13,15 +13,79 @@
 #include "require_apply0.hpp"
 #include "rewind_mode.hpp"
 
-#include "internal/dusel_mode.hpp"
-#include "internal/duseltronik.hpp"
 #include "internal/has_apply.hpp"
 #include "internal/has_apply0.hpp"
+#include "internal/has_unwind.hpp"
+#include "internal/marker.hpp"
 #include "internal/missing_apply.hpp"
 #include "internal/missing_apply0.hpp"
 
+#if defined( _MSC_VER )
+#pragma warning( push )
+#pragma warning( disable : 4702 )
+#endif
+
 namespace TAO_PEGTL_NAMESPACE
 {
+   namespace internal
+   {
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... st )
+         -> decltype( Rule::template match< A, M, Action, Control >( in, st... ) )
+      {
+         return Rule::template match< A, M, Action, Control >( in, st... );
+      }
+
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... /*unused*/ )
+         -> decltype( Rule::match( in ) )
+      {
+         return Rule::match( in );
+      }
+
+      template< typename Rule,
+                apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] auto match_control_unwind( ParseInput& in, States&&... st )
+      {
+         if constexpr( has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
+            try {
+               return match_no_control< Rule, A, M, Action, Control >( in, st... );
+            }
+            catch( ... ) {
+               Control< Rule >::unwind( static_cast< const ParseInput& >( in ), st... );
+               throw;
+            }
+         }
+         else {
+            return match_no_control< Rule, A, M, Action, Control >( in, st... );
+         }
+      }
+
+   }  // namespace internal
+
    template< typename Rule,
              apply_mode A,
              rewind_mode M,
@@ -31,42 +95,75 @@ namespace TAO_PEGTL_NAMESPACE
              class Control,
              typename ParseInput,
              typename... States >
-   [[nodiscard]] bool match( ParseInput& in, States&&... st )
+   [[nodiscard]] auto match( ParseInput& in, States&&... st )
    {
-      constexpr bool enable_control = Control< Rule >::enable;
-      constexpr bool enable_action = enable_control && ( A == apply_mode::action );
+      if constexpr( !Control< Rule >::enable ) {
+         return internal::match_no_control< Rule, A, M, Action, Control >( in, st... );
+      }
+      else {
+         constexpr bool enable_action = ( A == apply_mode::action );
 
-      using iterator_t = typename ParseInput::iterator_t;
-      constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >;
-      constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >;
-      constexpr bool has_apply = has_apply_void || has_apply_bool;
+         using iterator_t = typename ParseInput::iterator_t;
+         constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >;
+         constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >;
+         constexpr bool has_apply = has_apply_void || has_apply_bool;
 
-      constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >;
-      constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >;
-      constexpr bool has_apply0 = has_apply0_void || has_apply0_bool;
+         constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >;
+         constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >;
+         constexpr bool has_apply0 = has_apply0_void || has_apply0_bool;
 
-      static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" );
+         static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" );
 
-      constexpr bool is_nothing = std::is_base_of_v< nothing< Rule >, Action< Rule > >;
-      static_assert( !( has_apply && is_nothing ), "unexpected apply() defined" );
-      static_assert( !( has_apply0 && is_nothing ), "unexpected apply0() defined" );
+         constexpr bool is_nothing = std::is_base_of_v< nothing< Rule >, Action< Rule > >;
+         static_assert( !( has_apply && is_nothing ), "unexpected apply() defined" );
+         static_assert( !( has_apply0 && is_nothing ), "unexpected apply0() defined" );
 
-      if constexpr( !has_apply && std::is_base_of_v< require_apply, Action< Rule > > ) {
-         internal::missing_apply< Control< Rule >, Action >( in, st... );
-      }
+         if constexpr( !has_apply && std::is_base_of_v< require_apply, Action< Rule > > ) {
+            internal::missing_apply< Control< Rule >, Action >( in, st... );
+         }
 
-      if constexpr( !has_apply0 && std::is_base_of_v< require_apply0, Action< Rule > > ) {
-         internal::missing_apply0< Control< Rule >, Action >( in, st... );
-      }
+         if constexpr( !has_apply0 && std::is_base_of_v< require_apply0, Action< Rule > > ) {
+            internal::missing_apply0< Control< Rule >, Action >( in, st... );
+         }
 
-      constexpr bool validate_nothing = std::is_base_of_v< maybe_nothing, Action< void > >;
-      constexpr bool is_maybe_nothing = std::is_base_of_v< maybe_nothing, Action< Rule > >;
-      static_assert( !enable_action || !validate_nothing || is_nothing || is_maybe_nothing || has_apply || has_apply0, "either apply() or apply0() must be defined" );
+         constexpr bool validate_nothing = std::is_base_of_v< maybe_nothing, Action< void > >;
+         constexpr bool is_maybe_nothing = std::is_base_of_v< maybe_nothing, Action< Rule > >;
+         static_assert( !enable_action || !validate_nothing || is_nothing || is_maybe_nothing || has_apply || has_apply0, "either apply() or apply0() must be defined" );
 
-      constexpr auto mode = static_cast< internal::dusel_mode >( enable_control + has_apply_void + 2 * has_apply_bool + 3 * has_apply0_void + 4 * has_apply0_bool );
-      return internal::duseltronik< Rule, A, M, Action, Control, mode >::match( in, st... );
+         constexpr bool use_marker = has_apply || has_apply0_bool;
+
+         auto m = in.template mark< ( use_marker ? rewind_mode::required : rewind_mode::dontcare ) >();
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
+         auto result = internal::match_control_unwind< Rule, A, ( use_marker ? rewind_mode::active : M ), Action, Control >( in, st... );
+         if( result ) {
+            if constexpr( has_apply_void ) {
+               Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
+            }
+            else if constexpr( has_apply_bool ) {
+               result = Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
+            }
+            else if constexpr( has_apply0_void ) {
+               Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
+            }
+            else if constexpr( has_apply0_bool ) {
+               result = Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
+            }
+         }
+         if( result ) {
+            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
+         }
+         else {
+            Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
+         }
+         (void)m( result );
+         return result;
+      }
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
+#if defined( _MSC_VER )
+#pragma warning( pop )
+#endif
+
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/memory_input.hpp b/packages/PEGTL/include/tao/pegtl/memory_input.hpp
index 6c4c8c9a5f21944bbe74b36361126b413d8d93ba..6f303f57c002f8dc936c6ca9ec2066c338579bf4 100644
--- a/packages/PEGTL/include/tao/pegtl/memory_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/memory_input.hpp
@@ -4,6 +4,7 @@
 #ifndef TAO_PEGTL_MEMORY_INPUT_HPP
 #define TAO_PEGTL_MEMORY_INPUT_HPP
 
+#include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
@@ -89,9 +90,9 @@ namespace TAO_PEGTL_NAMESPACE
             return m_current.line;
          }
 
-         [[nodiscard]] std::size_t byte_in_line() const noexcept
+         [[nodiscard]] std::size_t column() const noexcept
          {
-            return m_current.byte_in_line;
+            return m_current.column;
          }
 
          void bump( const std::size_t in_count = 1 ) noexcept
@@ -114,12 +115,15 @@ namespace TAO_PEGTL_NAMESPACE
             return TAO_PEGTL_NAMESPACE::position( it, m_source );
          }
 
-         void restart( const std::size_t in_byte = 0, const std::size_t in_line = 1, const std::size_t in_byte_in_line = 0 )
+         void restart( const std::size_t in_byte = 0, const std::size_t in_line = 1, const std::size_t in_column = 1 )
          {
+            assert( in_line != 0 );
+            assert( in_column != 0 );
+
             m_current.data = m_begin;
             m_current.byte = in_byte;
             m_current.line = in_line;
-            m_current.byte_in_line = in_byte_in_line;
+            m_current.column = in_column;
          }
 
       protected:
@@ -255,8 +259,8 @@ namespace TAO_PEGTL_NAMESPACE
       {}
 
       template< typename T >
-      memory_input( const char* in_begin, const char* in_end, T&& in_source, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line ) noexcept( std::is_nothrow_constructible_v< Source, T&& > )
-         : memory_input( { in_begin, in_byte, in_line, in_byte_in_line }, in_end, std::forward< T >( in_source ) )
+      memory_input( const char* in_begin, const char* in_end, T&& in_source, const std::size_t in_byte, const std::size_t in_line, const std::size_t in_column ) noexcept( std::is_nothrow_constructible_v< Source, T&& > )
+         : memory_input( { in_begin, in_byte, in_line, in_column }, in_end, std::forward< T >( in_source ) )
       {}
 
       memory_input( const memory_input& ) = delete;
@@ -334,7 +338,7 @@ namespace TAO_PEGTL_NAMESPACE
 
       [[nodiscard]] const char* begin_of_line( const TAO_PEGTL_NAMESPACE::position& p ) const noexcept
       {
-         return at( p ) - p.byte_in_line;
+         return at( p ) - ( p.column - 1 );
       }
 
       [[nodiscard]] const char* end_of_line( const TAO_PEGTL_NAMESPACE::position& p ) const noexcept
@@ -354,7 +358,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   memory_input( Ts&&... )->memory_input<>;
+   memory_input( Ts&&... ) -> memory_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/mmap_input.hpp b/packages/PEGTL/include/tao/pegtl/mmap_input.hpp
index 82206dee5ce1e351acd426dcf9a1836b2d511266..acc24bbca28508ba862aa17501dd060cb59bc57e 100644
--- a/packages/PEGTL/include/tao/pegtl/mmap_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/mmap_input.hpp
@@ -4,14 +4,16 @@
 #ifndef TAO_PEGTL_MMAP_INPUT_HPP
 #define TAO_PEGTL_MMAP_INPUT_HPP
 
+#include <filesystem>
 #include <string>
-#include <utility>
 
 #include "config.hpp"
 #include "eol.hpp"
 #include "memory_input.hpp"
 #include "tracking_mode.hpp"
 
+#include "internal/path_to_string.hpp"
+
 #if defined( __unix__ ) || ( defined( __APPLE__ ) && defined( __MACH__ ) )
 #include <unistd.h>  // Required for _POSIX_MAPPED_FILES
 #endif
@@ -29,13 +31,10 @@ namespace TAO_PEGTL_NAMESPACE
    {
       struct mmap_holder
       {
-         const std::string filename;
          const file_mapper data;
 
-         template< typename T >
-         explicit mmap_holder( T&& in_filename )
-            : filename( std::forward< T >( in_filename ) ),
-              data( filename.c_str() )
+         explicit mmap_holder( const std::filesystem::path& path )
+            : data( path )
          {}
 
          mmap_holder( const mmap_holder& ) = delete;
@@ -52,12 +51,15 @@ namespace TAO_PEGTL_NAMESPACE
    template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf >
    struct mmap_input
       : private internal::mmap_holder,
-        public memory_input< P, Eol, const char* >
+        public memory_input< P, Eol >
    {
-      template< typename T >
-      explicit mmap_input( T&& in_filename )
-         : internal::mmap_holder( std::forward< T >( in_filename ) ),
-           memory_input< P, Eol, const char* >( data.begin(), data.end(), filename.c_str() )
+      mmap_input( const std::filesystem::path& path, const std::string& source )
+         : internal::mmap_holder( path ),
+           memory_input< P, Eol >( data.begin(), data.end(), source )
+      {}
+
+      explicit mmap_input( const std::filesystem::path& path )
+         : mmap_input( path, internal::path_to_string( path ) )
       {}
 
       mmap_input( const mmap_input& ) = delete;
@@ -70,7 +72,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   explicit mmap_input( Ts&&... )->mmap_input<>;
+   explicit mmap_input( Ts&&... ) -> mmap_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/must_if.hpp b/packages/PEGTL/include/tao/pegtl/must_if.hpp
index ab15cb6b6c71fbd0f287b3e5edda55c9ded4313e..d229ae5711fc221a8e554f1129d595ab5519bca7 100644
--- a/packages/PEGTL/include/tao/pegtl/must_if.hpp
+++ b/packages/PEGTL/include/tao/pegtl/must_if.hpp
@@ -4,6 +4,8 @@
 #ifndef TAO_PEGTL_MUST_IF_HPP
 #define TAO_PEGTL_MUST_IF_HPP
 
+#include <type_traits>
+
 #include "config.hpp"
 #include "normal.hpp"
 
@@ -11,15 +13,15 @@ namespace TAO_PEGTL_NAMESPACE
 {
    namespace internal
    {
-      template< typename T, typename Rule, typename = void >
-      inline constexpr bool raise_on_failure = ( T::template message< Rule > != nullptr );
+      template< typename Errors, typename Rule, typename = void >
+      inline constexpr bool raise_on_failure = ( Errors::template message< Rule > != nullptr );
 
-      template< typename T, typename Rule >
-      inline constexpr bool raise_on_failure< T, Rule, decltype( T::template raise_on_failure< Rule >, void() ) > = T::template raise_on_failure< Rule >;
+      template< typename Errors, typename Rule >
+      inline constexpr bool raise_on_failure< Errors, Rule, std::void_t< decltype( Errors::template raise_on_failure< Rule > ) > > = Errors::template raise_on_failure< Rule >;
 
    }  // namespace internal
 
-   template< typename T, template< typename... > class Base = normal, bool RequireMessage = true >
+   template< typename Errors, template< typename... > class Base = normal, bool RequireMessage = true >
    struct must_if
    {
       template< typename Rule >
@@ -27,9 +29,9 @@ namespace TAO_PEGTL_NAMESPACE
          : Base< Rule >
       {
          template< typename ParseInput, typename... States >
-         static void failure( const ParseInput& in, States&&... st ) noexcept( !internal::raise_on_failure< T, Rule > && noexcept( Base< Rule >::failure( in, st... ) ) )
+         static void failure( const ParseInput& in, States&&... st ) noexcept( noexcept( Base< Rule >::failure( in, st... ) ) && !internal::raise_on_failure< Errors, Rule > )
          {
-            if constexpr( internal::raise_on_failure< T, Rule > ) {
+            if constexpr( internal::raise_on_failure< Errors, Rule > ) {
                raise( in, st... );
             }
             else {
@@ -38,16 +40,16 @@ namespace TAO_PEGTL_NAMESPACE
          }
 
          template< typename ParseInput, typename... States >
-         [[noreturn]] static void raise( const ParseInput& in, States&&... st )
+         [[noreturn]] static void raise( const ParseInput& in, [[maybe_unused]] States&&... st )
          {
             if constexpr( RequireMessage ) {
-               static_assert( T::template message< Rule > != nullptr );
+               static_assert( Errors::template message< Rule > != nullptr );
             }
-            if constexpr( T::template message< Rule > != nullptr ) {
-               constexpr const char* p = T::template message< Rule >;
+            if constexpr( Errors::template message< Rule > != nullptr ) {
+               constexpr const char* p = Errors::template message< Rule >;
                throw parse_error( p, in );
 #if defined( _MSC_VER )
-               (void)( (void)st, ... );
+               ( (void)st, ... );
 #endif
             }
             else {
diff --git a/packages/PEGTL/include/tao/pegtl/normal.hpp b/packages/PEGTL/include/tao/pegtl/normal.hpp
index 5d7845b99433dd041d51ef05b1740d392f12dab7..dcb9e4d9430137ba2c5f9822d21e9ac8ae8a999a 100644
--- a/packages/PEGTL/include/tao/pegtl/normal.hpp
+++ b/packages/PEGTL/include/tao/pegtl/normal.hpp
@@ -10,11 +10,11 @@
 
 #include "apply_mode.hpp"
 #include "config.hpp"
+#include "demangle.hpp"
 #include "match.hpp"
 #include "parse_error.hpp"
 #include "rewind_mode.hpp"
 
-#include "internal/demangle.hpp"
 #include "internal/enable_control.hpp"
 #include "internal/has_match.hpp"
 
@@ -40,7 +40,7 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename ParseInput, typename... States >
       [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ )
       {
-         throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in );
+         throw parse_error( "parse error matching " + std::string( demangle< Rule >() ), in );
       }
 
       template< template< typename... > class Action,
diff --git a/packages/PEGTL/include/tao/pegtl/parse.hpp b/packages/PEGTL/include/tao/pegtl/parse.hpp
index 7d435708a06209082cca146350cd993c218acf70..02528a032f5eab1c3a85911c1dea0a622e907e46 100644
--- a/packages/PEGTL/include/tao/pegtl/parse.hpp
+++ b/packages/PEGTL/include/tao/pegtl/parse.hpp
@@ -22,7 +22,7 @@ namespace TAO_PEGTL_NAMESPACE
              rewind_mode M = rewind_mode::required,
              typename ParseInput,
              typename... States >
-   bool parse( ParseInput&& in, States&&... st )
+   auto parse( ParseInput&& in, States&&... st )
    {
       return Control< Rule >::template match< A, M, Action, Control >( in, st... );
    }
@@ -35,13 +35,13 @@ namespace TAO_PEGTL_NAMESPACE
              typename OuterInput,
              typename ParseInput,
              typename... States >
-   bool parse_nested( const OuterInput& oi, ParseInput&& in, States&&... st )
+   auto parse_nested( const OuterInput& oi, ParseInput&& in, States&&... st )
    {
       try {
          return parse< Rule, Action, Control, A, M >( in, st... );
       }
       catch( parse_error& e ) {
-         e.positions.push_back( oi.position() );
+         e.add_position( oi.position() );
          throw;
       }
    }
diff --git a/packages/PEGTL/include/tao/pegtl/parse_error.hpp b/packages/PEGTL/include/tao/pegtl/parse_error.hpp
index d48f95b830048929c62fbaba1348be9be915b721..b2f8741ff7ded4dc6343ec68276761eaee830947 100644
--- a/packages/PEGTL/include/tao/pegtl/parse_error.hpp
+++ b/packages/PEGTL/include/tao/pegtl/parse_error.hpp
@@ -4,10 +4,11 @@
 #ifndef TAO_PEGTL_PARSE_ERROR_HPP
 #define TAO_PEGTL_PARSE_ERROR_HPP
 
-#include <ostream>
-#include <sstream>
+#include <cstddef>
+#include <memory>
 #include <stdexcept>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -16,50 +17,97 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   struct parse_error
-      : std::runtime_error
+   namespace internal
    {
-      template< typename Msg >
-      parse_error( Msg&& msg, std::vector< position > in_positions )
-         : std::runtime_error( std::forward< Msg >( msg ) ),
-           positions( std::move( in_positions ) )
-      {}
+      class parse_error
+      {
+      private:
+         std::string m_msg;
+         std::size_t m_prefix = 0;
+         std::vector< position > m_positions;
 
-      template< typename Msg >
-      parse_error( Msg&& msg, const position& pos )
-         : std::runtime_error( std::forward< Msg >( msg ) ),
-           positions( 1, pos )
-      {}
+      public:
+         explicit parse_error( const char* msg )
+            : m_msg( msg )
+         {}
+
+         [[nodiscard]] const char* what() const noexcept
+         {
+            return m_msg.c_str();
+         }
+
+         [[nodiscard]] std::string_view message() const noexcept
+         {
+            return { m_msg.data() + m_prefix, m_msg.size() - m_prefix };
+         }
+
+         [[nodiscard]] const std::vector< position >& positions() const noexcept
+         {
+            return m_positions;
+         }
+
+         void add_position( position&& p )
+         {
+            const auto prefix = to_string( p );
+            m_msg = prefix + ": " + m_msg;
+            m_prefix += prefix.size() + 2;
+            m_positions.emplace_back( std::move( p ) );
+         }
+      };
 
-      template< typename Msg >
-      parse_error( Msg&& msg, position&& pos )
-         : std::runtime_error( std::forward< Msg >( msg ) )
+   }  // namespace internal
+
+   class parse_error
+      : public std::runtime_error
+   {
+   private:
+      std::shared_ptr< internal::parse_error > m_impl;
+
+   public:
+      parse_error( const char* msg, position p )
+         : std::runtime_error( msg ),
+           m_impl( std::make_shared< internal::parse_error >( msg ) )
       {
-         positions.emplace_back( std::move( pos ) );
+         m_impl->add_position( std::move( p ) );
       }
 
-      template< typename Msg, typename ParseInput >
-      parse_error( Msg&& msg, const ParseInput& in )
-         : parse_error( std::forward< Msg >( msg ), in.position() )
+      parse_error( const std::string& msg, position p )
+         : parse_error( msg.c_str(), std::move( p ) )
       {}
 
-      std::vector< position > positions;
-   };
+      template< typename ParseInput >
+      parse_error( const char* msg, const ParseInput& in )
+         : parse_error( msg, in.position() )
+      {}
 
-   inline std::ostream& operator<<( std::ostream& o, const parse_error& e )
-   {
-      for( auto it = e.positions.rbegin(); it != e.positions.rend(); ++it ) {
-         o << *it << ": ";
+      template< typename ParseInput >
+      parse_error( const std::string& msg, const ParseInput& in )
+         : parse_error( msg.c_str(), in.position() )
+      {}
+
+      [[nodiscard]] const char* what() const noexcept override
+      {
+         return m_impl->what();
       }
-      return o << e.what();
-   }
 
-   [[nodiscard]] inline std::string to_string( const parse_error& e )
-   {
-      std::ostringstream o;
-      o << e;
-      return o.str();
-   }
+      [[nodiscard]] std::string_view message() const noexcept
+      {
+         return m_impl->message();
+      }
+
+      [[nodiscard]] const std::vector< position >& positions() const noexcept
+      {
+         return m_impl->positions();
+      }
+
+      void add_position( position&& p )
+      {
+         if( m_impl.use_count() > 1 ) {
+            m_impl = std::make_shared< internal::parse_error >( *m_impl );
+         }
+         m_impl->add_position( std::move( p ) );
+      }
+   };
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/position.hpp b/packages/PEGTL/include/tao/pegtl/position.hpp
index 6cdc07bd02077901d81769ab60ff3f573b187190..7543fdb0ecbee4471381d9640bd0dadc35bd0369 100644
--- a/packages/PEGTL/include/tao/pegtl/position.hpp
+++ b/packages/PEGTL/include/tao/pegtl/position.hpp
@@ -23,7 +23,7 @@ namespace TAO_PEGTL_NAMESPACE
       position( position&& p ) noexcept
          : byte( p.byte ),
            line( p.line ),
-           byte_in_line( p.byte_in_line ),
+           column( p.column ),
            source( std::move( p.source ) )
       {}
 
@@ -33,7 +33,7 @@ namespace TAO_PEGTL_NAMESPACE
       {
          byte = p.byte;
          line = p.line;
-         byte_in_line = p.byte_in_line;
+         column = p.column;
          source = std::move( p.source );
          return *this;
       }
@@ -44,7 +44,7 @@ namespace TAO_PEGTL_NAMESPACE
       position( const internal::iterator& in_iter, T&& in_source )
          : byte( in_iter.byte ),
            line( in_iter.line ),
-           byte_in_line( in_iter.byte_in_line ),
+           column( in_iter.column ),
            source( std::forward< T >( in_source ) )
       {}
 
@@ -52,13 +52,23 @@ namespace TAO_PEGTL_NAMESPACE
 
       std::size_t byte;
       std::size_t line;
-      std::size_t byte_in_line;
+      std::size_t column;
       std::string source;
    };
 
-   inline std::ostream& operator<<( std::ostream& o, const position& p )
+   inline bool operator==( const position& lhs, const position& rhs ) noexcept
    {
-      return o << p.source << ':' << p.line << ':' << p.byte_in_line << '(' << p.byte << ')';
+      return ( lhs.byte == rhs.byte ) && ( lhs.source == rhs.source );
+   }
+
+   inline bool operator!=( const position& lhs, const position& rhs ) noexcept
+   {
+      return !( lhs == rhs );
+   }
+
+   inline std::ostream& operator<<( std::ostream& os, const position& p )
+   {
+      return os << p.source << ':' << p.line << ':' << p.column;
    }
 
    [[nodiscard]] inline std::string to_string( const position& p )
diff --git a/packages/PEGTL/include/tao/pegtl/read_input.hpp b/packages/PEGTL/include/tao/pegtl/read_input.hpp
index 224b2e9a75874cbac59aff00dbe95b950b29d241..f830de3b90bad0e4f56fcf966da7933ba3206520 100644
--- a/packages/PEGTL/include/tao/pegtl/read_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/read_input.hpp
@@ -4,6 +4,7 @@
 #ifndef TAO_PEGTL_READ_INPUT_HPP
 #define TAO_PEGTL_READ_INPUT_HPP
 
+#include <filesystem>
 #include <string>
 
 #include "config.hpp"
@@ -12,46 +13,28 @@
 #include "tracking_mode.hpp"
 
 #include "internal/file_reader.hpp"
+#include "internal/path_to_string.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   namespace internal
-   {
-      struct filename_holder
-      {
-         const std::string filename;
-
-         template< typename T >
-         explicit filename_holder( T&& in_filename )
-            : filename( std::forward< T >( in_filename ) )
-         {}
-
-         filename_holder( const filename_holder& ) = delete;
-         filename_holder( filename_holder&& ) = delete;
-
-         ~filename_holder() = default;
-
-         void operator=( const filename_holder& ) = delete;
-         void operator=( filename_holder&& ) = delete;
-      };
-
-   }  // namespace internal
-
    template< tracking_mode P = tracking_mode::eager, typename Eol = eol::lf_crlf >
    struct read_input
-      : private internal::filename_holder,
-        public string_input< P, Eol, const char* >
+      : string_input< P, Eol >
    {
-      template< typename T >
-      explicit read_input( T&& in_filename )
-         : internal::filename_holder( std::forward< T >( in_filename ) ),
-           string_input< P, Eol, const char* >( internal::file_reader( filename.c_str() ).read(), filename.c_str() )
+      read_input( const std::filesystem::path& path, const std::string& source )
+         : string_input< P, Eol >( internal::file_reader( path ).read(), source )
+      {}
+
+      explicit read_input( const std::filesystem::path& path )
+         : read_input( path, internal::path_to_string( path ) )
+      {}
+
+      read_input( FILE* file, const std::filesystem::path& path, const std::string& source )
+         : string_input< P, Eol >( internal::file_reader( file, path ).read(), source )
       {}
 
-      template< typename T >
-      read_input( FILE* in_file, T&& in_filename )
-         : internal::filename_holder( std::forward< T >( in_filename ) ),
-           string_input< P, Eol, const char* >( internal::file_reader( in_file, filename.c_str() ).read(), filename.c_str() )
+      read_input( FILE* file, const std::filesystem::path& path )
+         : read_input( file, path, internal::path_to_string( path ) )
       {}
 
       read_input( const read_input& ) = delete;
@@ -64,7 +47,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   explicit read_input( Ts&&... )->read_input<>;
+   explicit read_input( Ts&&... ) -> read_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/rules.hpp b/packages/PEGTL/include/tao/pegtl/rules.hpp
index 659619c0eda2725b8bf3d6d67ae1fb912ba17249..09f7ad5d188c881fc8ea08e020cc8b8d2cd98d6b 100644
--- a/packages/PEGTL/include/tao/pegtl/rules.hpp
+++ b/packages/PEGTL/include/tao/pegtl/rules.hpp
@@ -12,9 +12,9 @@
 namespace TAO_PEGTL_NAMESPACE
 {
    // clang-format off
+   template< template< typename... > class Action, typename... Rules > struct action : internal::action< Action, Rules... > {};
    template< typename... Actions > struct apply : internal::apply< Actions... > {};
    template< typename... Actions > struct apply0 : internal::apply0< Actions... > {};
-   template< template< typename... > class Action, typename... Rules > struct action : internal::action< Action, Rules... > {};
    template< typename... Rules > struct at : internal::at< Rules... > {};
    struct bof : internal::bof {};
    struct bol : internal::bol {};
@@ -58,7 +58,7 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename Cond, typename... Rules > struct star_must : internal::star_must< Cond, Rules... > {};
    template< typename State, typename... Rules > struct state : internal::state< State, Rules... > {};
    struct success : internal::success {};
-   template< typename... Rules > struct try_catch : internal::seq< internal::try_catch_type< parse_error, Rules... > > {};
+   template< typename... Rules > struct try_catch : internal::try_catch_type< parse_error, Rules... > {};
    template< typename Exception, typename... Rules > struct try_catch_type : internal::seq< internal::try_catch_type< Exception, Rules... > > {};
    template< typename Cond, typename... Rules > struct until : internal::until< Cond, Rules... > {};
    // clang-format on
diff --git a/packages/PEGTL/include/tao/pegtl/string_input.hpp b/packages/PEGTL/include/tao/pegtl/string_input.hpp
index 06fec70d670f3554e5f3f167d33416048b81ef41..8bacffbc4d1daffb98a69193a6330aae57b580e4 100644
--- a/packages/PEGTL/include/tao/pegtl/string_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/string_input.hpp
@@ -57,7 +57,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template< typename... Ts >
-   explicit string_input( Ts&&... )->string_input<>;
+   explicit string_input( Ts&&... ) -> string_input<>;
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/src/example/pegtl/CMakeLists.txt b/packages/PEGTL/src/example/pegtl/CMakeLists.txt
index 60518785710ccf34241b761ef4dfef3d6d6c4a52..0cbdd6288262e34785bd5aef39dff669aeb7d8e2 100644
--- a/packages/PEGTL/src/example/pegtl/CMakeLists.txt
+++ b/packages/PEGTL/src/example/pegtl/CMakeLists.txt
@@ -10,13 +10,19 @@ set(example_sources
   dynamic_match.cpp
   hello_world.cpp
   indent_aware.cpp
+  json_analyze.cpp
+  json_ast.cpp
   json_build.cpp
   json_count.cpp
   json_coverage.cpp
   json_parse.cpp
-  json_print_rules.cpp
-  json_print_sub_rules.cpp
+  json_print_debug.cpp
+  json_print_names.cpp
+  json_trace.cpp
+  lua53_analyze.cpp
   lua53_parse.cpp
+  lua53_print_debug.cpp
+  lua53_print_names.cpp
   modulus_match.cpp
   parse_tree.cpp
   parse_tree_user_state.cpp
@@ -27,6 +33,8 @@ set(example_sources
   symbol_table.cpp
   unescape.cpp
   uri.cpp
+  uri_print_debug.cpp
+  uri_print_names.cpp
   uri_trace.cpp
 )
 
diff --git a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
index 5af83c55112402a143afa902ce883e6b5bf2ce49..b019047c937ae57c44cfa5fbb2599f26cbbfd8bb 100644
--- a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
+++ b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
@@ -2,6 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include <algorithm>
+#include <iomanip>
 #include <iostream>
 #include <iterator>
 #include <map>
@@ -25,7 +26,6 @@
 
 #include <tao/pegtl.hpp>
 #include <tao/pegtl/contrib/abnf.hpp>
-#include <tao/pegtl/contrib/analyze.hpp>
 #include <tao/pegtl/contrib/parse_tree.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
@@ -145,7 +145,7 @@ namespace TAO_PEGTL_NAMESPACE
 
          rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v, const rules_t::reverse_iterator& rbegin )
          {
-            return std::find_if( rbegin, r.rend(), [&]( const rules_t::value_type& p ) { return TAO_PEGTL_STRCASECMP( p.c_str(), v.c_str() ) == 0; } );
+            return std::find_if( rbegin, r.rend(), [ & ]( const rules_t::value_type& p ) { return TAO_PEGTL_STRCASECMP( p.c_str(), v.c_str() ) == 0; } );
          }
 
          rules_t::reverse_iterator find_rule( rules_t& r, const std::string& v )
@@ -180,7 +180,7 @@ namespace TAO_PEGTL_NAMESPACE
          {
             it.data += delta;
             it.byte += delta;
-            it.byte_in_line += delta;
+            it.column += delta;
          }
 
       }  // namespace
@@ -535,7 +535,7 @@ namespace TAO_PEGTL_NAMESPACE
          template< typename T >
          void add( const function_t& f )
          {
-            map_.try_emplace( internal::demangle< T >(), f );
+            map_.try_emplace( demangle< T >(), f );
          }
 
          std::string operator()( const node_ptr& n ) const
@@ -717,14 +717,10 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
    using namespace TAO_PEGTL_NAMESPACE;
 
    if( argc != 2 ) {
-      std::cerr << "Usage: " << argv[ 0 ] << " SOURCE" << std::endl;
+      std::cerr << "Usage: " << argv[ 0 ] << " SOURCE\n";
       return 1;
    }
 
-   if( analyze< abnf::grammar::rulelist >() != 0 ) {
-      return 2;
-   }
-
    file_input in( argv[ 1 ] );
    try {
       const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector, nothing, abnf::control >( in );
@@ -734,14 +730,14 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
       }
 
       for( const auto& rule : root->children ) {
-         std::cout << abnf::to_string( rule ) << std::endl;
+         std::cout << abnf::to_string( rule ) << '\n';
       }
    }
    catch( const parse_error& e ) {
-      const auto p = e.positions.front();
-      std::cerr << e.what() << std::endl
-                << in.line_at( p ) << std::endl
-                << std::string( p.byte_in_line, ' ' ) << '^' << std::endl;
+      const auto p = e.positions().front();
+      std::cerr << e.what() << '\n'
+                << in.line_at( p ) << '\n'
+                << std::setw( p.column ) << '^' << '\n';
    }
 
    return 0;
diff --git a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
index da9f2dc24623dc5ce150b1847d1347c994aecc1f..1f35ee9ec3d15e86bc80f6de9faa3eb8443355c7 100644
--- a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
+++ b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
@@ -96,8 +96,10 @@ namespace TAO_PEGTL_NAMESPACE
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
-   const auto issues = pegtl::analyze< dynamic::grammar >();
-   assert( !issues );
+   if( pegtl::analyze< dynamic::grammar >() != 0 ) {
+      std::cerr << "cycles without progress detected!" << std::endl;
+      return 1;
+   }
 
    if( argc > 1 ) {
       std::string id;
diff --git a/packages/PEGTL/src/example/pegtl/json_analyze.cpp b/packages/PEGTL/src/example/pegtl/json_analyze.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bebef24754afbd5eb1a6c41032ca067c882c347d
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_analyze.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
+#include <tao/pegtl/contrib/json.hpp>
+
+namespace pegtl = TAO_PEGTL_NAMESPACE;
+
+namespace example
+{
+   using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+}  // namespace example
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   if( pegtl::analyze< example::grammar >() != 0 ) {
+      std::cerr << "cycles without progress detected!" << std::endl;
+      return 1;
+   }
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/json_ast.cpp b/packages/PEGTL/src/example/pegtl/json_ast.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ecc8e57a9fa8244cbaa060d8996026999b3d0297
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_ast.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iomanip>
+#include <iostream>
+
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/parse_tree.hpp>
+#include <tao/pegtl/contrib/parse_tree_to_dot.hpp>
+
+#include "json_errors.hpp"
+
+namespace pegtl = TAO_PEGTL_NAMESPACE;
+
+namespace example
+{
+   using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+   template< typename Rule >
+   using selector = pegtl::parse_tree::selector<
+      Rule,
+      pegtl::parse_tree::remove_content::on<
+         pegtl::json::null,
+         pegtl::json::true_,
+         pegtl::json::false_,
+         pegtl::json::array,
+         pegtl::json::object,
+         pegtl::json::member >,
+      pegtl::parse_tree::store_content::on<
+         pegtl::json::number,
+         pegtl::json::string,
+         pegtl::json::key > >;
+
+}  // namespace example
+
+int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
+{
+   if( argc != 2 ) {
+      std::cerr << "Usage: " << argv[ 0 ] << " JSON\n"
+                << "Generate a 'dot' file from the JSON text.\n\n"
+                << "Example: " << argv[ 0 ] << " \"{\"foo\":[42,null]}\" | dot -Tpng -o parse_tree.png\n";
+      return 1;
+   }
+
+   pegtl::argv_input in( argv, 1 );
+   try {
+      const auto root = pegtl::parse_tree::parse< example::grammar, example::selector, pegtl::nothing, example::control >( in );
+      pegtl::parse_tree::print_dot( std::cout, *root );
+   }
+   catch( const pegtl::parse_error& e ) {
+      const auto p = e.positions().front();
+      std::cerr << e.what() << std::endl
+                << in.line_at( p ) << std::endl
+                << std::setw( p.column ) << '^' << std::endl;
+      return 1;
+   }
+
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/json_build.cpp b/packages/PEGTL/src/example/pegtl/json_build.cpp
index f4ec3dc9f61b476969531ea45647a23d609fb7f0..fe8f06f44d1728529c4b34aa9d4aed0f6be572d1 100644
--- a/packages/PEGTL/src/example/pegtl/json_build.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_build.cpp
@@ -14,7 +14,7 @@
 
 namespace pegtl = TAO_PEGTL_NAMESPACE;
 
-namespace examples
+namespace example
 {
    // State class that stores the result of a JSON parsing run -- a single JSON object.
    // The other members are used temporarily, at the end of a (successful) parsing run.
@@ -157,7 +157,7 @@ namespace examples
 
    using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
 
-}  // namespace examples
+}  // namespace example
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
@@ -165,9 +165,9 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
       std::cerr << "usage: " << argv[ 0 ] << " <json>";
    }
    else {
-      examples::json_state state;
+      example::json_state state;
       pegtl::file_input in( argv[ 1 ] );
-      pegtl::parse< examples::grammar, examples::action, examples::control >( in, state );
+      pegtl::parse< example::grammar, example::action, example::control >( in, state );
       assert( state.keys.empty() );
       assert( state.arrays.empty() );
       assert( state.objects.empty() );
diff --git a/packages/PEGTL/src/example/pegtl/json_classes.hpp b/packages/PEGTL/src/example/pegtl/json_classes.hpp
index 8513ec804d8aa2d6913778467bc676bbec8a40a8..9b0c8bb1eb9cf574b80fdd1878e18ff0472eaaaf 100644
--- a/packages/PEGTL/src/example/pegtl/json_classes.hpp
+++ b/packages/PEGTL/src/example/pegtl/json_classes.hpp
@@ -10,7 +10,7 @@
 #include <string>
 #include <vector>
 
-namespace examples
+namespace example
 {
    enum class json_type
    {
@@ -209,6 +209,6 @@ namespace examples
       }
    };
 
-}  // namespace examples
+}  // namespace example
 
 #endif
diff --git a/packages/PEGTL/src/example/pegtl/json_count.cpp b/packages/PEGTL/src/example/pegtl/json_count.cpp
index e0fb731afaf1c260f367d49dbc8adcb8b35a80a0..ee4bb71c0b22b8e51dcfd07d74fac05cedb9df1c 100644
--- a/packages/PEGTL/src/example/pegtl/json_count.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_count.cpp
@@ -32,19 +32,19 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename Input >
       static void start( const Input& /*unused*/, counter_state& ts )
       {
-         ++ts.counts[ internal::demangle< Rule >() ].start;
+         ++ts.counts[ demangle< Rule >() ].start;
       }
 
       template< typename Input >
       static void success( const Input& /*unused*/, counter_state& ts )
       {
-         ++ts.counts[ internal::demangle< Rule >() ].success;
+         ++ts.counts[ demangle< Rule >() ].success;
       }
 
       template< typename Input >
       static void failure( const Input& /*unused*/, counter_state& ts )
       {
-         ++ts.counts[ internal::demangle< Rule >() ].failure;
+         ++ts.counts[ demangle< Rule >() ].failure;
       }
    };
 
diff --git a/packages/PEGTL/src/example/pegtl/json_coverage.cpp b/packages/PEGTL/src/example/pegtl/json_coverage.cpp
index b19c496929c3f5ce0cb3ad07c00599ed1b1b8c60..3d0ff1657d28288f8d8e457efa5db7b7e46bd375 100644
--- a/packages/PEGTL/src/example/pegtl/json_coverage.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_coverage.cpp
@@ -1,19 +1,45 @@
 // Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
+#include <iomanip>
 #include <iostream>
 
 #include <tao/pegtl.hpp>
-
 #include <tao/pegtl/contrib/coverage.hpp>
 #include <tao/pegtl/contrib/json.hpp>
 #include <tao/pegtl/contrib/print_coverage.hpp>
 
+#include "json_errors.hpp"
+
+namespace pegtl = TAO_PEGTL_NAMESPACE;
+
+namespace example
+{
+   using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+}  // namespace example
+
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
-   for( int i = 1; i < argc; ++i ) {
-      auto coverage = tao::pegtl::coverage< tao::pegtl::json::text >( tao::pegtl::file_input( argv[ i ] ) );
-      tao::pegtl::print_coverage( std::cout, coverage );
+   if( argc != 2 ) {
+      std::cerr << "Usage: " << argv[ 0 ] << " FILE\n"
+                << "Print coverage of parsing FILE as JSON." << std::endl;
+      return 1;
+   }
+
+   pegtl::file_input in( argv[ 1 ] );
+   try {
+      pegtl::coverage_result result;
+      pegtl::coverage< example::grammar, pegtl::nothing, example::control >( in, result );  // Ignore return value...?
+      std::cout << result;
    }
+   catch( const pegtl::parse_error& e ) {
+      const auto p = e.positions().front();
+      std::cerr << e.what() << '\n'
+                << in.line_at( p ) << '\n'
+                << std::setw( p.column ) << '^' << std::endl;
+      return 1;
+   }
+
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/json_errors.hpp b/packages/PEGTL/src/example/pegtl/json_errors.hpp
index 4f674f805188bfd015944c3dcd30f325e4e2a8d7..847ae6fa5e4f534ea1dbda2227224a0b4c66b8ca 100644
--- a/packages/PEGTL/src/example/pegtl/json_errors.hpp
+++ b/packages/PEGTL/src/example/pegtl/json_errors.hpp
@@ -9,7 +9,7 @@
 
 namespace pegtl = TAO_PEGTL_NAMESPACE;
 
-namespace examples
+namespace example
 {
    // This file shows how to throw exceptions with
    // custom error messages for parse errors.
@@ -38,12 +38,16 @@ namespace examples
 
    template<> inline constexpr auto error_message< pegtl::eof > = "unexpected character after JSON value";
 
-   // As must_if can not take error_message as a template parameter directly, we need to wrap it:
-   struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
+   // As must_if<> can not take error_message as a template parameter directly, we need to wrap it.
+   // Additionally, we make sure only must<>-rules trigger global error.
+   struct error {
+      template< typename Rule > static constexpr auto raise_on_failure = false;
+      template< typename Rule > static constexpr auto message = error_message< Rule >;
+   };
 
    template< typename Rule > using control = pegtl::must_if< error >::control< Rule >;
    // clang-format on
 
-}  // namespace examples
+}  // namespace example
 
 #endif
diff --git a/packages/PEGTL/src/example/pegtl/json_parse.cpp b/packages/PEGTL/src/example/pegtl/json_parse.cpp
index 7db715bcc5314983cda4d7808c0bad1f6047e6b5..53cbd81e4b23d45c5bb1233d5afa76e1cbe43e7b 100644
--- a/packages/PEGTL/src/example/pegtl/json_parse.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_parse.cpp
@@ -1,18 +1,43 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
+#include <iomanip>
+#include <iostream>
+
 #include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
 
 #include "json_errors.hpp"
 
-using namespace TAO_PEGTL_NAMESPACE;
-using grammar = must< json::text, eof >;
+namespace pegtl = TAO_PEGTL_NAMESPACE;
+
+namespace example
+{
+   using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+}  // namespace example
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
-   for( int i = 1; i < argc; ++i ) {
-      argv_input in( argv, i );
-      parse< grammar, nothing, examples::control >( in );
+   if( argc != 2 ) {
+      std::cerr << "Usage: " << argv[ 0 ] << " JSON\n"
+                << "Parse a JSON text.\n\n"
+                << "Example: " << argv[ 0 ] << " '{\"foo\":[42,null]}'" << std::endl;
+      return 1;
    }
+
+   pegtl::argv_input in( argv, 1 );
+   try {
+      pegtl::parse< example::grammar, pegtl::nothing, example::control >( in );
+   }
+   catch( const pegtl::parse_error& e ) {
+      const auto p = e.positions().front();
+      std::cerr << e.what() << '\n'
+                << in.line_at( p ) << '\n'
+                << std::setw( p.column ) << '^' << std::endl;
+      return 1;
+   }
+
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/json_print_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_debug.cpp
similarity index 82%
rename from packages/PEGTL/src/example/pegtl/json_print_rules.cpp
rename to packages/PEGTL/src/example/pegtl/json_print_debug.cpp
index 87850508fe761c236314a356b174f8d617a54146..9815d2c1e0fb29446e5321e74c2e0488c04d1b92 100644
--- a/packages/PEGTL/src/example/pegtl/json_print_rules.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_print_debug.cpp
@@ -8,6 +8,6 @@
 
 int main()  // NOLINT(bugprone-exception-escape)
 {
-   tao::pegtl::print_rules< tao::pegtl::json::text >( std::cout );
+   tao::pegtl::print_debug< tao::pegtl::json::text >( std::cout );
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_names.cpp
similarity index 80%
rename from packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp
rename to packages/PEGTL/src/example/pegtl/json_print_names.cpp
index e28a04ef9fd3cd6ecd1fb0ca211be35401749f71..9f97008cf0469dab69603598de2b670a3bfb0ef5 100644
--- a/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_print_names.cpp
@@ -8,6 +8,6 @@
 
 int main()  // NOLINT(bugprone-exception-escape)
 {
-   tao::pegtl::print_sub_rules< tao::pegtl::json::text >( std::cout );
+   tao::pegtl::print_names< tao::pegtl::json::text >( std::cout );
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/json_trace.cpp b/packages/PEGTL/src/example/pegtl/json_trace.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5cba1349f8cbe12123a6dc237aff6f392f15ba6a
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_trace.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iomanip>
+#include <iostream>
+
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
+
+#include "json_errors.hpp"
+
+namespace pegtl = TAO_PEGTL_NAMESPACE;
+
+namespace example
+{
+   using grammar = pegtl::must< pegtl::json::text, pegtl::eof >;
+
+}  // namespace example
+
+int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
+{
+   if( argc != 2 ) {
+      std::cerr << "Usage: " << argv[ 0 ] << " JSON\n"
+                << "Trace parsing a JSON text.\n\n"
+                << "Example: " << argv[ 0 ] << " '{\"foo\":[42,null]}'" << std::endl;
+      return 1;
+   }
+
+   pegtl::argv_input in( argv, 1 );
+   try {
+      pegtl::standard_trace< example::grammar, pegtl::nothing, example::control >( in );
+   }
+   catch( const pegtl::parse_error& e ) {
+      const auto p = e.positions().front();
+      std::cerr << e.what() << '\n'
+                << in.line_at( p ) << '\n'
+                << std::setw( p.column ) << '^' << std::endl;
+      return 1;
+   }
+
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/json_unescape.hpp b/packages/PEGTL/src/example/pegtl/json_unescape.hpp
index 974c6afb77f46aa04614f8fb629c45fd41b4175d..60e30c7beff0eddadd0077f0acb6171e002203ce 100644
--- a/packages/PEGTL/src/example/pegtl/json_unescape.hpp
+++ b/packages/PEGTL/src/example/pegtl/json_unescape.hpp
@@ -10,7 +10,7 @@
 #include <tao/pegtl/contrib/json.hpp>
 #include <tao/pegtl/contrib/unescape.hpp>
 
-namespace examples
+namespace example
 {
    // Action class for parsing literal strings, uses the PEGTL unescape utilities, cf. unescape.cpp.
 
@@ -24,6 +24,6 @@ namespace examples
 
    using json_unescape = tao::pegtl::change_action_and_states< json_unescape_action, std::string >;
 
-}  // namespace examples
+}  // namespace example
 
 #endif
diff --git a/packages/PEGTL/src/example/pegtl/lua53.hpp b/packages/PEGTL/src/example/pegtl/lua53.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f040509029fb3e8ef40d450032f92dad2af7dff
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/lua53.hpp
@@ -0,0 +1,335 @@
+// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_LUA53_HPP
+#define TAO_PEGTL_SRC_EXAMPLES_PEGTL_LUA53_HPP
+
+#include <tao/pegtl.hpp>
+#include <tao/pegtl/contrib/raw_string.hpp>
+
+namespace lua53
+{
+   // PEGTL grammar for the Lua 5.3.0 lexer and parser.
+   //
+   // The grammar here is not very similar to the grammar
+   // in the Lua reference documentation on which it is based
+   // which is due to multiple causes.
+   //
+   // The main difference is that this grammar includes really
+   // "everything", not just the structural parts from the
+   // reference documentation:
+   // - The PEG-approach combines lexer and parser; this grammar
+   //   handles comments and tokenisation.
+   // - The operator precedence and associativity are reflected
+   //   in the structure of this grammar.
+   // - All details for all types of literals are included, with
+   //   escape-sequences for literal strings, and long literals.
+   //
+   // The second necessary difference is that all left-recursion
+   // had to be eliminated.
+   //
+   // In some places the grammar was optimised to require as little
+   // back-tracking as possible, most prominently for expressions.
+   // The original grammar contains the following production rules:
+   //
+   //   prefixexp ::= var | functioncall | ‘(’ exp ‘)’
+   //   functioncall ::=  prefixexp args | prefixexp ‘:’ Name args
+   //   var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name
+   //
+   // We need to eliminate the left-recursion, and we also want to
+   // remove the ambiguity between function calls and variables,
+   // i.e. the fact that we can have expressions like
+   //
+   //   ( a * b ).c()[ d ].e:f()
+   //
+   // where only the last element decides between function call and
+   // variable, making it necessary to parse the whole thing again
+   // if we chose wrong at the beginning.
+   // First we eliminate prefixexp and obtain:
+   //
+   //   functioncall ::=  ( var | functioncall | ‘(’ exp ‘)’ ) ( args | ‘:’ Name args )
+   //   var ::=  Name | ( var | functioncall | ‘(’ exp ‘)’ ) ( ‘[’ exp ‘]’ | ‘.’ Name )
+   //
+   // Next we split function_call and variable into a first part,
+   // a "head", or how they can start, and a second part, the "tail",
+   // which, in a sequence like above, is the final deciding part:
+   //
+   //   vartail ::= '[' exp ']' | '.' Name
+   //   varhead ::= Name | '(' exp ')' vartail
+   //   functail ::= args | ':' Name args
+   //   funchead ::= Name | '(' exp ')'
+   //
+   // This allows us to rewrite var and function_call as follows.
+   //
+   //   var ::= varhead { { functail } vartail }
+   //   function_call ::= funchead [ { vartail } functail ]
+   //
+   // Finally we can define a single expression that takes care
+   // of var, function_call, and expressions in a bracket:
+   //
+   //   chead ::= '(' exp ')' | Name
+   //   combined ::= chead { functail | vartail }
+   //
+   // Such a combined expression starts with a bracketed
+   // expression or a name, and continues with an arbitrary
+   // number of functail and/or vartail parts, all in a one
+   // grammar rule without back-tracking.
+   //
+   // The rule expr_thirteen below implements "combined".
+   //
+   // Another issue of interest when writing a PEG is how to
+   // manage the separators, the white-space and comments that
+   // can occur in many places; in the classical two-stage
+   // lexer-parser approach the lexer would have taken care of
+   // this, but here we use the PEG approach that combines both.
+   //
+   // In the following grammar most rules adopt the convention
+   // that they take care of "internal padding", i.e. spaces
+   // and comments that can occur within the rule, but not
+   // "external padding", i.e. they don't start or end with
+   // a rule that "eats up" all extra padding (spaces and
+   // comments). In some places, where it is more efficient,
+   // right padding is used.
+
+   // clang-format off
+   struct short_comment : tao::pegtl::until< tao::pegtl::eolf > {};
+   struct long_string : tao::pegtl::raw_string< '[', '=', ']' > {};
+   struct comment : tao::pegtl::disable< tao::pegtl::two< '-' >, tao::pegtl::sor< long_string, short_comment > > {};
+
+   struct sep : tao::pegtl::sor< tao::pegtl::ascii::space, comment > {};
+   struct seps : tao::pegtl::star< sep > {};
+
+   struct str_and : TAO_PEGTL_STRING( "and" ) {};
+   struct str_break : TAO_PEGTL_STRING( "break" ) {};
+   struct str_do : TAO_PEGTL_STRING( "do" ) {};
+   struct str_else : TAO_PEGTL_STRING( "else" ) {};
+   struct str_elseif : TAO_PEGTL_STRING( "elseif" ) {};
+   struct str_end : TAO_PEGTL_STRING( "end" ) {};
+   struct str_false : TAO_PEGTL_STRING( "false" ) {};
+   struct str_for : TAO_PEGTL_STRING( "for" ) {};
+   struct str_function : TAO_PEGTL_STRING( "function" ) {};
+   struct str_goto : TAO_PEGTL_STRING( "goto" ) {};
+   struct str_if : TAO_PEGTL_STRING( "if" ) {};
+   struct str_in : TAO_PEGTL_STRING( "in" ) {};
+   struct str_local : TAO_PEGTL_STRING( "local" ) {};
+   struct str_nil : TAO_PEGTL_STRING( "nil" ) {};
+   struct str_not : TAO_PEGTL_STRING( "not" ) {};
+   struct str_or : TAO_PEGTL_STRING( "or" ) {};
+   struct str_repeat : TAO_PEGTL_STRING( "repeat" ) {};
+   struct str_return : TAO_PEGTL_STRING( "return" ) {};
+   struct str_then : TAO_PEGTL_STRING( "then" ) {};
+   struct str_true : TAO_PEGTL_STRING( "true" ) {};
+   struct str_until : TAO_PEGTL_STRING( "until" ) {};
+   struct str_while : TAO_PEGTL_STRING( "while" ) {};
+
+   // Note that 'elseif' precedes 'else' in order to prevent only matching
+   // the "else" part of an "elseif" and running into an error in the
+   // 'keyword' rule.
+
+   template< typename Key >
+   struct key : tao::pegtl::seq< Key, tao::pegtl::not_at< tao::pegtl::identifier_other > > {};
+
+   struct sor_keyword : tao::pegtl::sor< str_and, str_break, str_do, str_elseif, str_else, str_end, str_false, str_for, str_function, str_goto, str_if, str_in, str_local, str_nil, str_not, str_repeat, str_return, str_then, str_true, str_until, str_while > {};
+
+   struct key_and : key< str_and > {};
+   struct key_break : key< str_break > {};
+   struct key_do : key< str_do > {};
+   struct key_else : key< str_else > {};
+   struct key_elseif : key< str_elseif > {};
+   struct key_end : key< str_end > {};
+   struct key_false : key< str_false > {};
+   struct key_for : key< str_for > {};
+   struct key_function : key< str_function > {};
+   struct key_goto : key< str_goto > {};
+   struct key_if : key< str_if > {};
+   struct key_in : key< str_in > {};
+   struct key_local : key< str_local > {};
+   struct key_nil : key< str_nil > {};
+   struct key_not : key< str_not > {};
+   struct key_or : key< str_or > {};
+   struct key_repeat : key< str_repeat > {};
+   struct key_return : key< str_return > {};
+   struct key_then : key< str_then > {};
+   struct key_true : key< str_true > {};
+   struct key_until : key< str_until > {};
+   struct key_while : key< str_while > {};
+
+   struct keyword : key< sor_keyword > {};
+
+   template< typename R >
+   struct pad : tao::pegtl::pad< R, sep > {};
+
+   struct name : tao::pegtl::seq< tao::pegtl::not_at< keyword >, tao::pegtl::identifier > {};
+
+   struct single : tao::pegtl::one< 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"', '\'', '0', '\n' > {};
+   struct spaces : tao::pegtl::seq< tao::pegtl::one< 'z' >, tao::pegtl::star< tao::pegtl::space > > {};
+   struct hexbyte : tao::pegtl::if_must< tao::pegtl::one< 'x' >, tao::pegtl::xdigit, tao::pegtl::xdigit > {};
+   struct decbyte : tao::pegtl::if_must< tao::pegtl::digit, tao::pegtl::rep_opt< 2, tao::pegtl::digit > > {};
+   struct unichar : tao::pegtl::if_must< tao::pegtl::one< 'u' >, tao::pegtl::one< '{' >, tao::pegtl::plus< tao::pegtl::xdigit >, tao::pegtl::one< '}' > > {};
+   struct escaped : tao::pegtl::if_must< tao::pegtl::one< '\\' >, tao::pegtl::sor< hexbyte, decbyte, unichar, single, spaces > > {};
+   struct regular : tao::pegtl::not_one< '\r', '\n' > {};
+   struct character : tao::pegtl::sor< escaped, regular > {};
+
+   template< char Q >
+   struct short_string : tao::pegtl::if_must< tao::pegtl::one< Q >, tao::pegtl::until< tao::pegtl::one< Q >, character > > {};
+   struct literal_string : tao::pegtl::sor< short_string< '"' >, short_string< '\'' >, long_string > {};
+
+   template< typename E >
+   struct exponent : tao::pegtl::opt_must< E, tao::pegtl::opt< tao::pegtl::one< '+', '-' > >, tao::pegtl::plus< tao::pegtl::digit > > {};
+
+   template< typename D, typename E >
+   struct numeral_three : tao::pegtl::seq< tao::pegtl::if_must< tao::pegtl::one< '.' >, tao::pegtl::plus< D > >, exponent< E > > {};
+   template< typename D, typename E >
+   struct numeral_two : tao::pegtl::seq< tao::pegtl::plus< D >, tao::pegtl::opt< tao::pegtl::one< '.' >, tao::pegtl::star< D > >, exponent< E > > {};
+   template< typename D, typename E >
+   struct numeral_one : tao::pegtl::sor< numeral_two< D, E >, numeral_three< D, E > > {};
+
+   struct decimal : numeral_one< tao::pegtl::digit, tao::pegtl::one< 'e', 'E' > > {};
+   struct hexadecimal : tao::pegtl::if_must< tao::pegtl::istring< '0', 'x' >, numeral_one< tao::pegtl::xdigit, tao::pegtl::one< 'p', 'P' > > > {};
+   struct numeral : tao::pegtl::sor< hexadecimal, decimal > {};
+
+   struct label_statement : tao::pegtl::if_must< tao::pegtl::two< ':' >, seps, name, seps, tao::pegtl::two< ':' > > {};
+   struct goto_statement : tao::pegtl::if_must< key_goto, seps, name > {};
+
+   struct statement;
+   struct expression;
+
+   struct name_list : tao::pegtl::list< name, tao::pegtl::one< ',' >, sep > {};
+   struct name_list_must : tao::pegtl::list_must< name, tao::pegtl::one< ',' >, sep > {};
+   struct expr_list_must : tao::pegtl::list_must< expression, tao::pegtl::one< ',' >, sep > {};
+
+   struct statement_return : tao::pegtl::seq< tao::pegtl::pad_opt< expr_list_must, sep >, tao::pegtl::opt< tao::pegtl::one< ';' >, seps > > {};
+
+   template< typename E >
+   struct statement_list : tao::pegtl::seq< seps, tao::pegtl::until< tao::pegtl::sor< E, tao::pegtl::if_must< key_return, statement_return, E > >, statement, seps > > {};
+
+   template< char O, char... N >
+   struct op_one : tao::pegtl::seq< tao::pegtl::one< O >, tao::pegtl::at< tao::pegtl::not_one< N... > > > {};
+   template< char O, char P, char... N >
+   struct op_two : tao::pegtl::seq< tao::pegtl::string< O, P >, tao::pegtl::at< tao::pegtl::not_one< N... > > > {};
+
+   struct table_field_one : tao::pegtl::if_must< tao::pegtl::one< '[' >, seps, expression, seps, tao::pegtl::one< ']' >, seps, tao::pegtl::one< '=' >, seps, expression > {};
+   struct table_field_two : tao::pegtl::if_must< tao::pegtl::seq< name, seps, op_one< '=', '=' > >, seps, expression > {};
+   struct table_field : tao::pegtl::sor< table_field_one, table_field_two, expression > {};
+   struct table_field_list : tao::pegtl::list_tail< table_field, tao::pegtl::one< ',', ';' >, sep > {};
+   struct table_constructor : tao::pegtl::if_must< tao::pegtl::one< '{' >, tao::pegtl::pad_opt< table_field_list, sep >, tao::pegtl::one< '}' > > {};
+
+   struct parameter_list_one : tao::pegtl::seq< name_list, tao::pegtl::opt_must< pad< tao::pegtl::one< ',' > >, tao::pegtl::ellipsis > > {};
+   struct parameter_list : tao::pegtl::sor< tao::pegtl::ellipsis, parameter_list_one > {};
+
+   struct function_body : tao::pegtl::seq< tao::pegtl::one< '(' >, tao::pegtl::pad_opt< parameter_list, sep >, tao::pegtl::one< ')' >, seps, statement_list< key_end > > {};
+   struct function_literal : tao::pegtl::if_must< key_function, seps, function_body > {};
+
+   struct bracket_expr : tao::pegtl::if_must< tao::pegtl::one< '(' >, seps, expression, seps, tao::pegtl::one< ')' > > {};
+
+   struct function_args_one : tao::pegtl::if_must< tao::pegtl::one< '(' >, tao::pegtl::pad_opt< expr_list_must, sep >, tao::pegtl::one< ')' > > {};
+   struct function_args : tao::pegtl::sor< function_args_one, table_constructor, literal_string > {};
+
+   struct variable_tail_one : tao::pegtl::if_must< tao::pegtl::one< '[' >, seps, expression, seps, tao::pegtl::one< ']' > > {};
+   struct variable_tail_two : tao::pegtl::if_must< tao::pegtl::seq< tao::pegtl::not_at< tao::pegtl::two< '.' > >, tao::pegtl::one< '.' > >, seps, name > {};
+   struct variable_tail : tao::pegtl::sor< variable_tail_one, variable_tail_two > {};
+
+   struct function_call_tail_one : tao::pegtl::if_must< tao::pegtl::seq< tao::pegtl::not_at< tao::pegtl::two< ':' > >, tao::pegtl::one< ':' > >, seps, name, seps, function_args > {};
+   struct function_call_tail : tao::pegtl::sor< function_args, function_call_tail_one > {};
+
+   struct variable_head_one : tao::pegtl::seq< bracket_expr, seps, variable_tail > {};
+   struct variable_head : tao::pegtl::sor< name, variable_head_one > {};
+
+   struct function_call_head : tao::pegtl::sor< name, bracket_expr > {};
+
+   struct variable : tao::pegtl::seq< variable_head, tao::pegtl::star< tao::pegtl::star< seps, function_call_tail >, seps, variable_tail > > {};
+   struct function_call : tao::pegtl::seq< function_call_head, tao::pegtl::plus< tao::pegtl::until< tao::pegtl::seq< seps, function_call_tail >, seps, variable_tail > > > {};
+
+   template< typename S, typename O >
+   struct left_assoc : tao::pegtl::seq< S, seps, tao::pegtl::star_must< O, seps, S, seps > > {};
+   template< typename S, typename O >
+   struct right_assoc : tao::pegtl::seq< S, seps, tao::pegtl::opt_must< O, seps, right_assoc< S, O > > > {};
+
+   struct unary_operators : tao::pegtl::sor< tao::pegtl::one< '-' >,
+                                             tao::pegtl::one< '#' >,
+                                             op_one< '~', '=' >,
+                                             key_not > {};
+
+   struct expr_ten;
+   struct expr_thirteen : tao::pegtl::seq< tao::pegtl::sor< bracket_expr, name >, tao::pegtl::star< seps, tao::pegtl::sor< function_call_tail, variable_tail > > > {};
+   struct expr_twelve : tao::pegtl::sor< key_nil,
+                                         key_true,
+                                         key_false,
+                                         tao::pegtl::ellipsis,
+                                         numeral,
+                                         literal_string,
+                                         function_literal,
+                                         expr_thirteen,
+                                         table_constructor > {};
+   struct expr_eleven : tao::pegtl::seq< expr_twelve, seps, tao::pegtl::opt< tao::pegtl::one< '^' >, seps, expr_ten, seps > > {};
+   struct unary_apply : tao::pegtl::if_must< unary_operators, seps, expr_ten, seps > {};
+   struct expr_ten : tao::pegtl::sor< unary_apply, expr_eleven > {};
+   struct operators_nine : tao::pegtl::sor< tao::pegtl::two< '/' >,
+                                            tao::pegtl::one< '/' >,
+                                            tao::pegtl::one< '*' >,
+                                            tao::pegtl::one< '%' > > {};
+   struct expr_nine : left_assoc< expr_ten, operators_nine > {};
+   struct operators_eight : tao::pegtl::sor< tao::pegtl::one< '+' >,
+                                             tao::pegtl::one< '-' > > {};
+   struct expr_eight : left_assoc< expr_nine, operators_eight > {};
+   struct expr_seven : right_assoc< expr_eight, op_two< '.', '.', '.' > > {};
+   struct operators_six : tao::pegtl::sor< tao::pegtl::two< '<' >,
+                                           tao::pegtl::two< '>' > > {};
+   struct expr_six : left_assoc< expr_seven, operators_six > {};
+   struct expr_five : left_assoc< expr_six, tao::pegtl::one< '&' > > {};
+   struct expr_four : left_assoc< expr_five, op_one< '~', '=' > > {};
+   struct expr_three : left_assoc< expr_four, tao::pegtl::one< '|' > > {};
+   struct operators_two : tao::pegtl::sor< tao::pegtl::two< '=' >,
+                                           tao::pegtl::string< '<', '=' >,
+                                           tao::pegtl::string< '>', '=' >,
+                                           op_one< '<', '<' >,
+                                           op_one< '>', '>' >,
+                                           tao::pegtl::string< '~', '=' > > {};
+   struct expr_two : left_assoc< expr_three, operators_two > {};
+   struct expr_one : left_assoc< expr_two, key_and > {};
+   struct expression : left_assoc< expr_one, key_or > {};
+
+   struct do_statement : tao::pegtl::if_must< key_do, statement_list< key_end > > {};
+   struct while_statement : tao::pegtl::if_must< key_while, seps, expression, seps, key_do, statement_list< key_end > > {};
+   struct repeat_statement : tao::pegtl::if_must< key_repeat, statement_list< key_until >, seps, expression > {};
+
+   struct at_elseif_else_end : tao::pegtl::sor< tao::pegtl::at< key_elseif >, tao::pegtl::at< key_else >, tao::pegtl::at< key_end > > {};
+   struct elseif_statement : tao::pegtl::if_must< key_elseif, seps, expression, seps, key_then, statement_list< at_elseif_else_end > > {};
+   struct else_statement : tao::pegtl::if_must< key_else, statement_list< key_end > > {};
+   struct if_statement : tao::pegtl::if_must< key_if, seps, expression, seps, key_then, statement_list< at_elseif_else_end >, seps, tao::pegtl::until< tao::pegtl::sor< else_statement, key_end >, elseif_statement, seps > > {};
+
+   struct for_statement_one : tao::pegtl::seq< tao::pegtl::one< '=' >, seps, expression, seps, tao::pegtl::one< ',' >, seps, expression, tao::pegtl::pad_opt< tao::pegtl::if_must< tao::pegtl::one< ',' >, seps, expression >, sep > > {};
+   struct for_statement_two : tao::pegtl::seq< tao::pegtl::opt_must< tao::pegtl::one< ',' >, seps, name_list_must, seps >, key_in, seps, expr_list_must, seps > {};
+   struct for_statement : tao::pegtl::if_must< key_for, seps, name, seps, tao::pegtl::sor< for_statement_one, for_statement_two >, key_do, statement_list< key_end > > {};
+
+   struct assignment_variable_list : tao::pegtl::list_must< variable, tao::pegtl::one< ',' >, sep > {};
+   struct assignments_one : tao::pegtl::if_must< tao::pegtl::one< '=' >, seps, expr_list_must > {};
+   struct assignments : tao::pegtl::seq< assignment_variable_list, seps, assignments_one > {};
+   struct function_name : tao::pegtl::seq< tao::pegtl::list< name, tao::pegtl::one< '.' >, sep >, seps, tao::pegtl::opt_must< tao::pegtl::one< ':' >, seps, name, seps > > {};
+   struct function_definition : tao::pegtl::if_must< key_function, seps, function_name, function_body > {};
+
+   struct local_function : tao::pegtl::if_must< key_function, seps, name, seps, function_body > {};
+   struct local_variables : tao::pegtl::if_must< name_list_must, seps, tao::pegtl::opt< assignments_one > > {};
+   struct local_statement : tao::pegtl::if_must< key_local, seps, tao::pegtl::sor< local_function, local_variables > > {};
+
+   struct semicolon : tao::pegtl::one< ';' > {};
+   struct statement : tao::pegtl::sor< semicolon,
+                                       assignments,
+                                       function_call,
+                                       label_statement,
+                                       key_break,
+                                       goto_statement,
+                                       do_statement,
+                                       while_statement,
+                                       repeat_statement,
+                                       if_statement,
+                                       for_statement,
+                                       function_definition,
+                                       local_statement > {};
+
+   struct grammar : tao::pegtl::must< tao::pegtl::opt< tao::pegtl::shebang >, statement_list< tao::pegtl::eof > > {};
+   // clang-format on
+
+}  // namespace lua53
+
+#endif
diff --git a/packages/PEGTL/src/example/pegtl/lua53_analyze.cpp b/packages/PEGTL/src/example/pegtl/lua53_analyze.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6d6c847e7c576726bc6e86e6a7effd8929f205a
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/lua53_analyze.cpp
@@ -0,0 +1,17 @@
+// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/analyze.hpp>
+
+#include "lua53.hpp"
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   if( const auto problems = TAO_PEGTL_NAMESPACE::analyze< lua53::grammar >() != 0 ) {
+      std::cout << "problems: " << problems << std::endl;
+      return 1;
+   }
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
index ddb1df06b2c75ac04874ec1fc074e49a0cb81469..6b84aff24753be1b2027d050b7516e390badf282 100644
--- a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
+++ b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
@@ -1,347 +1,16 @@
 // Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#include <tao/pegtl.hpp>
-#include <tao/pegtl/contrib/analyze.hpp>
-#include <tao/pegtl/contrib/raw_string.hpp>
+#include <iostream>
 
-namespace lua53
-{
-   // PEGTL grammar for the Lua 5.3.0 lexer and parser.
-   //
-   // The grammar here is not very similar to the grammar
-   // in the Lua reference documentation on which it is based
-   // which is due to multiple causes.
-   //
-   // The main difference is that this grammar includes really
-   // "everything", not just the structural parts from the
-   // reference documentation:
-   // - The PEG-approach combines lexer and parser; this grammar
-   //   handles comments and tokenisation.
-   // - The operator precedence and associativity are reflected
-   //   in the structure of this grammar.
-   // - All details for all types of literals are included, with
-   //   escape-sequences for literal strings, and long literals.
-   //
-   // The second necessary difference is that all left-recursion
-   // had to be eliminated.
-   //
-   // In some places the grammar was optimised to require as little
-   // back-tracking as possible, most prominently for expressions.
-   // The original grammar contains the following production rules:
-   //
-   //   prefixexp ::= var | functioncall | ‘(’ exp ‘)’
-   //   functioncall ::=  prefixexp args | prefixexp ‘:’ Name args
-   //   var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name
-   //
-   // We need to eliminate the left-recursion, and we also want to
-   // remove the ambiguity between function calls and variables,
-   // i.e. the fact that we can have expressions like
-   //
-   //   ( a * b ).c()[ d ].e:f()
-   //
-   // where only the last element decides between function call and
-   // variable, making it necessary to parse the whole thing again
-   // if we chose wrong at the beginning.
-   // First we eliminate prefixexp and obtain:
-   //
-   //   functioncall ::=  ( var | functioncall | ‘(’ exp ‘)’ ) ( args | ‘:’ Name args )
-   //   var ::=  Name | ( var | functioncall | ‘(’ exp ‘)’ ) ( ‘[’ exp ‘]’ | ‘.’ Name )
-   //
-   // Next we split function_call and variable into a first part,
-   // a "head", or how they can start, and a second part, the "tail",
-   // which, in a sequence like above, is the final deciding part:
-   //
-   //   vartail ::= '[' exp ']' | '.' Name
-   //   varhead ::= Name | '(' exp ')' vartail
-   //   functail ::= args | ':' Name args
-   //   funchead ::= Name | '(' exp ')'
-   //
-   // This allows us to rewrite var and function_call as follows.
-   //
-   //   var ::= varhead { { functail } vartail }
-   //   function_call ::= funchead [ { vartail } functail ]
-   //
-   // Finally we can define a single expression that takes care
-   // of var, function_call, and expressions in a bracket:
-   //
-   //   chead ::= '(' exp ')' | Name
-   //   combined ::= chead { functail | vartail }
-   //
-   // Such a combined expression starts with a bracketed
-   // expression or a name, and continues with an arbitrary
-   // number of functail and/or vartail parts, all in a one
-   // grammar rule without back-tracking.
-   //
-   // The rule expr_thirteen below implements "combined".
-   //
-   // Another issue of interest when writing a PEG is how to
-   // manage the separators, the white-space and comments that
-   // can occur in many places; in the classical two-stage
-   // lexer-parser approach the lexer would have taken care of
-   // this, but here we use the PEG approach that combines both.
-   //
-   // In the following grammar most rules adopt the convention
-   // that they take care of "internal padding", i.e. spaces
-   // and comments that can occur within the rule, but not
-   // "external padding", i.e. they don't start or end with
-   // a rule that "eats up" all extra padding (spaces and
-   // comments). In some places, where it is more efficient,
-   // right padding is used.
-
-   namespace pegtl = TAO_PEGTL_NAMESPACE;
-
-   // clang-format off
-   struct short_comment : pegtl::until< pegtl::eolf > {};
-   struct long_string : pegtl::raw_string< '[', '=', ']' > {};
-   struct comment : pegtl::disable< pegtl::two< '-' >, pegtl::sor< long_string, short_comment > > {};
-
-   struct sep : pegtl::sor< pegtl::ascii::space, comment > {};
-   struct seps : pegtl::star< sep > {};
-
-   struct str_and : TAO_PEGTL_STRING( "and" ) {};
-   struct str_break : TAO_PEGTL_STRING( "break" ) {};
-   struct str_do : TAO_PEGTL_STRING( "do" ) {};
-   struct str_else : TAO_PEGTL_STRING( "else" ) {};
-   struct str_elseif : TAO_PEGTL_STRING( "elseif" ) {};
-   struct str_end : TAO_PEGTL_STRING( "end" ) {};
-   struct str_false : TAO_PEGTL_STRING( "false" ) {};
-   struct str_for : TAO_PEGTL_STRING( "for" ) {};
-   struct str_function : TAO_PEGTL_STRING( "function" ) {};
-   struct str_goto : TAO_PEGTL_STRING( "goto" ) {};
-   struct str_if : TAO_PEGTL_STRING( "if" ) {};
-   struct str_in : TAO_PEGTL_STRING( "in" ) {};
-   struct str_local : TAO_PEGTL_STRING( "local" ) {};
-   struct str_nil : TAO_PEGTL_STRING( "nil" ) {};
-   struct str_not : TAO_PEGTL_STRING( "not" ) {};
-   struct str_or : TAO_PEGTL_STRING( "or" ) {};
-   struct str_repeat : TAO_PEGTL_STRING( "repeat" ) {};
-   struct str_return : TAO_PEGTL_STRING( "return" ) {};
-   struct str_then : TAO_PEGTL_STRING( "then" ) {};
-   struct str_true : TAO_PEGTL_STRING( "true" ) {};
-   struct str_until : TAO_PEGTL_STRING( "until" ) {};
-   struct str_while : TAO_PEGTL_STRING( "while" ) {};
-
-   // Note that 'elseif' precedes 'else' in order to prevent only matching
-   // the "else" part of an "elseif" and running into an error in the
-   // 'keyword' rule.
-
-   struct str_keyword : pegtl::sor< str_and, str_break, str_do, str_elseif, str_else, str_end, str_false, str_for, str_function, str_goto, str_if, str_in, str_local, str_nil, str_not, str_repeat, str_return, str_then, str_true, str_until, str_while > {};
-
-   template< typename Key >
-   struct key : pegtl::seq< Key, pegtl::not_at< pegtl::identifier_other > > {};
-
-   struct key_and : key< str_and > {};
-   struct key_break : key< str_break > {};
-   struct key_do : key< str_do > {};
-   struct key_else : key< str_else > {};
-   struct key_elseif : key< str_elseif > {};
-   struct key_end : key< str_end > {};
-   struct key_false : key< str_false > {};
-   struct key_for : key< str_for > {};
-   struct key_function : key< str_function > {};
-   struct key_goto : key< str_goto > {};
-   struct key_if : key< str_if > {};
-   struct key_in : key< str_in > {};
-   struct key_local : key< str_local > {};
-   struct key_nil : key< str_nil > {};
-   struct key_not : key< str_not > {};
-   struct key_or : key< str_or > {};
-   struct key_repeat : key< str_repeat > {};
-   struct key_return : key< str_return > {};
-   struct key_then : key< str_then > {};
-   struct key_true : key< str_true > {};
-   struct key_until : key< str_until > {};
-   struct key_while : key< str_while > {};
-
-   struct keyword : key< str_keyword > {};
-
-   template< typename R >
-   struct pad : pegtl::pad< R, sep > {};
-
-   struct name : pegtl::seq< pegtl::not_at< keyword >, pegtl::identifier > {};
-
-   struct single : pegtl::one< 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"', '\'', '0', '\n' > {};
-   struct spaces : pegtl::seq< pegtl::one< 'z' >, pegtl::star< pegtl::space > > {};
-   struct hexbyte : pegtl::if_must< pegtl::one< 'x' >, pegtl::xdigit, pegtl::xdigit > {};
-   struct decbyte : pegtl::if_must< pegtl::digit, pegtl::rep_opt< 2, pegtl::digit > > {};
-   struct unichar : pegtl::if_must< pegtl::one< 'u' >, pegtl::one< '{' >, pegtl::plus< pegtl::xdigit >, pegtl::one< '}' > > {};
-   struct escaped : pegtl::if_must< pegtl::one< '\\' >, pegtl::sor< hexbyte, decbyte, unichar, single, spaces > > {};
-   struct regular : pegtl::not_one< '\r', '\n' > {};
-   struct character : pegtl::sor< escaped, regular > {};
-
-   template< char Q >
-   struct short_string : pegtl::if_must< pegtl::one< Q >, pegtl::until< pegtl::one< Q >, character > > {};
-   struct literal_string : pegtl::sor< short_string< '"' >, short_string< '\'' >, long_string > {};
-
-   template< typename E >
-   struct exponent : pegtl::opt_must< E, pegtl::opt< pegtl::one< '+', '-' > >, pegtl::plus< pegtl::digit > > {};
-
-   template< typename D, typename E >
-   struct numeral_three : pegtl::seq< pegtl::if_must< pegtl::one< '.' >, pegtl::plus< D > >, exponent< E > > {};
-   template< typename D, typename E >
-   struct numeral_two : pegtl::seq< pegtl::plus< D >, pegtl::opt< pegtl::one< '.' >, pegtl::star< D > >, exponent< E > > {};
-   template< typename D, typename E >
-   struct numeral_one : pegtl::sor< numeral_two< D, E >, numeral_three< D, E > > {};
-
-   struct decimal : numeral_one< pegtl::digit, pegtl::one< 'e', 'E' > > {};
-   struct hexadecimal : pegtl::if_must< pegtl::istring< '0', 'x' >, numeral_one< pegtl::xdigit, pegtl::one< 'p', 'P' > > > {};
-   struct numeral : pegtl::sor< hexadecimal, decimal > {};
-
-   struct label_statement : pegtl::if_must< pegtl::two< ':' >, seps, name, seps, pegtl::two< ':' > > {};
-   struct goto_statement : pegtl::if_must< key_goto, seps, name > {};
-
-   struct statement;
-   struct expression;
-
-   struct name_list : pegtl::list< name, pegtl::one< ',' >, sep > {};
-   struct name_list_must : pegtl::list_must< name, pegtl::one< ',' >, sep > {};
-   struct expr_list_must : pegtl::list_must< expression, pegtl::one< ',' >, sep > {};
-
-   struct statement_return : pegtl::seq< pegtl::pad_opt< expr_list_must, sep >, pegtl::opt< pegtl::one< ';' >, seps > > {};
-
-   template< typename E >
-   struct statement_list : pegtl::seq< seps, pegtl::until< pegtl::sor< E, pegtl::if_must< key_return, statement_return, E > >, statement, seps > > {};
-
-   template< char O, char... N >
-   struct op_one : pegtl::seq< pegtl::one< O >, pegtl::at< pegtl::not_one< N... > > > {};
-   template< char O, char P, char... N >
-   struct op_two : pegtl::seq< pegtl::string< O, P >, pegtl::at< pegtl::not_one< N... > > > {};
-
-   struct table_field_one : pegtl::if_must< pegtl::one< '[' >, seps, expression, seps, pegtl::one< ']' >, seps, pegtl::one< '=' >, seps, expression > {};
-   struct table_field_two : pegtl::if_must< pegtl::seq< name, seps, op_one< '=', '=' > >, seps, expression > {};
-   struct table_field : pegtl::sor< table_field_one, table_field_two, expression > {};
-   struct table_field_list : pegtl::list_tail< table_field, pegtl::one< ',', ';' >, sep > {};
-   struct table_constructor : pegtl::if_must< pegtl::one< '{' >, pegtl::pad_opt< table_field_list, sep >, pegtl::one< '}' > > {};
-
-   struct parameter_list_one : pegtl::seq< name_list, pegtl::opt_must< pad< pegtl::one< ',' > >, pegtl::ellipsis > > {};
-   struct parameter_list : pegtl::sor< pegtl::ellipsis, parameter_list_one > {};
-
-   struct function_body : pegtl::seq< pegtl::one< '(' >, pegtl::pad_opt< parameter_list, sep >, pegtl::one< ')' >, seps, statement_list< key_end > > {};
-   struct function_literal : pegtl::if_must< key_function, seps, function_body > {};
-
-   struct bracket_expr : pegtl::if_must< pegtl::one< '(' >, seps, expression, seps, pegtl::one< ')' > > {};
-
-   struct function_args_one : pegtl::if_must< pegtl::one< '(' >, pegtl::pad_opt< expr_list_must, sep >, pegtl::one< ')' > > {};
-   struct function_args : pegtl::sor< function_args_one, table_constructor, literal_string > {};
-
-   struct variable_tail_one : pegtl::if_must< pegtl::one< '[' >, seps, expression, seps, pegtl::one< ']' > > {};
-   struct variable_tail_two : pegtl::if_must< pegtl::seq< pegtl::not_at< pegtl::two< '.' > >, pegtl::one< '.' > >, seps, name > {};
-   struct variable_tail : pegtl::sor< variable_tail_one, variable_tail_two > {};
-
-   struct function_call_tail_one : pegtl::if_must< pegtl::seq< pegtl::not_at< pegtl::two< ':' > >, pegtl::one< ':' > >, seps, name, seps, function_args > {};
-   struct function_call_tail : pegtl::sor< function_args, function_call_tail_one > {};
-
-   struct variable_head_one : pegtl::seq< bracket_expr, seps, variable_tail > {};
-   struct variable_head : pegtl::sor< name, variable_head_one > {};
-
-   struct function_call_head : pegtl::sor< name, bracket_expr > {};
-
-   struct variable : pegtl::seq< variable_head, pegtl::star< pegtl::star< seps, function_call_tail >, seps, variable_tail > > {};
-   struct function_call : pegtl::seq< function_call_head, pegtl::plus< pegtl::until< pegtl::seq< seps, function_call_tail >, seps, variable_tail > > > {};
-
-   template< typename S, typename O >
-   struct left_assoc : pegtl::seq< S, seps, pegtl::star_must< O, seps, S, seps > > {};
-   template< typename S, typename O >
-   struct right_assoc : pegtl::seq< S, seps, pegtl::opt_must< O, seps, right_assoc< S, O > > > {};
-
-   struct unary_operators : pegtl::sor< pegtl::one< '-' >,
-                                        pegtl::one< '#' >,
-                                        op_one< '~', '=' >,
-                                        key_not > {};
-
-   struct expr_ten;
-   struct expr_thirteen : pegtl::seq< pegtl::sor< bracket_expr, name >, pegtl::star< seps, pegtl::sor< function_call_tail, variable_tail > > > {};
-   struct expr_twelve : pegtl::sor< key_nil,
-                                    key_true,
-                                    key_false,
-                                    pegtl::ellipsis,
-                                    numeral,
-                                    literal_string,
-                                    function_literal,
-                                    expr_thirteen,
-                                    table_constructor > {};
-   struct expr_eleven : pegtl::seq< expr_twelve, seps, pegtl::opt< pegtl::one< '^' >, seps, expr_ten, seps > > {};
-   struct unary_apply : pegtl::if_must< unary_operators, seps, expr_ten, seps > {};
-   struct expr_ten : pegtl::sor< unary_apply, expr_eleven > {};
-   struct operators_nine : pegtl::sor< pegtl::two< '/' >,
-                                       pegtl::one< '/' >,
-                                       pegtl::one< '*' >,
-                                       pegtl::one< '%' > > {};
-   struct expr_nine : left_assoc< expr_ten, operators_nine > {};
-   struct operators_eight : pegtl::sor< pegtl::one< '+' >,
-                                        pegtl::one< '-' > > {};
-   struct expr_eight : left_assoc< expr_nine, operators_eight > {};
-   struct expr_seven : right_assoc< expr_eight, op_two< '.', '.', '.' > > {};
-   struct operators_six : pegtl::sor< pegtl::two< '<' >,
-                                      pegtl::two< '>' > > {};
-   struct expr_six : left_assoc< expr_seven, operators_six > {};
-   struct expr_five : left_assoc< expr_six, pegtl::one< '&' > > {};
-   struct expr_four : left_assoc< expr_five, op_one< '~', '=' > > {};
-   struct expr_three : left_assoc< expr_four, pegtl::one< '|' > > {};
-   struct operators_two : pegtl::sor< pegtl::two< '=' >,
-                                      pegtl::string< '<', '=' >,
-                                      pegtl::string< '>', '=' >,
-                                      op_one< '<', '<' >,
-                                      op_one< '>', '>' >,
-                                      pegtl::string< '~', '=' > > {};
-   struct expr_two : left_assoc< expr_three, operators_two > {};
-   struct expr_one : left_assoc< expr_two, key_and > {};
-   struct expression : left_assoc< expr_one, key_or > {};
-
-   struct do_statement : pegtl::if_must< key_do, statement_list< key_end > > {};
-   struct while_statement : pegtl::if_must< key_while, seps, expression, seps, key_do, statement_list< key_end > > {};
-   struct repeat_statement : pegtl::if_must< key_repeat, statement_list< key_until >, seps, expression > {};
-
-   struct at_elseif_else_end : pegtl::sor< pegtl::at< key_elseif >, pegtl::at< key_else >, pegtl::at< key_end > > {};
-   struct elseif_statement : pegtl::if_must< key_elseif, seps, expression, seps, key_then, statement_list< at_elseif_else_end > > {};
-   struct else_statement : pegtl::if_must< key_else, statement_list< key_end > > {};
-   struct if_statement : pegtl::if_must< key_if, seps, expression, seps, key_then, statement_list< at_elseif_else_end >, seps, pegtl::until< pegtl::sor< else_statement, key_end >, elseif_statement, seps > > {};
-
-   struct for_statement_one : pegtl::seq< pegtl::one< '=' >, seps, expression, seps, pegtl::one< ',' >, seps, expression, pegtl::pad_opt< pegtl::if_must< pegtl::one< ',' >, seps, expression >, sep > > {};
-   struct for_statement_two : pegtl::seq< pegtl::opt_must< pegtl::one< ',' >, seps, name_list_must, seps >, key_in, seps, expr_list_must, seps > {};
-   struct for_statement : pegtl::if_must< key_for, seps, name, seps, pegtl::sor< for_statement_one, for_statement_two >, key_do, statement_list< key_end > > {};
-
-   struct assignment_variable_list : pegtl::list_must< variable, pegtl::one< ',' >, sep > {};
-   struct assignments_one : pegtl::if_must< pegtl::one< '=' >, seps, expr_list_must > {};
-   struct assignments : pegtl::seq< assignment_variable_list, seps, assignments_one > {};
-   struct function_name : pegtl::seq< pegtl::list< name, pegtl::one< '.' >, sep >, seps, pegtl::opt_must< pegtl::one< ':' >, seps, name, seps > > {};
-   struct function_definition : pegtl::if_must< key_function, seps, function_name, function_body > {};
-
-   struct local_function : pegtl::if_must< key_function, seps, name, seps, function_body > {};
-   struct local_variables : pegtl::if_must< name_list_must, seps, pegtl::opt< assignments_one > > {};
-   struct local_statement : pegtl::if_must< key_local, seps, pegtl::sor< local_function, local_variables > > {};
-
-   struct semicolon : pegtl::one< ';' > {};
-   struct statement : pegtl::sor< semicolon,
-                                  assignments,
-                                  function_call,
-                                  label_statement,
-                                  key_break,
-                                  goto_statement,
-                                  do_statement,
-                                  while_statement,
-                                  repeat_statement,
-                                  if_statement,
-                                  for_statement,
-                                  function_definition,
-                                  local_statement > {};
-
-   struct interpreter : pegtl::seq< pegtl::one< '#' >, pegtl::until< pegtl::eolf > > {};
-   struct grammar : pegtl::must< pegtl::opt< interpreter >, statement_list< pegtl::eof > > {};
-   // clang-format on
-
-}  // namespace lua53
+#include "lua53.hpp"
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
-   if( TAO_PEGTL_NAMESPACE::analyze< lua53::grammar >() != 0 ) {
-      return 1;
-   }
-
    for( int i = 1; i < argc; ++i ) {
       TAO_PEGTL_NAMESPACE::file_input in( argv[ i ] );
-      TAO_PEGTL_NAMESPACE::parse< lua53::grammar >( in );
+      const auto r = TAO_PEGTL_NAMESPACE::parse< lua53::grammar >( in );
+      std::cout << argv[ i ] << " " << r << std::endl;
    }
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/lua53_print_debug.cpp b/packages/PEGTL/src/example/pegtl/lua53_print_debug.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9303d54ab36b514b7856e36cc3b44d2426b55b3
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/lua53_print_debug.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/print.hpp>
+
+#include "lua53.hpp"
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_debug< lua53::grammar >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/lua53_print_names.cpp b/packages/PEGTL/src/example/pegtl/lua53_print_names.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..39bb917e710c1c8f6500279cd5567de3b92c6494
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/lua53_print_names.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/print.hpp>
+
+#include "lua53.hpp"
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_names< lua53::grammar >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/parse_tree.cpp b/packages/PEGTL/src/example/pegtl/parse_tree.cpp
index 9f0053f225a5d2bce91c51ce0e6489edf8d93547..1ccde1fef374eeb6ad47918a684bb9e2c8e24b61 100644
--- a/packages/PEGTL/src/example/pegtl/parse_tree.cpp
+++ b/packages/PEGTL/src/example/pegtl/parse_tree.cpp
@@ -2,6 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include <array>
+#include <iomanip>
 #include <iostream>
 #include <string>
 #include <type_traits>
@@ -174,10 +175,10 @@ int main( int argc, char** argv )
       return 0;
    }
    catch( const parse_error& e ) {
-      const auto p = e.positions.front();
+      const auto p = e.positions().front();
       std::cerr << e.what() << std::endl
                 << in.line_at( p ) << std::endl
-                << std::string( p.byte_in_line, ' ' ) << '^' << std::endl;
+                << std::setw( p.column ) << '^' << std::endl;
    }
    catch( const std::exception& e ) {
       std::cerr << e.what() << std::endl;
diff --git a/packages/PEGTL/src/example/pegtl/recover.cpp b/packages/PEGTL/src/example/pegtl/recover.cpp
index 6353a7442074a645a105e31999a2400bd3331adb..c76a5f9f3199700425203f8d1050d1dcec21ab6c 100644
--- a/packages/PEGTL/src/example/pegtl/recover.cpp
+++ b/packages/PEGTL/src/example/pegtl/recover.cpp
@@ -69,7 +69,7 @@ struct found
    static void apply( const ActionInput& in, bool& error )
    {
       if( !error ) {
-         std::cout << in.position() << ": Found " << internal::demangle< R >() << ": \"" << in.string() << "\"" << std::endl;
+         std::cout << in.position() << ": Found " << tao::demangle< R >() << ": \"" << in.string() << "\"" << std::endl;
       }
    }
 };
@@ -101,10 +101,10 @@ struct my_control
    : normal< Rule >
 {
    template< typename ParseInput, typename... States >
-   [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ )
+   [[noreturn]] static void raise( const ParseInput& in, States&&... st )
    {
-      std::cout << in.position() << ": Parse error matching " << internal::demangle< Rule >() << std::endl;
-      throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in );
+      std::cout << in.position() << ": Parse error matching " << tao::demangle< Rule >() << std::endl;
+      normal< Rule >::raise( in, st... );
    }
 };
 
diff --git a/packages/PEGTL/src/example/pegtl/s_expression.cpp b/packages/PEGTL/src/example/pegtl/s_expression.cpp
index 7c47f1c8b9b11217a070b5ac6d8355beca569f02..8eb4204708e80a9653613de26bfb9f108115c649 100644
--- a/packages/PEGTL/src/example/pegtl/s_expression.cpp
+++ b/packages/PEGTL/src/example/pegtl/s_expression.cpp
@@ -6,35 +6,33 @@
 #include <tao/pegtl.hpp>
 #include <tao/pegtl/contrib/analyze.hpp>
 
-using namespace TAO_PEGTL_NAMESPACE;
-
 namespace sexpr
 {
    // clang-format off
-   struct hash_comment : until< eolf > {};
+   struct hash_comment : tao::pegtl::until< tao::pegtl::eolf > {};
 
    struct list;
-   struct list_comment : if_must< at< one< '(' > >, disable< list > > {};
+   struct list_comment : tao::pegtl::if_must< tao::pegtl::at< tao::pegtl::one< '(' > >, tao::pegtl::disable< list > > {};
 
-   struct read_include : seq< one< ' ' >, one< '"' >, plus< not_one< '"' > >, one< '"' > > {};
-   struct hash_include : if_must< string< 'i', 'n', 'c', 'l', 'u', 'd', 'e' >, read_include > {};
+   struct read_include : tao::pegtl::seq< tao::pegtl::one< ' ' >, tao::pegtl::one< '"' >, tao::pegtl::plus< tao::pegtl::not_one< '"' > >, tao::pegtl::one< '"' > > {};
+   struct hash_include : tao::pegtl::if_must< tao::pegtl::string< 'i', 'n', 'c', 'l', 'u', 'd', 'e' >, read_include > {};
 
-   struct hashed : if_must< one< '#' >, sor< hash_include, list_comment, hash_comment > > {};
+   struct hashed : tao::pegtl::if_must< tao::pegtl::one< '#' >, tao::pegtl::sor< hash_include, list_comment, hash_comment > > {};
 
-   struct number : plus< digit > {};
-   struct symbol : identifier {};
+   struct number : tao::pegtl::plus< tao::pegtl::digit > {};
+   struct symbol : tao::pegtl::identifier {};
 
-   struct atom : sor< number, symbol > {};
+   struct atom : tao::pegtl::sor< number, symbol > {};
 
    struct anything;
 
-   struct list : if_must< one< '(' >, until< one< ')' >, anything > > {};
+   struct list : tao::pegtl::if_must< tao::pegtl::one< '(' >, tao::pegtl::until< tao::pegtl::one< ')' >, anything > > {};
 
-   struct normal : sor< atom, list > {};
+   struct normal : tao::pegtl::sor< atom, list > {};
 
-   struct anything : sor< space, hashed, normal > {};
+   struct anything : tao::pegtl::sor< tao::pegtl::space, hashed, normal > {};
 
-   struct main : until< eof, must< anything > > {};
+   struct main : tao::pegtl::until< tao::pegtl::eof, tao::pegtl::must< anything > > {};
    // clang-format on
 
    template< typename Rule >
@@ -42,7 +40,7 @@ namespace sexpr
    {};
 
    template<>
-   struct action< plus< not_one< '"' > > >
+   struct action< tao::pegtl::plus< tao::pegtl::not_one< '"' > > >
    {
       template< typename ActionInput >
       static void apply( const ActionInput& in, std::string& fn )
@@ -64,8 +62,8 @@ namespace sexpr
          // last string literal that we use as filename here, and
          // the input is passed on for chained error messages (as
          // in "error in line x file foo included from file bar...)
-         file_input i2( fn );
-         parse_nested< main, sexpr::action >( in, i2, f2 );
+         tao::pegtl::file_input i2( fn );
+         tao::pegtl::parse_nested< main, sexpr::action >( in, i2, f2 );
       }
    };
 
@@ -73,14 +71,13 @@ namespace sexpr
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
-   if( analyze< sexpr::main >() != 0 ) {
+   if( tao::pegtl::analyze< sexpr::main >() != 0 ) {
       return 1;
    }
-
    for( int i = 1; i < argc; ++i ) {
       std::string fn;
-      argv_input in( argv, i );
-      parse< sexpr::main, sexpr::action >( in, fn );
+      tao::pegtl::argv_input in( argv, i );
+      tao::pegtl::parse< sexpr::main, sexpr::action >( in, fn );
    }
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/symbol_table.cpp b/packages/PEGTL/src/example/pegtl/symbol_table.cpp
index 5d0a7b51ab7a503008cc787c3ade45738dcf4af2..75a520135bc31b9202ef01e6c6673cb1ca8f5f83 100644
--- a/packages/PEGTL/src/example/pegtl/symbol_table.cpp
+++ b/packages/PEGTL/src/example/pegtl/symbol_table.cpp
@@ -47,9 +47,12 @@ namespace example
 
    template<>
    struct action< value >
-      : public pegtl::unsigned_action
    {
-      // Sets st.converted to the integer value of the matched string.
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& st )
+      {
+         pegtl::unsigned_action::apply( in, st.converted );
+      }
    };
 
    template<>
diff --git a/packages/PEGTL/src/example/pegtl/uri_print_debug.cpp b/packages/PEGTL/src/example/pegtl/uri_print_debug.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25858179b541efb9f646892944be31b630b55315
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/uri_print_debug.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/print.hpp>
+#include <tao/pegtl/contrib/uri.hpp>
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_debug< tao::pegtl::uri::URI >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/uri_print_names.cpp b/packages/PEGTL/src/example/pegtl/uri_print_names.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6867333364e527b20fe24fd76e72f3e33f8368d9
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/uri_print_names.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/print.hpp>
+#include <tao/pegtl/contrib/uri.hpp>
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_names< tao::pegtl::uri::URI >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/uri_trace.cpp b/packages/PEGTL/src/example/pegtl/uri_trace.cpp
index cbd354ef15277ed3d126633757fd0adcc9316bc3..14a3a29588640562d1f2f73d4ad7cfb71c7abaf0 100644
--- a/packages/PEGTL/src/example/pegtl/uri_trace.cpp
+++ b/packages/PEGTL/src/example/pegtl/uri_trace.cpp
@@ -16,7 +16,7 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
    for( int i = 1; i < argc; ++i ) {
       std::cout << "Parsing " << argv[ i ] << std::endl;
       pegtl::argv_input in( argv, i );
-      pegtl::parse< grammar, pegtl::nothing, pegtl::trace_control >( in );
+      pegtl::complete_trace< grammar >( in );
    }
    return 0;
 }
diff --git a/packages/PEGTL/src/test/pegtl/CMakeLists.txt b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
index 964d99432ce8e434ccc7e807aaec5aaeb376cf92..446ef2921f64949a984155553cf0c099a6bcecf3 100644
--- a/packages/PEGTL/src/test/pegtl/CMakeLists.txt
+++ b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
@@ -25,6 +25,7 @@ set(test_sources
   change_states.cpp
   contrib_alphabet.cpp
   contrib_analyze.cpp
+  contrib_control_action.cpp
   contrib_http.cpp
   contrib_if_then.cpp
   contrib_integer.cpp
@@ -33,13 +34,16 @@ set(test_sources
   contrib_partial_trace.cpp
   contrib_raw_string.cpp
   contrib_rep_one_min_max.cpp
+  contrib_state_control.cpp
   contrib_to_string.cpp
   contrib_tracer.cpp
   contrib_unescape.cpp
   contrib_uri.cpp
+  control_unwind.cpp
   data_cstring.cpp
   demangle.cpp
   discard_input.cpp
+  enable_control.cpp
   error_message.cpp
   file_cstream.cpp
   file_file.cpp
@@ -49,6 +53,7 @@ set(test_sources
   internal_endian.cpp
   internal_file_mapper.cpp
   internal_file_opener.cpp
+  parse_error.cpp
   pegtl_string_t.cpp
   position.cpp
   rule_action.cpp
@@ -60,6 +65,7 @@ set(test_sources
   rule_bytes.cpp
   rule_control.cpp
   rule_disable.cpp
+  rule_discard.cpp
   rule_enable.cpp
   rule_eof.cpp
   rule_failure.cpp
@@ -78,6 +84,7 @@ set(test_sources
   rule_pad.cpp
   rule_pad_opt.cpp
   rule_plus.cpp
+  rule_raise.cpp
   rule_rematch.cpp
   rule_rep.cpp
   rule_rep_max.cpp
diff --git a/packages/PEGTL/src/test/pegtl/actions_one.cpp b/packages/PEGTL/src/test/pegtl/actions_one.cpp
index 1e5c2f81312439714ad6cd5475cde7480431e370..40128c1680bcc28b83eb49d148790449454cffc2 100644
--- a/packages/PEGTL/src/test/pegtl/actions_one.cpp
+++ b/packages/PEGTL/src/test/pegtl/actions_one.cpp
@@ -29,16 +29,16 @@ namespace TAO_PEGTL_NAMESPACE
       {
          TAO_PEGTL_TEST_ASSERT( applied.size() == 10 );
 
-         TAO_PEGTL_TEST_ASSERT( applied[ 0 ].first == internal::demangle< one< 'b' > >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 1 ].first == internal::demangle< foo >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 2 ].first == internal::demangle< at< one< 'a' > > >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 3 ].first == internal::demangle< two< 'a' > >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 4 ].first == internal::demangle< fiz >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 5 ].first == internal::demangle< foo >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 6 ].first == internal::demangle< one< 'b' > >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 7 ].first == internal::demangle< foo >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 8 ].first == internal::demangle< eof >() );
-         TAO_PEGTL_TEST_ASSERT( applied[ 9 ].first == internal::demangle< bar >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 0 ].first == tao::demangle< one< 'b' > >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 1 ].first == tao::demangle< foo >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 2 ].first == tao::demangle< at< one< 'a' > > >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 3 ].first == tao::demangle< two< 'a' > >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 4 ].first == tao::demangle< fiz >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 5 ].first == tao::demangle< foo >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 6 ].first == tao::demangle< one< 'b' > >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 7 ].first == tao::demangle< foo >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 8 ].first == tao::demangle< eof >() );
+         TAO_PEGTL_TEST_ASSERT( applied[ 9 ].first == tao::demangle< bar >() );
 
          TAO_PEGTL_TEST_ASSERT( applied[ 0 ].second == "b" );
          TAO_PEGTL_TEST_ASSERT( applied[ 1 ].second == "b" );
@@ -60,7 +60,7 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename ActionInput >
       static void apply( const ActionInput& in )
       {
-         applied.emplace_back( internal::demangle< Rule >(), in.string() );
+         applied.emplace_back( tao::demangle< Rule >(), in.string() );
       }
    };
 
@@ -69,7 +69,7 @@ namespace TAO_PEGTL_NAMESPACE
       parse< disable< test1::bar >, test_action >( memory_input( "baab", __FUNCTION__ ) );
       TAO_PEGTL_TEST_ASSERT( applied.size() == 1 );
 
-      TAO_PEGTL_TEST_ASSERT( applied[ 0 ].first == internal::demangle< disable< test1::bar > >() );
+      TAO_PEGTL_TEST_ASSERT( applied[ 0 ].first == tao::demangle< disable< test1::bar > >() );
       TAO_PEGTL_TEST_ASSERT( applied[ 0 ].second == "baab" );
 
       applied.clear();
diff --git a/packages/PEGTL/src/test/pegtl/actions_two.cpp b/packages/PEGTL/src/test/pegtl/actions_two.cpp
index a21d222ff32abb8014c7e0f9a6906298ccf8c2d3..d3dcb224ee3d83324ca39e5eebd72ea6d95338da 100644
--- a/packages/PEGTL/src/test/pegtl/actions_two.cpp
+++ b/packages/PEGTL/src/test/pegtl/actions_two.cpp
@@ -91,7 +91,7 @@ namespace TAO_PEGTL_NAMESPACE
 
       const std::size_t count_byte = 12345;
       const std::size_t count_line = 42;
-      const std::size_t count_byte_in_line = 12;
+      const std::size_t count_column = 12;
 
       const char* count_source = "count_source";
 
@@ -103,7 +103,7 @@ namespace TAO_PEGTL_NAMESPACE
          {
             TAO_PEGTL_TEST_ASSERT( in.iterator().byte == count_byte );
             TAO_PEGTL_TEST_ASSERT( in.iterator().line == count_line );
-            TAO_PEGTL_TEST_ASSERT( in.iterator().byte_in_line == count_byte_in_line );
+            TAO_PEGTL_TEST_ASSERT( in.iterator().column == count_column );
             TAO_PEGTL_TEST_ASSERT( in.input().source() == count_source );
             TAO_PEGTL_TEST_ASSERT( in.size() == 1 );
             TAO_PEGTL_TEST_ASSERT( in.begin() + 1 == in.end() );
@@ -115,7 +115,7 @@ namespace TAO_PEGTL_NAMESPACE
       void count_test()
       {
          const char* foo = "f";
-         memory_input in( foo, foo + 1, count_source, count_byte, count_line, count_byte_in_line );
+         memory_input in( foo, foo + 1, count_source, count_byte, count_line, count_column );
          const auto result = parse< must< alpha >, count_action >( in );
          TAO_PEGTL_TEST_ASSERT( result );
       }
diff --git a/packages/PEGTL/src/test/pegtl/ascii_classes.cpp b/packages/PEGTL/src/test/pegtl/ascii_classes.cpp
index c3301af9784c8cdd7dc3312b0945fc4f82452222..8271091cbe15d587337bf8d17b5016d758a096eb 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_classes.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_classes.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_eol.cpp b/packages/PEGTL/src/test/pegtl/ascii_eol.cpp
index 9724234d375da805ad1ae7de7de235b3ffe0921f..2d46c03a5b49600fd060201f49afc863c43862f4 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_eol.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_eol.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp b/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp
index 2cb54e528a1390a4e1f1f72490c8fa39344b9f16..c91c155100b4e230c32cf559d5f6b6b3c26201c6 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_eolf.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp
index fcce5471fefbd91eaa0a07bf5b8b2b297e6a3687..1bbc0c01db01dda98b504969936f5971fa05783f 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp b/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp
index 3a4fcbceb5cf43451afabe5469e5f91c60052fa1..5d521d4d2745c74b286ef486b0f08cfd7524f3d0 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_identifier.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_istring.cpp b/packages/PEGTL/src/test/pegtl/ascii_istring.cpp
index 73a9e733fbc181586a27e095cb524354c5239f92..b29b8a6eceafe1771a7f2b0d8b7e3334954b3e4d 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_istring.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_istring.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp b/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp
index 17746344dbd488e701312e6684a6adb1d1b83e80..6959625add9b26b1a96ea6828573039e4ad33591 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_keyword.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp b/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp
index 57042c9a2f0c7cae8c188d8f4238e530339f48c5..47d9bc9b3a82dcfb6a73e7c81c84f18dd5e3ea9a 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_shebang.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_string.cpp b/packages/PEGTL/src/test/pegtl/ascii_string.cpp
index 6d24356c9ac5e4d416751f8ffd724710b1ba5d80..bc97c6f947902773937886792ee2e6937dc0bc63 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_string.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_string.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_three.cpp b/packages/PEGTL/src/test/pegtl/ascii_three.cpp
index 23a9226306333bf57e75311db35c7b0c9634c5c5..e6341dcc4bb1df8c019324eabd0c5434ff5494e6 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_three.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_three.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/ascii_two.cpp b/packages/PEGTL/src/test/pegtl/ascii_two.cpp
index 020954b185a013a436acb149209f4df77c207788..5ca9d36b00716d44f8ed924e1ef421c648bbba19 100644
--- a/packages/PEGTL/src/test/pegtl/ascii_two.cpp
+++ b/packages/PEGTL/src/test/pegtl/ascii_two.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
index dee2d0408fa9d1188cb7cd556b53625e6092710a..65f1d4831fc4be550caf3fb191114105fe7e4af0 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
@@ -2,12 +2,35 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
+   template< typename... Rules >
+   struct strange
+   {
+      using rule_t = strange;
+      using subs_t = type_list< Rules... >;
+
+      static_assert( sizeof...( Rules ) > 1 );
+
+      // Pretend to be a rule that consumes on success by itself _and_ has sub-rules,
+      // to test a supported combination even though it is not frequently encountered.
+   };
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, strange< Rules... > >
+      : analyze_any_traits< Rules... >
+   {};
+
    void unit_test()
    {
+      verify_analyze< strange< alpha, digit > >( __LINE__, __FILE__, true, false );
+      verify_analyze< strange< opt< alpha >, opt< digit > > >( __LINE__, __FILE__, true, false );
+
+      verify_analyze< strange< star< star< alpha > >, digit > >( __LINE__, __FILE__, true, true );
+      verify_analyze< strange< digit, star< star< alpha > > > >( __LINE__, __FILE__, true, true );
+
       verify_analyze< eof >( __LINE__, __FILE__, false, false );
       verify_analyze< eolf >( __LINE__, __FILE__, false, false );
       verify_analyze< success >( __LINE__, __FILE__, false, false );
diff --git a/packages/PEGTL/src/test/pegtl/contrib_control_action.cpp b/packages/PEGTL/src/test/pegtl/contrib_control_action.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d03133953e1cfaf098ea167dcb30be1b4372bd9
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/contrib_control_action.cpp
@@ -0,0 +1,140 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <string>
+
+#include "test.hpp"
+
+#include <tao/pegtl/contrib/control_action.hpp>
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< typename Rule >
+   struct test_action
+      : nothing< Rule >
+   {};
+
+   struct first_rule
+      : sor< alpha, digit >
+   {};
+
+   struct second_rule
+      : must< alnum >
+   {};
+
+   std::string story;
+
+   template<>
+   struct test_action< first_rule >
+      : control_action
+   {
+      template< typename ParseInput >
+      static void start( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'a';
+      }
+
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'b';
+      }
+
+      template< typename ParseInput >
+      static void failure( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'c';
+      }
+   };
+
+   template<>
+   struct test_action< alpha >
+      : control_action
+   {
+      template< typename ParseInput >
+      static void start( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'd';
+      }
+
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'e';
+      }
+      template< typename ParseInput >
+      static void failure( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'f';
+      }
+   };
+
+   template<>
+   struct test_action< digit >
+      : control_action
+   {
+      template< typename ParseInput >
+      static void start( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'g';
+      }
+
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'h';
+      }
+      template< typename ParseInput >
+      static void failure( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'i';
+      }
+   };
+
+   template<>
+   struct test_action< second_rule >
+      : control_action
+   {
+      template< typename ParseInput >
+      static void start( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'j';
+      }
+
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'k';
+      }
+      template< typename ParseInput >
+      static void failure( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'l';
+      }
+
+      template< typename ParseInput >
+      static void unwind( const ParseInput& /*unused*/, int /*unused*/ )
+      {
+         story += 'm';
+      }
+   };
+
+   void unit_test()
+   {
+      {
+         memory_input in( "0", __FUNCTION__ );
+         const auto b = parse< first_rule, test_action >( in, 42 );
+         TAO_PEGTL_TEST_ASSERT( b );
+         TAO_PEGTL_TEST_ASSERT( story == "adfghb" );
+      }
+      story.clear();
+      {
+         memory_input in( "*", __FUNCTION__ );
+         TAO_PEGTL_TEST_THROWS( parse< second_rule, test_action >( in, 42 ) );
+         TAO_PEGTL_TEST_ASSERT( story == "jm" );
+      }
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/contrib_http.cpp b/packages/PEGTL/src/test/pegtl/contrib_http.cpp
index b4f74cd5adc0e3c5a2cdceccd8351e38a0ca0272..0273d43b10a34b25b94bf35bda4bc5ffaa0f4639 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_http.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_http.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 
 #include <tao/pegtl/contrib/http.hpp>
 
diff --git a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
index 9290f670de8575ba55f0feacaeaaee80912ac2c2..0a9cc8eaf857e700bb96b0ea237e5dee69b506e7 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
@@ -6,19 +6,13 @@
 
 #include "test.hpp"
 
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 #include <tao/pegtl/contrib/integer.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   template< typename I >
-   struct int_state
-   {
-      I converted = 55;
-   };
-
    template< typename Rule >
    struct int_action
       : nothing< Rule >
@@ -43,12 +37,6 @@ namespace TAO_PEGTL_NAMESPACE
          parse< must< signed_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
-      {
-         int_state< S > st;
-         memory_input in( i, __FUNCTION__ );
-         parse< must< signed_rule, eof >, int_action >( in, st );
-         TAO_PEGTL_TEST_ASSERT( st.converted == s );
-      }
       {
          S st = -123;
          memory_input in( i, __FUNCTION__ );
@@ -60,7 +48,7 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename S >
    void test_signed( const std::string& i )
    {
-      int_state< S > st;
+      S st;
       memory_input in( i, __FUNCTION__ );
       TAO_PEGTL_TEST_THROWS( parse< must< signed_rule, eof >, int_action >( in, st ) );
    }
@@ -76,11 +64,11 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename S >
    void test_signed( const S s )
    {
-      int_state< S > st;
+      S st;
       const auto i = lexical_cast( s );
       memory_input in( i, __FUNCTION__ );
       parse< must< signed_rule, eof >, int_action >( in, st );
-      TAO_PEGTL_TEST_ASSERT( st.converted == s );
+      TAO_PEGTL_TEST_ASSERT( st == s );
    }
 
    template< typename S >
@@ -92,12 +80,6 @@ namespace TAO_PEGTL_NAMESPACE
          parse< must< unsigned_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
-      {
-         int_state< S > st;
-         memory_input in( i, __FUNCTION__ );
-         parse< must< unsigned_rule, eof >, int_action >( in, st );
-         TAO_PEGTL_TEST_ASSERT( st.converted == s );
-      }
       {
          S st = 123;
          memory_input in( i, __FUNCTION__ );
diff --git a/packages/PEGTL/src/test/pegtl/contrib_json.cpp b/packages/PEGTL/src/test/pegtl/contrib_json.cpp
index 67abd1d1d9083abeb67e8d68ed0a5080fa6312b3..2cd30e1320783cbf066e844b8f3d40168b5b41b2 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_json.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_json.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_fail.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 #include <tao/pegtl/contrib/json.hpp>
diff --git a/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp
index 521a8140cdb8d7eaac1c78d370b38ee9cbbbf8f9..bce6834501b9d887fe3cae3bc773a6f6d8998cff 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp
@@ -13,6 +13,8 @@ namespace TAO_PEGTL_NAMESPACE
    struct C : one< 'c' > {};
 
    struct D : sor< seq< A, B >, seq< A, C > > {};
+
+   struct D2 : sor< try_catch< if_must< A, B > >, seq< A, C > > {};
    // clang-format on
 
    template< typename Rule >
@@ -22,28 +24,74 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
-      memory_input in( "ac", "input" );
-      const auto r = parse_tree::parse< D, selector >( in );
-      TAO_PEGTL_TEST_ASSERT( r->is_root() );
-      TAO_PEGTL_TEST_ASSERT( !r->has_content() );
-      TAO_PEGTL_TEST_ASSERT( r->children.size() == 1 );
-
-      const auto& d = r->children.front();
-      TAO_PEGTL_TEST_ASSERT( !d->is_root() );
-      TAO_PEGTL_TEST_ASSERT( d->is_type< D >() );
-
-      TAO_PEGTL_TEST_ASSERT( d->has_content() );
-      TAO_PEGTL_TEST_ASSERT( d->begin().byte == 0 );
-      TAO_PEGTL_TEST_ASSERT( d->end().byte == 2 );
-      TAO_PEGTL_TEST_ASSERT( d->string_view() == "ac" );
-
-      TAO_PEGTL_TEST_ASSERT( d->children.size() == 2 );
-      TAO_PEGTL_TEST_ASSERT( d->children.front()->is_type< A >() );
-      TAO_PEGTL_TEST_ASSERT( d->children.back()->is_type< C >() );
-
-      memory_input in2( "x", "input" );
-      const auto r2 = parse_tree::parse< D, selector >( in2 );
-      TAO_PEGTL_TEST_ASSERT( !r2 );
+      {
+         memory_input in( "ac", "input" );
+         const auto r = parse_tree::parse< D, selector >( in );
+         TAO_PEGTL_TEST_ASSERT( r );
+         TAO_PEGTL_TEST_ASSERT( r->is_root() );
+         TAO_PEGTL_TEST_ASSERT( !r->has_content() );
+         TAO_PEGTL_TEST_ASSERT( r->children.size() == 1 );
+
+         const auto& d = r->children.front();
+         TAO_PEGTL_TEST_ASSERT( !d->is_root() );
+         TAO_PEGTL_TEST_ASSERT( d->is_type< D >() );
+
+         TAO_PEGTL_TEST_ASSERT( d->has_content() );
+         TAO_PEGTL_TEST_ASSERT( d->begin().byte == 0 );
+         TAO_PEGTL_TEST_ASSERT( d->end().byte == 2 );
+         TAO_PEGTL_TEST_ASSERT( d->string_view() == "ac" );
+
+         TAO_PEGTL_TEST_ASSERT( d->children.size() == 2 );
+         TAO_PEGTL_TEST_ASSERT( d->children.front()->is_type< A >() );
+         TAO_PEGTL_TEST_ASSERT( d->children.back()->is_type< C >() );
+
+         memory_input in2( "x", "input" );
+         const auto r2 = parse_tree::parse< D, selector >( in2 );
+         TAO_PEGTL_TEST_ASSERT( !r2 );
+      }
+
+      {
+         memory_input in( "ac", "input" );
+         const auto r = parse_tree::parse< D2, selector >( in );
+         TAO_PEGTL_TEST_ASSERT( r );
+         TAO_PEGTL_TEST_ASSERT( r->is_root() );
+         TAO_PEGTL_TEST_ASSERT( !r->has_content() );
+
+         TAO_PEGTL_TEST_ASSERT( r->children.size() == 2 );
+         TAO_PEGTL_TEST_ASSERT( r->children.front()->is_type< A >() );
+         TAO_PEGTL_TEST_ASSERT( r->children.back()->is_type< C >() );
+      }
+
+      {
+         memory_input in( "ac", "input" );
+         const auto r = parse_tree::parse< D2 >( in );
+         TAO_PEGTL_TEST_ASSERT( r );
+         TAO_PEGTL_TEST_ASSERT( r->is_root() );
+         TAO_PEGTL_TEST_ASSERT( !r->has_content() );
+         TAO_PEGTL_TEST_ASSERT( r->children.size() == 1 );
+
+         const auto& d2 = r->children.front();
+         TAO_PEGTL_TEST_ASSERT( !d2->is_root() );
+         TAO_PEGTL_TEST_ASSERT( d2->is_type< D2 >() );
+
+         TAO_PEGTL_TEST_ASSERT( d2->has_content() );
+         TAO_PEGTL_TEST_ASSERT( d2->begin().byte == 0 );
+         TAO_PEGTL_TEST_ASSERT( d2->end().byte == 2 );
+         TAO_PEGTL_TEST_ASSERT( d2->string() == "ac" );
+
+         const auto& internal = d2->children.front();
+         TAO_PEGTL_TEST_ASSERT( !internal->is_root() );
+         TAO_PEGTL_TEST_ASSERT( internal->is_type< seq< A, C > >() );
+
+         TAO_PEGTL_TEST_ASSERT( internal->has_content() );
+         TAO_PEGTL_TEST_ASSERT( internal->begin().byte == 0 );
+         TAO_PEGTL_TEST_ASSERT( internal->end().byte == 2 );
+         TAO_PEGTL_TEST_ASSERT( internal->string_view() == "ac" );
+
+         TAO_PEGTL_TEST_ASSERT( internal->children.size() == 2 );
+         TAO_PEGTL_TEST_ASSERT( internal->children.front()->is_type< A >() );
+         TAO_PEGTL_TEST_ASSERT( internal->children.back()->is_type< C >() );
+      }
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
index b8ac7a168bbedd7c66f3020e04e4b35793febec5..5743114608c7c0adabe767034808b880443d4799 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
@@ -8,17 +8,17 @@
 namespace TAO_PEGTL_NAMESPACE
 {
    // clang-format off
-   struct inner : seq< one< 'a' >, sor< one< 'b' >, one< 'c' > > > {};
+   struct inner : seq< one< 'a' >, sor< one< 'b' >, one< 'c' >, inner > > {};
    struct outer : seq< one< 'x' >, inner, one< 'y' > > {};
 
    // how to run a tracer on a *part* of the grammar:
    template< typename > struct partial_action {};
-   template<> struct partial_action< inner > : change_control< trace_control > {};
+   template<> struct partial_action< inner > : trace_standard {};
    // clang-format on
 
    void unit_test()
    {
-      memory_input in( "xacy", "trace test please ignore" );
+      memory_input in( "xaacy", "trace test please ignore" );
       const auto result = parse< outer, partial_action >( in );
       TAO_PEGTL_TEST_ASSERT( result );
    }
diff --git a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
index 95d2737e72d37b5bea2ffce010c4e3e822503b72..6ae1980754fdc5f6402a5a8d96f437312063c00c 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_fail.hpp"
+#include "verify_meta.hpp"
 
 #include <tao/pegtl/contrib/raw_string.hpp>
 
@@ -54,13 +54,13 @@ namespace TAO_PEGTL_NAMESPACE
    void verify_data( const std::size_t line, const char* file, const char ( &m )[ M ], const char ( &n )[ N ] )
    {
       content.clear();
-      memory_input in( m, m + M - 1, file, 0, line, 0 );
+      memory_input in( m, m + M - 1, file, 0, line, 1 );
       const auto r = parse< Rule, Action >( in );
       if( ( !r ) || ( content != std::string_view( n, N - 1 ) ) ) {
          TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r << " ]" );
       }
       content.clear();
-      memory_input< tracking_mode::lazy > in2( m, m + M - 1, file, 0, line, 0 );
+      memory_input< tracking_mode::lazy > in2( m, m + M - 1, file, 0, line, 1 );
       const auto r2 = parse< Rule, Action >( in2 );
       if( ( !r2 ) || ( content != std::string_view( n, N - 1 ) ) ) {
          TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] with tracking_mode::lazy expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r2 << " ]" );
diff --git a/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp b/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp
index b190a0cca7737bf17dd160fdcff57b9f50a491df..ee9ecf7b6c2efa06b9a2249169698f1f03061f12 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_rep_one_min_max.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 #include <tao/pegtl/contrib/rep_one_min_max.hpp>
diff --git a/packages/PEGTL/src/test/pegtl/contrib_state_control.cpp b/packages/PEGTL/src/test/pegtl/contrib_state_control.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dc07cf3460ae9082b9b47a1977a45233301b6ac
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/contrib_state_control.cpp
@@ -0,0 +1,190 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+#include <string_view>
+#include <vector>
+
+#include "test.hpp"
+
+#include <tao/pegtl/contrib/state_control.hpp>
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   struct test_entry
+   {
+      std::string_view rule;
+      std::string_view func;
+      std::size_t b;
+   };
+
+   inline bool operator==( const test_entry& l, const test_entry& r ) noexcept
+   {
+      return ( l.rule == r.rule ) && ( l.func == r.func ) && ( l.b == r.b );
+   }
+
+   template< bool E >
+   struct test_state
+   {
+      std::vector< test_entry > trace;
+
+      template< typename Rule >
+      static constexpr bool enable = E;
+
+      template< typename Rule, typename Input, typename... States >
+      void start( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "start", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void success( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "success", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void failure( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "failure", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void raise( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "raise", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void unwind( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "unwind", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void apply( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "apply", ++b } );
+      }
+
+      template< typename Rule, typename Input, typename... States >
+      void apply0( const Input& /*unused*/, const int a, std::size_t& b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         trace.push_back( { demangle< Rule >(), "apply0", ++b } );
+      }
+   };
+
+   struct test_grammar : must< sor< one< 'a' >, try_catch< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > >, eof >
+   {};
+
+   template< typename Rule >
+   struct test_action
+      : nothing< Rule >
+   {};
+
+   bool test_action_one = false;
+
+   template<>
+   struct test_action< one< 'b' > >
+   {
+      static void apply0( const int a, const std::size_t b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         if( test_action_one ) {
+            TAO_PEGTL_TEST_ASSERT( b == 0 );
+            test_action_one = false;
+         }
+         else {
+            TAO_PEGTL_TEST_ASSERT( b == 9 );
+            test_action_one = true;
+         }
+      }
+   };
+
+   bool test_action_two = false;
+
+   template<>
+   struct test_action< two< 'b' > >
+   {
+      template< typename ActionInput >
+      static void apply( const ActionInput& /*unused*/, const int a, const std::size_t b )
+      {
+         TAO_PEGTL_TEST_ASSERT( a == -1 );
+         if( test_action_two ) {
+            TAO_PEGTL_TEST_ASSERT( b == 0 );
+            test_action_two = false;
+         }
+         else {
+            TAO_PEGTL_TEST_ASSERT( b == 19 );
+            test_action_two = true;
+         }
+      }
+   };
+
+   void unit_test()
+   {
+      {
+         test_state< true > st;
+         memory_input in( "bb", __FUNCTION__ );
+         std::size_t b = 0;
+         const bool result = parse< test_grammar, test_action, state_control< normal >::type >( in, -1, b, st );
+         TAO_PEGTL_TEST_ASSERT( result );
+         TAO_PEGTL_TEST_ASSERT( test_action_one );
+         TAO_PEGTL_TEST_ASSERT( test_action_two );
+         TAO_PEGTL_TEST_ASSERT( b == st.trace.size() );
+         b = 0;
+         std::size_t i = 0;
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< test_grammar >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< internal::must< sor< one< 'a' >, try_catch< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > > > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< sor< one< 'a' >, try_catch< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'a' > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'a' > >(), "failure", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch< seq< one< 'b' >, must< one< 'c' > > > > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< seq< one< 'b' >, must< one< 'c' > > > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'b' > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'b' > >(), "apply0", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'b' > >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< must< one< 'c' > > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'c' > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'c' > >(), "failure", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'c' > >(), "raise", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< must< one< 'c' > > >(), "unwind", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< seq< one< 'b' >, must< one< 'c' > > > >(), "unwind", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch< seq< one< 'b' >, must< one< 'c' > > > > >(), "failure", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< two< 'b' > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< two< 'b' > >(), "apply", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< two< 'b' > >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< sor< one< 'a' >, try_catch< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > > >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< internal::must< sor< one< 'a' >, try_catch< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > > > >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< internal::must< eof > >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< eof >(), "start", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< eof >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< internal::must< eof > >(), "success", ++b } );
+         TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< test_grammar >(), "success", ++b } );
+
+         TAO_PEGTL_TEST_ASSERT( i == st.trace.size() );
+         TAO_PEGTL_TEST_ASSERT( b == st.trace.size() );
+      }
+      {
+         test_state< false > st;
+         memory_input in( "bb", __FUNCTION__ );
+         std::size_t b = 0;
+         const bool result = parse< test_grammar, test_action, state_control< normal >::type >( in, -1, b, st );
+         TAO_PEGTL_TEST_ASSERT( result );
+         TAO_PEGTL_TEST_ASSERT( !test_action_one );
+         TAO_PEGTL_TEST_ASSERT( !test_action_two );
+         TAO_PEGTL_TEST_ASSERT( st.trace.empty() );
+         TAO_PEGTL_TEST_ASSERT( b == 0 );
+      }
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
index 074c701f71d2eed0486754949762ede23348fd3b..a6f20b1a04b4d87febd4877f128a57cdeac3c339 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
@@ -7,8 +7,10 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   using GRAMMAR = sor< failure, one< 'a' > >;
+   using GRAMMAR1 = sor< failure, one< 'a' > >;
    using GRAMMAR2 = seq< one< 'a' >, any, any, any, any, one< 'b' >, eof >;
+   using GRAMMAR3 = sor< one< 'a' >, one< 'b' > >;
+   using GRAMMAR4 = try_catch< sor< one< 'a' >, must< one< 'b' > > > >;
 
    template< typename Rule >
    struct trace_action
@@ -28,7 +30,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template<>
-   struct trace_action< GRAMMAR >
+   struct trace_action< GRAMMAR1 >
    {
       template< typename... Ts >
       static void apply( Ts&&... /*unused*/ )
@@ -41,47 +43,41 @@ namespace TAO_PEGTL_NAMESPACE
    {
       {
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, nothing, trace_control >( in );
+         const auto result = standard_trace< GRAMMAR1 >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 0 );
          TAO_PEGTL_TEST_ASSERT( a == 0 );
       }
       {
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, trace_action, trace_control >( in );
+         const auto result = standard_trace< GRAMMAR1, trace_action >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 1 );
          TAO_PEGTL_TEST_ASSERT( a == 1 );
       }
       {
-         trace_state ts;
-         memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, nothing, trace_control >( in, ts );
+         memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
+         const auto result = standard_trace< GRAMMAR2 >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 1 );
          TAO_PEGTL_TEST_ASSERT( a == 1 );
       }
       {
-         trace_state ts;
-         memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, trace_action, trace_control >( in, ts );
+         memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
+         const auto result = standard_trace< GRAMMAR2, trace_action >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 2 );
-         TAO_PEGTL_TEST_ASSERT( a == 2 );
+         TAO_PEGTL_TEST_ASSERT( a == 1 );
       }
       {
-         trace_state ts;
-         memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
-         const auto result = parse< GRAMMAR2, nothing, trace_control >( in, ts );
-         TAO_PEGTL_TEST_ASSERT( result );
-         TAO_PEGTL_TEST_ASSERT( a0 == 2 );
-         TAO_PEGTL_TEST_ASSERT( a == 2 );
+         memory_input in( "c", "trace test please ignore" );
+         const auto result = standard_trace< GRAMMAR3 >( in );
+         TAO_PEGTL_TEST_ASSERT( !result );
       }
       {
-         trace_state ts;
-         memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
-         const auto result = parse< GRAMMAR2, trace_action, trace_control >( in, ts );
-         TAO_PEGTL_TEST_ASSERT( result );
+         memory_input in( "c", "trace test please ignore" );
+         const auto result = standard_trace< GRAMMAR4 >( in );
+         TAO_PEGTL_TEST_ASSERT( !result );
       }
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/contrib_uri.cpp b/packages/PEGTL/src/test/pegtl/contrib_uri.cpp
index a35ce90992ce71826711abb2d3131b629ec110a8..e77c3996744537c9fc4692705b359ced4de14e94 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_uri.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_uri.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_fail.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 #include <tao/pegtl/contrib/uri.hpp>
diff --git a/packages/PEGTL/src/test/pegtl/control_unwind.cpp b/packages/PEGTL/src/test/pegtl/control_unwind.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad7d1251b84831c605f45256dc4b1e0f29318a8d
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/control_unwind.cpp
@@ -0,0 +1,70 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <tao/pegtl.hpp>
+
+#include "test.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   struct r
+      : seq< alpha, digit >
+   {};
+
+   template< typename R >
+   struct a
+      : nothing< R >
+   {};
+
+   template< typename R >
+   struct c
+      : normal< R >
+   {};
+
+   unsigned flags = 0;
+
+   template<>
+   struct a< alpha >
+   {
+      static void apply0()
+      {
+         flags |= 1;
+      }
+   };
+
+   template<>
+   struct a< digit >
+   {
+      static void apply0()
+      {
+         throw 42;
+      }
+   };
+
+   template<>
+   struct c< r >
+      : normal< r >
+   {
+      template< typename Input >
+      static void unwind( const Input& /*unused*/ )
+      {
+         flags |= 2;
+      }
+   };
+
+   void unit_test()
+   {
+      memory_input in( "a1", __FUNCTION__ );
+      try {
+         parse< r, a, c >( in );
+         TAO_PEGTL_TEST_ASSERT( false );
+      }
+      catch( const int& e ) {
+         TAO_PEGTL_TEST_ASSERT( e == 42 );
+      }
+      TAO_PEGTL_TEST_ASSERT( flags == 3 );
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/demangle.cpp b/packages/PEGTL/src/test/pegtl/demangle.cpp
index ee76d1db381833e12ee8df9d72c3792c0c18eb21..8288a5d87ca48d9abf703692f1630b9da73bd198 100644
--- a/packages/PEGTL/src/test/pegtl/demangle.cpp
+++ b/packages/PEGTL/src/test/pegtl/demangle.cpp
@@ -3,14 +3,14 @@
 
 #include "test.hpp"
 
-#include <tao/pegtl/internal/demangle.hpp>
+#include <tao/pegtl/demangle.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
 {
    template< typename T >
    void test( const std::string& s )
    {
-      TAO_PEGTL_TEST_ASSERT( internal::demangle< T >() == s );
+      TAO_PEGTL_TEST_ASSERT( demangle< T >() == s );
    }
 
    void unit_test()
@@ -23,6 +23,7 @@ namespace TAO_PEGTL_NAMESPACE
 #elif defined( _MSC_VER )
       test< int >( "int" );
       test< double >( "double" );
+      // in the Microsoft world, class and struct are not the same!
       test< seq< bytes< 42 >, eof > >( "struct tao::pegtl::seq<struct tao::pegtl::bytes<42>,struct tao::pegtl::eof>" );
 #else
       test< int >( "int" );
diff --git a/packages/PEGTL/src/test/pegtl/enable_control.cpp b/packages/PEGTL/src/test/pegtl/enable_control.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..672b4a4a932c97c6baf202d030dc5ee81aa805ae
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/enable_control.cpp
@@ -0,0 +1,70 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <tao/pegtl.hpp>
+
+#include "test.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   struct r
+      : seq< internal::seq< any > >
+   {};
+
+   static_assert( !internal::enable_control< internal::seq< any > > );
+   static_assert( internal::enable_control< seq< any > > );
+   static_assert( !internal::enable_control< internal::seq< internal::seq< any > > > );
+   static_assert( internal::enable_control< seq< internal::seq< any > > > );
+   static_assert( internal::enable_control< r > );
+
+   static_assert( !normal< internal::seq< any > >::enable );
+   static_assert( normal< seq< any > >::enable );
+   static_assert( !normal< internal::seq< internal::seq< any > > >::enable );
+   static_assert( normal< seq< internal::seq< any > > >::enable );
+   static_assert( normal< r >::enable );
+
+   template< typename R >
+   struct a
+      : nothing< R >
+   {};
+
+   unsigned flags = 0;
+
+   template<>
+   struct a< r >
+   {
+      static void apply0()
+      {
+         flags |= 0x01;
+      }
+   };
+
+   template<>
+   struct a< any >
+   {
+      static void apply0()
+      {
+         flags |= 0x02;
+      }
+   };
+
+   template<>
+   struct a< internal::seq< any > >
+   {
+      static void apply0()
+      {
+         flags |= 0x10;
+      }
+   };
+
+   void unit_test()
+   {
+      memory_input in( "a", __FUNCTION__ );
+      const bool b = parse< r, a >( in );
+      TAO_PEGTL_TEST_ASSERT( b );
+      TAO_PEGTL_TEST_ASSERT( flags == 3 );
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/error_message.cpp b/packages/PEGTL/src/test/pegtl/error_message.cpp
index 05870afbaf6e2ff595f9eefec1e27fdd6f8543c1..ff4d1780e9d69ce85a727d1d181c98fdb9168d95 100644
--- a/packages/PEGTL/src/test/pegtl/error_message.cpp
+++ b/packages/PEGTL/src/test/pegtl/error_message.cpp
@@ -13,7 +13,7 @@ namespace test1
    struct grammar : sor< a, b > {};
 
    template< typename > inline constexpr const char* error_message = nullptr;
-   template<> inline constexpr auto error_message< test1::a > = "test123";
+   template<> inline constexpr auto error_message< test1::b > = "test123";
 
    struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
    template< typename Rule > using control = must_if< error >::control< Rule >;
@@ -26,11 +26,11 @@ namespace TAO_PEGTL_NAMESPACE
    void unit_test()
    {
       try {
-         parse< test1::grammar, nothing, test1::control >( memory_input( "b", __FUNCTION__ ) );
+         parse< test1::grammar, nothing, test1::control >( memory_input( "c", __FUNCTION__ ) );
          TAO_PEGTL_TEST_ASSERT( false );
       }
       catch( const parse_error& e ) {
-         if( e.what() != std::string( "test123" ) ) {
+         if( e.message() != "test123" ) {
             throw;
          }
       }
diff --git a/packages/PEGTL/src/test/pegtl/file_read.cpp b/packages/PEGTL/src/test/pegtl/file_read.cpp
index 00b0184ee21b5190136da3c3334549a952f87bee..66f52fdd54e348df8d2265be8aec14dee403f51a 100644
--- a/packages/PEGTL/src/test/pegtl/file_read.cpp
+++ b/packages/PEGTL/src/test/pegtl/file_read.cpp
@@ -10,12 +10,8 @@ namespace TAO_PEGTL_NAMESPACE
    struct open_input
       : public read_input< P, Eol >
    {
-      explicit open_input( const char* in_filename )
-         : read_input< P, Eol >( internal::file_open( in_filename ), in_filename )
-      {}
-
-      explicit open_input( const std::string& in_filename )
-         : open_input( in_filename.c_str() )
+      explicit open_input( const std::filesystem::path& path )
+         : read_input< P, Eol >( internal::file_open( path ), path )
       {}
    };
 
diff --git "a/packages/PEGTL/src/test/pegtl/file_\303\244\303\266\303\274\360\235\204\236_data.txt" "b/packages/PEGTL/src/test/pegtl/file_\303\244\303\266\303\274\360\235\204\236_data.txt"
new file mode 100644
index 0000000000000000000000000000000000000000..d1c7bba09c907f77a6eb263e90b8a5d5b7873a7e
--- /dev/null
+++ "b/packages/PEGTL/src/test/pegtl/file_\303\244\303\266\303\274\360\235\204\236_data.txt"
@@ -0,0 +1,11 @@
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
+dummy content
diff --git a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
index 567ed28a6e1a1acd846e5831f00eba31cfb008e1..99133ba8b0638b9da36e5498b38f20e4df7f20cc 100644
--- a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
+++ b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
@@ -16,12 +16,21 @@ namespace TAO_PEGTL_NAMESPACE
          std::cerr << "pegtl: unit test failed for [ internal::file_mapper ]" << std::endl;
          ++failed;
       }
-      catch( const std::system_error& e ) {
+      catch( const std::system_error& ) {
       }
       catch( ... ) {
          std::cerr << "pegtl: unit test failed for [ internal::file_mapper ] with unexpected exception" << std::endl;
          ++failed;
       }
+
+      const std::string s = "dummy content\n";
+      const std::string dummy_content = s + s + s + s + s + s + s + s + s + s + s;
+
+      internal::file_mapper mapper( "src/test/pegtl/file_data.txt" );
+      TAO_PEGTL_TEST_ASSERT( !mapper.empty() );
+      TAO_PEGTL_TEST_ASSERT( mapper.size() == 154 );
+      TAO_PEGTL_TEST_ASSERT( std::string_view( mapper.data(), mapper.size() ) == dummy_content );
+      TAO_PEGTL_TEST_ASSERT( std::string_view( mapper.begin(), mapper.end() - mapper.begin() ) == dummy_content );
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/parse_error.cpp b/packages/PEGTL/src/test/pegtl/parse_error.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6cab22e9a71bb7982b9162cc70e4bbf880ca2af1
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/parse_error.cpp
@@ -0,0 +1,59 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+
+#include "verify_meta.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< tracking_mode M >
+   void unit_test()
+   {
+      const std::string rulename{ demangle< digit >() };
+
+      memory_input< M > in( "foo\nbar bla blubb\nbaz", "test_source" );
+
+      try {
+         parse< seq< identifier, eol, identifier, one< ' ' >, must< digit > > >( in );
+      }
+      catch( const parse_error& e ) {
+         TAO_PEGTL_TEST_ASSERT( e.what() == "test_source:2:5: parse error matching " + rulename );
+
+         TAO_PEGTL_TEST_ASSERT( e.message() == "parse error matching " + rulename );
+
+         TAO_PEGTL_TEST_ASSERT( e.positions().size() == 1 );
+         const auto& p = e.positions().front();
+
+         TAO_PEGTL_TEST_ASSERT( p.byte == 8 );
+         TAO_PEGTL_TEST_ASSERT( p.line == 2 );
+         TAO_PEGTL_TEST_ASSERT( p.column == 5 );
+         TAO_PEGTL_TEST_ASSERT( p.source == "test_source" );
+
+         TAO_PEGTL_TEST_ASSERT( in.line_at( p ) == "bar bla blubb" );
+
+         position p2 = p;
+         p2.source = "foo";
+         p2.line = 42;
+         p2.column = 123;
+
+         parse_error e2 = e;
+         e2.add_position( std::move( p2 ) );
+
+         TAO_PEGTL_TEST_ASSERT( e2.what() == "foo:42:123: test_source:2:5: parse error matching " + rulename );
+         TAO_PEGTL_TEST_ASSERT( e.what() == "test_source:2:5: parse error matching " + rulename );
+
+         return;
+      }
+      TAO_PEGTL_TEST_UNREACHABLE;
+   }
+
+   void unit_test()
+   {
+      unit_test< tracking_mode::eager >();
+      unit_test< tracking_mode::lazy >();
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/position.cpp b/packages/PEGTL/src/test/pegtl/position.cpp
index 92e8e45a0d64692e4bc42ab02c1ca54df1667749..c1912679067f95fd543519135bf6b5eaeb4a7bbd 100644
--- a/packages/PEGTL/src/test/pegtl/position.cpp
+++ b/packages/PEGTL/src/test/pegtl/position.cpp
@@ -24,7 +24,7 @@ namespace TAO_PEGTL_NAMESPACE
 
       TAO_PEGTL_TEST_ASSERT( parse< Rule >( i1 ) );
       TAO_PEGTL_TEST_ASSERT( i1.line() == 2 );
-      TAO_PEGTL_TEST_ASSERT( i1.byte_in_line() == 0 );
+      TAO_PEGTL_TEST_ASSERT( i1.column() == 1 );
    }
 
    template< typename Rule, typename ParseInput = memory_input<> >
@@ -36,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE
 
       TAO_PEGTL_TEST_ASSERT( parse< Rule >( i2 ) );
       TAO_PEGTL_TEST_ASSERT( i2.line() == 1 );
-      TAO_PEGTL_TEST_ASSERT( i2.byte_in_line() == 1 );
+      TAO_PEGTL_TEST_ASSERT( i2.column() == 2 );
    }
 
    template< typename Rule, typename ParseInput = memory_input<> >
@@ -48,7 +48,7 @@ namespace TAO_PEGTL_NAMESPACE
 
       TAO_PEGTL_TEST_ASSERT( !parse< Rule >( i3 ) );
       TAO_PEGTL_TEST_ASSERT( i3.line() == 1 );
-      TAO_PEGTL_TEST_ASSERT( i3.byte_in_line() == 0 );
+      TAO_PEGTL_TEST_ASSERT( i3.column() == 1 );
    }
 
    struct outer_grammar
@@ -73,7 +73,7 @@ namespace TAO_PEGTL_NAMESPACE
          TAO_PEGTL_TEST_ASSERT( p.source == "outer" );
          TAO_PEGTL_TEST_ASSERT( p.byte == 2 );
          TAO_PEGTL_TEST_ASSERT( p.line == 1 );
-         TAO_PEGTL_TEST_ASSERT( p.byte_in_line == 2 );
+         TAO_PEGTL_TEST_ASSERT( p.column == 3 );
          memory_input in( "dFF", "inner" );
          parse_nested< inner_grammar >( oi, in );
       }
@@ -87,15 +87,15 @@ namespace TAO_PEGTL_NAMESPACE
          parse< outer_grammar, outer_action >( oi );
       }
       catch( const parse_error& e ) {
-         TAO_PEGTL_TEST_ASSERT( e.positions.size() == 2 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 0 ].source == "inner" );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 0 ].byte == 1 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 0 ].line == 1 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 0 ].byte_in_line == 1 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 1 ].source == "outer" );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 1 ].byte == 2 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 1 ].line == 1 );
-         TAO_PEGTL_TEST_ASSERT( e.positions[ 1 ].byte_in_line == 2 );
+         TAO_PEGTL_TEST_ASSERT( e.positions().size() == 2 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 0 ].source == "inner" );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 0 ].byte == 1 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 0 ].line == 1 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 0 ].column == 2 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 1 ].source == "outer" );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 1 ].byte == 2 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 1 ].line == 1 );
+         TAO_PEGTL_TEST_ASSERT( e.positions()[ 1 ].column == 3 );
       }
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_action.cpp b/packages/PEGTL/src/test/pegtl/rule_action.cpp
index 6b0c1c0dc0f11c0eefc7d50b512d49837ee42ee0..2e5096da0c437c788d73ddf50d032bcb6d5b9065 100644
--- a/packages/PEGTL/src/test/pegtl/rule_action.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_action.cpp
@@ -2,6 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_apply.cpp b/packages/PEGTL/src/test/pegtl/rule_apply.cpp
index 92bf49220e739f065c782161800b5156ed46a9a6..147e27936eb67e2179a8725a5aa16585365daa50 100644
--- a/packages/PEGTL/src/test/pegtl/rule_apply.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_apply.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
index 4a25a5b3922409bcaa610d1b4fd7e019a1fbe094..1a5aebe7744ae421732a66289a017599bb9c1c20 100644
--- a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_at.cpp b/packages/PEGTL/src/test/pegtl/rule_at.cpp
index 3d7f6dd484ed45ca35161a6476779f30f2c61c95..0fd1626781d3ca9eb6c25ec2d31836b2fe02e7c8 100644
--- a/packages/PEGTL/src/test/pegtl/rule_at.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_at.cpp
@@ -2,7 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_bof.cpp b/packages/PEGTL/src/test/pegtl/rule_bof.cpp
index ee02311678a3825ed5eafe01ad55a3ebe8f1ecc6..996505c1645ad9bd9ec9273a6ffba2e231a67429 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bof.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bof.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_bol.cpp b/packages/PEGTL/src/test/pegtl/rule_bol.cpp
index d50a41bbedba9aa926a55784b3019fe599bd2f46..cda3de5a6ae3a24dedfef17d68582aa765db51cb 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bol.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bol.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
index 9485df93ff904fbc19338ed999d033c1ee8716c0..ea20546d3b80c25fe28db9512c6c05faad23a70d 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_control.cpp b/packages/PEGTL/src/test/pegtl/rule_control.cpp
index 7153086e24c9e34bdcbd0d5ddc56fec1e54a6fee..214e536b7010ea6f1d04dbeff3ce4e35c29e0645 100644
--- a/packages/PEGTL/src/test/pegtl/rule_control.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_control.cpp
@@ -2,6 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_disable.cpp b/packages/PEGTL/src/test/pegtl/rule_disable.cpp
index f48626d9e5be265c60b4a988cd5e66e8f7b2b9b6..f3b67b8ff55ab248327c465cb5fa1aec9d5258ed 100644
--- a/packages/PEGTL/src/test/pegtl/rule_disable.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_disable.cpp
@@ -2,6 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_discard.cpp b/packages/PEGTL/src/test/pegtl/rule_discard.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5cb4b52d3a15784cbee390b2d7695a474612cdd7
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/rule_discard.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+
+#include "verify_meta.hpp"
+#include "verify_rule.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   void unit_test()
+   {
+      verify_meta< discard, internal::discard >();
+
+      verify_analyze< discard >( __LINE__, __FILE__, false, false );
+
+      verify_rule< discard >( __LINE__, __FILE__, "", result_type::success, 0 );
+
+      for( char i = 1; i < 127; ++i ) {
+         char t[] = { i, 0 };
+         verify_rule< discard >( __LINE__, __FILE__, std::string( t ), result_type::success, 1 );
+      }
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/rule_enable.cpp b/packages/PEGTL/src/test/pegtl/rule_enable.cpp
index 121b18ce458da1c145df3f132f74fbb8ee3975e0..b045319e4b76b4d1185ee73ea64d321746a3fa19 100644
--- a/packages/PEGTL/src/test/pegtl/rule_enable.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_enable.cpp
@@ -2,6 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_eof.cpp b/packages/PEGTL/src/test/pegtl/rule_eof.cpp
index 2d200d564fc3b920ebe9cf120e0550fe5bd0f725..f608a1597d745b5de5fc8a2fcd35705ff1be4a89 100644
--- a/packages/PEGTL/src/test/pegtl/rule_eof.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_eof.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_failure.cpp b/packages/PEGTL/src/test/pegtl/rule_failure.cpp
index 2f116fa201fccec496bdf9a7d9deaf6a2db7288a..9beb769b89ce0d27079fffd66e323868b8fd29a5 100644
--- a/packages/PEGTL/src/test/pegtl/rule_failure.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_failure.cpp
@@ -2,8 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
 #include "verify_char.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
index 51ef74024c5e9bc45e83701b1f4c8fde7e5a10c2..54297f01d46e7e63e6b6d39c3253581a0bf31c03 100644
--- a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_list.cpp b/packages/PEGTL/src/test/pegtl/rule_list.cpp
index 08748154bc642f35494232acec7f526c323f3fe6..dfd789f75236b2283e54a81a0a20e90519c32c09 100644
--- a/packages/PEGTL/src/test/pegtl/rule_list.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_list.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_list_must.cpp b/packages/PEGTL/src/test/pegtl/rule_list_must.cpp
index 980a4214dc75169bf3749003187aa520a8ccce77..b036d33ce36ff105065c25e90f6e60ac138f39af 100644
--- a/packages/PEGTL/src/test/pegtl/rule_list_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_list_must.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp b/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp
index 02b18f1c5d62ade3db9698d1a7c606fb46f9b779..e121f083b2e43e9c0b7c615614680c727f9188ed 100644
--- a/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_list_tail.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_minus.cpp b/packages/PEGTL/src/test/pegtl/rule_minus.cpp
index b7c3431b30d899063fb5374d4660a33d26f83a19..8c55093e00cdb4c27bb155ccb90820b7ca32a113 100644
--- a/packages/PEGTL/src/test/pegtl/rule_minus.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_minus.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
index 7fe69a528d45ab2e6501c1d0f4abee690c685ff7..25dfc9648631ddecb9673b16c9b2eb170ce11f04 100644
--- a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
@@ -2,7 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_opt.cpp
index 05507c8c559c188671408d4dd3fdb7cbc71af81c..3c300b9a59a6bb7ba5c6fb7654938a704909a87a 100644
--- a/packages/PEGTL/src/test/pegtl/rule_opt.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_opt.cpp
@@ -2,7 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp b/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp
index 783b0d994cb14c8b9bda715ce80b7f527433c5c7..e13ef58af6f34396e5444c497241c5b5d1d72873 100644
--- a/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_opt_must.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_pad.cpp b/packages/PEGTL/src/test/pegtl/rule_pad.cpp
index 5e495b7d587dcb7602a3ed8c3de4e5528e2b1714..a3151dc20a7aca37a218cf7d3b48d1a553064874 100644
--- a/packages/PEGTL/src/test/pegtl/rule_pad.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_pad.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp
index 7b63fcd7566a8e8c2182ea56821f2f7ed7aea59e..bb06f3e483605f623bcbb6ef219207a5a91d29fb 100644
--- a/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_pad_opt.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_plus.cpp b/packages/PEGTL/src/test/pegtl/rule_plus.cpp
index 6882ebfced1f7765c662060b070fff3667ab24d7..6345b4a46a5cc56368d30e4eebce9bc70b16588e 100644
--- a/packages/PEGTL/src/test/pegtl/rule_plus.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_plus.cpp
@@ -2,13 +2,17 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< plus< alpha >, internal::plus< alpha >, alpha >();
+      verify_meta< plus< alpha, digit >, internal::plus< internal::seq< alpha, digit > >, internal::seq< alpha, digit > >();
+
       verify_analyze< plus< eof > >( __LINE__, __FILE__, false, true );
       verify_analyze< plus< any > >( __LINE__, __FILE__, true, false );
       verify_analyze< plus< eof, eof, eof > >( __LINE__, __FILE__, false, true );
diff --git a/packages/PEGTL/src/test/pegtl/rule_raise.cpp b/packages/PEGTL/src/test/pegtl/rule_raise.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..565df60d294c3f90d8546d53fd9018981db0d7fe
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/rule_raise.cpp
@@ -0,0 +1,37 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+
+#include "verify_meta.hpp"
+
+#if defined( _MSC_VER )
+#pragma warning( push )
+#pragma warning( disable : 4702 )
+#endif
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   void unit_test()
+   {
+      verify_meta< raise< int >, internal::raise< int > >();
+      verify_meta< raise< any >, internal::raise< any > >();
+
+      verify_analyze< raise< int > >( __LINE__, __FILE__, true, false );
+      verify_analyze< raise< any > >( __LINE__, __FILE__, true, false );
+
+      memory_input in( "foo", __FUNCTION__ );
+
+      TAO_PEGTL_TEST_THROWS( parse< raise< int > >( in ) );
+      TAO_PEGTL_TEST_ASSERT( in.size( 4 ) == 3 );
+      TAO_PEGTL_TEST_THROWS( parse< raise< any > >( in ) );
+      TAO_PEGTL_TEST_ASSERT( in.size( 4 ) == 3 );
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#if defined( _MSC_VER )
+#pragma warning( pop )
+#endif
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
index 6eec3dba03df0aa960660d090371929d39e2845e..ee467deee34864932f88d88e7c1144881fdb9011 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_rep.cpp b/packages/PEGTL/src/test/pegtl/rule_rep.cpp
index d57410382c60e1940b46ea148b32990f45122fea..b4bd7f97abd7f596e0e391741824c7e111bc54a9 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rep.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rep.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp
index 09b52e8587b2845cfdc5b4bba324c2675a5e48fa..db1205a68e79ba15dca8f677006d539d567ece23 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rep_max.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp
index 73fc6ea3797ac73125756d4dd7ad9700d132f4ed..c3648b94d43c67feb8c1b71938ba0422c517689a 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rep_min.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp
index 0833aa62c5b558f9f8bd555f272c33a3037e46cf..de847617749f3ff0d6756d6b6c415608fb92aa9e 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rep_min_max.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp
index 4c66f6eac4070464a368a8c86b51dfeac70fb9a3..5d3cbc708b6c624d6e1301cb3ec051b353efde72 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rep_opt.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_require.cpp b/packages/PEGTL/src/test/pegtl/rule_require.cpp
index 0d2ce914743f822b7cd8cb7f31ccca0c1b02e56d..4f4206696f49641626100bc79f5721ba15cf3c34 100644
--- a/packages/PEGTL/src/test/pegtl/rule_require.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_require.cpp
@@ -2,13 +2,17 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< require< 0 >, internal::success >();
+      verify_meta< require< 1 >, internal::require< 1 > >();
+
       verify_analyze< require< 0 > >( __LINE__, __FILE__, false, false );
       verify_analyze< require< 1 > >( __LINE__, __FILE__, false, false );
       verify_analyze< require< 9 > >( __LINE__, __FILE__, false, false );
diff --git a/packages/PEGTL/src/test/pegtl/rule_seq.cpp b/packages/PEGTL/src/test/pegtl/rule_seq.cpp
index 22505494a0df37cfee9b0523ef65df5b4335d9c9..c5e3722b3d3c419e05669fdc0dfe668a2c9f281c 100644
--- a/packages/PEGTL/src/test/pegtl/rule_seq.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_seq.cpp
@@ -2,12 +2,18 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< seq<>, internal::success >();
+      verify_meta< seq< alpha >, internal::seq< alpha >, alpha >();
+      verify_meta< seq< alpha, digit >, internal::seq< alpha, digit >, alpha, digit >();
+
       verify_seqs< seq >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_sor.cpp b/packages/PEGTL/src/test/pegtl/rule_sor.cpp
index b0792b4432c7b68b6f14ac4cbe3fa87c3aa2d69c..11eb9a623619aa5d3aa546f5a13bd9c7693bb3ce 100644
--- a/packages/PEGTL/src/test/pegtl/rule_sor.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_sor.cpp
@@ -2,13 +2,18 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< sor<>, internal::failure >();
+      verify_meta< sor< alpha >, internal::sor< alpha >, alpha >();
+      verify_meta< sor< alpha, digit >, internal::sor< alpha, digit >, alpha, digit >();
+
       verify_analyze< sor< eof > >( __LINE__, __FILE__, false, false );
       verify_analyze< sor< any > >( __LINE__, __FILE__, true, false );
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_star.cpp b/packages/PEGTL/src/test/pegtl/rule_star.cpp
index 8cfaa6ca695a69d54eac63338bac3c5dbaa93215..f870d6a4c475e721f595a29516c721d8b49198fa 100644
--- a/packages/PEGTL/src/test/pegtl/rule_star.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_star.cpp
@@ -2,13 +2,17 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< star< alpha >, internal::star< alpha >, alpha >();
+      verify_meta< star< alpha, digit >, internal::star< internal::seq< alpha, digit > >, internal::seq< alpha, digit > >();
+
       verify_analyze< star< eof > >( __LINE__, __FILE__, false, true );
       verify_analyze< star< any > >( __LINE__, __FILE__, false, false );
       verify_analyze< star< eof, eof, eof > >( __LINE__, __FILE__, false, true );
diff --git a/packages/PEGTL/src/test/pegtl/rule_star_must.cpp b/packages/PEGTL/src/test/pegtl/rule_star_must.cpp
index e0f863a3f45860fab3940b56f250067ef9e5d26b..0a6410ad554db9e40ca1c1288bdb7ce5cc3a56ee 100644
--- a/packages/PEGTL/src/test/pegtl/rule_star_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_star_must.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/rule_state.cpp b/packages/PEGTL/src/test/pegtl/rule_state.cpp
index 77ed17f01bb18186b64b8f6a6b2dd2ffa7647d0b..c940ac224445716b15358e941b6ea77bd15ff108 100644
--- a/packages/PEGTL/src/test/pegtl/rule_state.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_state.cpp
@@ -2,6 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_seqs.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
@@ -22,6 +24,10 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
+      verify_meta< state< test_state_state >, internal::success >();
+      verify_meta< state< test_state_state, any >, internal::state< test_state_state, any >, any >();
+      verify_meta< state< test_state_state, alpha, digit >, internal::state< test_state_state, internal::seq< alpha, digit > >, internal::seq< alpha, digit > >();
+
       verify_seqs< test_state_rule >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_success.cpp b/packages/PEGTL/src/test/pegtl/rule_success.cpp
index fcaff87acb0fd6f9562dedb90f4c7fd2ba78116e..a6917da3c701a709ca8a2eb24956ed9ec28d4870 100644
--- a/packages/PEGTL/src/test/pegtl/rule_success.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_success.cpp
@@ -2,13 +2,16 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< success, internal::success >();
+
       verify_analyze< success >( __LINE__, __FILE__, false, false );
 
       verify_rule< success >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_until.cpp b/packages/PEGTL/src/test/pegtl/rule_until.cpp
index f1e49d3946460dcf36194298c3a3b4f07ea7128d..24ab38ef008d8ebec2cfad979862dec765925ace 100644
--- a/packages/PEGTL/src/test/pegtl/rule_until.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_until.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/test.hpp b/packages/PEGTL/src/test/pegtl/test.hpp
index 18868e018cd60583c214a4073059bb9aaa193f71..5b017a559477a5b5fb499fdf2c6312b3f237a17c 100644
--- a/packages/PEGTL/src/test/pegtl/test.hpp
+++ b/packages/PEGTL/src/test/pegtl/test.hpp
@@ -25,7 +25,7 @@ namespace TAO_PEGTL_NAMESPACE
 #define TAO_PEGTL_TEST_FAILED( MeSSaGe )            \
    do {                                             \
       std::cerr << "pegtl: unit test failed for [ " \
-                << internal::demangle< Rule >()     \
+                << tao::demangle< Rule >()          \
                 << " ] "                            \
                 << TAO_PEGTL_TEST_UNWRAP( MeSSaGe ) \
                 << " in line [ "                    \
@@ -67,4 +67,10 @@ namespace TAO_PEGTL_NAMESPACE
       }                                             \
    } while( false )
 
+#define TAO_PEGTL_TEST_UNREACHABLE                                                                                              \
+   do {                                                                                                                         \
+      std::cerr << "Code should be unreachable in " << __FUNCTION__ << " (" << __FILE__ << ':' << __LINE__ << ')' << std::endl; \
+      std::abort();                                                                                                             \
+   } while( false )
+
 #endif
diff --git a/packages/PEGTL/src/test/pegtl/verify_file.hpp b/packages/PEGTL/src/test/pegtl/verify_file.hpp
index 7ac5683c4444ece26b41c569e5f6c831d09bbb94..2f8a16a87eb1a0d7e59b47819cbadc78b4d965e6 100644
--- a/packages/PEGTL/src/test/pegtl/verify_file.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_file.hpp
@@ -8,6 +8,12 @@
 
 #include "test.hpp"
 
+#if defined( _MSC_VER )
+#define TAO_PEGTL_TEST_FILENAME u"src/test/pegtl/file_äöü𝄞_data.txt"
+#else
+#define TAO_PEGTL_TEST_FILENAME "src/test/pegtl/file_äöü𝄞_data.txt"
+#endif
+
 namespace TAO_PEGTL_NAMESPACE
 {
    struct file_content
@@ -51,9 +57,8 @@ namespace TAO_PEGTL_NAMESPACE
    void verify_file()
    {
       {
-         const std::string f{ "src/test/pegtl/no_such_file.txt" };
          try {
-            T in( f );
+            T in( "src/test/pegtl/no_such_file.txt" );
             parse< file_grammar >( in );
             TAO_PEGTL_TEST_ASSERT( !"no error on opening non-existing file" );
          }
@@ -61,43 +66,34 @@ namespace TAO_PEGTL_NAMESPACE
          }
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( "src/test/pegtl/file_data.txt" );
          std::cout << in.source() << std::endl;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
+         TAO_PEGTL_TEST_ASSERT( in.source() == "src/test/pegtl/file_data.txt" );
          TAO_PEGTL_TEST_ASSERT( parse< file_grammar >( in ) );
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
+         TAO_PEGTL_TEST_ASSERT( in.source() == "src/test/pegtl/file_data.txt" );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = true;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          TAO_PEGTL_TEST_ASSERT( parse< file_grammar >( in, flag ) );
          TAO_PEGTL_TEST_ASSERT( flag == true );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          TAO_PEGTL_TEST_ASSERT( parse< file_grammar >( in, flag ) );
          TAO_PEGTL_TEST_ASSERT( flag == false );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          const bool result = parse< file_grammar, file_action >( in, flag );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( flag == true );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          const bool result = parse< file_grammar, nothing, file_control >( in, flag );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( flag == true );
@@ -105,42 +101,31 @@ namespace TAO_PEGTL_NAMESPACE
       const char* foo = "foo";
       const memory_input m( foo, foo + 3, foo );
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          TAO_PEGTL_TEST_ASSERT( parse_nested< file_grammar >( m, in ) );
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = true;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          TAO_PEGTL_TEST_ASSERT( parse_nested< file_grammar >( m, in, flag ) );
          TAO_PEGTL_TEST_ASSERT( flag == true );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          TAO_PEGTL_TEST_ASSERT( parse_nested< file_grammar >( m, in, flag ) );
          TAO_PEGTL_TEST_ASSERT( flag == false );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          const bool result = parse_nested< file_grammar, file_action >( m, in, flag );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( flag == true );
       }
       {
-         const std::string f{ "src/test/pegtl/file_data.txt" };
-         T in( f );
+         T in( TAO_PEGTL_TEST_FILENAME );
          bool flag = false;
-         TAO_PEGTL_TEST_ASSERT( in.source() == f );
          const bool result = parse_nested< file_grammar, nothing, file_control >( m, in, flag );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( flag == true );
diff --git a/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp b/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp
index ac9368178f87a178b186d7fd68c8334a1d42c30f..0e17e8c75a95df897949e4c44301567941a9f1e4 100644
--- a/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_ifmt.hpp
@@ -6,7 +6,7 @@
 
 #include <tao/pegtl.hpp>
 
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/verify_impl.hpp b/packages/PEGTL/src/test/pegtl/verify_impl.hpp
index 83ad2977ca4f4d6abc0e540f594d7bbfbe026ff6..b98cf45a35af2cdcc57fa9297adad95065f1b0c1 100644
--- a/packages/PEGTL/src/test/pegtl/verify_impl.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_impl.hpp
@@ -31,8 +31,7 @@ namespace TAO_PEGTL_NAMESPACE
          return result_type::global_failure;
       }
       catch( ... ) {
-         std::cerr << "Code should be unreachable in " << __FUNCTION__ << " (" << __FILE__ << ':' << __LINE__ << ')' << std::endl;
-         std::abort();
+         TAO_PEGTL_TEST_UNREACHABLE;
       }
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp b/packages/PEGTL/src/test/pegtl/verify_meta.hpp
similarity index 70%
rename from packages/PEGTL/src/test/pegtl/verify_analyze.hpp
rename to packages/PEGTL/src/test/pegtl/verify_meta.hpp
index befefba5b6d8eaf5046aaf672db2719719507718..9c005eb9f197a45cc7edaa1cf12592656421bbb3 100644
--- a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_meta.hpp
@@ -1,8 +1,12 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP
-#define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP
+#ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_META_HPP
+#define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_META_HPP
+
+#include <type_traits>
+
+#include <tao/pegtl/type_list.hpp>
 
 #include <tao/pegtl/contrib/analyze.hpp>
 
@@ -10,6 +14,13 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
+   template< typename Name, typename Rule, typename... Rules >
+   void verify_meta()
+   {
+      static_assert( std::is_same_v< typename Name::rule_t, Rule > );
+      static_assert( std::is_same_v< typename Name::subs_t, type_list< Rules... > > );
+   }
+
    template< typename Rule >
    void verify_analyze( const unsigned line, const char* file, const bool expect_consume, const bool expect_problems )
    {
diff --git a/packages/PEGTL/src/test/pegtl/verify_rule.hpp b/packages/PEGTL/src/test/pegtl/verify_rule.hpp
index fc614e06da2d5a0711f804544a245833de4cd1d3..4ee93a9c8bc228894736da8221f234e2514aa193 100644
--- a/packages/PEGTL/src/test/pegtl/verify_rule.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_rule.hpp
@@ -17,13 +17,6 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   template< typename Name, typename Rule, typename... Rules >
-   void verify_meta()
-   {
-      static_assert( std::is_same_v< typename Name::rule_t, Rule > );
-      static_assert( std::is_same_v< typename Name::subs_t, type_list< Rules... > > );
-   }
-
    template< typename Rule >
    struct verify_action_impl
    {
@@ -47,19 +40,19 @@ namespace TAO_PEGTL_NAMESPACE
          remain = ( expected == result_type::success ) ? 0 : int( data.size() );
       }
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, nothing >( line, file, data, in, expected, remain );
          memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
          verify_impl_one< Rule, nothing >( line, file, data, i2, expected, remain );
       }
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, verify_action_impl >( line, file, data, in, expected, remain );
          memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
          verify_impl_one< Rule, verify_action_impl >( line, file, data, i2, expected, remain );
       }
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, verify_action_impl0 >( line, file, data, in, expected, remain );
          memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
          verify_impl_one< Rule, verify_action_impl0 >( line, file, data, i2, expected, remain );
@@ -70,15 +63,15 @@ namespace TAO_PEGTL_NAMESPACE
    void verify_only( const std::size_t line, const char* file, const std::string& data, const result_type expected, const std::size_t remain )
    {
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, nothing >( line, file, data, in, expected, remain );
       }
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, verify_action_impl >( line, file, data, in, expected, remain );
       }
       {
-         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 0 );
+         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
          verify_impl_one< Rule, verify_action_impl0 >( line, file, data, in, expected, remain );
       }
    }
diff --git a/packages/PEGTL/src/test/pegtl/verify_seqs.hpp b/packages/PEGTL/src/test/pegtl/verify_seqs.hpp
index 82d84b0e8bd026a56d2fb0d911f2e27e4ba10fa4..29c21681233b6682511640ee51cf5732f001f99b 100644
--- a/packages/PEGTL/src/test/pegtl/verify_seqs.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_seqs.hpp
@@ -6,7 +6,7 @@
 
 #include <tao/pegtl.hpp>
 
-#include "verify_analyze.hpp"
+#include "verify_meta.hpp"
 #include "verify_rule.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index 336fb5583fb4e163f37feb30956acbf27cef36ab..61ba912a567c4a6d868d22cc7915e7557f484518 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -3,6 +3,8 @@
 
 #include <pegtl.hpp>
 
+#include <language/utils/ParseError.hpp>
+
 using namespace TAO_PEGTL_NAMESPACE;
 
 namespace language
@@ -325,12 +327,12 @@ struct errors : public normal<Rule>
   static void
   raise(const Input& in, States&&... /*unused*/)
   {
-    throw parse_error(error_message, std::vector{in.position()});
+    throw ParseError(error_message, std::vector{in.position()});
   }
 };
 
 template <typename Rule>
-inline const std::string errors<Rule>::error_message = "parse error matching "+ demangle(internal::demangle< Rule >());
+inline const std::string errors<Rule>::error_message = "parse error matching "+ demangle(tao::demangle< Rule >());
 
 template <>
 inline const std::string errors<language::module_name>::error_message = "parse error, missing module name";
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index 235eab368dccfd2c41dde312a6f24264388a7813..75842ad029795a579a213b2d50bed15bcfb68b30 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -90,14 +90,14 @@ parser(const std::string& filename)
     try {
       parse_and_execute(input);
     }
-    catch (const parse_error& e) {
-      const auto p = e.positions.front();
+    catch (const ParseError& e) {
+      const auto p = e.positions().front();
 
-      std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.byte_in_line << ": " << rang::style::reset
+      std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.column << ": " << rang::style::reset
                 << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset
                 << '\n'
                 << input.line_at(p) << '\n'
-                << std::string(p.byte_in_line, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n';
+                << std::string(p.column, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n';
       finalize();
       std::exit(1);
     }
diff --git a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
index 43bd40932c82310d039f851c9ddc810744c6f72b..e27bd531d743b410ecb381e665bb4af145e4731f 100644
--- a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
@@ -4,6 +4,7 @@
 #include <language/PEGGrammar.hpp>
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 #include <language/node_processor/AffectationProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 #include <utils/Exceptions.hpp>
 
@@ -33,8 +34,8 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: undefined operand type for affectation",
-                          std::vector{n.children[1]->begin()});
+        throw ParseError("unexpected error: undefined operand type for affectation",
+                         std::vector{n.children[1]->begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -83,7 +84,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
             }
           }
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid integral value", std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: invalid integral value", std::vector{n.children[1]->begin()});
           // LCOV_EXCL_STOP
         }
         case ASTNodeDataType::double_t: {
@@ -94,7 +95,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: invalid operand type", std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: invalid operand type", std::vector{n.children[1]->begin()});
         }
           // LCOV_EXCL_STOP
         }
@@ -107,7 +108,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: invalid operand type", std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: invalid operand type", std::vector{n.children[1]->begin()});
         }
           // LCOV_EXCL_STOP
         }
@@ -130,11 +131,11 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
           break;
         }
         default: {
-          throw parse_error("expecting scalar operand type", std::vector{n.children[1]->begin()});
+          throw ParseError("expecting scalar operand type", std::vector{n.children[1]->begin()});
         }
         }
       } else {
-        throw parse_error("invalid affectation operator for " + dataTypeName(n.m_data_type), std::vector{n.begin()});
+        throw ParseError("invalid affectation operator for " + dataTypeName(n.m_data_type), std::vector{n.begin()});
       }
     };
 
@@ -179,8 +180,8 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
           }
             // LCOV_EXCL_START
           default: {
-            throw parse_error("unexpected error: invalid vector dimension for string affectation",
-                              std::vector{n.children[1]->begin()});
+            throw ParseError("unexpected error: invalid vector dimension for string affectation",
+                             std::vector{n.children[1]->begin()});
           }
             // LCOV_EXCL_STOP
           }
@@ -188,13 +189,13 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: undefined operand type for string affectation",
-                            std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: undefined operand type for string affectation",
+                           std::vector{n.children[1]->begin()});
         }
           // LCOV_EXCL_STOP
         }
       } else {
-        throw parse_error("invalid affectation operator for string", std::vector{n.begin()});
+        throw ParseError("invalid affectation operator for string", std::vector{n.begin()});
       }
     };
 
@@ -209,14 +210,14 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: undefined operand type for embedded data affectation",
-                            std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: undefined operand type for embedded data affectation",
+                           std::vector{n.children[1]->begin()});
         }
           // LCOV_EXCL_STOP
         }
       } else {
-        throw parse_error("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'",
-                          std::vector{n.begin()});
+        throw ParseError("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'",
+                         std::vector{n.begin()});
       }
     };
 
@@ -266,8 +267,8 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
             }
               // LCOV_EXCL_START
             default: {
-              throw parse_error("unexpected error: invalid vector dimension for tuple affectation",
-                                std::vector{n.children[1]->begin()});
+              throw ParseError("unexpected error: invalid vector dimension for tuple affectation",
+                               std::vector{n.children[1]->begin()});
             }
               // LCOV_EXCL_STOP
             }
@@ -321,8 +322,8 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
             }
               // LCOV_EXCL_START
             default: {
-              throw parse_error("unexpected error: invalid vector dimension for tuple affectation",
-                                std::vector{n.children[1]->begin()});
+              throw ParseError("unexpected error: invalid vector dimension for tuple affectation",
+                               std::vector{n.children[1]->begin()});
             }
               // LCOV_EXCL_STOP
             }
@@ -330,15 +331,15 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
           }
           // LCOV_EXCL_START
           default: {
-            throw parse_error("unexpected error: undefined operand type for tuple affectation",
-                              std::vector{n.children[1]->begin()});
+            throw ParseError("unexpected error: undefined operand type for tuple affectation",
+                             std::vector{n.children[1]->begin()});
           }
             // LCOV_EXCL_STOP
           }
         }
       } else {
-        throw parse_error("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'",
-                          std::vector{n.begin()});
+        throw ParseError("invalid affectation operator for '" + dataTypeName(n.children[0]->m_data_type) + "'",
+                         std::vector{n.begin()});
       }
     };
 
@@ -378,7 +379,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: unexpected vector dimension", std::vector{n.begin()});
+          throw ParseError("unexpected error: unexpected vector dimension", std::vector{n.begin()});
         }
           // LCOV_EXCL_STOP
         }
@@ -398,8 +399,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         break;
       }
       default: {
-        throw parse_error("unexpected error: undefined value type for affectation",
-                          std::vector{n.children[0]->begin()});
+        throw ParseError("unexpected error: undefined value type for affectation", std::vector{n.children[0]->begin()});
       }
       }
     };
@@ -430,6 +430,6 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
   } else if (n.is_type<language::minuseq_op>()) {
     set_affectation_processor(n, language::minuseq_op{});
   } else {
-    throw parse_error("unexpected error: undefined affectation operator", std::vector{n.begin()});
+    throw ParseError("unexpected error: undefined affectation operator", std::vector{n.begin()});
   }
 }
diff --git a/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp
index e50b84668b6cb11d900554002ade3d6ba2937608..350a4070e9a6bc65906627d54b2e2ed87c403cc6 100644
--- a/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeArraySubscriptExpressionBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <algebra/TinyVector.hpp>
 #include <language/node_processor/ArraySubscriptProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 ASTNodeArraySubscriptExpressionBuilder::ASTNodeArraySubscriptExpressionBuilder(ASTNode& node)
 {
@@ -22,11 +23,11 @@ ASTNodeArraySubscriptExpressionBuilder::ASTNodeArraySubscriptExpressionBuilder(A
       break;
     }
     default: {
-      throw parse_error("unexpected error: invalid array dimension", array_expression.begin());
+      throw ParseError("unexpected error: invalid array dimension", array_expression.begin());
       break;
     }
     }
   } else {
-    throw parse_error("unexpected error: invalid array type", array_expression.begin());
+    throw ParseError("unexpected error: invalid array type", array_expression.begin());
   }
 }
diff --git a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
index 92074474abd0b1109feee7a53537deac2d4e44d4..64ff14deb191921c81e28ef1b3f36a0651ffc0e2 100644
--- a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
@@ -3,6 +3,7 @@
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/BinaryExpressionProcessor.hpp>
 #include <language/node_processor/ConcatExpressionProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(ASTNode& n)
 {
@@ -35,7 +36,7 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
             break;
           }
           default: {
-            throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
+            throw ParseError("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
           }
           }
 
@@ -44,10 +45,10 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
           if (data_type_b == ASTNodeDataType::string_t) {
             n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, std::string>>(n);
           } else {
-            throw parse_error("undefined operand type for binary operator", std::vector{n.begin()});
+            throw ParseError("undefined operand type for binary operator", std::vector{n.begin()});
           }
         } else {
-          throw parse_error("undefined operand type for binary operator", std::vector{n.begin()});
+          throw ParseError("undefined operand type for binary operator", std::vector{n.begin()});
         }
       } else if constexpr (std::is_same_v<DataTA, TinyVector<1>> or std::is_same_v<DataTA, TinyVector<2>> or
                            std::is_same_v<DataTA, TinyVector<3>>) {
@@ -58,15 +59,15 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
             if (data_a.dimension() == data_type_b.dimension()) {
               n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, DataTA>>(n);
             } else {
-              throw parse_error("incompatible dimensions of operands", std::vector{n.begin()});
+              throw ParseError("incompatible dimensions of operands", std::vector{n.begin()});
             }
           } else {
-            throw parse_error("invalid binary operator", std::vector{n.begin()});
+            throw ParseError("invalid binary operator", std::vector{n.begin()});
           }
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid operand type for binary operator",
-                            std::vector{n.children[1]->begin()});
+          throw ParseError("unexpected error: invalid operand type for binary operator",
+                           std::vector{n.children[1]->begin()});
           // LCOV_EXCL_STOP
         }
       } else {
@@ -104,7 +105,7 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
             }
               // LCOV_EXCL_START
             default: {
-              throw parse_error("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
+              throw ParseError("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
             }
               // LCOV_EXCL_STOP
             }
@@ -112,7 +113,7 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
           }
         }
         default: {
-          throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
+          throw ParseError("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
         }
         }
       }
@@ -157,14 +158,14 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
+          throw ParseError("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
         }
           // LCOV_EXCL_STOP
         }
         break;
       }
       default: {
-        throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()});
+        throw ParseError("undefined operand type for binary operator", std::vector{n.children[0]->begin()});
       }
       }
     };
@@ -201,6 +202,6 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
   } else if (n.is_type<language::not_eq_op>()) {
     set_binary_operator_processor(n, language::not_eq_op{});
   } else {
-    throw parse_error("unexpected error: undefined binary operator", std::vector{n.begin()});
+    throw ParseError("unexpected error: undefined binary operator", std::vector{n.begin()});
   }
 }
diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 9d914d7ee4799c9908253ffaa2958180a9d67bd3..6dc726f555219b855e2a125b0ab22b586dec2dad 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -4,6 +4,7 @@
 #include <language/ast/ASTNodeDataTypeFlattener.hpp>
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 #include <language/node_processor/BuiltinFunctionProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 
 PUGS_INLINE std::unique_ptr<IFunctionArgumentConverter>
@@ -29,8 +30,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid argument type for function",
-                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: invalid argument type for function",
+                       std::vector{argument_node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -47,8 +48,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
           return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number);
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid argument dimension",
-                            std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: invalid argument dimension",
+                           std::vector{argument_node_sub_data_type.m_parent_node.begin()});
           // LCOV_EXCL_STOP
         }
       }
@@ -66,8 +67,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid argument type",
-                          std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error: invalid argument type",
+                         std::vector{argument_node_sub_data_type.m_parent_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -78,8 +79,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
           return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number);
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid argument dimension",
-                            std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: invalid argument dimension",
+                           std::vector{argument_node_sub_data_type.m_parent_node.begin()});
           // LCOV_EXCL_STOP
         }
       }
@@ -88,8 +89,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
           return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(argument_number);
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid argument dimension",
-                            std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: invalid argument dimension",
+                           std::vector{argument_node_sub_data_type.m_parent_node.begin()});
           // LCOV_EXCL_STOP
         }
       }
@@ -103,8 +104,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid argument type",
-                          std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error: invalid argument type",
+                         std::vector{argument_node_sub_data_type.m_parent_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -122,8 +123,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid argument type for function",
-                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: invalid argument type for function",
+                       std::vector{argument_node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -213,8 +214,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid argument type for function",
-                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: invalid argument type for function",
+                       std::vector{argument_node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -247,8 +248,8 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: undefined parameter type for function",
-                          std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error: undefined parameter type for function",
+                         std::vector{argument_node_sub_data_type.m_parent_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -286,9 +287,9 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
         }
         // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: unexpected tuple content for function: '" +
-                              dataTypeName(parameter_type) + "'",
-                            std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: unexpected tuple content for function: '" + dataTypeName(parameter_type) +
+                             "'",
+                           std::vector{argument_node_sub_data_type.m_parent_node.begin()});
         }
           // LCOV_EXCL_STOP
         }
@@ -298,16 +299,16 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: unexpected tuple content type for function",
-                          std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error: unexpected tuple content type for function",
+                         std::vector{argument_node_sub_data_type.m_parent_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined parameter type for function",
-                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: undefined parameter type for function",
+                       std::vector{argument_node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -356,7 +357,7 @@ ASTNodeBuiltinFunctionExpressionBuilder::_buildArgumentProcessors(
     std::ostringstream error_message;
     error_message << "bad number of arguments: expecting " << rang::fgB::yellow << parameters_number
                   << rang::style::reset << ", provided " << rang::fgB::yellow << arguments_number << rang::style::reset;
-    throw parse_error(error_message.str(), argument_nodes.begin());
+    throw ParseError(error_message.str(), argument_nodes.begin());
   }
 
   for (size_t i = 0; i < arguments_number; ++i) {
diff --git a/src/language/ast/ASTNodeDataType.cpp b/src/language/ast/ASTNodeDataType.cpp
index 18b812c0e7bb7c62466a7bce6b1dfd279eacec43..c77659d983c58a571ac3dd8426437be6478ceddb 100644
--- a/src/language/ast/ASTNodeDataType.cpp
+++ b/src/language/ast/ASTNodeDataType.cpp
@@ -2,17 +2,18 @@
 
 #include <language/PEGGrammar.hpp>
 #include <language/ast/ASTNode.hpp>
+#include <language/utils/ParseError.hpp>
 #include <utils/PugsAssert.hpp>
 
 ASTNodeDataType
 getVectorDataType(const ASTNode& type_node)
 {
   if (not(type_node.is_type<language::vector_type>() and (type_node.children.size() == 2))) {
-    throw parse_error("unexpected node type", type_node.begin());
+    throw ParseError("unexpected node type", type_node.begin());
   }
   ASTNode& dimension_node = *type_node.children[1];
   if (not dimension_node.is_type<language::integer>()) {
-    throw parse_error("unexpected non integer constant dimension", dimension_node.begin());
+    throw ParseError("unexpected non integer constant dimension", dimension_node.begin());
   }
   const size_t dimension = std::stol(dimension_node.string());
   return ASTNodeDataType{ASTNodeDataType::vector_t, dimension};
diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp
index 96ff62bfc20cd9a6526f140d14a4cee7218e241d..7da94cc5f7d00132b226f8ba0e7e5d95d4097b35 100644
--- a/src/language/ast/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp
@@ -3,6 +3,7 @@
 #include <language/PEGGrammar.hpp>
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 #include <utils/PugsAssert.hpp>
 
@@ -17,7 +18,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
               << type_node.string() << rang::style::reset << rang::style::bold << " differs from number of variables ("
               << name_node.children.size() << ") " << rang::fgB::yellow << name_node.string() << rang::style::reset
               << std::ends;
-      throw parse_error(message.str(), name_node.begin());
+      throw ParseError(message.str(), name_node.begin());
     }
 
     for (size_t i = 0; i < type_node.children.size(); ++i) {
@@ -47,12 +48,12 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
 
         const auto [i_type_symbol, found] = symbol_table.find(type_name_id, content_node->begin());
         if (not found) {
-          throw parse_error("undefined type identifier", std::vector{content_node->begin()});
+          throw ParseError("undefined type identifier", std::vector{content_node->begin()});
         } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) {
           std::ostringstream os;
           os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '"
              << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends;
-          throw parse_error(os.str(), std::vector{content_node->begin()});
+          throw ParseError(os.str(), std::vector{content_node->begin()});
         }
 
         content_node->m_data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id};
@@ -84,19 +85,19 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
 
       auto [i_type_symbol, found] = symbol_table.find(type_name_id, type_node.begin());
       if (not found) {
-        throw parse_error("undefined type identifier", std::vector{type_node.begin()});
+        throw ParseError("undefined type identifier", std::vector{type_node.begin()});
       } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) {
         std::ostringstream os;
         os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '"
            << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends;
-        throw parse_error(os.str(), std::vector{type_node.begin()});
+        throw ParseError(os.str(), std::vector{type_node.begin()});
       }
 
       data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id};
     }
 
     if (name_node.is_type<language::name_list>()) {
-      throw parse_error("unexpected variable list for single space", std::vector{name_node.begin()});
+      throw ParseError("unexpected variable list for single space", std::vector{name_node.begin()});
     }
 
     Assert(name_node.is_type<language::name>());
@@ -196,7 +197,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
                   << parameters_domain_node.string() << rang::style::reset << rang::style::bold
                   << " differs from number of variables (" << nb_parameter_names << ") " << rang::fgB::yellow
                   << parameters_name_node.string() << rang::style::reset << std::ends;
-          throw parse_error(message.str(), parameters_domain_node.begin());
+          throw ParseError(message.str(), parameters_domain_node.begin());
         }
 
         auto simple_type_allocator = [&](const ASTNode& type_node, ASTNode& symbol_node) {
@@ -218,7 +219,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
           // LCOV_EXCL_START
           if (data_type == ASTNodeDataType::undefined_t) {
-            throw parse_error("invalid parameter type", type_node.begin());
+            throw ParseError("invalid parameter type", type_node.begin());
           }
           // LCOV_EXCL_STOP
 
@@ -270,7 +271,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
               message << "expecting " << image_type.dimension() << " scalar expressions or an "
                       << dataTypeName(image_type) << ", found " << nb_image_expressions << " scalar expressions"
                       << std::ends;
-              throw parse_error(message.str(), image_domain_node.begin());
+              throw ParseError(message.str(), image_domain_node.begin());
             }
           } else {
             std::ostringstream message;
@@ -278,7 +279,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
                     << image_domain_node.string() << rang::style::reset << rang::style::bold
                     << " differs from number of expressions (" << nb_image_expressions << ") " << rang::fgB::yellow
                     << image_expression_node.string() << rang::style::reset << std::ends;
-            throw parse_error(message.str(), image_domain_node.begin());
+            throw ParseError(message.str(), image_domain_node.begin());
           }
         }
 
@@ -300,7 +301,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
           // LCOV_EXCL_START
           if (value_type == ASTNodeDataType::undefined_t) {
-            throw parse_error("invalid value type", image_node.begin());
+            throw ParseError("invalid value type", image_node.begin());
           }
           // LCOV_EXCL_STOP
         };
@@ -399,7 +400,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
         message << "undefined binary operator\n"
                 << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0)
                 << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends;
-        throw parse_error(message.str(), n.begin());
+        throw ParseError(message.str(), n.begin());
       }
     } else if (n.is_type<language::function_evaluation>()) {
       if (n.children[0]->m_data_type == ASTNodeDataType::function_t) {
@@ -452,7 +453,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
         message << "invalid function call\n"
                 << "note: '" << n.children[0]->string() << "' (type: " << dataTypeName(n.children[0]->m_data_type)
                 << ") is not a function!" << std::ends;
-        throw parse_error(message.str(), n.begin());
+        throw ParseError(message.str(), n.begin());
       }
     } else if (n.is_type<language::subscript_expression>()) {
       Assert(n.children.size() == 2, "invalid number of sub-expressions in array subscript expression");
@@ -466,7 +467,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
                 << rang::style::reset << '[' << dataTypeName(index_expression.m_data_type) << ']'
                 << "' for array subscript" << std::ends;
 
-        throw parse_error(message.str(), n.begin());
+        throw ParseError(message.str(), n.begin());
       } else {
         n.m_data_type = ASTNodeDataType::double_t;
       }
diff --git a/src/language/ast/ASTNodeDataTypeChecker.cpp b/src/language/ast/ASTNodeDataTypeChecker.cpp
index 87ecba522b17666aa5ce1610f1caf54ce0db15e3..3e6774849a5bbef6386f606a1bfe8a6993a84192 100644
--- a/src/language/ast/ASTNodeDataTypeChecker.cpp
+++ b/src/language/ast/ASTNodeDataTypeChecker.cpp
@@ -1,10 +1,12 @@
 #include <language/ast/ASTNodeDataTypeChecker.hpp>
 
+#include <language/utils/ParseError.hpp>
+
 void
 ASTNodeDataTypeChecker::_checkNodeDataTypes(const ASTNode& n)
 {
   if (n.m_data_type == ASTNodeDataType::undefined_t) {
-    throw parse_error("unexpected error: undefined datatype for AST node for " + n.name(), n.begin());
+    throw ParseError("unexpected error: undefined datatype for AST node for " + n.name(), n.begin());
   }
 
   for (const auto& child : n.children) {
diff --git a/src/language/ast/ASTNodeDataTypeFlattener.cpp b/src/language/ast/ASTNodeDataTypeFlattener.cpp
index f19ed6667be11f429e9ab08e24ea33e264323cdb..da2d064c6dd677e9eae4444cde59700c3a61ec2d 100644
--- a/src/language/ast/ASTNodeDataTypeFlattener.cpp
+++ b/src/language/ast/ASTNodeDataTypeFlattener.cpp
@@ -51,7 +51,7 @@ ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataT
       }
         //    LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected function type", node.begin());
+        throw ParseError("unexpected function type", node.begin());
       }
         //    LCOV_EXCL_STOP
       }
diff --git a/src/language/ast/ASTNodeExpressionBuilder.cpp b/src/language/ast/ASTNodeExpressionBuilder.cpp
index 9b9a0efbcb206b164ad31d6db18b3ca3727e09f9..fcdc4e1b93ab9135a6942e0e338144dff9474116 100644
--- a/src/language/ast/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeExpressionBuilder.cpp
@@ -1,5 +1,6 @@
 #include <language/ast/ASTNodeExpressionBuilder.hpp>
 
+#include <language/PEGGrammar.hpp>
 #include <language/ast/ASTNodeAffectationExpressionBuilder.hpp>
 #include <language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp>
 #include <language/ast/ASTNodeBinaryOperatorExpressionBuilder.hpp>
@@ -22,8 +23,7 @@
 #include <language/node_processor/TupleToVectorProcessor.hpp>
 #include <language/node_processor/ValueProcessor.hpp>
 #include <language/node_processor/WhileProcessor.hpp>
-
-#include <language/PEGGrammar.hpp>
+#include <language/utils/ParseError.hpp>
 
 void
 ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
@@ -121,7 +121,7 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
   } else {
     std::ostringstream error_message;
     error_message << "undefined node processor type '" << rang::fgB::red << n.name() << rang::fg::reset << "'";
-    throw parse_error{error_message.str(), std::vector{n.begin()}};
+    throw ParseError{error_message.str(), std::vector{n.begin()}};
   }
 
   for (auto& child : n.children) {
diff --git a/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp
index 5eb2ed3b0defeb35d47cd6f8e6812f2f82319883..13af5a812bd46ae0a6309eb65c1eecdda2cb027e 100644
--- a/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeFunctionEvaluationExpressionBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <language/ast/ASTNodeBuiltinFunctionExpressionBuilder.hpp>
 #include <language/ast/ASTNodeFunctionExpressionBuilder.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 
 ASTNodeFunctionEvaluationExpressionBuilder::ASTNodeFunctionEvaluationExpressionBuilder(ASTNode& node)
@@ -20,7 +21,7 @@ ASTNodeFunctionEvaluationExpressionBuilder::ASTNodeFunctionEvaluationExpressionB
   }
     //    LCOV_EXCL_START
   default: {
-    throw parse_error("unexpected function type", node.begin());
+    throw ParseError("unexpected function type", node.begin());
   }
     //    LCOV_EXCL_STOP
   }
diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
index f2369940873394a33db2718a7ff42fe4870cffc2..072a2af6015eed0dab37468c0c5e7211ec887eff 100644
--- a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
@@ -35,7 +35,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid argument type 0",
+      throw ParseError("unexpected error: invalid argument type 0",
                         std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
@@ -51,7 +51,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
         return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id);
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid argument dimension",
+        throw ParseError("unexpected error: invalid argument dimension",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
         // LCOV_EXCL_STOP
       }
@@ -61,7 +61,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
         return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id);
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid argument dimension",
+        throw ParseError("unexpected error: invalid argument dimension",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
         // LCOV_EXCL_STOP
       }
@@ -76,7 +76,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid argument type",
+      throw ParseError("unexpected error: invalid argument type",
                         std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
@@ -121,7 +121,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
 
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined parameter type", std::vector{m_node.begin()});
+      throw ParseError("unexpected error: undefined parameter type", std::vector{m_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -171,7 +171,7 @@ ASTNodeFunctionExpressionBuilder::_buildArgumentConverter(FunctionDescriptor& fu
     std::ostringstream error_message;
     error_message << "bad number of arguments: expecting " << rang::fgB::yellow << parameters_number
                   << rang::style::reset << ", provided " << rang::fgB::yellow << arguments_number << rang::style::reset;
-    throw parse_error(error_message.str(), argument_nodes.begin());
+    throw ParseError(error_message.str(), argument_nodes.begin());
   }
 
   if (arguments_number > 1) {
@@ -211,13 +211,13 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
         return std::make_unique<FunctionExpressionProcessor<ReturnT, std::string>>(function_component_expression);
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid string conversion", std::vector{node.children[1]->begin()});
+        throw ParseError("unexpected error: invalid string conversion", std::vector{node.children[1]->begin()});
         // LCOV_EXCL_STOP
       }
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined expression value type for function",
+      throw ParseError("unexpected error: undefined expression value type for function",
                         std::vector{node.children[1]->begin()});
     }
       // LCOV_EXCL_STOP
@@ -232,7 +232,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
         return std::make_unique<FunctionExpressionProcessor<ReturnT, ReturnT>>(function_component_expression);
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid dimension for returned vector",
+        throw ParseError("unexpected error: invalid dimension for returned vector",
                           std::vector{function_component_expression.begin()});
         // LCOV_EXCL_STOP
       }
@@ -243,7 +243,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
           function_component_expression);
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid dimension for returned vector",
+        throw ParseError("unexpected error: invalid dimension for returned vector",
                           std::vector{function_component_expression.begin()});
         // LCOV_EXCL_STOP
       }
@@ -255,13 +255,13 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
         }
       }
       // LCOV_EXCL_START
-      throw parse_error("unexpected error: undefined expression value type for function",
+      throw ParseError("unexpected error: undefined expression value type for function",
                         std::vector{function_component_expression.begin()});
       // LCOV_EXCL_STOP
     }
     // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined expression value type for function",
+      throw ParseError("unexpected error: undefined expression value type for function",
                         std::vector{function_component_expression.begin()});
     }
       // LCOV_EXCL_STOP
@@ -299,7 +299,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid dimension in returned type", std::vector{node.begin()});
+        throw ParseError("unexpected error: invalid dimension in returned type", std::vector{node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -309,7 +309,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined return type for function", std::vector{node.begin()});
+      throw ParseError("unexpected error: undefined return type for function", std::vector{node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -393,7 +393,7 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
+        throw ParseError("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -417,13 +417,13 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
+          throw ParseError("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
         }
           // LCOV_EXCL_STOP
         }
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: expecting 0", std::vector{function_expression.begin()});
+        throw ParseError("unexpected error: expecting 0", std::vector{function_expression.begin()});
         // LCOV_EXCL_STOP
       }
     } else {
diff --git a/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp b/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp
index c5eccdfcf61c597f97be00afcb688e3da857a220..71e5c3c4b16d8535091b98cab298ff6624661508 100644
--- a/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeIncDecExpressionBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/IncDecExpressionProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
 {
@@ -22,7 +23,7 @@ ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
         break;
       }
       default: {
-        throw parse_error("unexpected error: undefined data type for unary operator", std::vector{n.begin()});
+        throw ParseError("unexpected error: undefined data type for unary operator", std::vector{n.begin()});
       }
       }
     };
@@ -30,9 +31,9 @@ ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
     if (not n.children[0]->is_type<language::name>()) {
       if (n.children[0]->is_type<language::post_minusminus>() or n.children[0]->is_type<language::post_plusplus>() or
           n.children[0]->is_type<language::unary_minusminus>() or n.children[0]->is_type<language::unary_plusplus>()) {
-        throw parse_error("chaining ++ or -- operators is not allowed", std::vector{n.children[0]->begin()});
+        throw ParseError("chaining ++ or -- operators is not allowed", std::vector{n.children[0]->begin()});
       } else {
-        throw parse_error("invalid operand type for unary operator", std::vector{n.children[0]->begin()});
+        throw ParseError("invalid operand type for unary operator", std::vector{n.children[0]->begin()});
       }
     }
 
@@ -48,6 +49,6 @@ ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
   } else if (n.is_type<language::post_plusplus>()) {
     set_inc_dec_operator_processor(n, language::post_plusplus{});
   } else {
-    throw parse_error("unexpected error: undefined increment/decrement operator", std::vector{n.begin()});
+    throw ParseError("unexpected error: undefined increment/decrement operator", std::vector{n.begin()});
   }
 }
diff --git a/src/language/ast/ASTNodeJumpPlacementChecker.cpp b/src/language/ast/ASTNodeJumpPlacementChecker.cpp
index c699d8dce4866cd229c46c9cd8ab3dde513226f6..3d34b8394ba39031ac04569a158fea2c4d4d5262 100644
--- a/src/language/ast/ASTNodeJumpPlacementChecker.cpp
+++ b/src/language/ast/ASTNodeJumpPlacementChecker.cpp
@@ -1,6 +1,7 @@
 #include <language/ast/ASTNodeJumpPlacementChecker.hpp>
 
 #include <language/PEGGrammar.hpp>
+#include <language/utils/ParseError.hpp>
 
 void
 ASTNodeJumpPlacementChecker::_checkJumpPlacement(ASTNode& n, bool is_inside_loop)
@@ -15,7 +16,7 @@ ASTNodeJumpPlacementChecker::_checkJumpPlacement(ASTNode& n, bool is_inside_loop
       std::ostringstream error_message;
       error_message << "unexpected '" << rang::fgB::red << n.string() << rang::fg::reset
                     << "' outside of loop or switch statement";
-      throw parse_error(error_message.str(), std::vector{n.begin()});
+      throw ParseError(error_message.str(), std::vector{n.begin()});
     }
   } else {
     for (auto& child : n.children) {
diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
index 48b7e4f5ddacd4b788ff38bf0bceb82442230f70..daa5a0bd371150ffd3d33a60993a3d4d10c48d96 100644
--- a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
@@ -4,6 +4,7 @@
 #include <language/ast/ASTNodeDataTypeFlattener.hpp>
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 #include <language/node_processor/AffectationProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 template <typename OperatorT>
 void
@@ -33,8 +34,8 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid operand type for affectation",
-                        std::vector{node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: invalid operand type for affectation",
+                       std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -62,17 +63,17 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
           list_affectation_processor->template add<ValueT, ZeroType>(value_node);
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid operand value",
-                            std::vector{node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: invalid operand value",
+                           std::vector{node_sub_data_type.m_parent_node.begin()});
           // LCOV_EXCL_STOP
         }
       } else {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid dimension", std::vector{node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error: invalid dimension", std::vector{node_sub_data_type.m_parent_node.begin()});
         // LCOV_EXCL_STOP
       }
     } else {
-      throw parse_error("unexpected error: invalid value type", std::vector{node_sub_data_type.m_parent_node.begin()});
+      throw ParseError("unexpected error: invalid value type", std::vector{node_sub_data_type.m_parent_node.begin()});
     }
   };
 
@@ -115,8 +116,8 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: invalid vector dimension",
-                            std::vector{node_sub_data_type.m_parent_node.begin()});
+          throw ParseError("unexpected error: invalid vector dimension",
+                           std::vector{node_sub_data_type.m_parent_node.begin()});
         }
           // LCOV_EXCL_STOP
         }
@@ -124,14 +125,13 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error:invalid operand type for string affectation",
-                          std::vector{node_sub_data_type.m_parent_node.begin()});
+        throw ParseError("unexpected error:invalid operand type for string affectation",
+                         std::vector{node_sub_data_type.m_parent_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
     } else {
-      throw parse_error("unexpected error: undefined operator type for string affectation",
-                        std::vector{m_node.begin()});
+      throw ParseError("unexpected error: undefined operator type for string affectation", std::vector{m_node.begin()});
     }
   };
 
@@ -170,7 +170,7 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("invalid dimension", std::vector{value_node.begin()});
+        throw ParseError("invalid dimension", std::vector{value_node.begin()});
       }
         // LCOV_EXCL_STOP
       }
@@ -182,8 +182,7 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: undefined value type for tuple affectation",
-                        std::vector{value_node.begin()});
+      throw ParseError("unexpected error: undefined value type for tuple affectation", std::vector{value_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -212,7 +211,7 @@ ASTNodeListAffectationExpressionBuilder::_buildListAffectationProcessor()
   ASTNode& name_list_node = *m_node.children[0];
 
   if (name_list_node.children.size() != flattened_rhs_data_type_list.size()) {
-    throw parse_error("incompatible list sizes in affectation", std::vector{m_node.begin()});
+    throw ParseError("incompatible list sizes in affectation", std::vector{m_node.begin()});
   }
 
   using ListAffectationProcessorT = ListAffectationProcessor<OperatorT>;
@@ -234,9 +233,9 @@ ASTNodeListAffectationExpressionBuilder::ASTNodeListAffectationExpressionBuilder
     if (node.is_type<language::eq_op>()) {
       this->_buildListAffectationProcessor<language::eq_op>();
     } else {
-      throw parse_error("undefined affectation operator for tuples", std::vector{node.begin()});
+      throw ParseError("undefined affectation operator for tuples", std::vector{node.begin()});
     }
   } else {
-    throw parse_error("invalid right hand side in tuple affectation", std::vector{node.children[1]->begin()});
+    throw ParseError("invalid right hand side in tuple affectation", std::vector{node.children[1]->begin()});
   }
 }
diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.cpp b/src/language/ast/ASTNodeNaturalConversionChecker.cpp
index b01ff1fc346856797b37f58a20b72039e8b49f59..0faabac4fa7d0cb197ba3b8f35ffcfadce3f162a 100644
--- a/src/language/ast/ASTNodeNaturalConversionChecker.cpp
+++ b/src/language/ast/ASTNodeNaturalConversionChecker.cpp
@@ -1,6 +1,7 @@
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 
 #include <language/PEGGrammar.hpp>
+#include <language/utils/ParseError.hpp>
 #include <utils/Exceptions.hpp>
 
 void
@@ -17,7 +18,7 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& no
     if ((data_type == ASTNodeDataType::undefined_t) or (target_data_type == ASTNodeDataType::undefined_t)) {
       throw UnexpectedError(error_message.str());
     } else {
-      throw parse_error(error_message.str(), node.begin());
+      throw ParseError(error_message.str(), node.begin());
     }
   }
 }
@@ -31,7 +32,7 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo
     switch (node.m_data_type) {
     case ASTNodeDataType::list_t: {
       if (node.children.size() != target_data_type.dimension()) {
-        throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()});
+        throw ParseError("incompatible dimensions in affectation", std::vector{node.begin()});
       }
       for (const auto& child : node.children) {
         this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, ASTNodeDataType::double_t);
@@ -41,7 +42,7 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo
     }
     case ASTNodeDataType::vector_t: {
       if (data_type.dimension() != target_data_type.dimension()) {
-        throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()});
+        throw ParseError("incompatible dimensions in affectation", std::vector{node.begin()});
       }
       break;
     }
diff --git a/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp
index ff081cea9e53378c6ea3639e3b7fd0a7b9162ca3..7d94c3f58fe1762b582a0d984edc797b0fafd021 100644
--- a/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeUnaryOperatorExpressionBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/UnaryExpressionProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(ASTNode& n)
 {
@@ -28,8 +29,8 @@ ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(AST
         break;
       }
       default: {
-        throw parse_error("unexpected error: invalid operand type for unary operator",
-                          std::vector{n.children[0]->begin()});
+        throw ParseError("unexpected error: invalid operand type for unary operator",
+                         std::vector{n.children[0]->begin()});
       }
       }
     };
@@ -69,19 +70,19 @@ ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(AST
           }
             // LCOV_EXCL_START
           default: {
-            throw parse_error("unexpected error: invalid vector dimension", std::vector{n.begin()});
+            throw ParseError("unexpected error: invalid vector dimension", std::vector{n.begin()});
           }
             // LCOV_EXCL_STOP
           }
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid unary operator for vector data", std::vector{n.begin()});
+          throw ParseError("unexpected error: invalid unary operator for vector data", std::vector{n.begin()});
           // LCOV_EXCL_STOP
         }
         break;
       }
       default: {
-        throw parse_error("undefined value type for unary operator", std::vector{n.begin()});
+        throw ParseError("undefined value type for unary operator", std::vector{n.begin()});
       }
       }
     };
@@ -94,6 +95,6 @@ ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(AST
   } else if (n.is_type<language::unary_not>()) {
     set_unary_operator_processor(n, language::unary_not{});
   } else {
-    throw parse_error("unexpected error: undefined unary operator", std::vector{n.begin()});
+    throw ParseError("unexpected error: undefined unary operator", std::vector{n.begin()});
   }
 }
diff --git a/src/language/ast/ASTSymbolInitializationChecker.cpp b/src/language/ast/ASTSymbolInitializationChecker.cpp
index b68e6d05a5872c95c546b108ad6ef8c9256e1965..3a8c846a3626a3acb815a401767d898b378f546c 100644
--- a/src/language/ast/ASTSymbolInitializationChecker.cpp
+++ b/src/language/ast/ASTSymbolInitializationChecker.cpp
@@ -1,6 +1,7 @@
 #include <language/ast/ASTSymbolInitializationChecker.hpp>
 
 #include <language/PEGGrammar.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 
 void
@@ -16,13 +17,13 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
 
     auto check_correct_name_in_definition = [](ASTNode& decl_name_node, ASTNode& def_name_node) {
       if (def_name_node.is_type<language::name_list>()) {
-        throw parse_error("unexpected variable list, expecting one identifier", std::vector{def_name_node.begin()});
+        throw ParseError("unexpected variable list, expecting one identifier", std::vector{def_name_node.begin()});
       }
       Assert(def_name_node.is_type<language::name>());
       if (decl_name_node.string() != def_name_node.string()) {
         std::ostringstream os;
         os << "invalid identifier, expecting '" << decl_name_node.string() << "'" << std::ends;
-        throw parse_error(os.str(), std::vector{def_name_node.begin()});
+        throw ParseError(os.str(), std::vector{def_name_node.begin()});
       }
     };
 
@@ -44,13 +45,13 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
           std::ostringstream os;
           os << "invalid number of definition identifiers, expecting " << decl_name_list_node.children.size()
              << " found " << def_name_list_node.children.size() << std::ends;
-          throw parse_error(os.str(), std::vector{def_name_list_node.begin()});
+          throw ParseError(os.str(), std::vector{def_name_list_node.begin()});
         }
         if (def_name_list_node.children.size() != expression_list_node.children.size()) {
           std::ostringstream os;
           os << "invalid number of definition expressions, expecting " << decl_name_list_node.children.size()
              << " found " << expression_list_node.children.size() << std::ends;
-          throw parse_error(os.str(), std::vector{expression_list_node.begin()});
+          throw ParseError(os.str(), std::vector{expression_list_node.begin()});
         }
 
         this->_checkSymbolInitialization(expression_list_node);
@@ -113,7 +114,7 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
     if (not i_symbol->attributes().isInitialized()) {
       std::ostringstream error_message;
       error_message << "uninitialized symbol '" << rang::fg::red << node.string() << rang::fg::reset << '\'';
-      throw parse_error(error_message.str(), std::vector{node.begin()});
+      throw ParseError(error_message.str(), std::vector{node.begin()});
     }
   }
 
diff --git a/src/language/ast/ASTSymbolTableBuilder.cpp b/src/language/ast/ASTSymbolTableBuilder.cpp
index 2c8f4850a5cd477eac43fb43c30d6eb0d7cca671..feb0b0130dd316df1cf768ad3506fa31f42b68b8 100644
--- a/src/language/ast/ASTSymbolTableBuilder.cpp
+++ b/src/language/ast/ASTSymbolTableBuilder.cpp
@@ -1,6 +1,7 @@
 #include <language/ast/ASTSymbolTableBuilder.hpp>
 
 #include <language/PEGGrammar.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 
 void
@@ -25,7 +26,7 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
     if (not success) {
       std::ostringstream error_message;
       error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << "' was already defined!";
-      throw parse_error(error_message.str(), std::vector{n.begin()});
+      throw ParseError(error_message.str(), std::vector{n.begin()});
     }
 
     for (auto& child : n.children) {
@@ -46,7 +47,7 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
             std::ostringstream error_message;
             error_message << "symbol '" << rang::fg::red << argument_node.string() << rang::fg::reset
                           << "' was already defined!";
-            throw parse_error(error_message.str(), std::vector{argument_node.begin()});
+            throw ParseError(error_message.str(), std::vector{argument_node.begin()});
           }
         };
 
@@ -65,7 +66,7 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
             std::ostringstream error_message;
             error_message << "symbol '" << rang::fg::red << argument_node.string() << rang::fg::reset
                           << "' was already defined!";
-            throw parse_error(error_message.str(), std::vector{argument_node.begin()});
+            throw ParseError(error_message.str(), std::vector{argument_node.begin()});
           }
           // Symbols will be initialized at call
           i_symbol->attributes().setIsInitialized();
@@ -84,7 +85,7 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
         if (not found) {
           std::ostringstream error_message;
           error_message << "undefined symbol '" << rang::fg::red << n.string() << rang::fg::reset << '\'';
-          throw parse_error(error_message.str(), std::vector{n.begin()});
+          throw ParseError(error_message.str(), std::vector{n.begin()});
         }
       }
     }
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index 768661e9999a3dd720455f23daa7c252f555d16f..aa5c1fce3ee96c5318d930d75f2047df0d209735 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -6,6 +6,7 @@
 #include <language/modules/SchemeModule.hpp>
 #include <language/modules/VTKModule.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 #include <utils/PugsAssert.hpp>
 
@@ -41,7 +42,7 @@ ModuleRepository::_populateEmbedderTableT(const ASTNode& module_name_node,
       std::ostringstream error_message;
       error_message << "importing module '" << module_name << "', cannot add symbol '" << symbol_name
                     << "', it is already defined!";
-      throw parse_error(error_message.str(), module_name_node.begin());
+      throw ParseError(error_message.str(), module_name_node.begin());
     }
 
     i_symbol->attributes().setDataType(data_type);
@@ -68,6 +69,6 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab
     this->_populateEmbedderTableT(module_name_node, populating_module.getNameTypeMap(), ASTNodeDataType::type_name_id_t,
                                   symbol_table, symbol_table.typeEmbedderTable());
   } else {
-    throw parse_error(std::string{"could not find module "} + module_name, std::vector{module_name_node.begin()});
+    throw ParseError(std::string{"could not find module "} + module_name, std::vector{module_name_node.begin()});
   }
 }
diff --git a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
index ec37d74ee5c815695c229d3b93d5d0acdb79bc9d..7ed93683d1b6bcfd54e624385429bce4319976d5 100644
--- a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
+++ b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
@@ -3,6 +3,7 @@
 
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 
 #include <vector>
@@ -61,7 +62,7 @@ class ASTNodeExpressionListProcessor final : public INodeProcessor
           }
             //    LCOV_EXCL_START
           default: {
-            throw parse_error("unexpected function type", m_node.begin());
+            throw ParseError("unexpected function type", m_node.begin());
           }
             //    LCOV_EXCL_STOP
           }
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index 31e1f070f5fadc1366ad4470b49a8052977bfce2..6898bb2c2b25e4fe44a8f6e9ad271930086f0a81 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -3,6 +3,7 @@
 
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsTraits.hpp>
@@ -86,7 +87,7 @@ class AffectationExecutor final : public IAffectationExecutor
   {
     // LCOV_EXCL_START
     if constexpr (not m_is_defined) {
-      throw parse_error("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
+      throw ParseError("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
     }
     // LCOV_EXCL_STOP
   }
@@ -186,7 +187,7 @@ class ComponentAffectationExecutor final : public IAffectationExecutor
   {
     // LCOV_EXCL_START
     if constexpr (not m_is_defined) {
-      throw parse_error("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
+      throw ParseError("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
     }
     // LCOV_EXCL_STOP
   }
@@ -204,7 +205,7 @@ class ComponentAffectationExecutor final : public IAffectationExecutor
               index_value = value;
             } else {
               // LCOV_EXCL_START
-              throw parse_error("unexpected error: invalid index type", std::vector{m_index_expression.begin()});
+              throw ParseError("unexpected error: invalid index type", std::vector{m_index_expression.begin()});
               // LCOV_EXCL_STOP
             }
           },
@@ -286,8 +287,8 @@ class AffectationProcessor final : public INodeProcessor
 
       // LCOV_EXCL_START
       if (array_expression.m_data_type != ASTNodeDataType::vector_t) {
-        throw parse_error("unexpected error: invalid lhs (expecting R^d)",
-                          std::vector{array_subscript_expression.begin()});
+        throw ParseError("unexpected error: invalid lhs (expecting R^d)",
+                         std::vector{array_subscript_expression.begin()});
       }
       // LCOV_EXCL_STOP
 
@@ -326,15 +327,14 @@ class AffectationProcessor final : public INodeProcessor
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid vector dimension",
-                          std::vector{array_subscript_expression.begin()});
+        throw ParseError("unexpected error: invalid vector dimension", std::vector{array_subscript_expression.begin()});
       }
         // LCOV_EXCL_STOP
       }
 
     } else {
       // LCOV_EXCL_START
-      throw parse_error("unexpected error: invalid lhs", std::vector{node.children[0]->begin()});
+      throw ParseError("unexpected error: invalid lhs", std::vector{node.children[0]->begin()});
       // LCOV_EXCL_STOP
     }
   }
@@ -366,7 +366,7 @@ class AffectationToTinyVectorFromListProcessor final : public INodeProcessor
             v[i] = child_value;
           } else {
             // LCOV_EXCL_START
-            throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin());
+            throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin());
             // LCOV_EXCL_STOP
           }
         },
@@ -421,7 +421,7 @@ class AffectationToTupleProcessor final : public INodeProcessor
           *m_lhs = std::vector{TinyVector<1>{static_cast<double>(v)}};
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin());
+          throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin());
           // LCOV_EXCL_STOP
         }
       },
@@ -480,8 +480,8 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor
                       v[j] = vj;
                     } else {
                       // LCOV_EXCL_START
-                      throw parse_error("unexpected error: unexpected right hand side type in affectation",
-                                        m_node.children[1]->children[i]->begin());
+                      throw ParseError("unexpected error: unexpected right hand side type in affectation",
+                                       m_node.children[1]->children[i]->begin());
                       // LCOV_EXCL_STOP
                     }
                   },
@@ -493,14 +493,14 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor
               tuple_value[i] = ZeroType{};
             } else {
               // LCOV_EXCL_START
-              throw parse_error("unexpected error: unexpected right hand side type in affectation",
-                                m_node.children[1]->children[i]->begin());
+              throw ParseError("unexpected error: unexpected right hand side type in affectation",
+                               m_node.children[1]->children[i]->begin());
               // LCOV_EXCL_STOP
             }
           } else {
             // LCOV_EXCL_START
-            throw parse_error("unexpected error: unexpected right hand side type in affectation",
-                              m_node.children[1]->children[i]->begin());
+            throw ParseError("unexpected error: unexpected right hand side type in affectation",
+                             m_node.children[1]->children[i]->begin());
             // LCOV_EXCL_STOP
           }
         },
@@ -536,8 +536,8 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor
       }
     } else {
       // LCOV_EXCL_START
-      throw parse_error("unexpected error: unexpected right hand side type in tuple affectation",
-                        m_node.children[1]->begin());
+      throw ParseError("unexpected error: unexpected right hand side type in tuple affectation",
+                       m_node.children[1]->begin());
       // LCOV_EXCL_STOP
     }
 
@@ -559,8 +559,8 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor
           this->_copyVector(value_list);
         } else {
           // LCOV_EXCL_START
-          throw parse_error("unexpected error: invalid lhs (expecting list or tuple)",
-                            std::vector{m_node.children[1]->begin()});
+          throw ParseError("unexpected error: invalid lhs (expecting list or tuple)",
+                           std::vector{m_node.children[1]->begin()});
           // LCOV_EXCL_STOP
         }
       },
@@ -645,8 +645,8 @@ class ListAffectationProcessor final : public INodeProcessor
 
       if (array_expression.m_data_type != ASTNodeDataType::vector_t) {
         // LCOV_EXCL_START
-        throw parse_error("unexpected error: invalid lhs (expecting R^d)",
-                          std::vector{array_subscript_expression.begin()});
+        throw ParseError("unexpected error: invalid lhs (expecting R^d)",
+                         std::vector{array_subscript_expression.begin()});
         // LCOV_EXCL_STOP
       }
 
@@ -685,14 +685,13 @@ class ListAffectationProcessor final : public INodeProcessor
       }
         // LCOV_EXCL_START
       default: {
-        throw parse_error("unexpected error: invalid vector dimension",
-                          std::vector{array_subscript_expression.begin()});
+        throw ParseError("unexpected error: invalid vector dimension", std::vector{array_subscript_expression.begin()});
       }
         // LCOV_EXCL_STOP
       }
     } else {
       // LCOV_EXCL_START
-      throw parse_error("unexpected error: invalid left hand side", std::vector{lhs_node.begin()});
+      throw ParseError("unexpected error: invalid left hand side", std::vector{lhs_node.begin()});
       // LCOV_EXCL_STOP
     }
   }
diff --git a/src/language/node_processor/ArraySubscriptProcessor.hpp b/src/language/node_processor/ArraySubscriptProcessor.hpp
index 4853c65d326657a63599d62fc9d52713a96d1d5f..3a71c01846b9e17ce28818d732716aea764d2496 100644
--- a/src/language/node_processor/ArraySubscriptProcessor.hpp
+++ b/src/language/node_processor/ArraySubscriptProcessor.hpp
@@ -3,6 +3,7 @@
 
 #include <language/ast/ASTNode.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 template <typename ArrayTypeT>
 class ArraySubscriptProcessor : public INodeProcessor
@@ -25,7 +26,7 @@ class ArraySubscriptProcessor : public INodeProcessor
             index_value = value;
           } else {
             // LCOV_EXCL_START
-            throw parse_error("unexpected error: invalid index type", std::vector{index_expression.begin()});
+            throw ParseError("unexpected error: invalid index type", std::vector{index_expression.begin()});
             // LCOV_EXCL_STOP
           }
         },
diff --git a/src/language/node_processor/BinaryExpressionProcessor.hpp b/src/language/node_processor/BinaryExpressionProcessor.hpp
index 2e4fcef12ffe74dcd5cf972b4353ba88ab8d0e55..8f5d9c3220cf3018104d5d53e2036b9bb8217214 100644
--- a/src/language/node_processor/BinaryExpressionProcessor.hpp
+++ b/src/language/node_processor/BinaryExpressionProcessor.hpp
@@ -4,6 +4,7 @@
 #include <language/PEGGrammar.hpp>
 #include <language/ast/ASTNode.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 template <typename Op>
 struct BinOp;
@@ -211,7 +212,7 @@ class BinaryExpressionProcessor final : public INodeProcessor
   {
     if constexpr (not m_is_defined) {
       // LCOV_EXCL_START
-      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
+      throw ParseError("invalid operands to binary expression", std::vector{m_node.begin()});
       // LCOV_EXCL_STOP
     }
   }
diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp
index 755680f5fee0a2da69e02f0fd04a550e7e971846..302cbaf2d2ce3570678fb62a57d4e463e47a2432 100644
--- a/src/language/node_processor/BuiltinFunctionProcessor.hpp
+++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp
@@ -5,6 +5,7 @@
 #include <language/node_processor/FunctionArgumentConverter.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
+#include <language/utils/ParseError.hpp>
 
 #include <utils/SignalManager.hpp>
 
@@ -69,7 +70,7 @@ class BuiltinFunctionProcessor : public INodeProcessor
         return m_function_expression_processor->execute(context_exec_policy);
       }
       catch (std::runtime_error& e) {
-        throw parse_error(e.what(), {m_argument_node.begin()});
+        throw ParseError(e.what(), {m_argument_node.begin()});
       }
     }
   }
diff --git a/src/language/node_processor/OStreamProcessor.hpp b/src/language/node_processor/OStreamProcessor.hpp
index 606247653b397998fab2016b970d87637201c527..e67dd7b6d9fcfa2440a59367efecd42ffd35a8ca 100644
--- a/src/language/node_processor/OStreamProcessor.hpp
+++ b/src/language/node_processor/OStreamProcessor.hpp
@@ -3,6 +3,7 @@
 
 #include <language/ast/ASTNode.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/ParseError.hpp>
 
 class OStreamProcessor final : public INodeProcessor
 {
@@ -27,8 +28,8 @@ class OStreamProcessor final : public INodeProcessor
       if ((child->m_data_type == ASTNodeDataType::type_name_id_t) or
           (child->m_data_type == ASTNodeDataType::function_t) or
           (child->m_data_type == ASTNodeDataType::builtin_function_t)) {
-        throw parse_error("invalid argument, cannot print a '" + dataTypeName(child->m_data_type) + "'",
-                          std::vector{child->begin()});
+        throw ParseError("invalid argument, cannot print a '" + dataTypeName(child->m_data_type) + "'",
+                         std::vector{child->begin()});
       }
     }
   }
diff --git a/src/language/utils/ParseError.hpp b/src/language/utils/ParseError.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c15b07cd49f2c5cd3f8a85d339e006822d2b4c1
--- /dev/null
+++ b/src/language/utils/ParseError.hpp
@@ -0,0 +1,38 @@
+#ifndef PARSE_ERROR_HPP
+#define PARSE_ERROR_HPP
+
+#include <utils/Exceptions.hpp>
+
+#include <pegtl/position.hpp>
+
+#include <vector>
+
+class ParseError : public IExitError
+{
+ private:
+  std::string m_error_msg;
+  std::vector<TAO_PEGTL_NAMESPACE::position> m_positions;
+
+ public:
+  const auto&
+  positions() const
+  {
+    return m_positions;
+  }
+
+  ParseError(const std::string_view msg, std::vector<TAO_PEGTL_NAMESPACE::position>&& positions)
+    : IExitError(msg), m_positions{std::move(positions)}
+  {}
+
+  ParseError(const std::string_view msg, const std::vector<TAO_PEGTL_NAMESPACE::position>& positions)
+    : IExitError(msg), m_positions{positions}
+  {}
+
+  ParseError(const std::string_view msg, const TAO_PEGTL_NAMESPACE::position& positions)
+    : IExitError(msg), m_positions{positions}
+  {}
+
+  ~ParseError() = default;
+};
+
+#endif   // PARSE_ERROR_HPP
diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp
index de9e8830fbbc200d724f3f49bf9d44db82e3438b..7ea50b0ed95845d2cee2633477e33080453f0f30 100644
--- a/src/utils/PugsUtils.cpp
+++ b/src/utils/PugsUtils.cpp
@@ -48,7 +48,7 @@ initialize(int& argc, char* argv[])
   {
     CLI::App app{"Pugs help"};
 
-    app.add_option("filename,-f,--filename", filename, "pugs script file")->check(CLI::ExistingFile);
+    app.add_option("filename", filename, "pugs script file")->required()->check(CLI::ExistingFile);
 
     int threads = -1;
     app.add_option("--threads", threads, "Number of Kokkos threads")
diff --git a/tests/test_ASTModulesImporter.cpp b/tests/test_ASTModulesImporter.cpp
index 7ac28918aec2110eefe734b67bf73da2a55ea952..42638d918a362516b53a0f05772096b477f943b4 100644
--- a/tests/test_ASTModulesImporter.cpp
+++ b/tests/test_ASTModulesImporter.cpp
@@ -84,7 +84,7 @@ import unknown_module;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
 
-      REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, ParseError);
     }
 
     SECTION("symbol already defined")
@@ -98,7 +98,7 @@ import math;
 
       ast->m_symbol_table->add("sin", ast->begin());
 
-      REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTModulesImporter{*ast}, ParseError);
     }
   }
 }
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index 9e44625e1ef31b116954e7b6859b1409873b6e11..c5c691a28db39749f1910521b875eca0af0e8271 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -5,6 +5,7 @@
 #include <language/ast/ASTSymbolTableBuilder.hpp>
 #include <language/utils/ASTNodeDataTypeTraits.hpp>
 #include <language/utils/ASTPrinter.hpp>
+#include <language/utils/ParseError.hpp>
 #include <language/utils/TypeDescriptor.hpp>
 #include <utils/Exceptions.hpp>
 
@@ -825,7 +826,7 @@ let f : R*Z -> B, x -> 3;
         auto ast = ASTBuilder::build(input);
         ASTSymbolTableBuilder{*ast};
 
-        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
       }
 
       SECTION("wrong parameter number 2")
@@ -837,7 +838,7 @@ let f : R -> B, (x,y) -> 3;
         auto ast = ASTBuilder::build(input);
         ASTSymbolTableBuilder{*ast};
 
-        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
       }
 
       SECTION("wrong image size")
@@ -1090,7 +1091,7 @@ not_a_function(2,3);
         auto ast = ASTBuilder::build(input);
         ASTSymbolTableBuilder{*ast};
 
-        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+        REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
       }
     }
   }
@@ -1545,7 +1546,7 @@ if ("string");
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
       ASTSymbolTableBuilder{*ast};
-      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
     }
   }
 
@@ -1631,7 +1632,7 @@ while ("string");
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
       ASTSymbolTableBuilder{*ast};
-      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
     }
   }
 
@@ -1717,7 +1718,7 @@ do 1; while ("string");
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
       ASTSymbolTableBuilder{*ast};
-      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
     }
   }
 
@@ -2036,7 +2037,7 @@ true xor false;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
       ASTSymbolTableBuilder{*ast};
-      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeDataTypeBuilder{*ast}, ParseError);
     }
   }
 }
diff --git a/tests/test_ASTNodeDataTypeChecker.cpp b/tests/test_ASTNodeDataTypeChecker.cpp
index 7ce833b6d43cecaaadf28086435378c0a6788933..e016e1087281b3175eba0076cb21aaab7234c89b 100644
--- a/tests/test_ASTNodeDataTypeChecker.cpp
+++ b/tests/test_ASTNodeDataTypeChecker.cpp
@@ -4,6 +4,7 @@
 #include <language/ast/ASTNodeDataTypeBuilder.hpp>
 #include <language/ast/ASTNodeDataTypeChecker.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ParseError.hpp>
 
 #include <pegtl/string_input.hpp>
 
@@ -46,6 +47,6 @@ for(let i:Z, i=0; i<10; ++i) {
 
     ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
 
-    REQUIRE_THROWS_AS(ASTNodeDataTypeChecker{*ast}, parse_error);
+    REQUIRE_THROWS_AS(ASTNodeDataTypeChecker{*ast}, ParseError);
   }
 }
diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp
index 801d27d01f0dd89f206d5e9902c9e9414687559f..956b5a2527e8e80bb1cef2287f9b2c72a16768aa 100644
--- a/tests/test_ASTNodeExpressionBuilder.cpp
+++ b/tests/test_ASTNodeExpressionBuilder.cpp
@@ -889,6 +889,6 @@ continue;
     // One is sure that language::ignored is not treated so its a good candidate
     // for this test
     ast->children[0]->set_type<language::ignored>();
-    REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, parse_error);
+    REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, ParseError);
   }
 }
diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
index 7e892c86367a3984cab7cb93a4d27631cda52d28..3ce9d041604f5a10cbe9ea97f063c3d24a1fd04d 100644
--- a/tests/test_ASTNodeFunctionExpressionBuilder.cpp
+++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
@@ -53,7 +53,7 @@
                                                                                    \
     ASTNodeTypeCleaner<language::var_declaration>{*ast};                           \
     ASTNodeTypeCleaner<language::fct_declaration>{*ast};                           \
-    REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, parse_error);                \
+    REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, ParseError);                \
   }
 
 #define CHECK_AST_THROWS_WITH(data, error)                                         \
diff --git a/tests/test_ASTNodeJumpPlacementChecker.cpp b/tests/test_ASTNodeJumpPlacementChecker.cpp
index 419519cd5803473aadb56abea772d537aaf38c2a..631b172775f381405bbc8ff830d19aad92b9c8e5 100644
--- a/tests/test_ASTNodeJumpPlacementChecker.cpp
+++ b/tests/test_ASTNodeJumpPlacementChecker.cpp
@@ -4,6 +4,7 @@
 #include <language/ast/ASTNodeDataTypeBuilder.hpp>
 #include <language/ast/ASTNodeJumpPlacementChecker.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ParseError.hpp>
 
 #include <pegtl/string_input.hpp>
 
@@ -76,7 +77,7 @@ do {
 
       ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
 
-      REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, ParseError);
     }
   }
 
@@ -145,7 +146,7 @@ do {
 
       ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
 
-      REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, ParseError);
     }
   }
 }
diff --git a/tests/test_ASTSymbolTableBuilder.cpp b/tests/test_ASTSymbolTableBuilder.cpp
index 0398914c084e4c264bcae9f28f8356ed5885d3dc..028f79882eed45e8dc99c17efd414ce63c7ddd4e 100644
--- a/tests/test_ASTSymbolTableBuilder.cpp
+++ b/tests/test_ASTSymbolTableBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <language/ast/ASTBuilder.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ParseError.hpp>
 
 #include <pegtl/string_input.hpp>
 
@@ -74,7 +75,7 @@ let n:N, n = a;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
 
-      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, ParseError);
     }
 
     SECTION("Re-declared symbol")
@@ -87,7 +88,7 @@ let n:N, n = 1;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
 
-      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, ParseError);
     }
 
     SECTION("Re-declared symbol (function)")
@@ -100,7 +101,7 @@ let f : R -> R, x -> 1;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
 
-      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, ParseError);
     }
 
     SECTION("Re-declared parameter (function)")
@@ -112,7 +113,7 @@ let f : R*R*N -> R, (x,y,x) -> 1;
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
 
-      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, parse_error);
+      REQUIRE_THROWS_AS(ASTSymbolTableBuilder{*ast}, ParseError);
     }
   }
 }
diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp
index fdf46213388b23e46c1457a56ea213cf17ac83f0..1583f1df99d7eddefc3337529611a5d5720912a0 100644
--- a/tests/test_BuiltinFunctionRegister.hpp
+++ b/tests/test_BuiltinFunctionRegister.hpp
@@ -162,7 +162,7 @@ class test_BuiltinFunctionRegister
       if (not success) {
         std::ostringstream error_message;
         error_message << "cannot add symbol '" << symbol_name << "' it is already defined";
-        throw parse_error(error_message.str(), root_node.begin());
+        throw ParseError(error_message.str(), root_node.begin());
       }
 
       i_symbol->attributes().setDataType(ASTNodeDataType::builtin_function_t);