[Git][ghc/ghc][wip/ci-interface-stability] 4 commits: gitlab-ci: Preserve unexpected output

Ben Gamari (@bgamari) gitlab at gitlab.haskell.org
Thu Jul 6 19:48:34 UTC 2023



Ben Gamari pushed to branch wip/ci-interface-stability at Glasgow Haskell Compiler / GHC


Commits:
b47106bf by Ben Gamari at 2023-07-06T15:32:27-04:00
gitlab-ci: Preserve unexpected output

Here we enable use of the testsuite driver's `--unexpected-output-dir`
flag by CI, preserving the result as an artifact for use by users.

- - - - -
375eba30 by Ben Gamari at 2023-07-06T15:47:57-04:00
gitlab-ci: Preserve unexpected output

Here we enable use of the testsuite driver's `--unexpected-output-dir`
flag by CI, preserving the result as an artifact for use by users.

- - - - -
fac83e2f by Ben Gamari at 2023-07-06T15:47:57-04:00
compiler: Rework ShowSome

Previously the field used to filter the sub-declarations to show
was rather ad-hoc and was only able to show at most one sub-declaration.

- - - - -
51244bd7 by Ben Gamari at 2023-07-06T15:47:57-04:00
testsuite: Add test to catch changes in core libraries

This adds testing infrastructure to ensure that changes in core
libraries (e.g. `base` and `ghc-prim`) are caught in CI.

- - - - -


20 changed files:

- .gitlab/ci.sh
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/Types/TyThing/Ppr.hs
- hadrian/src/Packages.hs
- hadrian/src/Rules/Test.hs
- hadrian/src/Settings/Default.hs
- testsuite/mk/boilerplate.mk
- testsuite/tests/ghci/scripts/ghci008.stdout
- + testsuite/tests/interface-stability/Makefile
- + testsuite/tests/interface-stability/README.mkd
- + testsuite/tests/interface-stability/all.T
- + testsuite/tests/interface-stability/base-exports.stdout
- + testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- + testsuite/tests/interface-stability/base-exports.stdout-mingw32
- + testsuite/tests/interface-stability/base-exports.stdout-ws-32
- + utils/dump-decls/Main.hs
- + utils/dump-decls/dump-decls.cabal


Changes:

=====================================
.gitlab/ci.sh
=====================================
@@ -43,12 +43,13 @@ $0 - GHC continuous integration driver
 
 Common Modes:
 
-  usage         Show this usage message.
-  setup         Prepare environment for a build.
-  configure     Run ./configure.
-  clean         Clean the tree
-  shell         Run an interactive shell with a configured build environment.
-  save_cache    Preserve the cabal cache
+  usage             Show this usage message.
+  setup             Prepare environment for a build.
+  configure         Run ./configure.
+  clean             Clean the tree
+  shell             Run an interactive shell with a configured build environment.
+  save_test_output  Generate unexpected-test-output.tar.gz
+  save_cache        Preserve the cabal cache
 
 Hadrian build system
   build_hadrian Build GHC via the Hadrian build system
@@ -614,12 +615,16 @@ function test_hadrian() {
       --summary-junit=./junit.xml \
       --test-have-intree-files    \
       --docs=none                 \
-      "runtest.opts+=${RUNTEST_ARGS:-}" || fail "cross-compiled hadrian main testsuite"
+      "runtest.opts+=${RUNTEST_ARGS:-}" \
+      "runtest.opts+=--unexpected-output-dir=$TOP/unexpected-test-output" \
+      || fail "cross-compiled hadrian main testsuite"
   elif [[ -n "${CROSS_TARGET:-}" ]] && [[ "${CROSS_TARGET:-}" == *"wasm"* ]]; then
     run_hadrian \
       test \
       --summary-junit=./junit.xml \
-      "runtest.opts+=${RUNTEST_ARGS:-}" || fail "hadrian main testsuite targetting $CROSS_TARGET"
+      "runtest.opts+=${RUNTEST_ARGS:-}" \
+      "runtest.opts+=--unexpected-output-dir=$TOP/unexpected-test-output" \
+      || fail "hadrian main testsuite targetting $CROSS_TARGET"
   elif [ -n "${CROSS_TARGET:-}" ]; then
     local instdir="$TOP/_build/install"
     local test_compiler="$instdir/bin/${cross_prefix}ghc$exe"
@@ -635,7 +640,9 @@ function test_hadrian() {
       --test-compiler=stage-cabal \
       --test-root-dirs=testsuite/tests/perf \
       --test-root-dirs=testsuite/tests/typecheck \
-      "runtest.opts+=${RUNTEST_ARGS:-}" || fail "hadrian cabal-install test"
+      "runtest.opts+=${RUNTEST_ARGS:-}" \
+      "runtest.opts+=--unexpected-output-dir=$TOP/unexpected-test-output" \
+      || fail "hadrian cabal-install test"
   else
     local instdir="$TOP/_build/install"
     local test_compiler="$instdir/bin/${cross_prefix}ghc$exe"
@@ -673,12 +680,14 @@ function test_hadrian() {
       --summary-junit=./junit.xml \
       --test-have-intree-files \
       --test-compiler="${test_compiler}" \
-      "runtest.opts+=${RUNTEST_ARGS:-}" || fail "hadrian main testsuite"
+      "runtest.opts+=${RUNTEST_ARGS:-}" \
+      "runtest.opts+=--unexpected-output-dir=$TOP/unexpected-test-output" \
+      || fail "hadrian main testsuite"
 
+    tar -czf unexpected-test-output.tar.gz unexpected-test-output
     info "STAGE2_TEST=$?"
 
-    fi
-
+  fi
 }
 
 function summarise_hi_files() {
@@ -770,6 +779,10 @@ function run_abi_test() {
   check_interfaces out/run1 out/run2 interfaces "Mismatched interface hashes"
 }
 
+function save_test_output() {
+    tar -czf unexpected-test-output.tar.gz unexpected-test-output
+}
+
 function save_cache () {
   info "Storing cabal cache from $CABAL_DIR to $CABAL_CACHE..."
   rm -Rf "$CABAL_CACHE"
@@ -935,6 +948,7 @@ case ${1:-help} in
   lint_author) shift; lint_author "$@" ;;
   compare_interfaces_of) shift; compare_interfaces_of "$@" ;;
   clean) clean ;;
+  save_test_output) save_test_output ;;
   save_cache) save_cache ;;
   shell) shift; shell "$@" ;;
   *) fail "unknown mode $1" ;;


=====================================
.gitlab/generate-ci/gen_ci.hs
=====================================
@@ -680,10 +680,12 @@ job arch opsys buildConfig = NamedJob { name = jobName, jobInfo = Job {..} }
     jobAfterScript
       | Windows <- opsys =
       [ "bash .gitlab/ci.sh save_cache"
+      , "bash .gitlab/ci.sh save_test_output"
       , "bash .gitlab/ci.sh clean"
       ]
       | otherwise =
       [ ".gitlab/ci.sh save_cache"
+      , ".gitlab/ci.sh save_test_output"
       , ".gitlab/ci.sh clean"
       , "cat ci_timings" ]
 
@@ -706,16 +708,19 @@ job arch opsys buildConfig = NamedJob { name = jobName, jobInfo = Job {..} }
           Emulator s       -> "CROSS_EMULATOR" =: s
           NoEmulatorNeeded -> mempty
       , if withNuma buildConfig then "ENABLE_NUMA" =: "1" else mempty
