[Git][ghc/ghc][wip/sjakobi/T2057] Add regression test for #2057
Simon Jakobi pushed to branch wip/sjakobi/T2057 at Glasgow Haskell Compiler / GHC Commits: 92031328 by Simon Jakobi at 2026-03-09T17:21:40+01:00 Add regression test for #2057 Test that GHC stops after an interface-file error instead of continuing into the linker. The test constructs a stale package dependency on purpose. `pkgB` is compiled against one version of package `A`, then the same unit id is replaced by an incompatible build of `A`. When `Main` imports `B`, GHC has to read `B.hi`, finds an unfolding that still mentions the old `A`, and should fail while loading interfaces. Closes #2057. Assisted-by: Codex - - - - - 12 changed files: - + testsuite/tests/driver/T2057/.gitignore - + testsuite/tests/driver/T2057/Makefile - + testsuite/tests/driver/T2057/README.md - + testsuite/tests/driver/T2057/T2057.stderr - + testsuite/tests/driver/T2057/all.T - + testsuite/tests/driver/T2057/app/Main.hs - + testsuite/tests/driver/T2057/pkgA1/A.hs - + testsuite/tests/driver/T2057/pkgA1/pkg.conf - + testsuite/tests/driver/T2057/pkgA2/A.hs - + testsuite/tests/driver/T2057/pkgA2/pkg.conf - + testsuite/tests/driver/T2057/pkgB/B.hs - + testsuite/tests/driver/T2057/pkgB/pkg.conf Changes: ===================================== testsuite/tests/driver/T2057/.gitignore ===================================== @@ -0,0 +1 @@ +work/ ===================================== testsuite/tests/driver/T2057/Makefile ===================================== @@ -0,0 +1,52 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +WORK = work +PKGDB = $(WORK)/pkgdb +PKGA1 = $(WORK)/pkgA1 +PKGA2 = $(WORK)/pkgA2 +PKGB = $(WORK)/pkgB +APP = $(WORK)/app +OUT = $(WORK)/T2057.out + +.PHONY: T2057 clean + +clean: + rm -rf $(WORK) + +T2057: clean + + # Create an isolated package DB and output directories for the repro. + mkdir -p '$(PKGA1)' '$(PKGA2)' '$(PKGB)' '$(APP)' + '$(GHC_PKG)' init '$(PKGDB)' + + # Build and register pkgA from the pkgA1 sources. + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \ + -this-unit-id pkgA -O -c pkgA1/A.hs -outputdir '$(PKGA1)' + ar q '$(PKGA1)/libHSpkgA.a' '$(PKGA1)/A.o' >/dev/null 2>&1 + cp pkgA1/pkg.conf '$(WORK)/pkgA1.conf' + '$(GHC_PKG)' --package-db '$(PKGDB)' register '$(WORK)/pkgA1.conf' >/dev/null + + # Build and register pkgB against pkgA so INLINE g records the unfolding g = f in B.hi. + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \ + -package pkgA -this-unit-id pkgB -O -c pkgB/B.hs \ + -outputdir '$(PKGB)' + ar q '$(PKGB)/libHSpkgB.a' '$(PKGB)/B.o' >/dev/null 2>&1 + cp pkgB/pkg.conf '$(WORK)/pkgB.conf' + '$(GHC_PKG)' --package-db '$(PKGDB)' register '$(WORK)/pkgB.conf' >/dev/null + + # Rebuild pkgA from the pkgA2 source tree, removing f. + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \ + -this-unit-id pkgA -O -c pkgA2/A.hs -outputdir '$(PKGA2)' + cp pkgA2/pkg.conf '$(WORK)/pkgA2.conf' + ar q '$(PKGA2)/libHSpkgA.a' '$(PKGA2)/A.o' >/dev/null 2>&1 + '$(GHC_PKG)' --package-db '$(PKGDB)' update '$(WORK)/pkgA2.conf' >/dev/null + + # Compiling Main against pkgB should now fail while loading the stale B.hi. + ! '$(TEST_HC)' $(TEST_HC_OPTS) -v0 --make app/Main.hs \ + -O -fforce-recomp -package-db '$(PKGDB)' -package pkgB \ + >'$(OUT)' 2>&1 || { echo "expected compilation failure" >&2; exit 1; } + + # Strip the absolute test directory prefix before comparing against T2057.stderr. + sed "s#$(CURDIR)/##g" '$(OUT)' >&2 ===================================== testsuite/tests/driver/T2057/README.md ===================================== @@ -0,0 +1,21 @@ +`T2057` checks that GHC stops after an interface-file error instead of +continuing into the linker. + +The test constructs a stale package dependency on purpose. The two directories +`pkgA1/` and `pkgA2/` are just two source trees for the same registered +package, `pkgA`. `pkgA` has no external package dependencies, and `pkgB` +depends only on `pkgA`. + +`pkgA1/` defines a local type `T` and `f :: T -> T`. `pkgB/` builds against +that package, keeps `{-# INLINE g #-}`, and therefore records the stale +unfolding `g = f` in `B.hi`. + +After that, the Makefile updates the same package `pkgA` from `pkgA2/`, where +module `A` still exports `T` but no longer exports `f`. When `Main` imports +`B`, GHC has to load `B.hi`, sees the stale reference to `f`, and should fail +while loading interfaces. + +The golden [`T2057.stderr`](T2057.stderr) captures the fixed behaviour: +diagnose the missing declaration in the stale interface and then stop with +`Cannot continue after interface file error`. Any linker output would be a +regression. ===================================== testsuite/tests/driver/T2057/T2057.stderr ===================================== @@ -0,0 +1,9 @@ +work/pkgB/B.hi +Declaration for g +Unfolding of g: + f ErrorWithoutFlag + Can't find interface-file declaration for variable f + Probable cause: bug in .hi-boot file, or inconsistent .hi file + Use -ddump-if-trace to get an idea of which file caused the error +<no location info>: + Cannot continue after interface file error ===================================== testsuite/tests/driver/T2057/all.T ===================================== @@ -0,0 +1,11 @@ +test( + 'T2057', + [ extra_files(['pkgA1', 'pkgA2', 'pkgB', 'app', 'README.md']) + , when(opsys('mingw32'), skip) + , js_skip + , wasm_skip + , ignore_stdout + ], + makefile_test, + [] +) ===================================== testsuite/tests/driver/T2057/app/Main.hs ===================================== @@ -0,0 +1,7 @@ +module Main where + +import B + +main :: IO () +main = case g MkT of + MkT -> print () ===================================== testsuite/tests/driver/T2057/pkgA1/A.hs ===================================== @@ -0,0 +1,7 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module A (T(..), f) where + +data T = MkT + +f :: T -> T +f x = x ===================================== testsuite/tests/driver/T2057/pkgA1/pkg.conf ===================================== @@ -0,0 +1,11 @@ +name: pkgA +version: 1.0 +id: pkgA +key: pkgA +exposed: True +exposed-modules: A +import-dirs: ${pkgroot}/pkgA1 +library-dirs: ${pkgroot}/pkgA1 +dynamic-library-dirs: ${pkgroot}/pkgA1 +hs-libraries: HSpkgA +depends: ===================================== testsuite/tests/driver/T2057/pkgA2/A.hs ===================================== @@ -0,0 +1,5 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module A where + +-- no f here +data T = MkT ===================================== testsuite/tests/driver/T2057/pkgA2/pkg.conf ===================================== @@ -0,0 +1,11 @@ +name: pkgA +version: 1.0 +id: pkgA +key: pkgA +exposed: True +exposed-modules: A +import-dirs: ${pkgroot}/pkgA2 +library-dirs: ${pkgroot}/pkgA2 +dynamic-library-dirs: ${pkgroot}/pkgA2 +hs-libraries: HSpkgA +depends: ===================================== testsuite/tests/driver/T2057/pkgB/B.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module B (T(..), g) where + +import A + +{-# INLINE g #-} +g :: T -> T +g x = f x ===================================== testsuite/tests/driver/T2057/pkgB/pkg.conf ===================================== @@ -0,0 +1,11 @@ +name: pkgB +version: 1.0 +id: pkgB +key: pkgB +exposed: True +exposed-modules: B +import-dirs: ${pkgroot}/pkgB +library-dirs: ${pkgroot}/pkgB +dynamic-library-dirs: ${pkgroot}/pkgB +hs-libraries: HSpkgB +depends: pkgA View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9203132832b84eba512e896aa043250d... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9203132832b84eba512e896aa043250d... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Simon Jakobi (@sjakobi2)