Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
905f8723
by Simon Jakobi at 2026-03-13T15:09:09-04:00
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:
| ... | ... | @@ -551,6 +551,7 @@ mk/ghcconfig*_test___spaces_ghc*.exe.mk |
| 551 | 551 | /tests/driver/T10970
|
| 552 | 552 | /tests/driver/T1959/E.hs
|
| 553 | 553 | /tests/driver/T1959/prog
|
| 554 | +/tests/driver/T2057/work/
|
|
| 554 | 555 | /tests/driver/T3007/A/Setup
|
| 555 | 556 | /tests/driver/T3007/A/dist/
|
| 556 | 557 | /tests/driver/T3007/B/Setup
|
| 1 | +TOP=../../..
|
|
| 2 | +include $(TOP)/mk/boilerplate.mk
|
|
| 3 | +include $(TOP)/mk/test.mk
|
|
| 4 | + |
|
| 5 | +WORK = work
|
|
| 6 | +PKGDB = $(WORK)/pkgdb
|
|
| 7 | +PKGA1 = $(WORK)/pkgA1
|
|
| 8 | +PKGA2 = $(WORK)/pkgA2
|
|
| 9 | +PKGB = $(WORK)/pkgB
|
|
| 10 | +APP = $(WORK)/app
|
|
| 11 | +OUT = $(WORK)/T2057.out
|
|
| 12 | + |
|
| 13 | +.PHONY: T2057 clean
|
|
| 14 | + |
|
| 15 | +clean:
|
|
| 16 | + rm -rf $(WORK)
|
|
| 17 | + |
|
| 18 | +T2057: clean
|
|
| 19 | + |
|
| 20 | + # Create an isolated package DB and output directories for the repro.
|
|
| 21 | + mkdir -p '$(PKGA1)' '$(PKGA2)' '$(PKGB)' '$(APP)'
|
|
| 22 | + '$(GHC_PKG)' init '$(PKGDB)'
|
|
| 23 | + |
|
| 24 | + # Build and register pkgA from the pkgA1 sources.
|
|
| 25 | + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \
|
|
| 26 | + -this-unit-id pkgA -O -c pkgA1/A.hs -outputdir '$(PKGA1)'
|
|
| 27 | + '$(AR)' q '$(PKGA1)/libHSpkgA.a' '$(PKGA1)/A.o' >/dev/null 2>&1
|
|
| 28 | + cp pkgA1/pkg.conf '$(WORK)/pkgA1.conf'
|
|
| 29 | + '$(GHC_PKG)' --package-db '$(PKGDB)' register '$(WORK)/pkgA1.conf' >/dev/null
|
|
| 30 | + |
|
| 31 | + # Build and register pkgB against pkgA so INLINE g records the unfolding g = f in B.hi.
|
|
| 32 | + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \
|
|
| 33 | + -package pkgA -this-unit-id pkgB -O -c pkgB/B.hs \
|
|
| 34 | + -outputdir '$(PKGB)'
|
|
| 35 | + '$(AR)' q '$(PKGB)/libHSpkgB.a' '$(PKGB)/B.o' >/dev/null 2>&1
|
|
| 36 | + cp pkgB/pkg.conf '$(WORK)/pkgB.conf'
|
|
| 37 | + '$(GHC_PKG)' --package-db '$(PKGDB)' register '$(WORK)/pkgB.conf' >/dev/null
|
|
| 38 | + |
|
| 39 | + # Rebuild pkgA from the pkgA2 source tree, removing f.
|
|
| 40 | + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -package-db '$(PKGDB)' \
|
|
| 41 | + -this-unit-id pkgA -O -c pkgA2/A.hs -outputdir '$(PKGA2)'
|
|
| 42 | + '$(AR)' q '$(PKGA2)/libHSpkgA.a' '$(PKGA2)/A.o' >/dev/null 2>&1
|
|
| 43 | + cp pkgA2/pkg.conf '$(WORK)/pkgA2.conf'
|
|
| 44 | + '$(GHC_PKG)' --package-db '$(PKGDB)' update '$(WORK)/pkgA2.conf' >/dev/null
|
|
| 45 | + |
|
| 46 | + # Compiling Main against pkgB should now fail while loading the stale B.hi.
|
|
| 47 | + ! '$(TEST_HC)' $(TEST_HC_OPTS) -v0 --make app/Main.hs \
|
|
| 48 | + -O -fforce-recomp -package-db '$(PKGDB)' -package pkgB \
|
|
| 49 | + >'$(OUT)' 2>&1 || { echo "expected compilation failure" >&2; exit 1; }
|
|
| 50 | + |
|
| 51 | + # Strip the absolute test directory prefix before comparing against T2057.stderr.
|
|
| 52 | + sed "s#$(CURDIR)/##g" '$(OUT)' >&2 |
| 1 | +`T2057` checks that GHC stops after an interface-file error instead of
|
|
| 2 | +continuing into the linker.
|
|
| 3 | + |
|
| 4 | +The test constructs a stale package dependency on purpose.
|
|
| 5 | + |
|
| 6 | +The dependency tree is
|
|
| 7 | + |
|
| 8 | + app/Main -> pkgB -> pkgA
|
|
| 9 | + |
|
| 10 | +where the two directories `pkgA1/` and `pkgA2/` are just two source trees
|
|
| 11 | +for the same package `pkgA`.
|
|
| 12 | + |
|
| 13 | +`pkgA1` defines a local type `T` and a function `f :: T -> T`.
|
|
| 14 | +`pkgB` builds against that package and records an unfolding `g = f` in `B.hi`.
|
|
| 15 | + |
|
| 16 | +After that, the Makefile updates the same package `pkgA` from `pkgA2/`, where
|
|
| 17 | +module `A` no longer exports `f`. When `Main` imports `B`, GHC has to load
|
|
| 18 | +`B.hi`, sees the stale reference to `f`, and must fail.
|
|
| 19 | + |
|
| 20 | +The golden [`T2057.stderr`](T2057.stderr) captures the fixed behaviour:
|
|
| 21 | +diagnose the missing declaration in the stale interface and then stop with
|
|
| 22 | +`Cannot continue after interface file error`. Any linker output would be a
|
|
| 23 | +regression. |
| 1 | +work/pkgB/B.hi
|
|
| 2 | +Declaration for g
|
|
| 3 | +Unfolding of g:
|
|
| 4 | + f ErrorWithoutFlag
|
|
| 5 | + Can't find interface-file declaration for variable f
|
|
| 6 | + Probable cause: bug in .hi-boot file, or inconsistent .hi file
|
|
| 7 | + Use -ddump-if-trace to get an idea of which file caused the error
|
|
| 8 | +<no location info>:
|
|
| 9 | + Cannot continue after interface file error |
| 1 | +test(
|
|
| 2 | + 'T2057',
|
|
| 3 | + [ extra_files(['pkgA1', 'pkgA2', 'pkgB', 'app', 'README.md'])
|
|
| 4 | + , ignore_stdout
|
|
| 5 | + ],
|
|
| 6 | + makefile_test,
|
|
| 7 | + []
|
|
| 8 | +) |
| 1 | +module Main where
|
|
| 2 | + |
|
| 3 | +import B
|
|
| 4 | + |
|
| 5 | +main :: IO ()
|
|
| 6 | +main = case g MkT of
|
|
| 7 | + MkT -> print () |
| 1 | +{-# LANGUAGE NoImplicitPrelude #-}
|
|
| 2 | +module A (T(..), f) where
|
|
| 3 | + |
|
| 4 | +data T = MkT
|
|
| 5 | + |
|
| 6 | +f :: T -> T
|
|
| 7 | +f x = x |
| 1 | +name: pkgA
|
|
| 2 | +version: 1.0
|
|
| 3 | +id: pkgA
|
|
| 4 | +key: pkgA
|
|
| 5 | +exposed: True
|
|
| 6 | +exposed-modules: A
|
|
| 7 | +import-dirs: ${pkgroot}/pkgA1
|
|
| 8 | +library-dirs: ${pkgroot}/pkgA1
|
|
| 9 | +dynamic-library-dirs: ${pkgroot}/pkgA1
|
|
| 10 | +hs-libraries: HSpkgA
|
|
| 11 | +depends: |
| 1 | +{-# LANGUAGE NoImplicitPrelude #-}
|
|
| 2 | +module A where
|
|
| 3 | + |
|
| 4 | +-- no f here
|
|
| 5 | +data T = MkT |
| 1 | +name: pkgA
|
|
| 2 | +version: 1.0
|
|
| 3 | +id: pkgA
|
|
| 4 | +key: pkgA
|
|
| 5 | +exposed: True
|
|
| 6 | +exposed-modules: A
|
|
| 7 | +import-dirs: ${pkgroot}/pkgA2
|
|
| 8 | +library-dirs: ${pkgroot}/pkgA2
|
|
| 9 | +dynamic-library-dirs: ${pkgroot}/pkgA2
|
|
| 10 | +hs-libraries: HSpkgA
|
|
| 11 | +depends: |
| 1 | +{-# LANGUAGE NoImplicitPrelude #-}
|
|
| 2 | +module B (T(..), g) where
|
|
| 3 | + |
|
| 4 | +import A
|
|
| 5 | + |
|
| 6 | +{-# INLINE g #-}
|
|
| 7 | +g :: T -> T
|
|
| 8 | +g x = f x |
| 1 | +name: pkgB
|
|
| 2 | +version: 1.0
|
|
| 3 | +id: pkgB
|
|
| 4 | +key: pkgB
|
|
| 5 | +exposed: True
|
|
| 6 | +exposed-modules: B
|
|
| 7 | +import-dirs: ${pkgroot}/pkgB
|
|
| 8 | +library-dirs: ${pkgroot}/pkgB
|
|
| 9 | +dynamic-library-dirs: ${pkgroot}/pkgB
|
|
| 10 | +hs-libraries: HSpkgB
|
|
| 11 | +depends: pkgA |