-      , if validateNonmovingGc buildConfig
-           then "RUNTEST_ARGS" =: "--way=nonmoving --way=nonmoving_thr --way=nonmoving_thr_sanity"
-           else mempty
+      , let runtestArgs =
+                [ "--way=nonmoving --way=nonmoving_thr --way=nonmoving_thr_sanity"
+                | validateNonmovingGc buildConfig
+                ]
+        in "RUNTEST_ARGS" =: unwords runtestArgs
       ]
 
     jobArtifacts = Artifacts
       { junitReport = "junit.xml"
       , expireIn = "2 weeks"
       , artifactPaths = [binDistName arch opsys buildConfig ++ ".tar.xz"
-                        ,"junit.xml"]
+                        ,"junit.xml"
+                        ,"unexpected-test-output.tar.gz"]
       , artifactsWhen = ArtifactsAlways
       }
 


=====================================
.gitlab/jobs.yaml
=====================================
@@ -3,6 +3,7 @@
   "aarch64-darwin-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -11,7 +12,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-aarch64-darwin-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -59,12 +61,14 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "11.0",
       "NIX_SYSTEM": "aarch64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-darwin-validate"
     }
   },
   "aarch64-linux-deb10-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -73,7 +77,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-aarch64-linux-deb10-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -117,12 +122,14 @@
       "BIN_DIST_NAME": "ghc-aarch64-linux-deb10-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-linux-deb10-validate"
     }
   },
   "i386-linux-deb9-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -131,7 +138,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-i386-linux-deb9-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -175,12 +183,14 @@
       "BIN_DIST_NAME": "ghc-i386-linux-deb9-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "i386-linux-deb9-validate"
     }
   },
   "nightly-aarch64-darwin-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -189,7 +199,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-aarch64-darwin-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -237,6 +248,7 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "11.0",
       "NIX_SYSTEM": "aarch64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-darwin-validate",
       "XZ_OPT": "-9"
     }
@@ -244,6 +256,7 @@
   "nightly-aarch64-linux-deb10-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -252,7 +265,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-aarch64-linux-deb10-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -296,6 +310,7 @@
       "BIN_DIST_NAME": "ghc-aarch64-linux-deb10-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-linux-deb10-validate",
       "XZ_OPT": "-9"
     }
@@ -303,6 +318,7 @@
   "nightly-aarch64-linux-deb10-validate+llvm": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -311,7 +327,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-aarch64-linux-deb10-validate+llvm.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -355,6 +372,7 @@
       "BIN_DIST_NAME": "ghc-aarch64-linux-deb10-validate+llvm",
       "BUILD_FLAVOUR": "validate+llvm",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-linux-deb10-validate+llvm",
       "XZ_OPT": "-9"
     }
@@ -362,6 +380,7 @@
   "nightly-i386-linux-deb9-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -370,7 +389,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-i386-linux-deb9-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -414,6 +434,7 @@
       "BIN_DIST_NAME": "ghc-i386-linux-deb9-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "i386-linux-deb9-validate",
       "XZ_OPT": "-9"
     }
@@ -421,6 +442,7 @@
   "nightly-x86_64-darwin-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -429,7 +451,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-darwin-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -477,6 +500,7 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "10.10",
       "NIX_SYSTEM": "x86_64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-darwin-validate",
       "XZ_OPT": "-9",
       "ac_cv_func_clock_gettime": "no",
@@ -487,6 +511,7 @@
   "nightly-x86_64-freebsd13-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -495,7 +520,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-freebsd13-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -541,6 +567,7 @@
       "CONFIGURE_ARGS": "--with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib ",
       "GHC_VERSION": "9.4.3",
       "HADRIAN_ARGS": "--docs=no-sphinx",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-freebsd13-validate",
       "XZ_OPT": "-9"
     }
@@ -548,6 +575,7 @@
   "nightly-x86_64-linux-alpine3_12-int_native-validate+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -556,7 +584,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-int_native-validate+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -603,6 +632,7 @@
       "CONFIGURE_ARGS": "--disable-ld-override ",
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-int_native-validate+fully_static",
       "XZ_OPT": "-9"
     }
@@ -610,6 +640,7 @@
   "nightly-x86_64-linux-alpine3_12-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -618,7 +649,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -665,6 +697,7 @@
       "CONFIGURE_ARGS": "--disable-ld-override ",
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-validate",
       "XZ_OPT": "-9"
     }
@@ -672,6 +705,7 @@
   "nightly-x86_64-linux-alpine3_12-validate+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -680,7 +714,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-validate+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -727,6 +762,7 @@
       "CONFIGURE_ARGS": "--disable-ld-override ",
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-validate+fully_static",
       "XZ_OPT": "-9"
     }
@@ -734,6 +770,7 @@
   "nightly-x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -742,7 +779,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -788,6 +826,7 @@
       "CONFIGURE_ARGS": "--with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static",
       "XZ_OPT": "-9"
     }
@@ -795,6 +834,7 @@
   "nightly-x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -803,7 +843,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -849,6 +890,7 @@
       "CONFIGURE_ARGS": "--with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static",
       "XZ_OPT": "-9"
     }
@@ -856,6 +898,7 @@
   "nightly-x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -864,7 +907,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -910,6 +954,7 @@
       "CONFIGURE_ARGS": "--enable-unregisterised --with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static",
       "XZ_OPT": "-9"
     }
@@ -917,6 +962,7 @@
   "nightly-x86_64-linux-centos7-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -925,7 +971,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-centos7-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -970,6 +1017,7 @@
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--docs=no-sphinx",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-centos7-validate",
       "XZ_OPT": "-9"
     }
@@ -977,6 +1025,7 @@
   "nightly-x86_64-linux-deb10-int_native-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -985,7 +1034,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-int_native-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1029,6 +1079,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-int_native-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-int_native-validate",
       "XZ_OPT": "-9"
     }
@@ -1036,6 +1087,7 @@
   "nightly-x86_64-linux-deb10-no_tntc-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1044,7 +1096,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-no_tntc-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1088,6 +1141,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-no_tntc-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "--disable-tables-next-to-code",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-no_tntc-validate",
       "XZ_OPT": "-9"
     }
@@ -1095,6 +1149,7 @@
   "nightly-x86_64-linux-deb10-numa-slow-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1103,7 +1158,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-numa-slow-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1148,6 +1204,7 @@
       "BUILD_FLAVOUR": "slow-validate",
       "CONFIGURE_ARGS": "",
       "ENABLE_NUMA": "1",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-numa-slow-validate",
       "XZ_OPT": "-9"
     }
@@ -1155,6 +1212,7 @@
   "nightly-x86_64-linux-deb10-unreg-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1163,7 +1221,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-unreg-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1207,6 +1266,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-unreg-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "--enable-unregisterised",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-unreg-validate",
       "XZ_OPT": "-9"
     }
@@ -1214,6 +1274,7 @@
   "nightly-x86_64-linux-deb10-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1222,7 +1283,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1266,6 +1328,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate",
       "XZ_OPT": "-9"
     }
@@ -1273,6 +1336,7 @@
   "nightly-x86_64-linux-deb10-validate+debug_info": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1281,7 +1345,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+debug_info.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1325,6 +1390,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate+debug_info",
       "BUILD_FLAVOUR": "validate+debug_info",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+debug_info",
       "XZ_OPT": "-9"
     }
