[Git][ghc/ghc][master] Add regression test for #2057
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: 905f8723 by Simon Jakobi at 2026-03-13T15:09:09-04: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/.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/.gitignore ===================================== @@ -551,6 +551,7 @@ mk/ghcconfig*_test___spaces_ghc*.exe.mk /tests/driver/T10970 /tests/driver/T1959/E.hs /tests/driver/T1959/prog +/tests/driver/T2057/work/ /tests/driver/T3007/A/Setup /tests/driver/T3007/A/dist/ /tests/driver/T3007/B/Setup ===================================== 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)' + '$(AR)' q '$(PKGA2)/libHSpkgA.a' '$(PKGA2)/A.o' >/dev/null 2>&1 + cp pkgA2/pkg.conf '$(WORK)/pkgA2.conf' + '$(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,23 @@ +`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 dependency tree is + + app/Main -> pkgB -> pkgA + +where the two directories `pkgA1/` and `pkgA2/` are just two source trees +for the same package `pkgA`. + +`pkgA1` defines a local type `T` and a function `f :: T -> T`. +`pkgB` builds against that package and records an unfolding `g = f` in `B.hi`. + +After that, the Makefile updates the same package `pkgA` from `pkgA2/`, where +module `A` no longer exports `f`. When `Main` imports `B`, GHC has to load +`B.hi`, sees the stale reference to `f`, and must fail. + +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,8 @@ +test( + 'T2057', + [ extra_files(['pkgA1', 'pkgA2', 'pkgB', 'app', 'README.md']) + , 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/905f8723b92cb34e9f1fa7b4306f32c4... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/905f8723b92cb34e9f1fa7b4306f32c4... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)