@@ -1332,6 +1398,7 @@
   "nightly-x86_64-linux-deb10-validate+llvm": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1340,7 +1407,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+llvm.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1384,6 +1452,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate+llvm",
       "BUILD_FLAVOUR": "validate+llvm",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+llvm",
       "XZ_OPT": "-9"
     }
@@ -1391,6 +1460,7 @@
   "nightly-x86_64-linux-deb10-validate+thread_sanitizer": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1399,7 +1469,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+thread_sanitizer.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1444,6 +1515,7 @@
       "BUILD_FLAVOUR": "validate+thread_sanitizer",
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+thread_sanitizer",
       "TSAN_OPTIONS": "suppressions=$CI_PROJECT_DIR/rts/.tsan-suppressions",
       "XZ_OPT": "-9"
@@ -1452,6 +1524,7 @@
   "nightly-x86_64-linux-deb11-cross_aarch64-linux-gnu-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1460,7 +1533,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-cross_aarch64-linux-gnu-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1506,6 +1580,7 @@
       "CONFIGURE_ARGS": "--with-intree-gmp",
       "CROSS_EMULATOR": "qemu-aarch64 -L /usr/aarch64-linux-gnu",
       "CROSS_TARGET": "aarch64-linux-gnu",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-cross_aarch64-linux-gnu-validate",
       "XZ_OPT": "-9"
     }
@@ -1513,6 +1588,7 @@
   "nightly-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1521,7 +1597,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1568,6 +1645,7 @@
       "CONFIGURE_WRAPPER": "emconfigure",
       "CROSS_EMULATOR": "js-emulator",
       "CROSS_TARGET": "javascript-unknown-ghcjs",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate",
       "XZ_OPT": "-9"
     }
@@ -1575,6 +1653,7 @@
   "nightly-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1583,7 +1662,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1630,6 +1710,7 @@
       "CONFIGURE_WRAPPER": "emconfigure",
       "CROSS_EMULATOR": "js-emulator",
       "CROSS_TARGET": "javascript-unknown-ghcjs",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate",
       "XZ_OPT": "-9"
     }
@@ -1637,6 +1718,7 @@
   "nightly-x86_64-linux-deb11-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1645,7 +1727,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1689,6 +1772,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb11-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-validate",
       "XZ_OPT": "-9"
     }
@@ -1696,6 +1780,7 @@
   "nightly-x86_64-linux-deb11-validate+boot_nonmoving_gc": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1704,7 +1789,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-validate+boot_nonmoving_gc.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1756,6 +1842,7 @@
   "nightly-x86_64-linux-deb9-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1764,7 +1851,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-deb9-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1808,6 +1896,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb9-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb9-validate",
       "XZ_OPT": "-9"
     }
@@ -1815,6 +1904,7 @@
   "nightly-x86_64-linux-fedora33-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1823,7 +1913,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-fedora33-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1869,6 +1960,7 @@
       "CONFIGURE_ARGS": "",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release",
       "XZ_OPT": "-9"
     }
@@ -1876,6 +1968,7 @@
   "nightly-x86_64-linux-fedora33-release-hackage": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1884,7 +1977,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-fedora33-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1931,6 +2025,7 @@
       "HADRIAN_ARGS": "--haddock-base-url",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release",
       "XZ_OPT": "-9"
     }
@@ -1938,6 +2033,7 @@
   "nightly-x86_64-linux-fedora33-validate+debug_info": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -1946,7 +2042,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-fedora33-validate+debug_info.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -1992,6 +2089,7 @@
       "CONFIGURE_ARGS": "",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-validate+debug_info",
       "XZ_OPT": "-9"
     }
@@ -1999,6 +2097,7 @@
   "nightly-x86_64-linux-rocky8-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2007,7 +2106,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-rocky8-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2052,6 +2152,7 @@
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--docs=no-sphinx",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-rocky8-validate",
       "XZ_OPT": "-9"
     }
@@ -2059,6 +2160,7 @@
   "nightly-x86_64-linux-ubuntu18_04-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2067,7 +2169,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-ubuntu18_04-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2111,6 +2214,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-ubuntu18_04-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-ubuntu18_04-validate",
       "XZ_OPT": "-9"
     }
@@ -2118,6 +2222,7 @@
   "nightly-x86_64-linux-ubuntu20_04-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2126,7 +2231,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-linux-ubuntu20_04-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2170,6 +2276,7 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-ubuntu20_04-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-ubuntu20_04-validate",
       "XZ_OPT": "-9"
     }
@@ -2177,6 +2284,7 @@
   "nightly-x86_64-windows-int_native-validate": {
     "after_script": [
       "bash .gitlab/ci.sh save_cache",
+      "bash .gitlab/ci.sh save_test_output",
       "bash .gitlab/ci.sh clean"
     ],
     "allow_failure": false,
@@ -2184,7 +2292,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-windows-int_native-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2229,6 +2338,7 @@
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "LANG": "en_US.UTF-8",
       "MSYSTEM": "CLANG64",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-windows-int_native-validate",
       "XZ_OPT": "-9"
     }
@@ -2236,6 +2346,7 @@
   "nightly-x86_64-windows-validate": {
     "after_script": [
       "bash .gitlab/ci.sh save_cache",
+      "bash .gitlab/ci.sh save_test_output",
       "bash .gitlab/ci.sh clean"
     ],
     "allow_failure": false,
@@ -2243,7 +2354,8 @@
       "expire_in": "8 weeks",
       "paths": [
         "ghc-x86_64-windows-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2288,6 +2400,7 @@
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "LANG": "en_US.UTF-8",
       "MSYSTEM": "CLANG64",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-windows-validate",
       "XZ_OPT": "-9"
     }
@@ -2295,6 +2408,7 @@
   "release-aarch64-darwin-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2303,7 +2417,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-aarch64-darwin-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2352,6 +2467,7 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "11.0",
       "NIX_SYSTEM": "aarch64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-darwin-release",
       "XZ_OPT": "-9"
     }
@@ -2359,6 +2475,7 @@
   "release-aarch64-linux-deb10-release+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2367,7 +2484,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-aarch64-linux-deb10-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2413,6 +2531,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "aarch64-linux-deb10-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -2420,6 +2539,7 @@
   "release-i386-linux-deb9-release+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2428,7 +2548,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-i386-linux-deb9-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2474,6 +2595,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "i386-linux-deb9-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -2481,6 +2603,7 @@
   "release-x86_64-darwin-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2489,7 +2612,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-darwin-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2538,6 +2662,7 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "10.10",
       "NIX_SYSTEM": "x86_64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-darwin-release",
       "XZ_OPT": "-9",
       "ac_cv_func_clock_gettime": "no",
@@ -2548,6 +2673,7 @@
   "release-x86_64-linux-alpine3_12-int_native-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2556,7 +2682,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-int_native-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2604,6 +2731,7 @@
       "HADRIAN_ARGS": "--hash-unit-ids --docs=no-sphinx",
       "IGNORE_PERF_FAILURES": "all",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-int_native-release+fully_static",
       "XZ_OPT": "-9"
     }
@@ -2611,6 +2739,7 @@
   "release-x86_64-linux-alpine3_12-release+fully_static+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2619,7 +2748,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-release+fully_static+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2667,6 +2797,7 @@
       "HADRIAN_ARGS": "--hash-unit-ids --docs=no-sphinx",
       "IGNORE_PERF_FAILURES": "all",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-release+fully_static+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -2674,6 +2805,7 @@
   "release-x86_64-linux-alpine3_12-release+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2682,7 +2814,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2730,6 +2863,7 @@
       "HADRIAN_ARGS": "--hash-unit-ids --docs=no-sphinx",
       "IGNORE_PERF_FAILURES": "all",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -2737,6 +2871,7 @@
   "release-x86_64-linux-centos7-release+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2745,7 +2880,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-centos7-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2791,6 +2927,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids --docs=no-sphinx",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-centos7-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -2798,6 +2935,7 @@
   "release-x86_64-linux-deb10-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2806,7 +2944,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb10-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2852,6 +2991,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-release",
       "XZ_OPT": "-9"
     }
@@ -2859,6 +2999,7 @@
   "release-x86_64-linux-deb10-release+debug_info": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2867,7 +3008,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb10-release+debug_info.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2913,6 +3055,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-release+debug_info",
       "XZ_OPT": "-9"
     }
@@ -2920,6 +3063,7 @@
   "release-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2928,7 +3072,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -2977,6 +3122,7 @@
       "CROSS_TARGET": "javascript-unknown-ghcjs",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-release",
       "XZ_OPT": "-9"
     }
@@ -2984,6 +3130,7 @@
   "release-x86_64-linux-deb11-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -2992,7 +3139,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb11-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3038,6 +3186,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-release",
       "XZ_OPT": "-9"
     }
@@ -3045,6 +3194,7 @@
   "release-x86_64-linux-deb11-release+boot_nonmoving_gc": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3053,7 +3203,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb11-release+boot_nonmoving_gc.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3107,6 +3258,7 @@
   "release-x86_64-linux-deb9-release+no_split_sections": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3115,7 +3267,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-deb9-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3161,6 +3314,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb9-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -3168,6 +3322,7 @@
   "release-x86_64-linux-fedora33-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3176,7 +3331,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-fedora33-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3224,6 +3380,7 @@
       "IGNORE_PERF_FAILURES": "all",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release",
       "XZ_OPT": "-9"
     }
@@ -3231,6 +3388,7 @@
   "release-x86_64-linux-fedora33-release+debug_info": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3239,7 +3397,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-fedora33-release+debug_info.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3287,6 +3446,7 @@
       "IGNORE_PERF_FAILURES": "all",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release+debug_info",
       "XZ_OPT": "-9"
     }
@@ -3294,6 +3454,7 @@
   "release-x86_64-linux-fedora33-release-hackage": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3302,7 +3463,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-fedora33-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3350,6 +3512,7 @@
       "IGNORE_PERF_FAILURES": "all",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release",
       "XZ_OPT": "-9"
     }
@@ -3357,6 +3520,7 @@
   "release-x86_64-linux-rocky8-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3365,7 +3529,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-rocky8-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3411,6 +3576,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids --docs=no-sphinx",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-rocky8-release",
       "XZ_OPT": "-9"
     }
@@ -3418,6 +3584,7 @@
   "release-x86_64-linux-ubuntu18_04-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3426,7 +3593,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-ubuntu18_04-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3472,6 +3640,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-ubuntu18_04-release",
       "XZ_OPT": "-9"
     }
@@ -3479,6 +3648,7 @@
   "release-x86_64-linux-ubuntu20_04-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3487,7 +3657,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-linux-ubuntu20_04-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3533,6 +3704,7 @@
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--hash-unit-ids",
       "IGNORE_PERF_FAILURES": "all",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-ubuntu20_04-release",
       "XZ_OPT": "-9"
     }
@@ -3540,6 +3712,7 @@
   "release-x86_64-windows-int_native-release+no_split_sections": {
     "after_script": [
       "bash .gitlab/ci.sh save_cache",
+      "bash .gitlab/ci.sh save_test_output",
       "bash .gitlab/ci.sh clean"
     ],
     "allow_failure": false,
@@ -3547,7 +3720,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-windows-int_native-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3593,6 +3767,7 @@
       "IGNORE_PERF_FAILURES": "all",
       "LANG": "en_US.UTF-8",
       "MSYSTEM": "CLANG64",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-windows-int_native-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -3600,6 +3775,7 @@
   "release-x86_64-windows-release+no_split_sections": {
     "after_script": [
       "bash .gitlab/ci.sh save_cache",
+      "bash .gitlab/ci.sh save_test_output",
       "bash .gitlab/ci.sh clean"
     ],
     "allow_failure": false,
@@ -3607,7 +3783,8 @@
       "expire_in": "1 year",
       "paths": [
         "ghc-x86_64-windows-release+no_split_sections.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3653,6 +3830,7 @@
       "IGNORE_PERF_FAILURES": "all",
       "LANG": "en_US.UTF-8",
       "MSYSTEM": "CLANG64",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-windows-release+no_split_sections",
       "XZ_OPT": "-9"
     }
@@ -3660,6 +3838,7 @@
   "x86_64-darwin-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3668,7 +3847,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-darwin-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3716,6 +3896,7 @@
       "LANG": "en_US.UTF-8",
       "MACOSX_DEPLOYMENT_TARGET": "10.10",
       "NIX_SYSTEM": "x86_64-darwin",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-darwin-validate",
       "ac_cv_func_clock_gettime": "no",
       "ac_cv_func_futimens": "no",
@@ -3725,6 +3906,7 @@
   "x86_64-freebsd13-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3733,7 +3915,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-freebsd13-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3779,12 +3962,14 @@
       "CONFIGURE_ARGS": "--with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib ",
       "GHC_VERSION": "9.4.3",
       "HADRIAN_ARGS": "--docs=no-sphinx",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-freebsd13-validate"
     }
   },
   "x86_64-linux-alpine3_12-validate+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3793,7 +3978,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_12-validate+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3840,12 +4026,14 @@
       "CONFIGURE_ARGS": "--disable-ld-override ",
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "INSTALL_CONFIGURE_ARGS": "--disable-ld-override",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_12-validate+fully_static"
     }
   },
   "x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3854,7 +4042,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3900,12 +4089,14 @@
       "CONFIGURE_ARGS": "--with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-cross_wasm32-wasi-release+fully_static"
     }
   },
   "x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3914,7 +4105,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -3961,12 +4153,14 @@
       "CONFIGURE_ARGS": "--with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-int_native-cross_wasm32-wasi-release+fully_static"
     }
   },
   "x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -3975,7 +4169,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4022,12 +4217,14 @@
       "CONFIGURE_ARGS": "--enable-unregisterised --with-intree-gmp --with-system-libffi",
       "CROSS_TARGET": "wasm32-wasi",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-alpine3_17-wasm-unreg-cross_wasm32-wasi-release+fully_static"
     }
   },
   "x86_64-linux-deb10-int_native-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4036,7 +4233,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-int_native-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4080,12 +4278,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-int_native-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-int_native-validate"
     }
   },
   "x86_64-linux-deb10-no_tntc-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4094,7 +4294,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-no_tntc-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4139,12 +4340,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-no_tntc-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "--disable-tables-next-to-code",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-no_tntc-validate"
     }
   },
   "x86_64-linux-deb10-numa-slow-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4153,7 +4356,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-numa-slow-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4198,12 +4402,14 @@
       "BUILD_FLAVOUR": "slow-validate",
       "CONFIGURE_ARGS": "",
       "ENABLE_NUMA": "1",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-numa-slow-validate"
     }
   },
   "x86_64-linux-deb10-unreg-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4212,7 +4418,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-unreg-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4256,12 +4463,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-unreg-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "--enable-unregisterised",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-unreg-validate"
     }
   },
   "x86_64-linux-deb10-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4270,7 +4479,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4314,12 +4524,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate",
       "BUILD_FLAVOUR": "validate",
       "CONFIGURE_ARGS": "--enable-ipe-data-compression",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate"
     }
   },
   "x86_64-linux-deb10-validate+debug_info": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4328,7 +4540,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+debug_info.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4372,12 +4585,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate+debug_info",
       "BUILD_FLAVOUR": "validate+debug_info",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+debug_info"
     }
   },
   "x86_64-linux-deb10-validate+llvm": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4386,7 +4601,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+llvm.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4430,12 +4646,14 @@
       "BIN_DIST_NAME": "ghc-x86_64-linux-deb10-validate+llvm",
       "BUILD_FLAVOUR": "validate+llvm",
       "CONFIGURE_ARGS": "",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+llvm"
     }
   },
   "x86_64-linux-deb10-validate+thread_sanitizer": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4444,7 +4662,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb10-validate+thread_sanitizer.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4490,6 +4709,7 @@
       "BUILD_FLAVOUR": "validate+thread_sanitizer",
       "CONFIGURE_ARGS": "",
       "HADRIAN_ARGS": "--docs=none",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb10-validate+thread_sanitizer",
       "TSAN_OPTIONS": "suppressions=$CI_PROJECT_DIR/rts/.tsan-suppressions"
     }
@@ -4497,6 +4717,7 @@
   "x86_64-linux-deb11-cross_aarch64-linux-gnu-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4505,7 +4726,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-cross_aarch64-linux-gnu-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4551,12 +4773,14 @@
       "CONFIGURE_ARGS": "--with-intree-gmp",
       "CROSS_EMULATOR": "qemu-aarch64 -L /usr/aarch64-linux-gnu",
       "CROSS_TARGET": "aarch64-linux-gnu",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-cross_aarch64-linux-gnu-validate"
     }
   },
   "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4565,7 +4789,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4612,12 +4837,14 @@
       "CONFIGURE_WRAPPER": "emconfigure",
       "CROSS_EMULATOR": "js-emulator",
       "CROSS_TARGET": "javascript-unknown-ghcjs",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-slow-validate"
     }
   },
   "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4626,7 +4853,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4673,12 +4901,14 @@
       "CONFIGURE_WRAPPER": "emconfigure",
       "CROSS_EMULATOR": "js-emulator",
       "CROSS_TARGET": "javascript-unknown-ghcjs",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-deb11-int_native-cross_javascript-unknown-ghcjs-validate"
     }
   },
   "x86_64-linux-deb11-validate+boot_nonmoving_gc": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4687,7 +4917,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-deb11-validate+boot_nonmoving_gc.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4738,6 +4969,7 @@
   "x86_64-linux-fedora33-release": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
       ".gitlab/ci.sh clean",
       "cat ci_timings"
     ],
@@ -4746,7 +4978,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-linux-fedora33-release.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4792,12 +5025,14 @@
       "CONFIGURE_ARGS": "",
       "LLC": "/bin/false",
       "OPT": "/bin/false",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-linux-fedora33-release"
     }
   },
   "x86_64-windows-validate": {
     "after_script": [
       "bash .gitlab/ci.sh save_cache",
+      "bash .gitlab/ci.sh save_test_output",
       "bash .gitlab/ci.sh clean"
     ],
     "allow_failure": false,
@@ -4805,7 +5040,8 @@
       "expire_in": "2 weeks",
       "paths": [
         "ghc-x86_64-windows-validate.tar.xz",
-        "junit.xml"
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
       ],
       "reports": {
         "junit": "junit.xml"
@@ -4850,6 +5086,7 @@
       "HADRIAN_ARGS": "--docs=no-sphinx",
       "LANG": "en_US.UTF-8",
       "MSYSTEM": "CLANG64",
+      "RUNTEST_ARGS": "",
       "TEST_ENV": "x86_64-windows-validate"
     }
   }


=====================================
compiler/GHC/Iface/Syntax.hs
=====================================
@@ -834,10 +834,13 @@ When printing an interface file (--show-iface), we want to print
 everything unqualified, so we can just print the OccName directly.
 -}
 
+-- | Show a declaration but not its RHS.
 showToHeader :: ShowSub
 showToHeader = ShowSub { ss_how_much = ShowHeader $ AltPpr Nothing
                        , ss_forall = ShowForAllWhen }
 
+-- | Show declaration and its RHS, including GHc-internal information (e.g.
+-- for @--show-iface@).
 showToIface :: ShowSub
 showToIface = ShowSub { ss_how_much = ShowIface
                       , ss_forall = ShowForAllWhen }
@@ -848,18 +851,20 @@ ppShowIface _                                     _   = Outputable.empty
 
 -- show if all sub-components or the complete interface is shown
 ppShowAllSubs :: ShowSub -> SDoc -> SDoc -- See Note [Minimal complete definition]
-ppShowAllSubs (ShowSub { ss_how_much = ShowSome [] _ }) doc = doc
-ppShowAllSubs (ShowSub { ss_how_much = ShowIface })     doc = doc
-ppShowAllSubs _                                         _   = Outputable.empty
+ppShowAllSubs (ShowSub { ss_how_much = ShowSome Nothing _ }) doc
+                                                        = doc
+ppShowAllSubs (ShowSub { ss_how_much = ShowIface }) doc = doc
+ppShowAllSubs _                                     _   = Outputable.empty
 
 ppShowRhs :: ShowSub -> SDoc -> SDoc
 ppShowRhs (ShowSub { ss_how_much = ShowHeader _ }) _   = Outputable.empty
 ppShowRhs _                                        doc = doc
 
 showSub :: HasOccName n => ShowSub -> n -> Bool
-showSub (ShowSub { ss_how_much = ShowHeader _ })     _     = False
-showSub (ShowSub { ss_how_much = ShowSome (n:_) _ }) thing = n == occName thing
-showSub (ShowSub { ss_how_much = _ })              _     = True
+showSub (ShowSub { ss_how_much = ShowHeader _ }) _     = False
+showSub (ShowSub { ss_how_much = ShowSome (Just f) _ }) thing
+                                                       = f (occName thing)
+showSub (ShowSub { ss_how_much = _ })            _     = True
 
 ppr_trim :: [Maybe SDoc] -> [SDoc]
 -- Collapse a group of Nothings to a single "..."


=====================================
compiler/GHC/Iface/Type.hs
=====================================
@@ -1361,21 +1361,18 @@ data ShowSub
 newtype AltPpr = AltPpr (Maybe (OccName -> SDoc))
 
 data ShowHowMuch
-  = ShowHeader AltPpr -- ^Header information only, not rhs
-  | ShowSome [OccName] AltPpr
-  -- ^ Show only some sub-components. Specifically,
-  --
-  -- [@\[\]@] Print all sub-components.
-  -- [@(n:ns)@] Print sub-component @n@ with @ShowSub = ns@;
-  -- elide other sub-components to @...@
-  -- May 14: the list is max 1 element long at the moment
+  = ShowHeader AltPpr -- ^ Header information only, not rhs
+  | ShowSome (Maybe (OccName -> Bool)) AltPpr
+  -- ^ Show the declaration and its RHS. The @Maybe@ predicate
+  -- allows filtering of the sub-components which should be printing;
+  -- any sub-components filtered out will be elided with @... at .
   | ShowIface
-  -- ^Everything including GHC-internal information (used in --show-iface)
+  -- ^ Everything including GHC-internal information (used in --show-iface)
 
 instance Outputable ShowHowMuch where
-  ppr (ShowHeader _)    = text "ShowHeader"
-  ppr ShowIface         = text "ShowIface"
-  ppr (ShowSome occs _) = text "ShowSome" <+> ppr occs
+  ppr (ShowHeader _) = text "ShowHeader"
+  ppr ShowIface      = text "ShowIface"
+  ppr (ShowSome _ _) = text "ShowSome"
 
 pprIfaceSigmaType :: ShowForAllFlag -> IfaceType -> SDoc
 pprIfaceSigmaType show_forall ty


=====================================
compiler/GHC/Types/TyThing/Ppr.hs
=====================================
@@ -145,16 +145,24 @@ pprTyThingHdr = pprTyThing showToHeader
 -- parts omitted.
 pprTyThingInContext :: ShowSub -> TyThing -> SDoc
 pprTyThingInContext show_sub thing
-  = go [] thing
+  = case parents thing of
+      -- If there are no parents print everything.
+      [] -> print_it Nothing thing
+      -- If `thing` has a parent, print the parent and only its child `thing`
+      thing':rest -> let subs = map getOccName (thing:rest)
+                         filt = (`elem` subs)
+                     in print_it (Just filt) thing'
   where
-    go ss thing
-      = case tyThingParent_maybe thing of
-          Just parent ->
-            go (getOccName thing : ss) parent
-          Nothing ->
-            pprTyThing
-              (show_sub { ss_how_much = ShowSome ss (AltPpr Nothing) })
-              thing
+    parents = go
+      where
+        go thing =
+          case tyThingParent_maybe thing of
+            Just parent -> parent : go parent
+            Nothing     -> []
+
+    print_it :: Maybe (OccName -> Bool) -> TyThing -> SDoc
+    print_it mb_filt thing =
+      pprTyThing (show_sub { ss_how_much = ShowSome mb_filt (AltPpr Nothing) }) thing
 
 -- | Like 'pprTyThingInContext', but adds the defining location.
 pprTyThingInContextLoc :: TyThing -> SDoc
@@ -171,8 +179,8 @@ pprTyThing ss ty_thing
       pprIfaceDecl ss' (tyThingToIfaceDecl show_linear_types ty_thing)
   where
     ss' = case ss_how_much ss of
-      ShowHeader (AltPpr Nothing)  -> ss { ss_how_much = ShowHeader ppr' }
-      ShowSome xs (AltPpr Nothing) -> ss { ss_how_much = ShowSome xs ppr' }
+      ShowHeader (AltPpr Nothing)    -> ss { ss_how_much = ShowHeader ppr' }
+      ShowSome filt (AltPpr Nothing) -> ss { ss_how_much = ShowSome filt ppr' }
       _                   -> ss
 
     ppr' = AltPpr $ ppr_bndr $ getName ty_thing


=====================================
hadrian/src/Packages.hs
=====================================
@@ -3,7 +3,7 @@ module Packages (
     -- * GHC packages
     array, base, binary, bytestring, cabal, cabalSyntax, checkPpr,
     checkExact, countDeps,
-    compareSizes, compiler, containers, deepseq, deriveConstants, directory,
+    compareSizes, compiler, containers, deepseq, deriveConstants, directory, dumpDecls,
     exceptions, filepath, genapply, genprimopcode, ghc, ghcBignum, ghcBoot, ghcBootTh,
     ghcCompact, ghcConfig, ghcHeap, ghci, ghciWrapper, ghcPkg, ghcPrim, haddock, haskeline,
     hsc2hs, hp2ps, hpc, hpcBin, integerGmp, integerSimple, iserv, iservProxy,
@@ -35,7 +35,7 @@ import Oracles.Setting
 ghcPackages :: [Package]
 ghcPackages =
     [ array, base, binary, bytestring, cabalSyntax, cabal, checkPpr, checkExact, countDeps
-    , compareSizes, compiler, containers, deepseq, deriveConstants, directory
+    , compareSizes, compiler, containers, deepseq, deriveConstants, directory, dumpDecls
     , exceptions, filepath, genapply, genprimopcode, ghc, ghcBignum, ghcBoot, ghcBootTh
     , ghcCompact, ghcConfig, ghcHeap, ghci, ghciWrapper, ghcPkg, ghcPrim, haddock, haskeline, hsc2hs
     , hp2ps, hpc, hpcBin, integerGmp, integerSimple, iserv, libffi, mtl
@@ -51,7 +51,7 @@ isGhcPackage = (`elem` ghcPackages)
 
 -- | Package definitions, see 'Package'.
 array, base, binary, bytestring, cabalSyntax, cabal, checkPpr, checkExact, countDeps,
-  compareSizes, compiler, containers, deepseq, deriveConstants, directory,
+  compareSizes, compiler, containers, deepseq, deriveConstants, directory, dumpDecls,
   exceptions, filepath, genapply, genprimopcode, ghc, ghcBignum, ghcBoot, ghcBootTh,
   ghcCompact, ghcConfig, ghcHeap, ghci, ghciWrapper, ghcPkg, ghcPrim, haddock, haskeline, hsc2hs,
   hp2ps, hpc, hpcBin, integerGmp, integerSimple, iserv, iservProxy, remoteIserv, libffi, mtl,
@@ -75,6 +75,7 @@ containers          = lib  "containers"      `setPath` "libraries/containers/con
 deepseq             = lib  "deepseq"
 deriveConstants     = util "deriveConstants"
 directory           = lib  "directory"
+dumpDecls           = util "dump-decls"
 exceptions          = lib  "exceptions"
 filepath            = lib  "filepath"
 genapply            = util "genapply"


=====================================
hadrian/src/Rules/Test.hs
=====================================
@@ -40,6 +40,12 @@ countDepsSourcePath = "utils/count-deps/Main.hs"
 countDepsExtra :: [String]
 countDepsExtra = ["-iutils/count-deps"]
 
+dumpDeclsProgPath, dumpDeclsSourcePath :: FilePath
+dumpDeclsProgPath = "test/bin/dump-decls" <.> exe
+dumpDeclsSourcePath = "utils/dump-decls/Main.hs"
+dumpDeclsExtra :: [String]
+dumpDeclsExtra = []
+
 noteLinterProgPath, noteLinterSourcePath :: FilePath
 noteLinterProgPath = "test/bin/lint-notes" <.> exe
 noteLinterSourcePath = "linters/lint-notes/Main.hs"
@@ -67,6 +73,7 @@ checkPrograms =
     [ CheckProgram "test:check-ppr" checkPprProgPath checkPprSourcePath checkPprExtra checkPpr id id
     , CheckProgram "test:check-exact" checkExactProgPath checkExactSourcePath checkExactExtra checkExact id id
     , CheckProgram "test:count-deps" countDepsProgPath countDepsSourcePath countDepsExtra countDeps id id
+    , CheckProgram "test:dump-decls" dumpDeclsProgPath dumpDeclsSourcePath dumpDeclsExtra dumpDecls id id
     , CheckProgram "lint:notes" noteLinterProgPath  noteLinterSourcePath  noteLinterExtra  lintNotes  (const stage0Boot)  id
     , CheckProgram "lint:whitespace"  whitespaceLinterProgPath  whitespaceLinterSourcePath  whitespaceLinterExtra  lintWhitespace  (const stage0Boot)  (filter (/= lintersCommon))
     ]
@@ -260,6 +267,7 @@ testRules = do
 
             setEnv "CHECK_PPR" (top -/- root -/- checkPprProgPath)
             setEnv "CHECK_EXACT" (top -/- root -/- checkExactProgPath)
+            setEnv "DUMP_DECLS" (top -/- root -/- dumpDeclsProgPath)
             setEnv "COUNT_DEPS" (top -/- root -/- countDepsProgPath)
             setEnv "LINT_NOTES" (top -/- root -/- noteLinterProgPath)
             setEnv "LINT_WHITESPACE" (top -/- root -/- whitespaceLinterProgPath)


=====================================
hadrian/src/Settings/Default.hs
=====================================
@@ -167,7 +167,7 @@ stage2Packages = stage1Packages
 
 -- | Packages that are built only for the testsuite.
 testsuitePackages :: Action [Package]
-testsuitePackages = return ([ timeout | windowsHost ] ++ [ checkPpr, checkExact, countDeps, ghcConfig ])
+testsuitePackages = return ([ timeout | windowsHost ] ++ [ checkPpr, checkExact, countDeps, ghcConfig, dumpDecls ])
 
 -- | Default build ways for library packages:
 -- * We always build 'vanilla' way.


=====================================
testsuite/mk/boilerplate.mk
=====================================
@@ -227,6 +227,10 @@ ifeq "$(CHECK_EXACT)" ""
 CHECK_EXACT := $(abspath $(TOP)/../inplace/bin/check-exact)
 endif
 
+ifeq "$(DUMP_DECLS)" ""
+DUMP_DECLS := $(abspath $(TOP)/../inplace/bin/dump-decls)
+endif
+
 ifeq "$(COUNT_DEPS)" ""
 COUNT_DEPS := $(abspath $(TOP)/../inplace/bin/count-deps)
 endif


=====================================
testsuite/tests/ghci/scripts/ghci008.stdout
=====================================
@@ -40,5 +40,5 @@ class (RealFrac a, Floating a) => RealFloat a where
   	-- Defined in ‘GHC.Float’
 instance RealFloat Double -- Defined in ‘GHC.Float’
 instance RealFloat Float -- Defined in ‘GHC.Float’
-base-4.16.0.0:Data.OldList.isPrefixOf :: Eq a => [a] -> [a] -> Bool
-  	-- Defined in ‘base-4.16.0.0:Data.OldList’
+base-4.18.0.0:Data.OldList.isPrefixOf :: Eq a => [a] -> [a] -> Bool
+  	-- Defined in ‘base-4.18.0.0:Data.OldList’


=====================================
testsuite/tests/interface-stability/Makefile
=====================================
@@ -0,0 +1,6 @@
+TOP=../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+exports_% :
+	"$(DUMP_DECLS)" "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`" $*


=====================================
testsuite/tests/interface-stability/README.mkd
=====================================
@@ -0,0 +1,11 @@
+# Interface stability testing
+
+The tests in this directory verify that the interfaces of exposed by GHC's
+core libraries do not inadvertently change. They use the `utils/dump-decls`
+utility to dump all exported declarations of all exposed modules for the
+following packages:
+
+  * base
+
+These are compared against the expected exports in the test's corresponding
+`.stdout` file.


=====================================
testsuite/tests/interface-stability/all.T
=====================================
@@ -0,0 +1,7 @@
+def check_package(pkg_name):
+    test(f'{pkg_name}-exports',
+         req_hadrian_deps(['test:dump-decls']),
+         makefile_test,
+         [f'exports_{pkg_name}'])
+
+check_package('base')


=====================================
testsuite/tests/interface-stability/base-exports.stdout
=====================================
The diff for this file was not included because it is too large.

=====================================
testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
=====================================
The diff for this file was not included because it is too large.

=====================================
testsuite/tests/interface-stability/base-exports.stdout-mingw32
=====================================
The diff for this file was not included because it is too large.

=====================================
testsuite/tests/interface-stability/base-exports.stdout-ws-32
=====================================
The diff for this file was not included because it is too large.

=====================================
utils/dump-decls/Main.hs
=====================================
@@ -0,0 +1,243 @@
+module Main where
+
+import GHC
+import GHC.Core.InstEnv (instEnvElts, instanceHead)
+import GHC.Core.Class (classMinimalDef)
+import GHC.Core.TyCo.FVs (tyConsOfType)
+import GHC.Driver.Ppr (showSDocForUser)
+import GHC.Unit.State (lookupUnitId, lookupPackageName)
+import GHC.Unit.Info (UnitInfo, unitExposedModules, PackageName(..))
+import GHC.Data.FastString (fsLit)
+import GHC.Driver.Env (hsc_units, hscEPS)
+import GHC.Utils.Outputable
+import GHC.Types.Unique.Set (nonDetEltsUniqSet)
+import GHC.Types.TyThing (tyThingParent_maybe)
+import GHC.Types.TyThing.Ppr (pprTyThing)
+import GHC.Types.Name (nameOccName, nameModule_maybe, stableNameCmp)
+import GHC.Types.Name.Occurrence (OccName, mkDataOcc, mkVarOcc)
+import GHC.Unit.External (eps_inst_env)
+import GHC.Iface.Syntax (ShowSub(..), ShowHowMuch(..), AltPpr(..))
+import GHC.Iface.Type (ShowForAllFlag(..))
+
+import Data.Function (on)
+import Data.List (sortBy)
+import Control.Monad.IO.Class
+import System.Environment (getArgs)
+import Prelude hiding ((<>))
+
+main :: IO ()
+main = do
+    ghcRoot:pkg_names <- getArgs
+    mapM_ (run ghcRoot) pkg_names
+
+run :: FilePath -> String -> IO ()
+run root pkg_nm = runGhc (Just root) $ do
+    let args = map noLoc
+            [ "-package=" ++ pkg_nm
+            , "-dppr-cols=1000"
+            , "-fprint-explicit-runtime-reps"
+            , "-fprint-explicit-foralls"
+            ]
+    dflags <- do
+        dflags <- getSessionDynFlags
+        logger <- getLogger
+        (dflags', _fileish_args, _dynamicFlagWarnings) <-
+          GHC.parseDynamicFlags logger dflags args
+        return dflags'
+
+    _ <- setProgramDynFlags dflags
+    unit_state <- hsc_units <$> getSession
+    unit_id <- case lookupPackageName unit_state (PackageName $ fsLit pkg_nm) of
+                    Just unit_id -> return unit_id
+                    Nothing -> fail "failed to find package"
+    unit_info <- case lookupUnitId unit_state unit_id of
+      Just unit_info -> return unit_info
+      Nothing -> fail "unknown package"
+
+    decls_doc <- reportUnitDecls unit_info
+    insts_doc <- reportInstances
+
+    name_ppr_ctx <- GHC.getNamePprCtx
+    let rendered = showSDocForUser dflags unit_state name_ppr_ctx (vcat [decls_doc, insts_doc])
+    liftIO $ putStrLn rendered
+
+ignoredModules :: [ModuleName]
+ignoredModules =
+    map mkModuleName $ concat
+    [ unstableModules
+    , platformDependentModules
+    ]
+  where
+    unstableModules =
+        [ "GHC.Prim"
+        , "GHC.Conc.POSIX"
+        , "GHC.Conc.IO"
+        ]
+    platformDependentModules =
+        [ "System.Posix.Types"
+        , "Foreign.C.Types"
+        ]
+
+ignoredOccNames :: [OccName]
+ignoredOccNames =
+    map mkDataOcc cTypeCons ++
+    map mkVarOcc integerConversionIds
+  where
+    -- Data constructors from Foreign.C.Types whose RHSs are inherently platform-dependent
+    cTypeCons =
+        [ "CBool"
+        , "CChar"
+        , "CClock"
+        , "CDouble"
+        , "CFile"
+        , "CFloat"
+        , "CFpos"
+        , "CInt"
+        , "CIntMax"
+        , "CIntPtr"
+        , "CJmpBuf"
+        , "CLLong"
+        , "CLong"
+        , "CPtrdiff"
+        , "CSChar"
+        , "CSUSeconds"
+        , "CShort"
+        , "CSigAtomic"
+        , "CSize"
+        , "CTime"
+        , "CUChar"
+        , "CUInt"
+        , "CUIntMax"
+        , "CUIntPtr"
+        , "CULLong"
+        , "CULong"
+        , "CUSeconds"
+        , "CUShort"
+        , "CWchar"
+        ]
+
+    -- Conversion functions in GHC.Integer which are only exposed on 32-bit
+    -- platforms
+    integerConversionIds =
+        [ "int64ToInteger"
+        , "integerToInt64"
+        , "integerToWord64"
+        , "word64ToInteger"
+        ]
+
+ignoredOccName :: OccName -> Bool
+ignoredOccName occ = occ `elem` ignoredOccNames
+
+ignoredName :: Name -> Bool
+ignoredName nm
+  | ignoredOccName (getOccName nm)
+  = True
+  | Just md <- nameModule_maybe nm
+  , moduleName md `elem` ignoredModules
+  = True
+  | otherwise
+  = False
+
+ignoredTyThing :: TyThing -> Bool
+ignoredTyThing _ = False
+
+ignoredTyCon :: TyCon -> Bool
+ignoredTyCon = ignoredName . getName
+
+ignoredType :: Type -> Bool
+ignoredType = any ignoredTyCon . nonDetEltsUniqSet . tyConsOfType
+
+-- | Ignore instances whose heads mention ignored types.
+ignoredInstance :: ClsInst -> Bool
+ignoredInstance inst
+  | ignoredName $ getName cls
+  = True
+  | any ignoredType tys
+  = True
+  | otherwise
+  = False
+  where
+    (_, cls, tys) = instanceHead inst
+
+reportUnitDecls :: UnitInfo -> Ghc SDoc
+reportUnitDecls unit_info = do
+    let exposed :: [ModuleName]
+        exposed = map fst (unitExposedModules unit_info)
+    vcat <$> mapM reportModuleDecls exposed
+
+reportModuleDecls :: ModuleName -> Ghc SDoc
+reportModuleDecls modl_nm
+  | modl_nm `elem` ignoredModules = do
+      return $ vcat [ mod_header, text "-- ignored", text "" ]
+  | otherwise = do
+    modl <- GHC.lookupQualifiedModule NoPkgQual modl_nm
+    mb_mod_info <- GHC.getModuleInfo modl
+    mod_info <- case mb_mod_info of
+      Nothing -> fail "Failed to find module"
+      Just mod_info -> return mod_info
+
+    Just name_ppr_ctx <- mkNamePprCtxForModule mod_info
+    let names = GHC.modInfoExports mod_info
+        sorted_names = sortBy (compare `on` nameOccName) names
+
+        exported_occs :: [OccName]
+        exported_occs = map nameOccName names
+
+        is_exported :: OccName -> Bool
+        is_exported occ = occ `elem` exported_occs
+
+        show_occ :: OccName -> Bool
+        show_occ occ = is_exported occ && not (ignoredOccName occ)
+
+    things <- mapM GHC.lookupName sorted_names
+    let contents = vcat $
+            [ text "-- Safety:" <+> ppr (modInfoSafe mod_info) ] ++
+            [ pprTyThing ss thing $$ extras
+            | Just thing <- things
+            , case tyThingParent_maybe thing of
+                Just parent
+                  | is_exported (getOccName parent) -> False
+                _ -> True
+            , not $ ignoredTyThing thing
+            , let ss = ShowSub { ss_how_much = ShowSome (Just show_occ) (AltPpr Nothing)
+                               , ss_forall = ShowForAllMust
+                               }
+            , let extras = case thing of
+                             ATyCon tycon
+                               | Just cls <- tyConClass_maybe tycon
+                               -> nest 2 (text "{-# MINIMAL" <+> ppr (classMinimalDef cls) <+> text "#-}")
+                             _ -> empty
+            ]
+
+    return $ withUserStyle name_ppr_ctx AllTheWay $
+        hang mod_header 2 contents <>
+        text ""
+  where
+    mod_header = vcat
+        [ text ""
+        , text "module" <+> ppr modl_nm <+> text "where"
+        , text ""
+        ]
+
+reportInstances :: Ghc SDoc
+reportInstances = do
+    hsc_env <- getSession
+    eps <- liftIO $ hscEPS hsc_env
+    let instances = eps_inst_env eps
+    return $ vcat $
+        [ text ""
+        , text ""
+        , text "-- Instances:"
+        ] ++
+        [ ppr inst
+        | inst <- sortBy compareInstances (instEnvElts instances)
+        , not $ ignoredInstance inst
+        ]
+
+compareInstances :: ClsInst -> ClsInst -> Ordering
+compareInstances inst1 inst2 = mconcat
+    [ stableNameCmp (getName cls1) (getName cls2)
+    ]
+  where
+      (_, cls1, _tys1) = instanceHead inst1
+      (_, cls2, _tys2) = instanceHead inst2


=====================================
utils/dump-decls/dump-decls.cabal
=====================================
@@ -0,0 +1,13 @@
+cabal-version:      2.4
+name:               dump-decls
+version:            0.1.0.0
+synopsis:           Dump the declarations of a package.
+license:            BSD-3-Clause
+author:             Ben Gamari
+maintainer:         ben at smart-cactus.org
+copyright:          (c) 2023 Ben Gamari
+
+executable dump-decls
+    main-is:          Main.hs
+    build-depends:    base, ghc
+    default-language: Haskell2010



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/498fdbf8049d1b003fb108d0cbe6eab8799458a4...51244bd7e51feaa0b2ef6c75c77ede3c5657f21d

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/498fdbf8049d1b003fb108d0cbe6eab8799458a4...51244bd7e51feaa0b2ef6c75c77ede3c5657f21d
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230706/1809fc7c/attachment-0001.html>


More information about the ghc-commits mailing list