[Git][ghc/ghc][wip/supersven/flags-pin-test] 70 commits: Move the `Text.Read` implementation into `base`
by Sven Tennie (@supersven) 07 Jun '26
by Sven Tennie (@supersven) 07 Jun '26
07 Jun '26
Sven Tennie pushed to branch wip/supersven/flags-pin-test at Glasgow Haskell Compiler / GHC
Commits:
44cf9cd7 by Wolfgang Jeltsch at 2026-05-12T09:48:18-04:00
Move the `Text.Read` implementation into `base`
- - - - -
4ac3f7d6 by Vladislav Zavialov at 2026-05-12T09:49:03-04:00
EPA: Use AnnParen for tuples and sums
Summary of changes
* Do not use AnnParen in XListTy, replace it with EpToken "[" and "]"
* Specialise AnnParen to tuple/sums by dropping the AnnParensSquare
and keeping only AnnParens and AnnParensHash
* Use AnnParen in XExplicitTuple
* Use AnnParen in XExplicitTupleTy
* Use AnnParen in XTuplePat
* Use AnnParen in XExplicitSum (via AnnExplicitSum)
* Use AnnParen in XSumPat (via EpAnnSumPat)
This is a refactoring with no user-facing changes.
- - - - -
1bdcddec by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add minimal dlltool support to ghc-toolchain
The dlltool is a tool that can create dll import libraries from .def
files. These .def files list the exported symbols of dlls. Its somewhat
like gnu linker scripts, but more limited.
We will need dlltool to build the rts and ghc-internal libraries as DLLs
on Windows. The rts and ghc-internal libraries have a recursive
dependency on each other. Import libraries can be used to resolve
recursive dependencies between dlls. We will use an import library for
the rts when linking the ghc-internal library.
- - - - -
f7fc3770 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add minimal dlltool support into ./configure
Find dlltool, and hopefully support finding it within the bundled llvm
toolchain on windows.
- - - - -
e4e22bfb by Duncan Coutts at 2026-05-12T09:49:48-04:00
Update the default host and target files for dlltool support
- - - - -
5666c8f9 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add dlltool as a hadrian builder
Optional except on windows.
- - - - -
5e14fe3f by Duncan Coutts at 2026-05-12T09:49:48-04:00
Update and generate libHSghc-internal.def from .def.in file
The only symbol that the rts imports from the ghc-internal package now
is init_ghc_hs_iface. So the rts only needs an import lib that defines
that one symbol.
Also, remove the libHSghc-prim.def because it is redundant. The rts no
longer imports anything from ghc-prim.
Keep libHSffi.def for now. We may yet need it once it is clear how
libffi is going to be built/used for ghc.
- - - - -
3d91e4a6 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add rule to build libHSghc-internal.dll.a and link into the rts
On windows only, with dynamic linking.
This is needed because on windows, all symbols in dlls must be resolved.
No dangling symbols allowed. References to external symbols must be
explicit. We resolve this with an import library. We create an import
library for ghc-internal, a .dll.a file. This is a static archive
containing .o files that define the symbols we need, and crucially have
".idata" sections that specifies the symbols the dll imports and from
where.
Note that we do not install this libHSghc-internal.dll.a, and it does
not need to list all the symbols exported by that package. We create a
special purpose import lib and only use it when linking the rts dll, so
it only has to list the symbols that the rts uses from ghc-internal
(which is exactly one symbol: init_ghc_hs_iface).
- - - - -
c8dae539 by Alice Rixte at 2026-05-12T09:50:52-04:00
Script for downloading and copying `base-exports` file
- - - - -
5fab2238 by Wolfgang Jeltsch at 2026-05-12T21:24:27+03:00
Introduce a cache of home module name providers
This contribution introduces to the module graph a cache that maps home
module names to sets of units providing them and changes the finder to
use that cache. This is a performance optimization, especially for
multi-home-unit builds.
The particular changes are as follows:
* In `GHC.Unit.Module.Graph`, `ModuleGraph` is extended with a new
field `mg_home_module_name_providers_map`, exposed as
`mgHomeModuleNameProvidersMap`. This is a cache that assigns to each
home module name the set of IDs of home units that define it.
Operations that construct module graphs are updated such that this
cache stays synchronized.
* In `GHC.Unit.Finder`, `findImportedModule` is changed to pull
`mgHomeModuleNameProvidersMap` from `hsc_mod_graph` and pass it to
`findImportedModuleNoHsc`, which now does not search home units in
arbitrary order but prioritizes those units that the cache mentions
as potential providers of the requested module.
In addition, this contribution adds variants of the two multi-component
compiler performance tests that use 100 units instead of 20, because
with just 20 units the benefits from caching of home module name
providers are still negligible.
The following table shows the total time needed for running both
multi-component tests before and after this contribution and with
different numbers of units:
| # of units | Before | After |
|-----------:|-------:|------:|
| 20 | 0:12 | 0:12 |
| 100 | 0:47 | 0:42 |
| 200 | 3:05 | 2:08 |
Note that there seems to be a general overhead of 12 seconds that is not
attributable to the actual tests, so that the real running times should
be 12 seconds smaller than shown above.
Resolves #27055.
Metric Decrease:
MultiComponentModules
MultiComponentModulesRecomp
Co-authored-by: Matthew Pickering <matthewtpickering(a)gmail.com>
Co-authored-by: Fendor <fendor(a)posteo.de>
- - - - -
38b76b2f by Cheng Shao at 2026-05-13T17:48:48-04:00
testsuite: mark T22159 as fragile
This patch marks T22159 as fragile on Windows for issue described in #27248.
Before we get to the bottom of those failures, this unblocks newer
Windows runners.
- - - - -
50188615 by Ian Duncan at 2026-05-14T13:45:07+02:00
AArch64: use ASR not LSR for MO_U_Shr at W8/W16
The unsigned right shift (MO_U_Shr) for sub-word widths (W8, W16)
with a variable shift amount was emitting ASR (arithmetic/signed shift
right) after zero-extending with UXTB/UXTH. This should be LSR
(logical/unsigned shift right). After zero-extension the upper bits
happen to be 0 so ASR produces the same result, but it is semantically
wrong and would break if the zero-extension were ever optimized away.
Includes assembly output test (grep for lsr) and runtime test
verifying unsigned right shift of Word8 and Word16 values.
- - - - -
28666fbf by Vladislav Zavialov at 2026-05-19T12:44:05-04:00
Add type families: Tuple, Constraints, Tuple#, Sum# (#27179)
These type families map tuples of types to the corresponding Tuple<N>,
Tuple<N>#, CTuple<N>, and Sum<N># types. Some examples at N=2:
Tuple (Int, Bool) = Tuple2 Int Bool
Constraints (Show a, Eq a) = CTuple2 (Show a) (Eq a)
Tuple# (Int#, Float#) = Tuple2# Int# Float#
Sum# (Int#, Float#) = Sum2# Int# Float#
See GHC Proposal #145 "Non-punning list and tuple syntax".
To make the Sum# instance at N=64 possible, this patch also introduces
the Sum64# constructor declaration and bumps mAX_SUM_SIZE from 63 to 64.
Metric Increase:
ghc_experimental_dir
- - - - -
41c2448b by Wen Kokke at 2026-05-19T12:44:53-04:00
rts: Add IPE event class for -l
This commit adds a new IPE event class to the -l RTS flag.
Previously, IPE events were enabled unconditionally.
However, the IPE events can easily grow to hundreds or thousands of megabytes.
With the new event class you can pass, e.g., -l-I to disable IPE events.
- - - - -
62536551 by Wen Kokke at 2026-05-19T12:44:53-04:00
ghc-internal: Add TraceFlags.traceIPE
- - - - -
e45312d1 by Wen Kokke at 2026-05-19T12:44:53-04:00
testsuite: Add test for TraceFlags.traceIpe
- - - - -
4768d9aa by Wen Kokke at 2026-05-19T12:44:53-04:00
ghc-internal: Add DebugFlags.ipe
- - - - -
bc1b5c69 by Wen Kokke at 2026-05-19T12:44:53-04:00
testsuite: Add test for DebugFlags.ipe
- - - - -
0da1543f by Duncan Coutts at 2026-05-19T12:45:37-04:00
Document removal of the signal-based interval timer
Update mentions within the RTS section of the users guide.
Add a changelog entry.
- - - - -
b2911514 by Duncan Coutts at 2026-05-19T12:45:37-04:00
Fix section for an recent changelog entry
- - - - -
d6d76a7a by David Eichmann at 2026-05-19T12:46:19-04:00
ghc-toolchain: implement llvm program versioning logic
- - - - -
2dd36fa3 by Wolfgang Jeltsch at 2026-05-20T04:49:52-04:00
Turn `Trustworthy` into `Safe` in `base` where possible
- - - - -
f4399dd1 by Wolfgang Jeltsch at 2026-05-20T04:50:37-04:00
Make the current `base` buildable with GHC 10.0
- - - - -
1a7de232 by Duncan Coutts at 2026-05-20T12:26:25-04:00
Hadrian: remove legacy rts .so symlinks
For compatibility with the old makefile based build system, hadrian had
rules to generate symlinks from unversioned to versioned names for the
rts .so/.dynlib file, like libHSrts-ghcx.y.so -> libHSrts-1.0.3-ghcx.y.so
We no longer need these symlinks since the makefile build system has
been retired some time ago. The need for these symlinks is awkward on
windows where we cannot (in practice) create symlinks. So rather than
make them conditional (non-windows), just remove them entirely.
- - - - -
286f1adf by fendor at 2026-05-20T12:27:09-04:00
Fix regression T27202: `:load` and `:add` work in GHCi
To fix the regression there are conceptually two major things that we
fix:
* We don't remove the `importDirs` from `interactive-session`
* When `:add`ing a module, we don't try to find them via PackageImports
* The PackageImport is wrong as we can't know the package-name at
this stage in ghc/UI.hs
What does it mean to not remove the `importDirs` from
`interactive-session`?
It means that, given some initial `DynFlags`, we will use those
`importDirs` in `interactive-session`.
The initial `DynFlags`, however, depend on how you initialise the GHC
session.
For a simple session, initialised by
ghc -isrc -this-unit-id main
It is simple, just use the `DynFlags` given on the cli.
Thus, `main` and `interactive-session` will have the same `DynFlags`,
except for the `homeUnitId` and `interactive-session` depends on `main`
by construction of the GHCi session.
What about a multiple home unit session, though?
ghc -unit @unit1 -unit @unit2
What are the `DynFlags` in this cli invocation? It shouldn't be either
`@unti1` nor `@unit2`, as the order shouldn't matter or any other
implicit condition.
For consistency, we decide that the initial `DynFlags` are the top
`DynFlags` on the cli, ignoring `-unit` flags.
Thus, in this example, there are no `importsDirs` regardless of what we
might find in `@unit1` and `@unit2`.
But in this invocation:
ghc -isrc -unit @unit1 -unit @unit2
The `interactive-session` will have the `importsDirs` `src`.
Note, `-isrc` will be inherited in `@unit1` and `@unit2`, so you need to
explicitly use `-i` to clear the `importsDirs`, in order to avoid
accidentally adding `src` as an import directory to all other home
units.
This fix has been made possible by the improvements introduced in
!15888, which avoids ambiguity when a home unit shares the `importsDirs`
with the `interactive-session`, on top of being much faster for multiple
home units.
Adds regression tests for T27202 for `:load`ing and `:add`ing modules
that are located in import directories.
- - - - -
728662de by fendor at 2026-05-20T12:27:09-04:00
Use home unit package db stacks in GHCi prompt and session unit
In order to import modules from home unit dependencies (e.g., `Data.Map`),
the ghci prompt unit needs to populate its `UnitState`.
This is tricky to handle correctly, which `PackageDBFlag`s should we use
to populate the `UnitState`?
We decide, the most intuitive solution for users is to depend on all
`PackageDBFlag`s, so that any dependency can be imported in GHCi.
This assumes consistency in the `PackageDBFlag`s, so no two home units
specify `PackageDBFlag`s that are inconsistent with each other.
We could simply concat all the `PackageDBFlag`s of the existing home
units, but later `PackageDBFlag`s shadow earlier ones, leading to the
last processed home units' `PackageDBFlag`s to shadow the earlier ones.
This is hard to fix, we need to give users the capability to provide ghc
options for the ghci prompt home unit.
However, as this is considerably more work, we decided on an
approximation that should work out most of the time.
Package Db stacks in cabal and stack follow a certain structure:
-no-user-package-db > -package-db $cabal-store > -package-db $local-db
The first two arguments are always the same, namely the
`-no-user-package-db` and `-package-db`.
We compute the longest common prefix over all home units, and use that
as the start of the package db stack. Then, over the rest of the
`PackageDBFlag`s, we simply take the union and append them to our
initial stack.
We assume, that the rest of package dbs only defines very few, "local"
units that are usually not shadowing each other.
This allows us to get a relatively consistent package database stack for
the ghci prompt home unit.
Similar reasoning applies to the session unit in order to add modules to
the session and have dependencies available in the module.
We do something similar for `-package` flags, to make sure only the
correct units are actually visible in the ghci session.
This time, we simply take the union of all `PackageFlag`s, allowing us
to import modules from the home unit dependencies.
In the future, it would be beneficial to allow the user to provide the
exact ghc options to control the visibilities. For now, this will have
to do.
- - - - -
740d89a0 by Simon Peyton Jones at 2026-05-20T17:20:44-04:00
Do not use mkCast during typechecking
This commit fixes #27219. The problem was that the typechecker was using
`mkCast`, whose assertion checks legitimately fail when applied to types
that contain unification variables.
- - - - -
a50fdb06 by Simon Peyton Jones at 2026-05-20T17:20:45-04:00
Major refactor of the Simplifier
The main payload of this patch is to refactor the Simplifer to avoid
repeated simplification when using Plan (AFTER) for rule rewrites.
The need for this was shown up by #26989.
See Note [Avoid repeated simplification] in GHC.Core.Opt.Simplify.Iteration.
Related refactoring:
* Refactor the two fields `sc_dup` and `sc_env` in `ApplyToVal` into one, `sc_env`.
Reason: the envt is irrelevant in the "simplified" case, so the data type describes
the possiblitiies much more accurately now.
* Some refactoring in `knownCon` to split off `wrapDataConFloats`.
* Refactor `lookupRule` and its auxiliary functions to return `RuleMatch`,
a new data type. See Note [data RuleMatch] in GHC.Core. Ditto for BuiltinRule.
This RuleMatch returns fragments of the target in rm_args and rm_floats,
leaving `rm_rhs` to be the stuff from the RULE itself.
Doing this has routine consequences in GHC.Core.Opt.ConstantFold. Many changes
there but all routine.
* When doing occurrence analysis on RULEs, make the occ-info on the rule
binders relate just to the RHS, not the LHS. See (OUR1) in
Note Note [OccInfo in unfoldings and rules]
This means that Lint must not complain about the fact that the patterns
in the RULE mentions binders that are marked dead.
See Note [Dead occurrences] in GHC.Core.Lint.
I changed the Core pretty-printer so that it didn't suppress dead binders,
else I can't see those binders in RULEs. That led to quite a lot of testsuite wibbles.
* Refactor FloatBinds, so that it is used both by
`exprIsConApp_mabye` and by `lookupRule`
* Move the definition of FloatBinds out of GHc.Core.Make, into GHC.Core.
* Add FloatTick as an extra constructor.
* Refactor `lookupRule` to use `FloatBinds` instead of `BindWrapper`.
This refactor just shares more code.
(Rename GHC.Core.Opt.FloatOut.FloatBinds to FloatLets, to avoid gratuitious
name clash with GHC.Core.FloatBinds.)
Corecion optimisation
* In simpleOpt, when composing coercions, call new function `optTransCo`.
This is much lighter weight than full blown coercion optimisation.
* Make `GHC.Core.Opt.Arity.pushCoValArg` and `pushCoTyArg` return the
coercionLKind of the coercion. This saves recomputing that coercionLKind
at the key call sites in GHC.Core.Opt.Simplify.Iteration.pushCast.
* Rename `addCoerce` in GHC.Core.Simplify.Iteration to become `pushCast`.
* In the `ApplyToVal` case of `pushCast` we had a very unsavoury call to `simplArg`.
I eliminated it by adding a field `sc_cast` to `ApplyToVal` that records any
pending casts. Much nicer now. See Note [The sc_cast field of ApplyToVal].
* Don't optimise coercions if the type-substitution is empty.
See Note [Optimising coercions] in GHC.Core.Opt.Simplify.Iteration.
The fix for #26838 is dramatic. For the test in perf/compiler/T26839 we have
Compiler allocs: Before: 7,363M
After: 688M
Compile time goes down generally. Here are compiler-alloc changes
over 0.5%:
CoOpt_Read(normal) 729,184,920 -0.7%
CoOpt_Singletons(normal) 666,916,960 -4.6% GOOD
LargeRecord(normal) 1,227,056,876 +1.1%
T12227(normal) 256,827,604 -4.6% GOOD
T12425(optasm) 76,879,410 -0.8%
T12545(normal) 787,826,918 -10.8% GOOD
T12707(normal) 775,186,464 -0.9%
T13253(normal) 318,599,596 -0.8%
T14766(normal) 685,857,320 -1.0%
T15304(normal) 1,123,333,422 -2.2%
T15630(normal) 123,142,330 -2.6%
T15630a(normal) 123,092,100 -2.6%
T15703(normal) 299,751,682 -2.9% GOOD
T17516(normal) 964,072,280 +1.0%
T18223(normal) 367,016,820 -6.2% GOOD
T18730(optasm) 130,643,770 -3.3% GOOD
T20261(normal) 535,608,584 -0.7%
T21839c(normal) 340,340,436 -0.9%
T24984(normal) 85,568,392 -1.9%
T3064(normal) 174,631,992 -1.2%
T3294(normal) 1,215,886,432 -0.7%
T5030(normal) 141,449,704 -17.2% GOOD
T5321Fun(normal) 258,484,744 -1.9%
T8095(normal) 770,532,232 -2.7%
T9630(normal) 858,423,408 -14.5% GOOD
T9872c(normal) 1,591,709,448 +0.7%
info_table_map_perf(normal) 19,700,614,458 -1.3%
geo. mean -0.7%
minimum -17.2%
maximum +1.1%
However, strangely there seems to be a 5.0% increase in CoOpt_Read in
the x86_64-linux-fedora43-validate+debug_info+ubsan job, although
there generally a /decrease/ in this test in other builds. The baseline
value looks strange. Anyway I'll just accept it.
Metric Decrease:
CoOpt_Singletons
T12227
T12545
T12707
T15703
T18223
T18730
T21839c
T5030
T9630
Metric Increase:
CoOpt_Read
- - - - -
834623d4 by Mrjtjmn at 2026-05-20T17:21:41-04:00
users-guide: Fix weird notation in "Summary of stolen syntax"
- - - - -
6f9d7c71 by Markus Läll at 2026-05-21T15:25:34-04:00
Use "grimily" instead of "grimly"
Fixes https://gitlab.haskell.org/ghc/ghc/-/issues/27221
- - - - -
50e999ca by fendor at 2026-05-21T15:26:18-04:00
Speed up 'closure' computation in `ghc-pkg`
Cache the set of already seen `UnitId`s and use `Set` operations to
speed up 'closure' computation.
Further simplify the implementation of 'closure' to account for the
actual usage.
As a consequence, we rename 'closure' to 'brokenPackages' to reflect its
purpose better after the simplification.
- - - - -
7ecc6184 by sheaf at 2026-05-21T15:27:10-04:00
TcMPluginHandling: be more lenient when no plugins
This change ensures that, if a function such as 'typecheckModule' was
invoked with 'NoTcMPlugins', GHC doesn't spuriously complain about TcM
plugins having already been stopped, as there were none to start with.
- - - - -
72c8de5c by Simon Jakobi at 2026-05-23T18:41:42-04:00
Implement List.elem via foldr
...in order to allow specialization to Eq instances.
The implementation of notElem is updated for consistency.`
Corresponding CLC proposal:
https://github.com/haskell/core-libraries-committee/issues/412
Addresses #27096.
- - - - -
3268c610 by Alan Zimmerman at 2026-05-23T18:42:30-04:00
EPA: Fix span for qualified multiline string
Fix the span for a qualified multiline string like
Text."""
I'm a multiline
Text value
!
"""
to extend to the end of the entire string, not just the first line.
Closes #27274
- - - - -
1f096790 by Alan Zimmerman at 2026-05-23T18:43:20-04:00
EPA: Fix exact printing namespace-specified wildcards
Ensures correct printing of imports of the form
import Data.Bool (data True(data ..))
import Data.Bool (data True(type ..))
Closes #27291
- - - - -
56ada7c0 by Mrjtjmn at 2026-05-23T18:44:19-04:00
Fix ambiguous syntax of BangPatterns in users guide
Update documentation for the BangPatterns extension to specify
how surrounding whitespace affects interpretation of `!`.
* Only when there is whitespace before `!` and no whitespace after,
it is recognized as a BangPattern.
* Other cases `⟨varid⟩!⟨varid⟩`, `⟨varid⟩ ! ⟨varid⟩`, `⟨varid⟩! ⟨varid⟩`
are treated as infix operators.
- - - - -
579aa0b7 by Simon Jakobi at 2026-05-25T16:31:26-04:00
Ensure that SetOps.{minusList,unionListsOrd} can be specialized
...by marking them INLINABLE. Haddock allocates 0.1–0.3% less as a
result.
This also removes some redundant constraints on unionListsOrd.
- - - - -
cccf45da by Cheng Shao at 2026-05-25T16:32:13-04:00
wasm: ensure post-linker output is synchronous ESM
This patch fixes wasm backend's post-linker output script to ensure
it's synchronous ESM and doesn't use top-level await, which doesn't
work in ServiceWorkers. Fixes #27257.
- - - - -
8db331a3 by Zubin Duggal at 2026-05-26T04:54:03-04:00
Update to semaphore-compat 2.0.0 using v2 of the protocol
On Linux and other POSIX platforms, GHC's -jsem jobserver client now
speaks v2 of the semaphore-compat protocol, which uses Unix domain
sockets in place of POSIX named semaphores. This avoids the libc-ABI
issues that affected the old implementation. Windows is unaffected
and continues to use the v1 protocol (Win32 named semaphores); its
reported protocol version remains v1.
When GHC receives a -jsem name whose protocol version it does not
support, it emits a -Wsemaphore-version-mismatch warning and falls
back to -j<N> rather than crashing. ghc --info exposes the supported
version in a new "Semaphore version" entry so cabal-install can detect
a mismatch before invoking GHC.
Users on a cabal-install that predates the v2 update will continue to
build successfully on Linux/POSIX, but will lose the cross-process
-jsem coordination and fall back to -j<N> per GHC invocation. Users
must upgrade to a cabal-install that supports protocol v2 to recover
full parallelism.
Also fix a leak in cleanupSem (#27253): cleanupSem used to snapshot
heldTokens and release them before killing the loop, while the loop's
in-flight acquire/release children could still be mutating it.
Cleanup now runs inside the loop's own exit handler, after draining
the active child via a new activeChild TVar, so the snapshot has no
concurrent mutator.
See also:
- GHC proposal amendment: https://github.com/ghc-proposals/ghc-proposals/pull/673
- cabal-install patch: https://github.com/haskell/cabal/pull/11628
- semaphore-compat MR: https://gitlab.haskell.org/ghc/semaphore-compat/-/merge_requests/8
Bump semaphore-compat submodule to 2.0.0
Fixes #25087 and #27253
- - - - -
17be4f1f by Alan Zimmerman at 2026-05-26T04:54:52-04:00
EPA: Record semicolons in HsModifier
Ensure the semi colons are captured in the ParsedSource for code like
%True;; %False;
instance C D
It makes HsModifier (and hence HsModifierOf) LocatedA, so the semi
colons can be recorded as [TrailingAnn]
Also rename pprHsModifiers to pprLHsModifiers to match.
Closes #27294
- - - - -
8f991755 by fendor at 2026-05-26T11:02:52-04:00
Revert prog003 acceptance
We thought the commit 286f1adff3e78d775ff325caff71d0cee25d710b fixed the
test, but due to changes to ghci, modules loaded during the GHCi
session, the test was actually no longer testing what it set out to do,
"fixing" the broken test.
As modules are added to the `interactive-session` home unit, the object code needs
to be compiled with `-this-unit-id interactive-session`, otherwise the
object code won't be used.
Once this has been fixed in the test, the test fails as expected again.
- - - - -
277a3687 by mangoiv at 2026-05-26T11:03:40-04:00
libraries/process: bump submodule to v1.6.29.0
This submodule bump resolves a segfault on macos 15.
Fixes #27144
- - - - -
6779bb0c by mangoiv at 2026-05-26T11:03:40-04:00
libraries/unix: in submodule, don't pick branch 2.7
The 2.7 branch is outdated and the module has been advanced far beyond
it anyway, so remove that line.
- - - - -
4a645683 by Simon Peyton Jones at 2026-05-27T21:41:59-04:00
Trim the continuation in mkDupableContWithDmds
When there are no remaining argument demands, it means the application
is bottoming. In this case, we can trim the continuation to avoid the
panic that was observed in #27261.
See Note [Trimming the continuation for bottoming functions] in
GHC.Core.Opt.Simplify.Iteration.
- - - - -
8ab506ff by Cheng Shao at 2026-05-27T21:42:47-04:00
ghci: fix module name string lifetime in hs_hpc_module invocation
This patch makes hpcAddModule pass a properly malloced module name
string to hs_hpc_module, instead of using useAsCString which causes
use-after-free of module name string. Fixes #27297.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
b0233814 by sheaf at 2026-05-27T21:43:31-04:00
Relax acceptance threshold for T10421
As seen in #27289, the 1% acceptance threshold for this text was
overly narrow, resulting in spurious test failures. This commit widens
the acceptance threshold to 2%. Fixes #27289.
- - - - -
63ce5770 by Luite Stegeman at 2026-05-28T12:23:35-04:00
Fixes for black holes
- suspend duplicate work for eager black holes
- detect eager black holes in checkBlockingQueues
- don't overwrite existing black holes even if they're not
in an eager blackhole frame
- don't deadlock on self when thunk is already blackholed
Fixes #26936
- - - - -
037a80dc by Tom McLaughlin at 2026-05-28T12:24:36-04:00
Event/Windows.hsc: rethrow exceptions in overlapped IO
This prevents the WinIO manager from swallowing exceptions in overlapped IO. It
was added to make WinIO support possible in the `network` library. See
https://gitlab.haskell.org/ghc/ghc/-/issues/27283.
We also bump __IO_MANAGER_WINIO__ to 2 so libraries can gate on this using CPP.
- - - - -
2d53bcdb by Wolfgang Jeltsch at 2026-05-28T12:25:21-04:00
Allow `downsweep` to use nodes of an existing module graph
To this end, `downsweep` has not been able to use the nodes of a module
graph obtained from a previous downsweeping round. In some GHC API
applications, downsweeping is performed somewhat incrementally and
therefore could profit from reusing such existing results. This
contribution makes this possible.
Resolves #27054.
Co-authored-by: Matthew Pickering <matthewtpickering(a)gmail.com>
- - - - -
f4fbb583 by Simon Jakobi at 2026-05-28T12:26:04-04:00
Add regression test for T11226
Closes #11226.
- - - - -
ed29a5e6 by Sven Tennie at 2026-05-28T17:30:36-04:00
Add optional config setting for LibDir (#19174)
Previously, the `libDir` was derived from `topDir`. This won't work for
inplace stage2 cross-compilers where binaries and libraries are in
different stage dirs (`_build/stage1/` for executables and
`_build/stage2` for libraries).
`LibDir` is set in the inplace `settings` files. For bindists, we
generate a new `settings` file with no `LibDir` entry. GHC then defaults
to use `topDir` as `libDir` again. This keeps the bindist relocatable.
If `LibDir` is a relative path, it is interpreted relatively to
`topDir`.
The global package db is part of the `lib/` folder. If we want to point
for inplace cross-compilers to the succeeding stage's folder, this is
done by setting `LibDir`. Thus, the global package db must be found
relative to `libDir`` (which may default to `topDir` or be set by
`LibDir`).
The complexity of settings becomes scary. So, add a test to ensure
`LibDir` works as expected.
- - - - -
8339cf8f by Sven Tennie at 2026-05-28T17:30:36-04:00
Add Haddock to FileSettings
Helping to understand the fields' meanings without deeper analyses.
- - - - -
4ce251e4 by Sylvain Henry at 2026-05-28T17:31:39-04:00
foundation test: skip signed minBound `quot` (-1) (#27222)
`minBound `quot` (-1)` for fixed-width signed integers is platform
dependent: the mathematical result -minBound is not representable in
the type. On x86, IDIV traps; LLVM's sdiv is undefined behaviour in
this case; on AArch64/RISC-V, SDIV wraps to minBound.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
b8ba7e61 by Simon Jakobi at 2026-05-28T17:32:23-04:00
Prevent dictionary-passing in checkTyEqRhs
...by pre-specializing it to TcM.
Previously, wherever checkTyEqRhs was used in other modules, the
Core showed dictionary passing ($fMonadIOEnv). The added SPECIALIZE
pragma prevents this.
- - - - -
d603477f by David Eichmann at 2026-05-29T13:17:12-04:00
Hadrian: create a ghc-internal .def file per ghc-internal dll
The .def file generated from rts/win32/libHSghc-internal.def.in contains
the name of the ghc-internal dll. The correct dll name differs based
on if the dll is inplace/final and if using the Dynamic way. Previously,
this was not accounted for and inconsistent dlls names where used. That
led to failure when loading dlls at runtime in experiments with windows
dynamic linking.
- - - - -
1fc21753 by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: copy backend interface haddocks to Native backend (#27305)
The haddock comments documenting the BigNat backend interface (function
contracts, expected MutableWordArray# sizes, return-value semantics, etc.)
were attached to the FFI backend module. Copy them to the Native backend
so they remain in tree once the FFI backend is removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
717059df by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: remove FFI backend (#27305)
The FFI backend of ghc-bignum (now part of ghc-internal) had no known
users and is easy to recreate by relinking ghc-internal with a custom
backend. Remove the backend module, the bignum-ffi cabal flag, and the
ffi option from Hadrian's --bignum selector. The backend interface
documentation now lives in the Native backend module.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
4bb3b1d8 by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: remove Check backend (#27305)
The Check backend of ghc-bignum (now part of ghc-internal) compared the
selected backend's output against the Native backend for validation.
It had no known users. Remove the backend module, the bignum-check
cabal flag, the bignumCheck Hadrian flavour field, and the check-
prefix in Hadrian's --bignum selector.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
6b3044a0 by David Eichmann at 2026-05-30T11:58:48-04:00
Add code comments to allocator code
- - - - -
f4e04210 by Matthew Pickering at 2026-05-30T11:59:34-04:00
hadrian: Refactor system-cxx-std-lib rules
I noticed a few things wrong with the hadrian rules for
`system-cxx-std-lib` rules.
* For `text` there is an ad-hoc check to depend on `system-cxx-std-lib`
outside of `configurePackage`.
* The `system-cxx-std-lib` dependency is not read from cabal files.
* Recache is not called on the packge database after the `.conf` file is
generated, a more natural place for this rule is `registerRules`.
Treating this uniformly like other packages is complicated by it not
having any source code or a cabal file. However we can do a bit better
by reporting the dependency firstly in `PackageData` and then needing
the `.conf` file in the same place as every other package in
`configurePackage`.
This commit increases the `shakeVersion`, to provide backwards
compatibility to previous builds with different PackageData.
Fixes #25303
Co-authored-by: Sven Tennie <sven.tennie(a)gmail.com>
- - - - -
576987d0 by Simon Jakobi at 2026-06-02T04:53:36-04:00
compiler: use nubOrd from containers
Address #27103 by replacing GHC.Utils.Misc.ordNub[On] with
Data.Containers.ListUtils.nubOrd[On].
Note that nubOrd suffers from a small inefficiency, a fix for which
will be included in the next containers release:
https://github.com/haskell/containers/issues/1202
- - - - -
deea53c3 by David Eichmann at 2026-06-02T04:54:22-04:00
Hadrian: disable response files for GHC/Haddock builders on non-Windows
This makes debugging build errors easier on non-windows hosts.
See issue #27230
- - - - -
f2f5c6ba by Nikita Efremov at 2026-06-02T16:04:54+00:00
fix typo : compete with performance, not complete
- - - - -
5524ea0e by Wolfgang Jeltsch at 2026-06-03T08:01:26-04:00
Make the current `base` buildable with GHC 9.14
This comprises the following changes:
* Disable some imports into `GHC.Base` for GHC 9.14
* Disable some imports into `Prelude` for GHC 9.14
* Disable separate `ArrowLoop` import for GHC 9.14
* Disable `GHC.Internal.STM` import for GHC 9.14
* Disable `GHC.Internal.Unicode.Version` import for GHC 9.14
* Disable `GHC.Internal.TH.Monad` import for GHC 9.14
* Add alternative `fixIO` import for GHC 9.14
* Add alternative `unsafeCodeCoerce` import for GHC 9.14
* Disable hiding of imported SIMD operations for GHC 9.14
* Disable use of GHC 9.14’s `printToHandleFinalizerExceptionHandler`
* Enable use of `getFileHash` from `ghc-internal` for GHC 9.14
* Make `thenA` available for GHC 9.14
* Make `thenM` available for GHC 9.14
* Disable translation of `IoManagerFlagPoll` for GHC 9.14
* Add `hGetNewlineMode` for GHC 9.14
- - - - -
d3438055 by Enrico Maria De Angelis at 2026-06-03T08:02:17-04:00
Fix #27067 - Clarify haddocks on `minusNaturalMaybe`
- - - - -
f9bcfac2 by sheaf at 2026-06-03T14:47:19-04:00
Avoid mkTick in Core Prep breaking ANF
As discovered in #27182, mkTick can break ANF. This patch introduces a
variant of mkTick that skips the single optimisation that could break
ANF. This is preferrable over switching to the raw Tick constructor,
as the latter may introduce spurious cost centres in profiling reports.
This is a temporary measure until we more thoroughly refactor how
mkTick works (see #27141).
See Note [mkTick breaks ANF] in GHC.CoreToStg.Prep.
Fixes #27182
- - - - -
cf1fd661 by Artem Pelenitsyn at 2026-06-03T14:48:09-04:00
clarify comment for getSizeofMutableByteArray#: we get the size in bytes, not "elements"
- - - - -
a3b431f3 by David Eichmann at 2026-06-04T10:10:19+00:00
Hadrian: convert env variable ACLOCAL_PATH to unix paths.
Convert ACLOCAL_PATH to a unix style path when invoking autoreconf.
Autoreconf doesn't handle windows paths.
See Note [Autoreconf unix paths from ACLOCAL_PATH].
Fixes #27311
- - - - -
18f6138a by Simon Jakobi at 2026-06-04T20:20:31-04:00
testsuite: Deduplicate --only test names
config.only is assumed to be a set, but supplying --only overwrote it
with the (list) argparse result, which can contain duplicates. When a
test ran, config.only.remove(name) dropped only the first occurrence,
so a duplicated name lingered and was later misreported as a
"test not found" framework failure. Store it as a set instead.
Fixes #27322
Co-Authored-By: Claude Opus 4.7 <noreply(a)anthropic.com>
- - - - -
3db0b38c by Sven Tennie at 2026-06-07T16:53:57+00:00
testsuite: add GHC build-system regression detection tests
Pin arch-specific GHC config values so that build-system refactors that
accidentally change compiler configuration are caught by the testsuite.
Two tests:
- GhcInfoPins: runs ghc --info and checks 18 pinned fields
- TestsuiteConfigPins: checks 12 Hadrian-supplied config.* values
Both tests print a ready-to-paste entry when run on an unknown platform.
Tests are Python run_command (not compiled Haskell) because wasm32/WASI
targets cannot call runInteractiveProcess from compiled binaries.
- - - - -
425 changed files:
- .gitmodules
- boot
- + changelog.d/T26979
- + changelog.d/T27182.md
- + changelog.d/T27202
- + changelog.d/T27261
- + changelog.d/bump-process
- changelog.d/dynamic-trace-flags
- + changelog.d/elem-via-foldr-27096
- + changelog.d/fix-blackhole-handling
- + changelog.d/ghc-api-epa-parens
- + changelog.d/ghc-pkg-faster-closure
- + changelog.d/hadrian-system-cxx-std-lib-25303
- + changelog.d/ipe-event-class
- + changelog.d/jobserver-leak-fix
- + changelog.d/lib-add-tuple-tyfam-27179
- + changelog.d/libdir-setting
- + changelog.d/module-graph-reuse-in-downsweep
- + changelog.d/more-efficient-home-unit-imports-finding
- + changelog.d/no-more-timer-signal
- + changelog.d/remove-bignum-check-backend
- + changelog.d/remove-bignum-ffi-backend
- + changelog.d/rts_symlinks.md
- + changelog.d/semaphore-v2
- + changelog.d/wasm-fix-serviceworker
- + changelog.d/windows-rethrow-overlapped-exception
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/BlockLayout.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Core/Opt/FloatIn.hs
- compiler/GHC/Core/Opt/FloatOut.hs
- compiler/GHC/Core/Opt/Monad.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Data/List/SetOps.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Driver/Config/Interpreter.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/Driver/MakeAction.hs
- compiler/GHC/Driver/MakeSem.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Driver/Session/Units.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/HsToCore/Errors/Ppr.hs
- compiler/GHC/HsToCore/Errors/Types.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Binary.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Linker/Unit.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/Types.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Settings.hs
- compiler/GHC/Settings/Constants.hs
- compiler/GHC/Settings/IO.hs
- compiler/GHC/Stg/Pipeline.hs
- compiler/GHC/StgToJS/Ids.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Bind.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Name/Cache.hs
- compiler/GHC/Types/Unique.hs
- compiler/GHC/Types/Unique/Supply.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Info.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Utils/Misc.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Decls/Foreign.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Type.hs
- configure.ac
- distrib/configure.ac.in
- docs/users_guide/exts/stolen_syntax.rst
- docs/users_guide/exts/template_haskell.rst
- docs/users_guide/javascript.rst
- docs/users_guide/profiling.rst
- docs/users_guide/runtime_control.rst
- docs/users_guide/using-warnings.rst
- docs/users_guide/using.rst
- ghc/GHCi/UI.hs
- ghc/Main.hs
- hadrian/README.md
- hadrian/cfg/default.host.target.in
- hadrian/cfg/default.target.in
- hadrian/doc/user-settings.md
- hadrian/src/Builder.hs
- hadrian/src/CommandLine.hs
- hadrian/src/Flavour.hs
- hadrian/src/Flavour/Type.hs
- hadrian/src/Hadrian/Haskell/Cabal/Parse.hs
- hadrian/src/Hadrian/Haskell/Cabal/Type.hs
- hadrian/src/Hadrian/Oracles/Path.hs
- hadrian/src/Hadrian/Utilities.hs
- hadrian/src/Main.hs
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Rules/Library.hs
- hadrian/src/Rules/Register.hs
- hadrian/src/Rules/Rts.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/RunTest.hs
- hadrian/src/Settings/Default.hs
- hadrian/src/Settings/Packages.hs
- libraries/base/changelog.md
- libraries/base/src/Control/Applicative.hs
- libraries/base/src/Control/Arrow.hs
- libraries/base/src/Control/Exception.hs
- libraries/base/src/Control/Monad.hs
- libraries/base/src/Control/Monad/IO/Class.hs
- libraries/base/src/Data/Array/Byte.hs
- libraries/base/src/Data/Data.hs
- libraries/base/src/Data/Fixed.hs
- libraries/base/src/Data/Functor/Classes.hs
- libraries/base/src/Data/Functor/Compose.hs
- libraries/base/src/Data/List/NonEmpty.hs
- libraries/base/src/Data/Version.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/ByteOrder.hs
- libraries/base/src/GHC/Conc.hs
- libraries/base/src/GHC/Conc/Sync.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/GHC/Fingerprint.hs
- libraries/base/src/GHC/IO/Handle.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/base/src/GHC/Unicode.hs
- libraries/base/src/GHC/Weak.hs
- libraries/base/src/GHC/Weak/Finalize.hs
- libraries/base/src/Numeric.hs
- libraries/base/src/Prelude.hs
- libraries/base/src/System/IO.hs
- libraries/base/src/System/Mem/Weak.hs
- libraries/base/src/System/Timeout.hs
- libraries/base/src/Text/Read.hs
- libraries/base/tests/perf/ElemNoFusion_O1.stderr
- libraries/base/tests/perf/ElemNoFusion_O2.stderr
- libraries/ghc-bignum/ghc-bignum.cabal
- + libraries/ghc-boot/GHC/Data/ShortByteString.hs
- libraries/ghc-boot/GHC/Settings/Utils.hs
- libraries/ghc-boot/ghc-boot.cabal.in
- libraries/ghc-experimental/src/Data/Sum/Experimental.hs
- libraries/ghc-experimental/src/Data/Tuple/Experimental.hs
- libraries/ghc-internal/bignum-backend.rst
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Base.hs
- libraries/ghc-internal/src/GHC/Internal/Bignum/Backend.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Check.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/FFI.hs
- libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Native.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Selected.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Windows.hsc
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/List.hs
- libraries/ghc-internal/src/GHC/Internal/Natural.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- − libraries/ghc-internal/src/GHC/Internal/Text/Read.hs
- libraries/ghc-internal/src/GHC/Internal/Types.hs
- libraries/ghci/GHCi/Coverage.hs
- libraries/ghci/GHCi/Run.hs
- libraries/process
- libraries/semaphore-compat
- m4/find_llvm_prog.m4
- m4/fp_setup_windows_toolchain.m4
- m4/ghc_toolchain.m4
- m4/prep_target_file.m4
- rts/.gitignore
- rts/IPE.c
- rts/Messages.c
- rts/RtsFlags.c
- rts/ThreadPaused.c
- rts/Threads.c
- rts/Trace.c
- rts/Trace.h
- rts/Updates.h
- rts/include/rts/EventLogWriter.h
- rts/include/rts/Flags.h
- rts/include/rts/storage/ClosureMacros.h
- rts/sm/BlockAlloc.c
- rts/sm/MBlock.c
- + rts/win32/libHSghc-internal.def.in
- testsuite/driver/runtests.py
- testsuite/tests/MiniQuickCheck.hs
- testsuite/tests/codeGen/should_compile/T25177.stderr
- + testsuite/tests/codeGen/should_gen_asm/aarch64-shl-subword.asm
- + testsuite/tests/codeGen/should_gen_asm/aarch64-shl-subword.hs
- + testsuite/tests/codeGen/should_gen_asm/aarch64-ushr-subword.asm
- + testsuite/tests/codeGen/should_gen_asm/aarch64-ushr-subword.hs
- testsuite/tests/codeGen/should_gen_asm/all.T
- + testsuite/tests/codeGen/should_run/aarch64-subword-ops.hs
- + testsuite/tests/codeGen/should_run/aarch64-subword-ops.stdout
- + testsuite/tests/codeGen/should_run/aarch64-ushr-subword-run.hs
- + testsuite/tests/codeGen/should_run/aarch64-ushr-subword-run.stdout
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/deSugar/should_compile/T13208.stdout
- testsuite/tests/diagnostic-codes/codes.stdout
- + testsuite/tests/driver/config-pins/ConfigPinsExpected.py
- + testsuite/tests/driver/config-pins/GhcInfoPins.py
- + testsuite/tests/driver/config-pins/TestsuiteConfigPins.py
- + testsuite/tests/driver/config-pins/all.T
- testsuite/tests/driver/fat-iface/fat014.stdout
- testsuite/tests/ffi/should_run/all.T
- testsuite/tests/ghc-api/T25121_status.stdout
- + testsuite/tests/ghc-api/T27273.hs
- testsuite/tests/ghc-api/all.T
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/A.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/B.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/C.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/D.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/X.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Y.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Z.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.stdout
- testsuite/tests/ghc-api/downsweep/OldModLocation.hs
- testsuite/tests/ghc-api/downsweep/PartialDownsweep.hs
- testsuite/tests/ghc-api/downsweep/all.T
- testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
- + testsuite/tests/ghc-api/settings/LibDir.hs
- + testsuite/tests/ghc-api/settings/LibDir.stdout
- + testsuite/tests/ghc-api/settings/all.T
- + testsuite/tests/ghci/prog-mhu006/Makefile
- + testsuite/tests/ghci/prog-mhu006/a/A.hs
- + testsuite/tests/ghci/prog-mhu006/all.T
- + testsuite/tests/ghci/prog-mhu006/b/B.hs
- + testsuite/tests/ghci/prog-mhu006/prog-mhu006a.script
- + testsuite/tests/ghci/prog-mhu006/prog-mhu006a.stdout
- + testsuite/tests/ghci/prog-mhu006/unitA
- + testsuite/tests/ghci/prog-mhu006/unitB
- testsuite/tests/ghci/prog003/prog003.script
- testsuite/tests/ghci/prog018/prog018.stdout
- testsuite/tests/ghci/prog020/Makefile
- testsuite/tests/ghci/prog020/all.T
- testsuite/tests/ghci/prog020/ghci.prog020.script → testsuite/tests/ghci/prog020/ghci.prog020a.script
- testsuite/tests/ghci/prog020/ghci.prog020.stderr → testsuite/tests/ghci/prog020/ghci.prog020a.stderr
- testsuite/tests/ghci/prog020/ghci.prog020.stdout → testsuite/tests/ghci/prog020/ghci.prog020a.stdout
- + testsuite/tests/ghci/prog020/ghci.prog020b.script
- + testsuite/tests/ghci/prog020/ghci.prog020b.stderr
- + testsuite/tests/ghci/prog020/ghci.prog020b.stdout
- + testsuite/tests/ghci/prog023/Makefile
- + testsuite/tests/ghci/prog023/all.T
- + testsuite/tests/ghci/prog023/prog023a.script
- + testsuite/tests/ghci/prog023/prog023a.stdout
- + testsuite/tests/ghci/prog023/prog023b.script
- + testsuite/tests/ghci/prog023/prog023b.stdout
- + testsuite/tests/ghci/prog023/src/A.hs
- + testsuite/tests/ghci/prog024/Makefile
- + testsuite/tests/ghci/prog024/all.T
- + testsuite/tests/ghci/prog024/prog024a.script
- + testsuite/tests/ghci/prog024/prog024a.stdout
- + testsuite/tests/ghci/prog024/prog024b.script
- + testsuite/tests/ghci/prog024/prog024b.stdout
- + testsuite/tests/ghci/prog024/prog024c.script
- + testsuite/tests/ghci/prog024/prog024c.stderr
- + testsuite/tests/ghci/prog024/prog024c.stdout
- + testsuite/tests/ghci/prog024/prog024d.script
- + testsuite/tests/ghci/prog024/prog024d.stderr
- + testsuite/tests/ghci/prog024/prog024d.stdout
- + testsuite/tests/ghci/prog024/prog024e.script
- + testsuite/tests/ghci/prog024/prog024e.stdout
- + testsuite/tests/ghci/prog024/prog024f.script
- + testsuite/tests/ghci/prog024/prog024f.stdout
- + testsuite/tests/ghci/prog024/src/A.hs
- + testsuite/tests/ghci/prog024/src/B.hs
- + testsuite/tests/ghci/prog025/Makefile
- + testsuite/tests/ghci/prog025/a/A.hs
- + testsuite/tests/ghci/prog025/all.T
- + testsuite/tests/ghci/prog025/prog025a.script
- + testsuite/tests/ghci/prog025/prog025a.stdout
- + testsuite/tests/ghci/prog025/prog025b.script
- + testsuite/tests/ghci/prog025/prog025b.stdout
- + testsuite/tests/ghci/prog025/testpkg/Test.hs
- + testsuite/tests/ghci/prog025/testpkg/testpkg-0.1.0.0.pkg
- + testsuite/tests/ghci/prog025/testpkg/testpkg-0.2.0.0.pkg
- + testsuite/tests/ghci/prog025/unitA
- testsuite/tests/ghci/scripts/ListTuplePunsPprNoAbbrevTuple.stdout
- testsuite/tests/ghci/scripts/T13997.stdout
- testsuite/tests/ghci/scripts/T1914.stdout
- testsuite/tests/ghci/scripts/T20217.stdout
- testsuite/tests/ghci/scripts/T8042.stdout
- testsuite/tests/ghci/scripts/T8042recomp.stdout
- testsuite/tests/ghci/scripts/all.T
- testsuite/tests/ghci/should_run/T10920.stderr
- + testsuite/tests/interface-stability/.gitignore
- testsuite/tests/interface-stability/README.mkd
- 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/download-base-exports.sh
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- testsuite/tests/linters/notes.stdout
- testsuite/tests/numeric/should_compile/T15547.stderr
- testsuite/tests/numeric/should_compile/T20347.stderr
- testsuite/tests/numeric/should_compile/T20374.stderr
- testsuite/tests/numeric/should_compile/T20376.stderr
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/parser/should_compile/DumpParsedAst.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/KindSigs.stderr
- testsuite/tests/parser/should_compile/ListTuplePunsSuccess1.hs
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/parser/should_compile/all.T
- + testsuite/tests/parser/should_fail/ListTuplePunsFail6.hs
- + testsuite/tests/parser/should_fail/ListTuplePunsFail6.stderr
- testsuite/tests/parser/should_fail/all.T
- testsuite/tests/parser/should_run/ListTuplePunsConstraints.hs
- testsuite/tests/perf/compiler/Makefile
- + testsuite/tests/perf/compiler/T26989.hs
- + testsuite/tests/perf/compiler/T26989a.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/perf/compiler/genMultiComp.py
- + testsuite/tests/perf/should_run/T11226.hs
- + testsuite/tests/perf/should_run/T11226.stdout
- testsuite/tests/perf/should_run/all.T
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/PprModifiers.hs
- + testsuite/tests/printer/PprQualifiedStrings.hs
- testsuite/tests/printer/T18052a.stderr
- + testsuite/tests/printer/Test27291.hs
- testsuite/tests/printer/all.T
- + testsuite/tests/profiling/should_compile/T27182.hs
- testsuite/tests/profiling/should_compile/all.T
- testsuite/tests/profiling/should_run/callstack001.stdout
- + testsuite/tests/rts/T25275/DebugIpe.hs
- + testsuite/tests/rts/T25275/T25275_A.stdout
- + testsuite/tests/rts/T25275/T25275_B.stdout
- + testsuite/tests/rts/T25275/T25275_C.stdout
- + testsuite/tests/rts/T25275/T25275_D.stdout
- + testsuite/tests/rts/T25275/TraceIpe.hs
- + testsuite/tests/rts/T25275/all.T
- testsuite/tests/simplCore/should_compile/DsSpecPragmas.stderr
- testsuite/tests/simplCore/should_compile/RewriteHigherOrderPatterns.stderr
- testsuite/tests/simplCore/should_compile/T15205.stderr
- testsuite/tests/simplCore/should_compile/T18668.stderr
- testsuite/tests/simplCore/should_compile/T19246.stderr
- testsuite/tests/simplCore/should_compile/T19599.stderr
- testsuite/tests/simplCore/should_compile/T19599a.stderr
- testsuite/tests/simplCore/should_compile/T21917.stderr
- testsuite/tests/simplCore/should_compile/T23074.stderr
- testsuite/tests/simplCore/should_compile/T24359a.stderr
- testsuite/tests/simplCore/should_compile/T25160.stderr
- testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-32
- testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-64
- testsuite/tests/simplCore/should_compile/T26051.stderr
- testsuite/tests/simplCore/should_compile/T26116.stderr
- + testsuite/tests/simplCore/should_compile/T27261.hs
- + testsuite/tests/simplCore/should_compile/T27261_aux.hs
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/T8848a.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/simplCore/should_compile/spec004.stderr
- testsuite/tests/th/T24111.stdout
- testsuite/tests/typecheck/should_compile/T13032.stderr
- + testsuite/tests/typecheck/should_compile/T23135.hs
- testsuite/tests/typecheck/should_compile/all.T
- testsuite/tests/typecheck/should_compile/subsumption_sort_hole_fits.stderr
- testsuite/tests/typecheck/should_fail/T21130.stderr
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/ghc-pkg/Main.hs
- utils/ghc-toolchain/exe/Main.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Program.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Target.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Interface/RenameType.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/jsffi/prelude.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ba973f65f52302c0cc76db713f3020…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ba973f65f52302c0cc76db713f3020…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/supersven/flags-pin-test] testsuite: simplify config-pins scripts
by Sven Tennie (@supersven) 07 Jun '26
by Sven Tennie (@supersven) 07 Jun '26
07 Jun '26
Sven Tennie pushed to branch wip/supersven/flags-pin-test at Glasgow Haskell Compiler / GHC
Commits:
ba973f65 by Sven Tennie at 2026-06-07T16:21:49+00:00
testsuite: simplify config-pins scripts
- Extract platform_key() to ConfigPinsExpected.py; import in both scripts
- Build actual dict directly in GhcInfoPins.py (drop list→dict roundtrip)
- Add comment to all.T explaining why tests are Python not Haskell
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
4 changed files:
- testsuite/tests/driver/config-pins/ConfigPinsExpected.py
- testsuite/tests/driver/config-pins/GhcInfoPins.py
- testsuite/tests/driver/config-pins/TestsuiteConfigPins.py
- testsuite/tests/driver/config-pins/all.T
Changes:
=====================================
testsuite/tests/driver/config-pins/ConfigPinsExpected.py
=====================================
@@ -9,6 +9,14 @@
#
# When a new platform is encountered the test prints a ready-to-paste entry.
+
+def platform_key(platform, is_cross, is_unreg, no_tntc):
+ key = platform
+ if is_cross: key += "-cross"
+ if is_unreg: key += "-unreg"
+ elif no_tntc: key += "-no_tntc"
+ return key
+
PINNED_GHC_INFO_FIELDS = [
"target arch",
"target os",
=====================================
testsuite/tests/driver/config-pins/GhcInfoPins.py
=====================================
@@ -5,19 +5,16 @@ import subprocess
import sys
sys.path.insert(0, '.')
-from ConfigPinsExpected import GHC_INFO_EXPECTED, PINNED_GHC_INFO_FIELDS
+from ConfigPinsExpected import GHC_INFO_EXPECTED, PINNED_GHC_INFO_FIELDS, platform_key
-def platform_key(info_map):
- platform = info_map.get("target platform string", "<unknown>")
- is_cross = info_map.get("cross compiling", "NO") == "YES"
- is_unreg = info_map.get("Unregisterised", "NO") == "YES"
- no_tntc = info_map.get("Tables next to code", "YES") == "NO"
- key = platform
- if is_cross: key += "-cross"
- if is_unreg: key += "-unreg"
- elif no_tntc: key += "-no_tntc"
- return key
+def info_platform_key(info_map):
+ return platform_key(
+ info_map.get("target platform string", "<unknown>"),
+ info_map.get("cross compiling", "NO") == "YES",
+ info_map.get("Unregisterised", "NO") == "YES",
+ info_map.get("Tables next to code", "YES") == "NO",
+ )
def main():
@@ -39,26 +36,25 @@ def main():
except (ValueError, SyntaxError) as e:
print(f"Failed to parse {compiler!r} --info output: {e}")
sys.exit(1)
- key = platform_key(info_map)
+ key = info_platform_key(info_map)
- actual = [(f, info_map.get(f, "<missing>")) for f in PINNED_GHC_INFO_FIELDS]
+ actual = {f: info_map.get(f, "<missing>") for f in PINNED_GHC_INFO_FIELDS}
if key not in GHC_INFO_EXPECTED:
print(f"Platform key {key!r} not in ConfigPinsExpected.")
print("Add this entry to GHC_INFO_EXPECTED in ConfigPinsExpected.py:")
print()
print(f" {key!r}: {{")
- for f, v in actual:
+ for f, v in actual.items():
print(f" {f!r}: {v!r},")
print(" },")
sys.exit(1)
expected = GHC_INFO_EXPECTED[key]
- actual_map = dict(actual)
mismatches = [
- (f, ev, actual_map.get(f, "<missing>"))
+ (f, ev, actual.get(f, "<missing>"))
for f, ev in sorted(expected.items())
- if ev != actual_map.get(f, "<missing>")
+ if ev != actual.get(f, "<missing>")
]
if mismatches:
=====================================
testsuite/tests/driver/config-pins/TestsuiteConfigPins.py
=====================================
@@ -3,15 +3,7 @@
import sys
sys.path.insert(0, '.')
-from ConfigPinsExpected import TESTSUITE_CONFIG_EXPECTED
-
-
-def platform_key(platform, is_cross, is_unreg, no_tntc):
- key = platform
- if is_cross: key += "-cross"
- if is_unreg: key += "-unreg"
- elif no_tntc: key += "-no_tntc"
- return key
+from ConfigPinsExpected import TESTSUITE_CONFIG_EXPECTED, platform_key
def main():
=====================================
testsuite/tests/driver/config-pins/all.T
=====================================
@@ -1,5 +1,9 @@
import sys
+# Python run_command rather than compiled Haskell: wasm32/WASI targets cannot
+# call runInteractiveProcess from compiled binaries (no process creation in
+# WASI). Python scripts run on the host regardless of the target under test.
+
test('GhcInfoPins',
[extra_files(['ConfigPinsExpected.py', 'GhcInfoPins.py']),
ignore_stdout],
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ba973f65f52302c0cc76db713f3020c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ba973f65f52302c0cc76db713f3020c…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/supersven/flags-pin-test] 2 commits: testsuite: migrate config-pins tests to Python
by Sven Tennie (@supersven) 07 Jun '26
by Sven Tennie (@supersven) 07 Jun '26
07 Jun '26
Sven Tennie pushed to branch wip/supersven/flags-pin-test at Glasgow Haskell Compiler / GHC
Commits:
62ef8f48 by Sven Tennie at 2026-06-07T15:59:50+00:00
testsuite: migrate config-pins tests to Python
Python scripts run on the host via run_command, so they work on all
cross-compilation targets including wasm32 (where WASI does not support
process creation and the previous Haskell compile_and_run approach could
not call readProcess to invoke the compiler with --info).
Also fixes expected values caught by the first CI run:
- OSMinGW32 (not OSMingw32) for Windows targets
- ArchAArch64 (not ArchAarch64) for native aarch64 Linux/macOS builds
- aarch64-apple-darwin: target has subsections via symbols = NO
- x86_64-unreg: Support SMP = NO, backend = "compiling via C"
- JavaScript: Tables next to code = YES, backend = "compiling to JavaScript"
- wasm32: key suffix -no_tntc (not bare -cross); tcHaveInterp/tcInterpForceDyn = True
- FreeBSD: platform string "x86_64-portbld-freebsd" (no version), nonexec stack = YES
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
0079eaa5 by Sven Tennie at 2026-06-07T16:06:30+00:00
testsuite: fix config-pins post-review issues
- GhcInfoPins.py: catch OSError/SyntaxError from subprocess/ast to give
clean error messages instead of tracebacks on bad compiler path or
unexpected --info output
- TestsuiteConfigPins.py: quote field names in mismatch output (k!r)
- ConfigPinsExpected.py: fix wasm32-cross-no_tntc Have/Use interpreter to
YES (consistent with CI-reported have_interp=True in testsuite config)
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
7 changed files:
- − testsuite/tests/driver/config-pins/ConfigPinsExpected.hs
- + testsuite/tests/driver/config-pins/ConfigPinsExpected.py
- − testsuite/tests/driver/config-pins/GhcInfoPins.hs
- + testsuite/tests/driver/config-pins/GhcInfoPins.py
- − testsuite/tests/driver/config-pins/TestsuiteConfigPins.hs
- + testsuite/tests/driver/config-pins/TestsuiteConfigPins.py
- testsuite/tests/driver/config-pins/all.T
Changes:
=====================================
testsuite/tests/driver/config-pins/ConfigPinsExpected.hs deleted
=====================================
@@ -1,681 +0,0 @@
-module ConfigPinsExpected where
-
-import Data.Map.Strict (Map)
-import qualified Data.Map.Strict as Map
-
--- | Fields from ghc --info that we pin. Order preserved in unknown-key output.
-pinnedGhcInfoFields :: [String]
-pinnedGhcInfoFields =
- [ "target arch"
- , "target os"
- , "target platform string"
- , "target word size"
- , "target word big endian"
- , "Tables next to code"
- , "Support SMP"
- , "Have interpreter"
- , "Use interpreter"
- , "Have native code generator"
- , "Unregisterised"
- , "Leading underscore"
- , "target has RTS linker"
- , "target RTS linker only supports shared libraries"
- , "cross compiling"
- , "target has GNU nonexec stack"
- , "target has subsections via symbols"
- , "Target default backend"
- ]
-
--- | Expected ghc --info values keyed by platform key.
---
--- Platform key construction:
--- base = "target platform string" from ghc --info
--- key = base
--- ++ (if cross-compiling then "-cross" else "")
--- ++ (if Unregisterised then "-unreg"
--- else if TNC==NO then "-no_tntc"
--- else "")
---
--- Add entries here when a new platform is encountered —
--- the test prints the exact entry to paste in.
-ghcInfoExpected :: Map String (Map String String)
-ghcInfoExpected = Map.fromList
-
- -- ── x86_64 Linux (all distros share the same config) ────────────────────
- [ ( "x86_64-unknown-linux", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSLinux")
- , ("target platform string", "x86_64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── x86_64 Linux unregisterised (deb13-unreg job) ───────────────────────
- , ( "x86_64-unknown-linux-unreg", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSLinux")
- , ("target platform string", "x86_64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "NO")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "NO")
- , ("Unregisterised", "YES")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "C") -- FIXME: verify exact string
- ] )
-
- -- ── x86_64 Linux no tables-next-to-code (deb13-no_tntc job) ────────────
- , ( "x86_64-unknown-linux-no_tntc", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSLinux")
- , ("target platform string", "x86_64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "NO")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── aarch64 Linux (all distros) ─────────────────────────────────────────
- , ( "aarch64-unknown-linux", Map.fromList
- [ ("target arch", "ArchAarch64")
- , ("target os", "OSLinux")
- , ("target platform string", "aarch64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── aarch64 Linux cross (x86_64-linux-deb13-cross_aarch64 job) ──────────
- , ( "aarch64-unknown-linux-cross", Map.fromList
- [ ("target arch", "ArchAarch64")
- , ("target os", "OSLinux")
- , ("target platform string", "aarch64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── i386 Linux ───────────────────────────────────────────────────────────
- , ( "i386-unknown-linux", Map.fromList
- [ ("target arch", "ArchX86")
- , ("target os", "OSLinux")
- , ("target platform string", "i386-unknown-linux")
- , ("target word size", "4")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── aarch64 macOS (aarch64-darwin jobs) ─────────────────────────────────
- -- FIXME: platform string may have a version suffix, e.g. "aarch64-apple-darwin23"
- , ( "aarch64-apple-darwin", Map.fromList
- [ ("target arch", "ArchAarch64")
- , ("target os", "OSDarwin")
- , ("target platform string", "aarch64-apple-darwin")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "YES")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "YES")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── x86_64 macOS (x86_64-darwin jobs) ───────────────────────────────────
- -- FIXME: platform string may have a version suffix
- , ( "x86_64-apple-darwin", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSDarwin")
- , ("target platform string", "x86_64-apple-darwin")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "YES")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "YES")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── x86_64 FreeBSD (freebsd14 jobs) ─────────────────────────────────────
- -- FIXME: exact platform triple may differ (e.g. "x86_64-portbld-freebsd14.0")
- , ( "x86_64-portbld-freebsd14", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSFreeBSD")
- , ("target platform string", "x86_64-portbld-freebsd14")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── x86_64 Windows native (x86_64-windows jobs) ─────────────────────────
- , ( "x86_64-unknown-mingw32", Map.fromList
- [ ("target arch", "ArchX86_64")
- , ("target os", "OSMingw32")
- , ("target platform string", "x86_64-unknown-mingw32")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "YES")
- , ("Use interpreter", "YES")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "NO")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── aarch64 Windows cross (aarch64-linux-deb12-wine jobs) ───────────────
- , ( "aarch64-unknown-mingw32-cross", Map.fromList
- [ ("target arch", "ArchAarch64")
- , ("target os", "OSMingw32")
- , ("target platform string", "aarch64-unknown-mingw32")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── wasm32 cross (x86_64-linux-alpine3_23-wasm jobs) ────────────────────
- , ( "wasm32-unknown-wasi-cross", Map.fromList
- [ ("target arch", "ArchWasm32")
- , ("target os", "OSWasi")
- , ("target platform string", "wasm32-unknown-wasi")
- , ("target word size", "4")
- , ("target word big endian", "NO")
- , ("Tables next to code", "NO")
- , ("Support SMP", "NO")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── wasm32 cross unregisterised (wasm-unreg job) ────────────────────────
- , ( "wasm32-unknown-wasi-cross-unreg", Map.fromList
- [ ("target arch", "ArchWasm32")
- , ("target os", "OSWasi")
- , ("target platform string", "wasm32-unknown-wasi")
- , ("target word size", "4")
- , ("target word big endian", "NO")
- , ("Tables next to code", "NO")
- , ("Support SMP", "NO")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "NO")
- , ("Unregisterised", "YES")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "C") -- FIXME: verify
- ] )
-
- -- ── JavaScript cross (deb11-emsdk job) ──────────────────────────────────
- , ( "javascript-unknown-ghcjs-cross", Map.fromList
- [ ("target arch", "ArchJavaScript")
- , ("target os", "OSGhcjs")
- , ("target platform string", "javascript-unknown-ghcjs")
- , ("target word size", "4")
- , ("target word big endian", "NO")
- , ("Tables next to code", "NO")
- , ("Support SMP", "NO")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "NO")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "NO")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "NO")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "JavaScript") -- FIXME: verify exact string
- ] )
-
- -- ── riscv64 Linux cross (deb13-riscv job) ───────────────────────────────
- , ( "riscv64-unknown-linux-cross", Map.fromList
- [ ("target arch", "ArchRISCV64")
- , ("target os", "OSLinux")
- , ("target platform string", "riscv64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "YES")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- -- ── loongarch64 Linux cross (ubuntu24_04-loongarch job) ─────────────────
- , ( "loongarch64-unknown-linux-cross", Map.fromList
- [ ("target arch", "ArchLoongArch64")
- , ("target os", "OSLinux")
- , ("target platform string", "loongarch64-unknown-linux")
- , ("target word size", "8")
- , ("target word big endian", "NO")
- , ("Tables next to code", "YES")
- , ("Support SMP", "YES")
- , ("Have interpreter", "NO")
- , ("Use interpreter", "NO")
- , ("Have native code generator", "YES")
- , ("Unregisterised", "NO")
- , ("Leading underscore", "NO")
- , ("target has RTS linker", "NO")
- , ("target RTS linker only supports shared libraries", "NO")
- , ("cross compiling", "YES")
- , ("target has GNU nonexec stack", "YES")
- , ("target has subsections via symbols", "NO")
- , ("Target default backend", "native code generator")
- ] )
-
- ]
-
-
-data TestsuiteConfig = TestsuiteConfig
- { tcPlatform :: String
- , tcArch :: String
- , tcWordsize :: String
- , tcHaveNcg :: Bool
- , tcHaveInterp :: Bool
- , tcUnregisterised :: Bool
- , tcTablesNextToCode :: Bool
- , tcLeadingUnderscore :: Bool
- , tcTargetHasSmp :: Bool
- , tcHaveRtsLinker :: Bool
- , tcInterpForceDyn :: Bool
- , tcCross :: Bool
- } deriving (Eq, Show)
-
--- | Expected testsuite config values keyed by platform key.
--- Same key derivation as ghcInfoExpected (see above).
-testsuiteConfigExpected :: Map String TestsuiteConfig
-testsuiteConfigExpected = Map.fromList
-
- -- ── x86_64 Linux ────────────────────────────────────────────────────────
- [ ( "x86_64-unknown-linux", TestsuiteConfig
- { tcPlatform = "x86_64-unknown-linux"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── x86_64 Linux unregisterised ─────────────────────────────────────────
- , ( "x86_64-unknown-linux-unreg", TestsuiteConfig
- { tcPlatform = "x86_64-unknown-linux"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = False
- , tcHaveInterp = True
- , tcUnregisterised = True
- , tcTablesNextToCode = False
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── x86_64 Linux no tables-next-to-code ─────────────────────────────────
- , ( "x86_64-unknown-linux-no_tntc", TestsuiteConfig
- { tcPlatform = "x86_64-unknown-linux"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = False
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── aarch64 Linux ────────────────────────────────────────────────────────
- , ( "aarch64-unknown-linux", TestsuiteConfig
- { tcPlatform = "aarch64-unknown-linux"
- , tcArch = "aarch64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── aarch64 Linux cross ───────────────────────────────────────────────────
- , ( "aarch64-unknown-linux-cross", TestsuiteConfig
- { tcPlatform = "aarch64-unknown-linux"
- , tcArch = "aarch64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── i386 Linux ───────────────────────────────────────────────────────────
- , ( "i386-unknown-linux", TestsuiteConfig
- { tcPlatform = "i386-unknown-linux"
- , tcArch = "i386"
- , tcWordsize = "32"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── aarch64 macOS ─────────────────────────────────────────────────────────
- -- FIXME: tcPlatform may have version suffix e.g. "aarch64-apple-darwin23"
- , ( "aarch64-apple-darwin", TestsuiteConfig
- { tcPlatform = "aarch64-apple-darwin"
- , tcArch = "aarch64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = True
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── x86_64 macOS ─────────────────────────────────────────────────────────
- -- FIXME: tcPlatform may have version suffix
- , ( "x86_64-apple-darwin", TestsuiteConfig
- { tcPlatform = "x86_64-apple-darwin"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = True
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── x86_64 FreeBSD ───────────────────────────────────────────────────────
- -- FIXME: tcPlatform triple may differ (e.g. "x86_64-portbld-freebsd14.0")
- , ( "x86_64-portbld-freebsd14", TestsuiteConfig
- { tcPlatform = "x86_64-portbld-freebsd14"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── x86_64 Windows native ────────────────────────────────────────────────
- , ( "x86_64-unknown-mingw32", TestsuiteConfig
- { tcPlatform = "x86_64-unknown-mingw32"
- , tcArch = "x86_64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = True
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = False
- } )
-
- -- ── aarch64 Windows cross ─────────────────────────────────────────────────
- , ( "aarch64-unknown-mingw32-cross", TestsuiteConfig
- { tcPlatform = "aarch64-unknown-mingw32"
- , tcArch = "aarch64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── wasm32 cross ─────────────────────────────────────────────────────────
- , ( "wasm32-unknown-wasi-cross", TestsuiteConfig
- { tcPlatform = "wasm32-unknown-wasi"
- , tcArch = "wasm32"
- , tcWordsize = "32"
- , tcHaveNcg = True
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = False
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = False
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── wasm32 cross unregisterised ───────────────────────────────────────────
- , ( "wasm32-unknown-wasi-cross-unreg", TestsuiteConfig
- { tcPlatform = "wasm32-unknown-wasi"
- , tcArch = "wasm32"
- , tcWordsize = "32"
- , tcHaveNcg = False
- , tcHaveInterp = False
- , tcUnregisterised = True
- , tcTablesNextToCode = False
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = False
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── JavaScript cross ─────────────────────────────────────────────────────
- , ( "javascript-unknown-ghcjs-cross", TestsuiteConfig
- { tcPlatform = "javascript-unknown-ghcjs"
- , tcArch = "javascript"
- , tcWordsize = "32"
- , tcHaveNcg = False
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = False
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = False
- , tcHaveRtsLinker = False
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── riscv64 Linux cross ───────────────────────────────────────────────────
- , ( "riscv64-unknown-linux-cross", TestsuiteConfig
- { tcPlatform = "riscv64-unknown-linux"
- , tcArch = "riscv64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = True
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- -- ── loongarch64 Linux cross ───────────────────────────────────────────────
- , ( "loongarch64-unknown-linux-cross", TestsuiteConfig
- { tcPlatform = "loongarch64-unknown-linux"
- , tcArch = "loongarch64"
- , tcWordsize = "64"
- , tcHaveNcg = True
- , tcHaveInterp = False
- , tcUnregisterised = False
- , tcTablesNextToCode = True
- , tcLeadingUnderscore = False
- , tcTargetHasSmp = True
- , tcHaveRtsLinker = False
- , tcInterpForceDyn = False
- , tcCross = True
- } )
-
- ]
=====================================
testsuite/tests/driver/config-pins/ConfigPinsExpected.py
=====================================
@@ -0,0 +1,649 @@
+# Expected GHC config values, keyed by platform key.
+#
+# Platform key construction:
+# base = "target platform string" from ghc --info (or config.platform)
+# key = base
+# + ("-cross" if cross-compiling)
+# + ("-unreg" if Unregisterised,
+# "-no_tntc" elif Tables-next-to-code == NO)
+#
+# When a new platform is encountered the test prints a ready-to-paste entry.
+
+PINNED_GHC_INFO_FIELDS = [
+ "target arch",
+ "target os",
+ "target platform string",
+ "target word size",
+ "target word big endian",
+ "Tables next to code",
+ "Support SMP",
+ "Have interpreter",
+ "Use interpreter",
+ "Have native code generator",
+ "Unregisterised",
+ "Leading underscore",
+ "target has RTS linker",
+ "target RTS linker only supports shared libraries",
+ "cross compiling",
+ "target has GNU nonexec stack",
+ "target has subsections via symbols",
+ "Target default backend",
+]
+
+GHC_INFO_EXPECTED = {
+
+ # ── x86_64 Linux (all distros) ───────────────────────────────────────────
+ "x86_64-unknown-linux": {
+ "target arch": "ArchX86_64",
+ "target os": "OSLinux",
+ "target platform string": "x86_64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── x86_64 Linux unregisterised ──────────────────────────────────────────
+ "x86_64-unknown-linux-unreg": {
+ "target arch": "ArchX86_64",
+ "target os": "OSLinux",
+ "target platform string": "x86_64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "NO",
+ "Support SMP": "NO",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "NO",
+ "Unregisterised": "YES",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "compiling via C",
+ },
+
+ # ── x86_64 Linux no tables-next-to-code ──────────────────────────────────
+ "x86_64-unknown-linux-no_tntc": {
+ "target arch": "ArchX86_64",
+ "target os": "OSLinux",
+ "target platform string": "x86_64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "NO",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── aarch64 Linux native ─────────────────────────────────────────────────
+ "aarch64-unknown-linux": {
+ "target arch": "ArchAArch64",
+ "target os": "OSLinux",
+ "target platform string": "aarch64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── aarch64 Linux cross ──────────────────────────────────────────────────
+ "aarch64-unknown-linux-cross": {
+ "target arch": "ArchAarch64",
+ "target os": "OSLinux",
+ "target platform string": "aarch64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── i386 Linux ───────────────────────────────────────────────────────────
+ "i386-unknown-linux": {
+ "target arch": "ArchX86",
+ "target os": "OSLinux",
+ "target platform string": "i386-unknown-linux",
+ "target word size": "4",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── aarch64 macOS ────────────────────────────────────────────────────────
+ # FIXME: platform string may have a version suffix, e.g. "aarch64-apple-darwin23"
+ "aarch64-apple-darwin": {
+ "target arch": "ArchAArch64",
+ "target os": "OSDarwin",
+ "target platform string": "aarch64-apple-darwin",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "YES",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── x86_64 macOS ─────────────────────────────────────────────────────────
+ # FIXME: platform string may have a version suffix
+ "x86_64-apple-darwin": {
+ "target arch": "ArchX86_64",
+ "target os": "OSDarwin",
+ "target platform string": "x86_64-apple-darwin",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "YES",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "YES",
+ "Target default backend": "native code generator",
+ },
+
+ # ── x86_64 FreeBSD ───────────────────────────────────────────────────────
+ "x86_64-portbld-freebsd": {
+ "target arch": "ArchX86_64",
+ "target os": "OSFreeBSD",
+ "target platform string": "x86_64-portbld-freebsd",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── x86_64 Windows native ────────────────────────────────────────────────
+ "x86_64-unknown-mingw32": {
+ "target arch": "ArchX86_64",
+ "target os": "OSMinGW32",
+ "target platform string": "x86_64-unknown-mingw32",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "NO",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── aarch64 Windows cross ────────────────────────────────────────────────
+ "aarch64-unknown-mingw32-cross": {
+ "target arch": "ArchAarch64",
+ "target os": "OSMinGW32",
+ "target platform string": "aarch64-unknown-mingw32",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── wasm32 cross ─────────────────────────────────────────────────────────
+ "wasm32-unknown-wasi-cross-no_tntc": {
+ "target arch": "ArchWasm32",
+ "target os": "OSWasi",
+ "target platform string": "wasm32-unknown-wasi",
+ "target word size": "4",
+ "target word big endian": "NO",
+ "Tables next to code": "NO",
+ "Support SMP": "NO",
+ "Have interpreter": "YES",
+ "Use interpreter": "YES",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── wasm32 cross unregisterised ──────────────────────────────────────────
+ "wasm32-unknown-wasi-cross-unreg": {
+ "target arch": "ArchWasm32",
+ "target os": "OSWasi",
+ "target platform string": "wasm32-unknown-wasi",
+ "target word size": "4",
+ "target word big endian": "NO",
+ "Tables next to code": "NO",
+ "Support SMP": "NO",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "NO",
+ "Unregisterised": "YES",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "compiling via C", # FIXME: verify
+ },
+
+ # ── JavaScript cross ─────────────────────────────────────────────────────
+ "javascript-unknown-ghcjs-cross": {
+ "target arch": "ArchJavaScript",
+ "target os": "OSGhcjs",
+ "target platform string": "javascript-unknown-ghcjs",
+ "target word size": "4",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "NO",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "NO",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "NO",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "NO",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "compiling to JavaScript",
+ },
+
+ # ── riscv64 Linux cross ──────────────────────────────────────────────────
+ "riscv64-unknown-linux-cross": {
+ "target arch": "ArchRISCV64",
+ "target os": "OSLinux",
+ "target platform string": "riscv64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "YES",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+
+ # ── loongarch64 Linux cross ──────────────────────────────────────────────
+ "loongarch64-unknown-linux-cross": {
+ "target arch": "ArchLoongArch64",
+ "target os": "OSLinux",
+ "target platform string": "loongarch64-unknown-linux",
+ "target word size": "8",
+ "target word big endian": "NO",
+ "Tables next to code": "YES",
+ "Support SMP": "YES",
+ "Have interpreter": "NO",
+ "Use interpreter": "NO",
+ "Have native code generator": "YES",
+ "Unregisterised": "NO",
+ "Leading underscore": "NO",
+ "target has RTS linker": "NO",
+ "target RTS linker only supports shared libraries": "NO",
+ "cross compiling": "YES",
+ "target has GNU nonexec stack": "YES",
+ "target has subsections via symbols": "NO",
+ "Target default backend": "native code generator",
+ },
+}
+
+TESTSUITE_CONFIG_EXPECTED = {
+
+ # ── x86_64 Linux ─────────────────────────────────────────────────────────
+ "x86_64-unknown-linux": {
+ "platform": "x86_64-unknown-linux",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── x86_64 Linux unregisterised ──────────────────────────────────────────
+ "x86_64-unknown-linux-unreg": {
+ "platform": "x86_64-unknown-linux",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": False,
+ "have_interp": True,
+ "unregisterised": True,
+ "tables_next_to_code": False,
+ "leading_underscore": False,
+ "target_has_smp": False,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── x86_64 Linux no tables-next-to-code ──────────────────────────────────
+ "x86_64-unknown-linux-no_tntc": {
+ "platform": "x86_64-unknown-linux",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": False,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── aarch64 Linux native ─────────────────────────────────────────────────
+ "aarch64-unknown-linux": {
+ "platform": "aarch64-unknown-linux",
+ "arch": "aarch64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── aarch64 Linux cross ──────────────────────────────────────────────────
+ "aarch64-unknown-linux-cross": {
+ "platform": "aarch64-unknown-linux",
+ "arch": "aarch64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": False,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+
+ # ── i386 Linux ───────────────────────────────────────────────────────────
+ "i386-unknown-linux": {
+ "platform": "i386-unknown-linux",
+ "arch": "i386",
+ "wordsize": "32",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── aarch64 macOS ────────────────────────────────────────────────────────
+ # FIXME: platform may have version suffix e.g. "aarch64-apple-darwin23"
+ "aarch64-apple-darwin": {
+ "platform": "aarch64-apple-darwin",
+ "arch": "aarch64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": True,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── x86_64 macOS ─────────────────────────────────────────────────────────
+ # FIXME: platform may have version suffix
+ "x86_64-apple-darwin": {
+ "platform": "x86_64-apple-darwin",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": True,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── x86_64 FreeBSD ───────────────────────────────────────────────────────
+ "x86_64-portbld-freebsd": {
+ "platform": "x86_64-portbld-freebsd",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── x86_64 Windows native ────────────────────────────────────────────────
+ "x86_64-unknown-mingw32": {
+ "platform": "x86_64-unknown-mingw32",
+ "arch": "x86_64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": False,
+ },
+
+ # ── aarch64 Windows cross ────────────────────────────────────────────────
+ "aarch64-unknown-mingw32-cross": {
+ "platform": "aarch64-unknown-mingw32",
+ "arch": "aarch64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": False,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+
+ # ── wasm32 cross ─────────────────────────────────────────────────────────
+ "wasm32-unknown-wasi-cross-no_tntc": {
+ "platform": "wasm32-unknown-wasi",
+ "arch": "wasm32",
+ "wordsize": "32",
+ "have_ncg": True,
+ "have_interp": True,
+ "unregisterised": False,
+ "tables_next_to_code": False,
+ "leading_underscore": False,
+ "target_has_smp": False,
+ "have_RTS_linker": True,
+ "interp_force_dyn": True,
+ "cross": True,
+ },
+
+ # ── wasm32 cross unregisterised ──────────────────────────────────────────
+ "wasm32-unknown-wasi-cross-unreg": {
+ "platform": "wasm32-unknown-wasi",
+ "arch": "wasm32",
+ "wordsize": "32",
+ "have_ncg": False,
+ "have_interp": False,
+ "unregisterised": True,
+ "tables_next_to_code": False,
+ "leading_underscore": False,
+ "target_has_smp": False,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+
+ # ── JavaScript cross ─────────────────────────────────────────────────────
+ "javascript-unknown-ghcjs-cross": {
+ "platform": "javascript-unknown-ghcjs",
+ "arch": "javascript",
+ "wordsize": "32",
+ "have_ncg": False,
+ "have_interp": False,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": False,
+ "have_RTS_linker": False,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+
+ # ── riscv64 Linux cross ──────────────────────────────────────────────────
+ "riscv64-unknown-linux-cross": {
+ "platform": "riscv64-unknown-linux",
+ "arch": "riscv64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": False,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": True,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+
+ # ── loongarch64 Linux cross ──────────────────────────────────────────────
+ "loongarch64-unknown-linux-cross": {
+ "platform": "loongarch64-unknown-linux",
+ "arch": "loongarch64",
+ "wordsize": "64",
+ "have_ncg": True,
+ "have_interp": False,
+ "unregisterised": False,
+ "tables_next_to_code": True,
+ "leading_underscore": False,
+ "target_has_smp": True,
+ "have_RTS_linker": False,
+ "interp_force_dyn": False,
+ "cross": True,
+ },
+}
=====================================
testsuite/tests/driver/config-pins/GhcInfoPins.hs deleted
=====================================
@@ -1,64 +0,0 @@
-module Main where
-
-import System.Environment (getArgs)
-import System.Exit (exitFailure)
-import System.Process (readProcess)
-import qualified Data.Map.Strict as Map
-
-import ConfigPinsExpected (ghcInfoExpected, pinnedGhcInfoFields)
-
-platformKey :: Map.Map String String -> String
-platformKey infoMap =
- let platform = Map.findWithDefault "<unknown>" "target platform string" infoMap
- isCross = Map.findWithDefault "NO" "cross compiling" infoMap == "YES"
- isUnreg = Map.findWithDefault "NO" "Unregisterised" infoMap == "YES"
- noTntc = Map.findWithDefault "YES" "Tables next to code" infoMap == "NO"
- in platform
- ++ (if isCross then "-cross" else "")
- ++ (if isUnreg then "-unreg"
- else if noTntc then "-no_tntc"
- else "")
-
-main :: IO ()
-main = do
- args <- getArgs
- compilerPath <- case args of
- [c] -> return c
- _ -> putStrLn "Usage: GhcInfoPins <compiler-path>" >> exitFailure
-
- infoStr <- readProcess compilerPath ["--info"] ""
- let allInfo = read infoStr :: [(String, String)]
- infoMap = Map.fromList allInfo
- key = platformKey infoMap
-
- let actual = [ (k, Map.findWithDefault "<missing>" k infoMap)
- | k <- pinnedGhcInfoFields ]
-
- case Map.lookup key ghcInfoExpected of
- Nothing -> do
- putStrLn $ "Platform key " ++ show key ++ " not in ConfigPinsExpected."
- putStrLn "Add this entry to ghcInfoExpected in ConfigPinsExpected.hs:"
- putStrLn ""
- putStrLn $ " , ( " ++ show key ++ ", Map.fromList"
- case actual of
- [] -> putStrLn " [] )"
- (k0, v0) : rest -> do
- putStrLn $ " [ (" ++ show k0 ++ ", " ++ show v0 ++ ")"
- mapM_ (\(k, v) -> putStrLn $ " , (" ++ show k ++ ", " ++ show v ++ ")") rest
- putStrLn " ] )"
- exitFailure
- Just expected -> do
- let actualMap = Map.fromList actual
- mismatches =
- [ (k, ev, Map.findWithDefault "<missing>" k actualMap)
- | (k, ev) <- Map.toAscList expected
- , ev /= Map.findWithDefault "<missing>" k actualMap
- ]
- if null mismatches
- then putStrLn $ "OK: " ++ key
- else do
- putStrLn $ "MISMATCH for " ++ show key ++ ":"
- mapM_ (\(k, ev, av) ->
- putStrLn $ " " ++ show k ++ ": expected " ++ show ev ++ ", got " ++ show av
- ) mismatches
- exitFailure
=====================================
testsuite/tests/driver/config-pins/GhcInfoPins.py
=====================================
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+"""Check that ghc --info output matches pinned expected values."""
+import ast
+import subprocess
+import sys
+
+sys.path.insert(0, '.')
+from ConfigPinsExpected import GHC_INFO_EXPECTED, PINNED_GHC_INFO_FIELDS
+
+
+def platform_key(info_map):
+ platform = info_map.get("target platform string", "<unknown>")
+ is_cross = info_map.get("cross compiling", "NO") == "YES"
+ is_unreg = info_map.get("Unregisterised", "NO") == "YES"
+ no_tntc = info_map.get("Tables next to code", "YES") == "NO"
+ key = platform
+ if is_cross: key += "-cross"
+ if is_unreg: key += "-unreg"
+ elif no_tntc: key += "-no_tntc"
+ return key
+
+
+def main():
+ if len(sys.argv) != 2:
+ print("Usage: GhcInfoPins.py <compiler-path>")
+ sys.exit(1)
+
+ compiler = sys.argv[1]
+ try:
+ result = subprocess.run([compiler, "--info"], capture_output=True, text=True)
+ except OSError as e:
+ print(f"Failed to run {compiler!r} --info: {e}")
+ sys.exit(1)
+ if result.returncode != 0:
+ print(f"Error running {compiler!r} --info:\n{result.stderr}")
+ sys.exit(1)
+ try:
+ info_map = dict(ast.literal_eval(result.stdout.strip()))
+ except (ValueError, SyntaxError) as e:
+ print(f"Failed to parse {compiler!r} --info output: {e}")
+ sys.exit(1)
+ key = platform_key(info_map)
+
+ actual = [(f, info_map.get(f, "<missing>")) for f in PINNED_GHC_INFO_FIELDS]
+
+ if key not in GHC_INFO_EXPECTED:
+ print(f"Platform key {key!r} not in ConfigPinsExpected.")
+ print("Add this entry to GHC_INFO_EXPECTED in ConfigPinsExpected.py:")
+ print()
+ print(f" {key!r}: {{")
+ for f, v in actual:
+ print(f" {f!r}: {v!r},")
+ print(" },")
+ sys.exit(1)
+
+ expected = GHC_INFO_EXPECTED[key]
+ actual_map = dict(actual)
+ mismatches = [
+ (f, ev, actual_map.get(f, "<missing>"))
+ for f, ev in sorted(expected.items())
+ if ev != actual_map.get(f, "<missing>")
+ ]
+
+ if mismatches:
+ print(f"MISMATCH for {key!r}:")
+ for f, ev, av in mismatches:
+ print(f" {f!r}: expected {ev!r}, got {av!r}")
+ sys.exit(1)
+
+ print(f"OK: {key}")
+
+
+if __name__ == "__main__":
+ main()
=====================================
testsuite/tests/driver/config-pins/TestsuiteConfigPins.hs deleted
=====================================
@@ -1,106 +0,0 @@
-module Main where
-
-import System.Environment (getArgs)
-import System.Exit (exitFailure)
-import qualified Data.Map.Strict as Map
-
-import ConfigPinsExpected (TestsuiteConfig(..), testsuiteConfigExpected)
-
-parseBool :: String -> String -> Bool
-parseBool _ "1" = True
-parseBool _ "0" = False
-parseBool fieldName s =
- error $ "parseBool: field " ++ show fieldName ++ " expected 0 or 1, got " ++ show s
-
-platformKey :: String -> Bool -> Bool -> Bool -> String
-platformKey platform isCross isUnreg noTntc =
- platform
- ++ (if isCross then "-cross" else "")
- ++ (if isUnreg then "-unreg"
- else if noTntc then "-no_tntc"
- else "")
-
-main :: IO ()
-main = do
- args <- getArgs
- case args of
- [platform, arch, wordsize,
- haveNcg, haveInterp, unreg, tntc,
- leadUs, hasSmp, rtsLinker, interpDyn, cross] -> do
-
- let bHaveNcg = parseBool "have_ncg" haveNcg
- bInterp = parseBool "have_interp" haveInterp
- bUnreg = parseBool "unregisterised" unreg
- bTntc = parseBool "tables_next_to_code" tntc
- bLeadUs = parseBool "leading_underscore" leadUs
- bSmp = parseBool "target_has_smp" hasSmp
- bRtsLnk = parseBool "have_RTS_linker" rtsLinker
- bIntDyn = parseBool "interp_force_dyn" interpDyn
- bCross = parseBool "cross" cross
- actual = TestsuiteConfig
- { tcPlatform = platform
- , tcArch = arch
- , tcWordsize = wordsize
- , tcHaveNcg = bHaveNcg
- , tcHaveInterp = bInterp
- , tcUnregisterised = bUnreg
- , tcTablesNextToCode = bTntc
- , tcLeadingUnderscore = bLeadUs
- , tcTargetHasSmp = bSmp
- , tcHaveRtsLinker = bRtsLnk
- , tcInterpForceDyn = bIntDyn
- , tcCross = bCross
- }
- key = platformKey platform bCross bUnreg (not bTntc)
-
- case Map.lookup key testsuiteConfigExpected of
- Nothing -> do
- putStrLn $ "Platform key " ++ show key ++ " not in ConfigPinsExpected."
- putStrLn "Add this entry to testsuiteConfigExpected in ConfigPinsExpected.hs:"
- putStrLn ""
- putStrLn $ " , ( " ++ show key ++ ", TestsuiteConfig"
- putStrLn $ " { tcPlatform = " ++ show (tcPlatform actual)
- putStrLn $ " , tcArch = " ++ show (tcArch actual)
- putStrLn $ " , tcWordsize = " ++ show (tcWordsize actual)
- putStrLn $ " , tcHaveNcg = " ++ show (tcHaveNcg actual)
- putStrLn $ " , tcHaveInterp = " ++ show (tcHaveInterp actual)
- putStrLn $ " , tcUnregisterised = " ++ show (tcUnregisterised actual)
- putStrLn $ " , tcTablesNextToCode = " ++ show (tcTablesNextToCode actual)
- putStrLn $ " , tcLeadingUnderscore = " ++ show (tcLeadingUnderscore actual)
- putStrLn $ " , tcTargetHasSmp = " ++ show (tcTargetHasSmp actual)
- putStrLn $ " , tcHaveRtsLinker = " ++ show (tcHaveRtsLinker actual)
- putStrLn $ " , tcInterpForceDyn = " ++ show (tcInterpForceDyn actual)
- putStrLn $ " , tcCross = " ++ show (tcCross actual)
- putStrLn " } )"
- exitFailure
-
- Just expected -> do
- let fields =
- [ ("tcPlatform", tcPlatform expected, tcPlatform actual)
- , ("tcArch", tcArch expected, tcArch actual)
- , ("tcWordsize", tcWordsize expected, tcWordsize actual)
- , ("tcHaveNcg", show (tcHaveNcg expected), show (tcHaveNcg actual))
- , ("tcHaveInterp", show (tcHaveInterp expected), show (tcHaveInterp actual))
- , ("tcUnregisterised", show (tcUnregisterised expected), show (tcUnregisterised actual))
- , ("tcTablesNextToCode", show (tcTablesNextToCode expected), show (tcTablesNextToCode actual))
- , ("tcLeadingUnderscore", show (tcLeadingUnderscore expected), show (tcLeadingUnderscore actual))
- , ("tcTargetHasSmp", show (tcTargetHasSmp expected), show (tcTargetHasSmp actual))
- , ("tcHaveRtsLinker", show (tcHaveRtsLinker expected), show (tcHaveRtsLinker actual))
- , ("tcInterpForceDyn", show (tcInterpForceDyn expected), show (tcInterpForceDyn actual))
- , ("tcCross", show (tcCross expected), show (tcCross actual))
- ]
- mismatches = [ (f, ev, av) | (f, ev, av) <- fields, ev /= av ]
- if null mismatches
- then putStrLn $ "OK: " ++ key
- else do
- putStrLn $ "MISMATCH for " ++ show key ++ ":"
- mapM_ (\(f, ev, av) ->
- putStrLn $ " " ++ f ++ ": expected " ++ show ev ++ ", got " ++ show av
- ) mismatches
- exitFailure
-
- _ -> do
- putStrLn $ "Usage: TestsuiteConfigPins platform arch wordsize \
- \have_ncg have_interp unreg tntc leading_us has_smp rts_linker interp_dyn cross"
- putStrLn $ "Got " ++ show (length args) ++ " args: " ++ show args
- exitFailure
=====================================
testsuite/tests/driver/config-pins/TestsuiteConfigPins.py
=====================================
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""Check that Hadrian-supplied testsuite config values match pinned expected values."""
+import sys
+
+sys.path.insert(0, '.')
+from ConfigPinsExpected import TESTSUITE_CONFIG_EXPECTED
+
+
+def platform_key(platform, is_cross, is_unreg, no_tntc):
+ key = platform
+ if is_cross: key += "-cross"
+ if is_unreg: key += "-unreg"
+ elif no_tntc: key += "-no_tntc"
+ return key
+
+
+def main():
+ if len(sys.argv) != 13:
+ print("Usage: TestsuiteConfigPins.py platform arch wordsize "
+ "have_ncg have_interp unreg tntc leading_us has_smp "
+ "rts_linker interp_dyn cross")
+ print(f"Got {len(sys.argv) - 1} args: {sys.argv[1:]}")
+ sys.exit(1)
+
+ (platform, arch, wordsize,
+ have_ncg, have_interp, unreg, tntc,
+ lead_us, has_smp, rts_linker, interp_dyn, cross) = sys.argv[1:]
+
+ b = lambda s: s == "1"
+ actual = {
+ "platform": platform,
+ "arch": arch,
+ "wordsize": wordsize,
+ "have_ncg": b(have_ncg),
+ "have_interp": b(have_interp),
+ "unregisterised": b(unreg),
+ "tables_next_to_code": b(tntc),
+ "leading_underscore": b(lead_us),
+ "target_has_smp": b(has_smp),
+ "have_RTS_linker": b(rts_linker),
+ "interp_force_dyn": b(interp_dyn),
+ "cross": b(cross),
+ }
+ key = platform_key(platform, b(cross), b(unreg), not b(tntc))
+
+ if key not in TESTSUITE_CONFIG_EXPECTED:
+ print(f"Platform key {key!r} not in ConfigPinsExpected.")
+ print("Add this entry to TESTSUITE_CONFIG_EXPECTED in ConfigPinsExpected.py:")
+ print()
+ print(f" {key!r}: {{")
+ for k, v in actual.items():
+ print(f" {k!r}: {v!r},")
+ print(" },")
+ sys.exit(1)
+
+ expected = TESTSUITE_CONFIG_EXPECTED[key]
+ mismatches = [
+ (k, ev, actual[k])
+ for k, ev in expected.items()
+ if ev != actual.get(k)
+ ]
+
+ if mismatches:
+ print(f"MISMATCH for {key!r}:")
+ for k, ev, av in mismatches:
+ print(f" {k!r}: expected {ev!r}, got {av!r}")
+ sys.exit(1)
+
+ print(f"OK: {key}")
+
+
+if __name__ == "__main__":
+ main()
=====================================
testsuite/tests/driver/config-pins/all.T
=====================================
@@ -1,26 +1,26 @@
+import sys
+
test('GhcInfoPins',
- [ extra_files(['ConfigPinsExpected.hs'])
- , extra_run_opts('"' + config.compiler + '"')
- , ignore_stdout
- ],
- compile_and_run, ['-package process -package containers'])
+ [extra_files(['ConfigPinsExpected.py', 'GhcInfoPins.py']),
+ ignore_stdout],
+ run_command,
+ [sys.executable + ' GhcInfoPins.py "' + config.compiler + '"'])
test('TestsuiteConfigPins',
- [ extra_files(['ConfigPinsExpected.hs'])
- , extra_run_opts(' '.join([
- config.platform,
- config.arch,
- config.wordsize,
- str(int(config.have_ncg)),
- str(int(config.have_interp)),
- str(int(config.unregisterised)),
- str(int(config.tables_next_to_code)),
- str(int(config.leading_underscore)),
- str(int(config.target_has_smp)),
- str(int(config.have_RTS_linker)),
- str(int(config.interp_force_dyn)),
- str(int(config.cross)),
- ]))
- , ignore_stdout
- ],
- compile_and_run, ['-package containers'])
+ [extra_files(['ConfigPinsExpected.py', 'TestsuiteConfigPins.py']),
+ ignore_stdout],
+ run_command,
+ [sys.executable + ' TestsuiteConfigPins.py ' + ' '.join([
+ config.platform,
+ config.arch,
+ config.wordsize,
+ str(int(config.have_ncg)),
+ str(int(config.have_interp)),
+ str(int(config.unregisterised)),
+ str(int(config.tables_next_to_code)),
+ str(int(config.leading_underscore)),
+ str(int(config.target_has_smp)),
+ str(int(config.have_RTS_linker)),
+ str(int(config.interp_force_dyn)),
+ str(int(config.cross)),
+ ])])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8228c5b18bfeba95ba8b8ec791f695…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8228c5b18bfeba95ba8b8ec791f695…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/az/exactprint-annotation-rationalisation] 10 commits: Hadrian: convert env variable ACLOCAL_PATH to unix paths.
by Alan Zimmerman (@alanz) 07 Jun '26
by Alan Zimmerman (@alanz) 07 Jun '26
07 Jun '26
Alan Zimmerman pushed to branch wip/az/exactprint-annotation-rationalisation at Glasgow Haskell Compiler / GHC
Commits:
a3b431f3 by David Eichmann at 2026-06-04T10:10:19+00:00
Hadrian: convert env variable ACLOCAL_PATH to unix paths.
Convert ACLOCAL_PATH to a unix style path when invoking autoreconf.
Autoreconf doesn't handle windows paths.
See Note [Autoreconf unix paths from ACLOCAL_PATH].
Fixes #27311
- - - - -
18f6138a by Simon Jakobi at 2026-06-04T20:20:31-04:00
testsuite: Deduplicate --only test names
config.only is assumed to be a set, but supplying --only overwrote it
with the (list) argparse result, which can contain duplicates. When a
test ran, config.only.remove(name) dropped only the first occurrence,
so a duplicated name lingered and was later misreported as a
"test not found" framework failure. Store it as a set instead.
Fixes #27322
Co-Authored-By: Claude Opus 4.7 <noreply(a)anthropic.com>
- - - - -
876bfb74 by Alan Zimmerman at 2026-06-06T18:24:26+01:00
EPA: Rename Transform.anchorEof to addModuleCommentOrigDeltas
This matches what it actually does.
- - - - -
55055acd by Alan Zimmerman at 2026-06-06T18:24:26+01:00
AZ: add some exactprint allium specs
- - - - -
7c23b35e by Alan Zimmerman at 2026-06-06T18:24:26+01:00
EPA: Add an overview doc for exact printing
- - - - -
eb1b544a by Simon Peyton Jones at 2026-06-06T18:24:26+01:00
Added an intro section
- - - - -
fb267917 by Alan Zimmerman at 2026-06-06T18:24:26+01:00
EPA: Use standard type family declaration for Anno
- - - - -
630ec63c by Alan Zimmerman at 2026-06-06T18:24:26+01:00
TTG: Add extension points to HsConDetails
In contrast to normal TTG extension points, these are indexed by the
arg and rec type parameters, since HsConDetails is a container type
used in various roles. Each of these uses a GhcPass based structure,
so the overall effect is a family of pass-sensitive extension points.
data HsConDetails p arg rec
= PrefixCon !(XPrefixCon p) [arg] -- C @t1 @t2 p1 p2 p3
| RecCon !(XRecCon p) rec -- C { x = p1, y = p2 }
| InfixCon !(XInfixCon p) arg arg -- p1 `C` p2
| XHsConDetails !(XXHsConDetails p)
type family XPrefixCon p
type family XRecCon p
type family XInfixCon p
type family XXHsConDetails p
- - - - -
9d6d688f by Alan Zimmerman at 2026-06-06T18:24:26+01:00
EPA: remove LocatedLI / SrcSpanAnnLI
These were used for module export lists, and import decl lists.
Replace them with direct capture of the relevant EP Annotations in
HsModule and ImportDecl annotation extension points.
Also use the HsConDetails RecCon extension point to capture the braces
in a record constructor
- - - - -
8f181f91 by Alan Zimmerman at 2026-06-07T16:32:49+01:00
EPA: Remove LocatedC / SrcSpanAnnC
Used for contexts
- - - - -
102 changed files:
- + ExactPrint.md
- boot
- compiler/GHC/Data/BooleanFormula.hs
- compiler/GHC/Hs.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Match.hs
- compiler/GHC/HsToCore/Match/Constructor.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Rename/Bind.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Rename/Utils.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Generate.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Pat.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/PatSyn.hs
- compiler/GHC/Tc/TyCl/Utils.hs
- compiler/GHC/Tc/Utils/Backpack.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/GHC/ThToHs.hs
- compiler/Language/Haskell/Syntax.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- compiler/Language/Haskell/Syntax/ImpExp.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Type.hs
- ghc/GHCi/UI.hs
- hadrian/src/Hadrian/Oracles/Path.hs
- hadrian/src/Rules/BinaryDist.hs
- + specs/exact-print-core.allium
- + specs/exact-print-cpp.allium
- + specs/exact-print-parser.allium
- + specs/exact-print-printing.allium
- + specs/exact-print-transform.allium
- testsuite/driver/runtests.py
- testsuite/tests/ghc-api/T25121_status.stdout
- testsuite/tests/ghc-api/exactprint/T22919.stderr
- testsuite/tests/ghc-api/exactprint/Test20239.stderr
- testsuite/tests/ghc-api/exactprint/ZeroWidthSemi.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T24221.stderr
- testsuite/tests/module/mod185.stderr
- testsuite/tests/parser/should_compile/DumpParsedAst.stderr
- testsuite/tests/parser/should_compile/DumpParsedAstComments.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/parser/should_compile/KindSigs.stderr
- testsuite/tests/parser/should_compile/T14189.stderr
- testsuite/tests/parser/should_compile/T15323.stderr
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/parser/should_compile/T20718.stderr
- testsuite/tests/parser/should_compile/T20718b.stderr
- testsuite/tests/parser/should_compile/T20846.stderr
- testsuite/tests/parser/should_compile/T23315/T23315.stderr
- testsuite/tests/printer/AnnotationNoListTuplePuns.stdout
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/T18791.stderr
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/printer/Test24533.stdout
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Transform.hs
- utils/check-exact/Utils.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
- utils/haddock/haddock-api/src/Haddock/Interface/LexParseRn.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Interface/RenameType.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/daeacc5bc2d3fa6652991ad0fe277d…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/daeacc5bc2d3fa6652991ad0fe277d…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/amg/castz] WIP: introduce cast zapping as an alternative to coercion zapping
by Adam Gundry (@adamgundry) 07 Jun '26
by Adam Gundry (@adamgundry) 07 Jun '26
07 Jun '26
Adam Gundry pushed to branch wip/amg/castz at Glasgow Haskell Compiler / GHC
Commits:
8298f85e by Adam Gundry at 2026-06-07T17:56:38+02:00
WIP: introduce cast zapping as an alternative to coercion zapping
- - - - -
60 changed files:
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/FVs.hs
- compiler/GHC/Core/LateCC/OverloadedCalls.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Lint/SubstTypeLets.hs
- compiler/GHC/Core/Map/Expr.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/CSE.hs
- compiler/GHC/Core/Opt/CprAnal.hs
- compiler/GHC/Core/Opt/DmdAnal.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/Core/Seq.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/Stats.hs
- compiler/GHC/Core/Subst.hs
- compiler/GHC/Core/Tidy.hs
- compiler/GHC/Core/TyCo/FVs.hs
- compiler/GHC/Core/TyCo/Ppr.hs
- compiler/GHC/Core/TyCo/Ppr.hs-boot
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCo/Rep.hs-boot
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/TyCo/Tidy.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Foreign/Prim.hs
- compiler/GHC/HsToCore/Foreign/Wasm.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Tc/Solver/Solve.hs
- + compiler/GHC/Tc/Types/EvTerm.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/GHC/Types/Id/Make.hs
- docs/core-spec/CoreLint.ott
- docs/core-spec/CoreSyn.ott
- docs/users_guide/debugging.rst
- testsuite/tests/ghci/prog-mhu002/prog-mhu002c.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8298f85ec048e042de7b08fe76040a7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8298f85ec048e042de7b08fe76040a7…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/supersven/cross-compiler-manual-test-jobs] 3 commits: ci: fix platform_mapping collision for manual testsuite jobs
by Sven Tennie (@supersven) 07 Jun '26
by Sven Tennie (@supersven) 07 Jun '26
07 Jun '26
Sven Tennie pushed to branch wip/supersven/cross-compiler-manual-test-jobs at Glasgow Haskell Compiler / GHC
Commits:
508cc020 by Sven Tennie at 2026-06-07T10:23:11+00:00
ci: fix platform_mapping collision for manual testsuite jobs
Both the build job and its manual test job share the same (Arch, Opsys)
platform, causing platform_mapping's combine function to error. Prefer
the build job when one of the two has the -manual-testsuite suffix.
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
5ffab85d by Sven Tennie at 2026-06-07T15:36:12+00:00
ci: simplify crossTestJob helpers
- Remove WHAT-explaining haddocks on crossTestJob and withCrossTestJob
- renameRule fallback now errors explicitly rather than silently no-oping
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
7206c32b by Sven Tennie at 2026-06-07T15:47:09+00:00
ci: set jobDependencies in crossTestJob to enable artifact download
GitLab: dependencies:[] overrides needs:[{artifacts:true}], preventing
artifact download. Set dependencies:[buildName] so the bindist tarball
is actually fetched from the build job.
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
- - - - -
2 changed files:
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
Changes:
=====================================
.gitlab/generate-ci/gen_ci.hs
=====================================
@@ -591,7 +591,7 @@ manualRule rules = rules { when = Manual }
renameRule :: String -> OnOffRules -> OnOffRules
renameRule n (OnOffRules (ValidateOnly _ rs) w) = OnOffRules (ValidateOnly n rs) w
-renameRule _ r = r
+renameRule _ r = error $ "renameRule: not a ValidateOnly rule: " ++ show (rule_set r)
-- Given 'OnOffRules', returns a list of ALL rules with their toggled status.
-- For example, even if you don't explicitly disable a rule it will end up in the
@@ -1009,14 +1009,13 @@ release arch opsys bc =
. ignorePerfFailures
. highCompression $ j
}
--- | Derive a manually-triggered full-testsuite job from a cross-compiler build job.
--- The test job downloads the build job's bindist artifact and runs the full testsuite.
crossTestJob :: NamedJob Job -> NamedJob Job
crossTestJob (NamedJob buildName buildJob) =
NamedJob testName $
buildJob
{ jobNeeds = ["hadrian-ghc-in-ghci"]
, jobNeedsWithArtifacts = [buildName]
+ , jobDependencies = [buildName]
, jobScript = testScript (jobPlatform buildJob)
, jobRules = renameRule testName $ manualRule (jobRules buildJob)
, jobAllowFailure = True
@@ -1030,8 +1029,6 @@ crossTestJob (NamedJob buildName buildJob) =
, ".gitlab/ci.sh test_hadrian_cross_full"
]
--- | Pair a cross-compiler build JobGroup with a manual test job derived from
--- its validate variant.
withCrossTestJob :: JobGroup Job -> [JobGroup Job]
withCrossTestJob jg@(StandardTriple (Just vj) _ _) =
[jg, StandardTriple (Just (crossTestJob vj)) Nothing Nothing]
@@ -1485,6 +1482,8 @@ platform_mapping = Map.map go combined_result
, show (name b) ] -- Explicitly selected
| name a `elem` whitelist = a -- Explicitly selected
| name b `elem` whitelist = b
+ | "-manual-testsuite" `isSuffixOf` name a = b -- prefer build job over manual test job
+ | "-manual-testsuite" `isSuffixOf` name b = a
| otherwise = error (show (name a) ++ show (name b))
go = fmap (BindistInfo . unwords . fromJust . mmlookup "BIN_DIST_NAME" . jobVariables)
=====================================
.gitlab/jobs.yaml
=====================================
@@ -444,7 +444,9 @@
"toolchain"
]
},
- "dependencies": [],
+ "dependencies": [
+ "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm"
+ ],
"image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_…",
"needs": [
{
@@ -530,7 +532,9 @@
"toolchain"
]
},
- "dependencies": [],
+ "dependencies": [
+ "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate"
+ ],
"image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_…",
"needs": [
{
@@ -6546,7 +6550,9 @@
"toolchain"
]
},
- "dependencies": [],
+ "dependencies": [
+ "x86_64-linux-deb13-cross_aarch64-linux-gnu-validate"
+ ],
"image": "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV",
"needs": [
{
@@ -6928,7 +6934,9 @@
"toolchain"
]
},
- "dependencies": [],
+ "dependencies": [
+ "x86_64-linux-deb13-riscv-cross_riscv64-linux-gnu-validate"
+ ],
"image": "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-riscv:$DOCKER_…",
"needs": [
{
@@ -7872,7 +7880,9 @@
"toolchain"
]
},
- "dependencies": [],
+ "dependencies": [
+ "x86_64-linux-ubuntu24_04-loongarch-cross_loongarch64-linux-gnu-validate"
+ ],
"image": "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-ubuntu24_04-loongarc…",
"needs": [
{
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7ae6c7ae4a20054de2721d29b8590b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7ae6c7ae4a20054de2721d29b8590b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/abstract-q] 83 commits: rts: Add dynamic trace flags API
by Teo Camarasu (@teo) 07 Jun '26
by Teo Camarasu (@teo) 07 Jun '26
07 Jun '26
Teo Camarasu pushed to branch wip/abstract-q at Glasgow Haskell Compiler / GHC
Commits:
1cb1d672 by Wen Kokke at 2026-05-06T09:53:40-04:00
rts: Add dynamic trace flags API
This commit adds an API to the RTS (exposed via Rts.h) that allows users to dynamically change the trace flags.
Prior to this commit, users were able to stop and start the profiling and heap profiling timers (via startProfTimer/stopProfTimer and startHeapProfTimer/stopHeapProfTimer).
This extends that functionality to also cover the core event types.
The getTraceFlag/setTraceFlag functions read and write the values of the trace flag cache, which is allocated by Trace.c, rather than modifying the members of RtsFlags.TraceFlags.
This is done under the assumption that the members of RtsFlags should not be modified after RTS initialisation.
Consequently, if the user modifies the trace flags using setTraceFlag, the object returned by getTraceFlags (from base) will not reflect these changes.
The trace flags are not protected by locks of any sort.
Hence, these functions are not thread-safe.
However, the trace flags are not modified by the RTS after initialisation, only read, so the race conditions introduced by one user modifying them are most likely benign.
This PR also puts the trace flag cache in a single global struct, as opposed to a collection of global variables, and changes the types of the individual flags from uint8_t to bool, as these have the same size on both Clang and GCC and are a better semantic match.
Prior to the change to uint8_t, they had type int, see 42c47cd6.
Even with its deprecation in C23, I don't think there should be any issue depending on stdbool.h.
The TRACE_X macros are redefined to access the global struct, with values cast to const bool to ensure they are read-only.
- - - - -
9d54dc94 by Wen Kokke at 2026-05-06T09:53:40-04:00
rts: Ensure TRACE_X values are used in place of RtsFlags.TraceFlags.X
- - - - -
418d737b by Wen Kokke at 2026-05-06T09:53:40-04:00
rts: Fix nonmoving-GC tracing
The current nonmoving-GC tracing functions were written in a different
style from the other tracing functions. They were directly implemented
as, e.g., a traceConcMarkEnd function that called postConcMarkEnd.
The other tracing functions are implemented as, e.g., traceThreadLabel_,
a function that posts the thread label event, and traceThreadLabel, a
macro that checks whether TRACE_scheduler is set. This commit fixes that
implementation, and ensures that the nonmoving-GC tracing functions only
emit events if nonmoving-GC tracing is enabled.
- - - - -
99f4afa4 by Wen Kokke at 2026-05-06T09:53:40-04:00
rts: Add SymI_HasProto for get/setTraceFlag
- - - - -
7e9eb8b9 by Wen Kokke at 2026-05-06T09:53:40-04:00
rts: Add SymI_HasProto for start/endEventLogging
- - - - -
3a3045fb by Wen Kokke at 2026-05-06T09:53:41-04:00
rts: Add changelog entry
- - - - -
a3b339a4 by Teo Camarasu at 2026-05-06T09:54:25-04:00
interface-stability/base: don't distinguish ws-32
The interface of base is identical when the Word size is 32bits.
Therefore, there is no need to have another file for this case.
So, we delete it.
Step towards: #26752
- - - - -
eb922183 by Duncan Coutts at 2026-05-07T14:28:50+01:00
Add a rts posix FdWakup utility module
This will be used to implement wakeupIOManager for in-RTS I/O managers.
It provides a notification/wakeup mechanism using FDs, suitable for
situations when a thread is blocked on a set of fds anyway. It uses the
classic self-pipe trick, or equivalently eventfd on supported platforms.
This will initially be used to implement prompt interrupt or shutdown of
the posix ticker thread.
- - - - -
01b0e233 by Duncan Coutts at 2026-05-07T14:28:50+01:00
Add prompt shutdown to the pthread ticker implementation.
The Linux timerfd ticker monitors a pipe which is used by exitTicker to
ensure a prompt wakeup and shutdown. The pthread ticker lacked this and
so would only exit at the next ticker wakeup (10ms by default).
This patch adds the same mechanism to the pthread ticker.
This changes the pthread ticker from waiting by using nanosleep() to
waiting using either ppoll() or select(), so that it can wait on both
a time and a file descriptor. On Linux at least, a test program to
compare the timing jitter of these APIs shows that using nanpsleep,
ppoll or select makes no statistical difference to the maximum or
average jitter.
This is a step towards unifying the posix ticker implementations, so
that we can have just one portable one (albeit with some limited cpp).
It is also a step towards using the ticker as part of a more general
implementation of wakeUpRts, since this will require a method to wake
the rts from a signal handler context (ctl-c handler).
- - - - -
bc41d646 by Duncan Coutts at 2026-05-07T14:28:50+01:00
Update ticker header commentary
It was antique and didn't apply even to the previous implementation, and
certainly not to the updated one.
- - - - -
4ed9a386 by Duncan Coutts at 2026-05-07T14:28:50+01:00
Remove the timerfd-based ticker implementation
There does not appear to be any remaining advantage on Linux to using
the timerfd ticker implementation over the portable one (using ppoll on
Linux for precise timing).
The eventfd implementation was originally added at a time when Linux was
still using a signal based implementation. So it made sense at the time.
See (closed) issue #10840.
- - - - -
97504fa6 by Duncan Coutts at 2026-05-07T14:28:50+01:00
Consolidate to a single posix ticker implementation
Previously we had four implementations, two using signals and two using
threads. Having just one should make behaviour more consistent between
platforms, and should make maintenance easier.
- - - - -
1e60023b by Facundo Domínguez at 2026-05-07T18:01:16-04:00
Generalize so_inline to specify which bindings should be preserved
This commit generalizes the so_inline option of the simple optimizer
so we can indicate with a predicate the specific bindings that should
be kept.
This feature is important for the LiquidHaskell plugin, which relies on the
simple optimizer to make core programs easier to read, but needs to preserve
bindings that are relevant for verification.
See https://gitlab.haskell.org/ghc/ghc/-/issues/24386 for the full discussion.
- - - - -
44cf9cd7 by Wolfgang Jeltsch at 2026-05-12T09:48:18-04:00
Move the `Text.Read` implementation into `base`
- - - - -
4ac3f7d6 by Vladislav Zavialov at 2026-05-12T09:49:03-04:00
EPA: Use AnnParen for tuples and sums
Summary of changes
* Do not use AnnParen in XListTy, replace it with EpToken "[" and "]"
* Specialise AnnParen to tuple/sums by dropping the AnnParensSquare
and keeping only AnnParens and AnnParensHash
* Use AnnParen in XExplicitTuple
* Use AnnParen in XExplicitTupleTy
* Use AnnParen in XTuplePat
* Use AnnParen in XExplicitSum (via AnnExplicitSum)
* Use AnnParen in XSumPat (via EpAnnSumPat)
This is a refactoring with no user-facing changes.
- - - - -
1bdcddec by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add minimal dlltool support to ghc-toolchain
The dlltool is a tool that can create dll import libraries from .def
files. These .def files list the exported symbols of dlls. Its somewhat
like gnu linker scripts, but more limited.
We will need dlltool to build the rts and ghc-internal libraries as DLLs
on Windows. The rts and ghc-internal libraries have a recursive
dependency on each other. Import libraries can be used to resolve
recursive dependencies between dlls. We will use an import library for
the rts when linking the ghc-internal library.
- - - - -
f7fc3770 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add minimal dlltool support into ./configure
Find dlltool, and hopefully support finding it within the bundled llvm
toolchain on windows.
- - - - -
e4e22bfb by Duncan Coutts at 2026-05-12T09:49:48-04:00
Update the default host and target files for dlltool support
- - - - -
5666c8f9 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add dlltool as a hadrian builder
Optional except on windows.
- - - - -
5e14fe3f by Duncan Coutts at 2026-05-12T09:49:48-04:00
Update and generate libHSghc-internal.def from .def.in file
The only symbol that the rts imports from the ghc-internal package now
is init_ghc_hs_iface. So the rts only needs an import lib that defines
that one symbol.
Also, remove the libHSghc-prim.def because it is redundant. The rts no
longer imports anything from ghc-prim.
Keep libHSffi.def for now. We may yet need it once it is clear how
libffi is going to be built/used for ghc.
- - - - -
3d91e4a6 by Duncan Coutts at 2026-05-12T09:49:48-04:00
Add rule to build libHSghc-internal.dll.a and link into the rts
On windows only, with dynamic linking.
This is needed because on windows, all symbols in dlls must be resolved.
No dangling symbols allowed. References to external symbols must be
explicit. We resolve this with an import library. We create an import
library for ghc-internal, a .dll.a file. This is a static archive
containing .o files that define the symbols we need, and crucially have
".idata" sections that specifies the symbols the dll imports and from
where.
Note that we do not install this libHSghc-internal.dll.a, and it does
not need to list all the symbols exported by that package. We create a
special purpose import lib and only use it when linking the rts dll, so
it only has to list the symbols that the rts uses from ghc-internal
(which is exactly one symbol: init_ghc_hs_iface).
- - - - -
c8dae539 by Alice Rixte at 2026-05-12T09:50:52-04:00
Script for downloading and copying `base-exports` file
- - - - -
5fab2238 by Wolfgang Jeltsch at 2026-05-12T21:24:27+03:00
Introduce a cache of home module name providers
This contribution introduces to the module graph a cache that maps home
module names to sets of units providing them and changes the finder to
use that cache. This is a performance optimization, especially for
multi-home-unit builds.
The particular changes are as follows:
* In `GHC.Unit.Module.Graph`, `ModuleGraph` is extended with a new
field `mg_home_module_name_providers_map`, exposed as
`mgHomeModuleNameProvidersMap`. This is a cache that assigns to each
home module name the set of IDs of home units that define it.
Operations that construct module graphs are updated such that this
cache stays synchronized.
* In `GHC.Unit.Finder`, `findImportedModule` is changed to pull
`mgHomeModuleNameProvidersMap` from `hsc_mod_graph` and pass it to
`findImportedModuleNoHsc`, which now does not search home units in
arbitrary order but prioritizes those units that the cache mentions
as potential providers of the requested module.
In addition, this contribution adds variants of the two multi-component
compiler performance tests that use 100 units instead of 20, because
with just 20 units the benefits from caching of home module name
providers are still negligible.
The following table shows the total time needed for running both
multi-component tests before and after this contribution and with
different numbers of units:
| # of units | Before | After |
|-----------:|-------:|------:|
| 20 | 0:12 | 0:12 |
| 100 | 0:47 | 0:42 |
| 200 | 3:05 | 2:08 |
Note that there seems to be a general overhead of 12 seconds that is not
attributable to the actual tests, so that the real running times should
be 12 seconds smaller than shown above.
Resolves #27055.
Metric Decrease:
MultiComponentModules
MultiComponentModulesRecomp
Co-authored-by: Matthew Pickering <matthewtpickering(a)gmail.com>
Co-authored-by: Fendor <fendor(a)posteo.de>
- - - - -
38b76b2f by Cheng Shao at 2026-05-13T17:48:48-04:00
testsuite: mark T22159 as fragile
This patch marks T22159 as fragile on Windows for issue described in #27248.
Before we get to the bottom of those failures, this unblocks newer
Windows runners.
- - - - -
50188615 by Ian Duncan at 2026-05-14T13:45:07+02:00
AArch64: use ASR not LSR for MO_U_Shr at W8/W16
The unsigned right shift (MO_U_Shr) for sub-word widths (W8, W16)
with a variable shift amount was emitting ASR (arithmetic/signed shift
right) after zero-extending with UXTB/UXTH. This should be LSR
(logical/unsigned shift right). After zero-extension the upper bits
happen to be 0 so ASR produces the same result, but it is semantically
wrong and would break if the zero-extension were ever optimized away.
Includes assembly output test (grep for lsr) and runtime test
verifying unsigned right shift of Word8 and Word16 values.
- - - - -
28666fbf by Vladislav Zavialov at 2026-05-19T12:44:05-04:00
Add type families: Tuple, Constraints, Tuple#, Sum# (#27179)
These type families map tuples of types to the corresponding Tuple<N>,
Tuple<N>#, CTuple<N>, and Sum<N># types. Some examples at N=2:
Tuple (Int, Bool) = Tuple2 Int Bool
Constraints (Show a, Eq a) = CTuple2 (Show a) (Eq a)
Tuple# (Int#, Float#) = Tuple2# Int# Float#
Sum# (Int#, Float#) = Sum2# Int# Float#
See GHC Proposal #145 "Non-punning list and tuple syntax".
To make the Sum# instance at N=64 possible, this patch also introduces
the Sum64# constructor declaration and bumps mAX_SUM_SIZE from 63 to 64.
Metric Increase:
ghc_experimental_dir
- - - - -
41c2448b by Wen Kokke at 2026-05-19T12:44:53-04:00
rts: Add IPE event class for -l
This commit adds a new IPE event class to the -l RTS flag.
Previously, IPE events were enabled unconditionally.
However, the IPE events can easily grow to hundreds or thousands of megabytes.
With the new event class you can pass, e.g., -l-I to disable IPE events.
- - - - -
62536551 by Wen Kokke at 2026-05-19T12:44:53-04:00
ghc-internal: Add TraceFlags.traceIPE
- - - - -
e45312d1 by Wen Kokke at 2026-05-19T12:44:53-04:00
testsuite: Add test for TraceFlags.traceIpe
- - - - -
4768d9aa by Wen Kokke at 2026-05-19T12:44:53-04:00
ghc-internal: Add DebugFlags.ipe
- - - - -
bc1b5c69 by Wen Kokke at 2026-05-19T12:44:53-04:00
testsuite: Add test for DebugFlags.ipe
- - - - -
0da1543f by Duncan Coutts at 2026-05-19T12:45:37-04:00
Document removal of the signal-based interval timer
Update mentions within the RTS section of the users guide.
Add a changelog entry.
- - - - -
b2911514 by Duncan Coutts at 2026-05-19T12:45:37-04:00
Fix section for an recent changelog entry
- - - - -
d6d76a7a by David Eichmann at 2026-05-19T12:46:19-04:00
ghc-toolchain: implement llvm program versioning logic
- - - - -
2dd36fa3 by Wolfgang Jeltsch at 2026-05-20T04:49:52-04:00
Turn `Trustworthy` into `Safe` in `base` where possible
- - - - -
f4399dd1 by Wolfgang Jeltsch at 2026-05-20T04:50:37-04:00
Make the current `base` buildable with GHC 10.0
- - - - -
1a7de232 by Duncan Coutts at 2026-05-20T12:26:25-04:00
Hadrian: remove legacy rts .so symlinks
For compatibility with the old makefile based build system, hadrian had
rules to generate symlinks from unversioned to versioned names for the
rts .so/.dynlib file, like libHSrts-ghcx.y.so -> libHSrts-1.0.3-ghcx.y.so
We no longer need these symlinks since the makefile build system has
been retired some time ago. The need for these symlinks is awkward on
windows where we cannot (in practice) create symlinks. So rather than
make them conditional (non-windows), just remove them entirely.
- - - - -
286f1adf by fendor at 2026-05-20T12:27:09-04:00
Fix regression T27202: `:load` and `:add` work in GHCi
To fix the regression there are conceptually two major things that we
fix:
* We don't remove the `importDirs` from `interactive-session`
* When `:add`ing a module, we don't try to find them via PackageImports
* The PackageImport is wrong as we can't know the package-name at
this stage in ghc/UI.hs
What does it mean to not remove the `importDirs` from
`interactive-session`?
It means that, given some initial `DynFlags`, we will use those
`importDirs` in `interactive-session`.
The initial `DynFlags`, however, depend on how you initialise the GHC
session.
For a simple session, initialised by
ghc -isrc -this-unit-id main
It is simple, just use the `DynFlags` given on the cli.
Thus, `main` and `interactive-session` will have the same `DynFlags`,
except for the `homeUnitId` and `interactive-session` depends on `main`
by construction of the GHCi session.
What about a multiple home unit session, though?
ghc -unit @unit1 -unit @unit2
What are the `DynFlags` in this cli invocation? It shouldn't be either
`@unti1` nor `@unit2`, as the order shouldn't matter or any other
implicit condition.
For consistency, we decide that the initial `DynFlags` are the top
`DynFlags` on the cli, ignoring `-unit` flags.
Thus, in this example, there are no `importsDirs` regardless of what we
might find in `@unit1` and `@unit2`.
But in this invocation:
ghc -isrc -unit @unit1 -unit @unit2
The `interactive-session` will have the `importsDirs` `src`.
Note, `-isrc` will be inherited in `@unit1` and `@unit2`, so you need to
explicitly use `-i` to clear the `importsDirs`, in order to avoid
accidentally adding `src` as an import directory to all other home
units.
This fix has been made possible by the improvements introduced in
!15888, which avoids ambiguity when a home unit shares the `importsDirs`
with the `interactive-session`, on top of being much faster for multiple
home units.
Adds regression tests for T27202 for `:load`ing and `:add`ing modules
that are located in import directories.
- - - - -
728662de by fendor at 2026-05-20T12:27:09-04:00
Use home unit package db stacks in GHCi prompt and session unit
In order to import modules from home unit dependencies (e.g., `Data.Map`),
the ghci prompt unit needs to populate its `UnitState`.
This is tricky to handle correctly, which `PackageDBFlag`s should we use
to populate the `UnitState`?
We decide, the most intuitive solution for users is to depend on all
`PackageDBFlag`s, so that any dependency can be imported in GHCi.
This assumes consistency in the `PackageDBFlag`s, so no two home units
specify `PackageDBFlag`s that are inconsistent with each other.
We could simply concat all the `PackageDBFlag`s of the existing home
units, but later `PackageDBFlag`s shadow earlier ones, leading to the
last processed home units' `PackageDBFlag`s to shadow the earlier ones.
This is hard to fix, we need to give users the capability to provide ghc
options for the ghci prompt home unit.
However, as this is considerably more work, we decided on an
approximation that should work out most of the time.
Package Db stacks in cabal and stack follow a certain structure:
-no-user-package-db > -package-db $cabal-store > -package-db $local-db
The first two arguments are always the same, namely the
`-no-user-package-db` and `-package-db`.
We compute the longest common prefix over all home units, and use that
as the start of the package db stack. Then, over the rest of the
`PackageDBFlag`s, we simply take the union and append them to our
initial stack.
We assume, that the rest of package dbs only defines very few, "local"
units that are usually not shadowing each other.
This allows us to get a relatively consistent package database stack for
the ghci prompt home unit.
Similar reasoning applies to the session unit in order to add modules to
the session and have dependencies available in the module.
We do something similar for `-package` flags, to make sure only the
correct units are actually visible in the ghci session.
This time, we simply take the union of all `PackageFlag`s, allowing us
to import modules from the home unit dependencies.
In the future, it would be beneficial to allow the user to provide the
exact ghc options to control the visibilities. For now, this will have
to do.
- - - - -
740d89a0 by Simon Peyton Jones at 2026-05-20T17:20:44-04:00
Do not use mkCast during typechecking
This commit fixes #27219. The problem was that the typechecker was using
`mkCast`, whose assertion checks legitimately fail when applied to types
that contain unification variables.
- - - - -
a50fdb06 by Simon Peyton Jones at 2026-05-20T17:20:45-04:00
Major refactor of the Simplifier
The main payload of this patch is to refactor the Simplifer to avoid
repeated simplification when using Plan (AFTER) for rule rewrites.
The need for this was shown up by #26989.
See Note [Avoid repeated simplification] in GHC.Core.Opt.Simplify.Iteration.
Related refactoring:
* Refactor the two fields `sc_dup` and `sc_env` in `ApplyToVal` into one, `sc_env`.
Reason: the envt is irrelevant in the "simplified" case, so the data type describes
the possiblitiies much more accurately now.
* Some refactoring in `knownCon` to split off `wrapDataConFloats`.
* Refactor `lookupRule` and its auxiliary functions to return `RuleMatch`,
a new data type. See Note [data RuleMatch] in GHC.Core. Ditto for BuiltinRule.
This RuleMatch returns fragments of the target in rm_args and rm_floats,
leaving `rm_rhs` to be the stuff from the RULE itself.
Doing this has routine consequences in GHC.Core.Opt.ConstantFold. Many changes
there but all routine.
* When doing occurrence analysis on RULEs, make the occ-info on the rule
binders relate just to the RHS, not the LHS. See (OUR1) in
Note Note [OccInfo in unfoldings and rules]
This means that Lint must not complain about the fact that the patterns
in the RULE mentions binders that are marked dead.
See Note [Dead occurrences] in GHC.Core.Lint.
I changed the Core pretty-printer so that it didn't suppress dead binders,
else I can't see those binders in RULEs. That led to quite a lot of testsuite wibbles.
* Refactor FloatBinds, so that it is used both by
`exprIsConApp_mabye` and by `lookupRule`
* Move the definition of FloatBinds out of GHc.Core.Make, into GHC.Core.
* Add FloatTick as an extra constructor.
* Refactor `lookupRule` to use `FloatBinds` instead of `BindWrapper`.
This refactor just shares more code.
(Rename GHC.Core.Opt.FloatOut.FloatBinds to FloatLets, to avoid gratuitious
name clash with GHC.Core.FloatBinds.)
Corecion optimisation
* In simpleOpt, when composing coercions, call new function `optTransCo`.
This is much lighter weight than full blown coercion optimisation.
* Make `GHC.Core.Opt.Arity.pushCoValArg` and `pushCoTyArg` return the
coercionLKind of the coercion. This saves recomputing that coercionLKind
at the key call sites in GHC.Core.Opt.Simplify.Iteration.pushCast.
* Rename `addCoerce` in GHC.Core.Simplify.Iteration to become `pushCast`.
* In the `ApplyToVal` case of `pushCast` we had a very unsavoury call to `simplArg`.
I eliminated it by adding a field `sc_cast` to `ApplyToVal` that records any
pending casts. Much nicer now. See Note [The sc_cast field of ApplyToVal].
* Don't optimise coercions if the type-substitution is empty.
See Note [Optimising coercions] in GHC.Core.Opt.Simplify.Iteration.
The fix for #26838 is dramatic. For the test in perf/compiler/T26839 we have
Compiler allocs: Before: 7,363M
After: 688M
Compile time goes down generally. Here are compiler-alloc changes
over 0.5%:
CoOpt_Read(normal) 729,184,920 -0.7%
CoOpt_Singletons(normal) 666,916,960 -4.6% GOOD
LargeRecord(normal) 1,227,056,876 +1.1%
T12227(normal) 256,827,604 -4.6% GOOD
T12425(optasm) 76,879,410 -0.8%
T12545(normal) 787,826,918 -10.8% GOOD
T12707(normal) 775,186,464 -0.9%
T13253(normal) 318,599,596 -0.8%
T14766(normal) 685,857,320 -1.0%
T15304(normal) 1,123,333,422 -2.2%
T15630(normal) 123,142,330 -2.6%
T15630a(normal) 123,092,100 -2.6%
T15703(normal) 299,751,682 -2.9% GOOD
T17516(normal) 964,072,280 +1.0%
T18223(normal) 367,016,820 -6.2% GOOD
T18730(optasm) 130,643,770 -3.3% GOOD
T20261(normal) 535,608,584 -0.7%
T21839c(normal) 340,340,436 -0.9%
T24984(normal) 85,568,392 -1.9%
T3064(normal) 174,631,992 -1.2%
T3294(normal) 1,215,886,432 -0.7%
T5030(normal) 141,449,704 -17.2% GOOD
T5321Fun(normal) 258,484,744 -1.9%
T8095(normal) 770,532,232 -2.7%
T9630(normal) 858,423,408 -14.5% GOOD
T9872c(normal) 1,591,709,448 +0.7%
info_table_map_perf(normal) 19,700,614,458 -1.3%
geo. mean -0.7%
minimum -17.2%
maximum +1.1%
However, strangely there seems to be a 5.0% increase in CoOpt_Read in
the x86_64-linux-fedora43-validate+debug_info+ubsan job, although
there generally a /decrease/ in this test in other builds. The baseline
value looks strange. Anyway I'll just accept it.
Metric Decrease:
CoOpt_Singletons
T12227
T12545
T12707
T15703
T18223
T18730
T21839c
T5030
T9630
Metric Increase:
CoOpt_Read
- - - - -
834623d4 by Mrjtjmn at 2026-05-20T17:21:41-04:00
users-guide: Fix weird notation in "Summary of stolen syntax"
- - - - -
6f9d7c71 by Markus Läll at 2026-05-21T15:25:34-04:00
Use "grimily" instead of "grimly"
Fixes https://gitlab.haskell.org/ghc/ghc/-/issues/27221
- - - - -
50e999ca by fendor at 2026-05-21T15:26:18-04:00
Speed up 'closure' computation in `ghc-pkg`
Cache the set of already seen `UnitId`s and use `Set` operations to
speed up 'closure' computation.
Further simplify the implementation of 'closure' to account for the
actual usage.
As a consequence, we rename 'closure' to 'brokenPackages' to reflect its
purpose better after the simplification.
- - - - -
7ecc6184 by sheaf at 2026-05-21T15:27:10-04:00
TcMPluginHandling: be more lenient when no plugins
This change ensures that, if a function such as 'typecheckModule' was
invoked with 'NoTcMPlugins', GHC doesn't spuriously complain about TcM
plugins having already been stopped, as there were none to start with.
- - - - -
72c8de5c by Simon Jakobi at 2026-05-23T18:41:42-04:00
Implement List.elem via foldr
...in order to allow specialization to Eq instances.
The implementation of notElem is updated for consistency.`
Corresponding CLC proposal:
https://github.com/haskell/core-libraries-committee/issues/412
Addresses #27096.
- - - - -
3268c610 by Alan Zimmerman at 2026-05-23T18:42:30-04:00
EPA: Fix span for qualified multiline string
Fix the span for a qualified multiline string like
Text."""
I'm a multiline
Text value
!
"""
to extend to the end of the entire string, not just the first line.
Closes #27274
- - - - -
1f096790 by Alan Zimmerman at 2026-05-23T18:43:20-04:00
EPA: Fix exact printing namespace-specified wildcards
Ensures correct printing of imports of the form
import Data.Bool (data True(data ..))
import Data.Bool (data True(type ..))
Closes #27291
- - - - -
56ada7c0 by Mrjtjmn at 2026-05-23T18:44:19-04:00
Fix ambiguous syntax of BangPatterns in users guide
Update documentation for the BangPatterns extension to specify
how surrounding whitespace affects interpretation of `!`.
* Only when there is whitespace before `!` and no whitespace after,
it is recognized as a BangPattern.
* Other cases `⟨varid⟩!⟨varid⟩`, `⟨varid⟩ ! ⟨varid⟩`, `⟨varid⟩! ⟨varid⟩`
are treated as infix operators.
- - - - -
579aa0b7 by Simon Jakobi at 2026-05-25T16:31:26-04:00
Ensure that SetOps.{minusList,unionListsOrd} can be specialized
...by marking them INLINABLE. Haddock allocates 0.1–0.3% less as a
result.
This also removes some redundant constraints on unionListsOrd.
- - - - -
cccf45da by Cheng Shao at 2026-05-25T16:32:13-04:00
wasm: ensure post-linker output is synchronous ESM
This patch fixes wasm backend's post-linker output script to ensure
it's synchronous ESM and doesn't use top-level await, which doesn't
work in ServiceWorkers. Fixes #27257.
- - - - -
8db331a3 by Zubin Duggal at 2026-05-26T04:54:03-04:00
Update to semaphore-compat 2.0.0 using v2 of the protocol
On Linux and other POSIX platforms, GHC's -jsem jobserver client now
speaks v2 of the semaphore-compat protocol, which uses Unix domain
sockets in place of POSIX named semaphores. This avoids the libc-ABI
issues that affected the old implementation. Windows is unaffected
and continues to use the v1 protocol (Win32 named semaphores); its
reported protocol version remains v1.
When GHC receives a -jsem name whose protocol version it does not
support, it emits a -Wsemaphore-version-mismatch warning and falls
back to -j<N> rather than crashing. ghc --info exposes the supported
version in a new "Semaphore version" entry so cabal-install can detect
a mismatch before invoking GHC.
Users on a cabal-install that predates the v2 update will continue to
build successfully on Linux/POSIX, but will lose the cross-process
-jsem coordination and fall back to -j<N> per GHC invocation. Users
must upgrade to a cabal-install that supports protocol v2 to recover
full parallelism.
Also fix a leak in cleanupSem (#27253): cleanupSem used to snapshot
heldTokens and release them before killing the loop, while the loop's
in-flight acquire/release children could still be mutating it.
Cleanup now runs inside the loop's own exit handler, after draining
the active child via a new activeChild TVar, so the snapshot has no
concurrent mutator.
See also:
- GHC proposal amendment: https://github.com/ghc-proposals/ghc-proposals/pull/673
- cabal-install patch: https://github.com/haskell/cabal/pull/11628
- semaphore-compat MR: https://gitlab.haskell.org/ghc/semaphore-compat/-/merge_requests/8
Bump semaphore-compat submodule to 2.0.0
Fixes #25087 and #27253
- - - - -
17be4f1f by Alan Zimmerman at 2026-05-26T04:54:52-04:00
EPA: Record semicolons in HsModifier
Ensure the semi colons are captured in the ParsedSource for code like
%True;; %False;
instance C D
It makes HsModifier (and hence HsModifierOf) LocatedA, so the semi
colons can be recorded as [TrailingAnn]
Also rename pprHsModifiers to pprLHsModifiers to match.
Closes #27294
- - - - -
8f991755 by fendor at 2026-05-26T11:02:52-04:00
Revert prog003 acceptance
We thought the commit 286f1adff3e78d775ff325caff71d0cee25d710b fixed the
test, but due to changes to ghci, modules loaded during the GHCi
session, the test was actually no longer testing what it set out to do,
"fixing" the broken test.
As modules are added to the `interactive-session` home unit, the object code needs
to be compiled with `-this-unit-id interactive-session`, otherwise the
object code won't be used.
Once this has been fixed in the test, the test fails as expected again.
- - - - -
277a3687 by mangoiv at 2026-05-26T11:03:40-04:00
libraries/process: bump submodule to v1.6.29.0
This submodule bump resolves a segfault on macos 15.
Fixes #27144
- - - - -
6779bb0c by mangoiv at 2026-05-26T11:03:40-04:00
libraries/unix: in submodule, don't pick branch 2.7
The 2.7 branch is outdated and the module has been advanced far beyond
it anyway, so remove that line.
- - - - -
4a645683 by Simon Peyton Jones at 2026-05-27T21:41:59-04:00
Trim the continuation in mkDupableContWithDmds
When there are no remaining argument demands, it means the application
is bottoming. In this case, we can trim the continuation to avoid the
panic that was observed in #27261.
See Note [Trimming the continuation for bottoming functions] in
GHC.Core.Opt.Simplify.Iteration.
- - - - -
8ab506ff by Cheng Shao at 2026-05-27T21:42:47-04:00
ghci: fix module name string lifetime in hs_hpc_module invocation
This patch makes hpcAddModule pass a properly malloced module name
string to hs_hpc_module, instead of using useAsCString which causes
use-after-free of module name string. Fixes #27297.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
b0233814 by sheaf at 2026-05-27T21:43:31-04:00
Relax acceptance threshold for T10421
As seen in #27289, the 1% acceptance threshold for this text was
overly narrow, resulting in spurious test failures. This commit widens
the acceptance threshold to 2%. Fixes #27289.
- - - - -
63ce5770 by Luite Stegeman at 2026-05-28T12:23:35-04:00
Fixes for black holes
- suspend duplicate work for eager black holes
- detect eager black holes in checkBlockingQueues
- don't overwrite existing black holes even if they're not
in an eager blackhole frame
- don't deadlock on self when thunk is already blackholed
Fixes #26936
- - - - -
037a80dc by Tom McLaughlin at 2026-05-28T12:24:36-04:00
Event/Windows.hsc: rethrow exceptions in overlapped IO
This prevents the WinIO manager from swallowing exceptions in overlapped IO. It
was added to make WinIO support possible in the `network` library. See
https://gitlab.haskell.org/ghc/ghc/-/issues/27283.
We also bump __IO_MANAGER_WINIO__ to 2 so libraries can gate on this using CPP.
- - - - -
2d53bcdb by Wolfgang Jeltsch at 2026-05-28T12:25:21-04:00
Allow `downsweep` to use nodes of an existing module graph
To this end, `downsweep` has not been able to use the nodes of a module
graph obtained from a previous downsweeping round. In some GHC API
applications, downsweeping is performed somewhat incrementally and
therefore could profit from reusing such existing results. This
contribution makes this possible.
Resolves #27054.
Co-authored-by: Matthew Pickering <matthewtpickering(a)gmail.com>
- - - - -
f4fbb583 by Simon Jakobi at 2026-05-28T12:26:04-04:00
Add regression test for T11226
Closes #11226.
- - - - -
ed29a5e6 by Sven Tennie at 2026-05-28T17:30:36-04:00
Add optional config setting for LibDir (#19174)
Previously, the `libDir` was derived from `topDir`. This won't work for
inplace stage2 cross-compilers where binaries and libraries are in
different stage dirs (`_build/stage1/` for executables and
`_build/stage2` for libraries).
`LibDir` is set in the inplace `settings` files. For bindists, we
generate a new `settings` file with no `LibDir` entry. GHC then defaults
to use `topDir` as `libDir` again. This keeps the bindist relocatable.
If `LibDir` is a relative path, it is interpreted relatively to
`topDir`.
The global package db is part of the `lib/` folder. If we want to point
for inplace cross-compilers to the succeeding stage's folder, this is
done by setting `LibDir`. Thus, the global package db must be found
relative to `libDir`` (which may default to `topDir` or be set by
`LibDir`).
The complexity of settings becomes scary. So, add a test to ensure
`LibDir` works as expected.
- - - - -
8339cf8f by Sven Tennie at 2026-05-28T17:30:36-04:00
Add Haddock to FileSettings
Helping to understand the fields' meanings without deeper analyses.
- - - - -
4ce251e4 by Sylvain Henry at 2026-05-28T17:31:39-04:00
foundation test: skip signed minBound `quot` (-1) (#27222)
`minBound `quot` (-1)` for fixed-width signed integers is platform
dependent: the mathematical result -minBound is not representable in
the type. On x86, IDIV traps; LLVM's sdiv is undefined behaviour in
this case; on AArch64/RISC-V, SDIV wraps to minBound.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
b8ba7e61 by Simon Jakobi at 2026-05-28T17:32:23-04:00
Prevent dictionary-passing in checkTyEqRhs
...by pre-specializing it to TcM.
Previously, wherever checkTyEqRhs was used in other modules, the
Core showed dictionary passing ($fMonadIOEnv). The added SPECIALIZE
pragma prevents this.
- - - - -
d603477f by David Eichmann at 2026-05-29T13:17:12-04:00
Hadrian: create a ghc-internal .def file per ghc-internal dll
The .def file generated from rts/win32/libHSghc-internal.def.in contains
the name of the ghc-internal dll. The correct dll name differs based
on if the dll is inplace/final and if using the Dynamic way. Previously,
this was not accounted for and inconsistent dlls names where used. That
led to failure when loading dlls at runtime in experiments with windows
dynamic linking.
- - - - -
1fc21753 by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: copy backend interface haddocks to Native backend (#27305)
The haddock comments documenting the BigNat backend interface (function
contracts, expected MutableWordArray# sizes, return-value semantics, etc.)
were attached to the FFI backend module. Copy them to the Native backend
so they remain in tree once the FFI backend is removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
717059df by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: remove FFI backend (#27305)
The FFI backend of ghc-bignum (now part of ghc-internal) had no known
users and is easy to recreate by relinking ghc-internal with a custom
backend. Remove the backend module, the bignum-ffi cabal flag, and the
ffi option from Hadrian's --bignum selector. The backend interface
documentation now lives in the Native backend module.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
4bb3b1d8 by Sylvain Henry at 2026-05-29T13:18:14-04:00
ghc-bignum: remove Check backend (#27305)
The Check backend of ghc-bignum (now part of ghc-internal) compared the
selected backend's output against the Native backend for validation.
It had no known users. Remove the backend module, the bignum-check
cabal flag, the bignumCheck Hadrian flavour field, and the check-
prefix in Hadrian's --bignum selector.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply(a)anthropic.com>
- - - - -
6b3044a0 by David Eichmann at 2026-05-30T11:58:48-04:00
Add code comments to allocator code
- - - - -
f4e04210 by Matthew Pickering at 2026-05-30T11:59:34-04:00
hadrian: Refactor system-cxx-std-lib rules
I noticed a few things wrong with the hadrian rules for
`system-cxx-std-lib` rules.
* For `text` there is an ad-hoc check to depend on `system-cxx-std-lib`
outside of `configurePackage`.
* The `system-cxx-std-lib` dependency is not read from cabal files.
* Recache is not called on the packge database after the `.conf` file is
generated, a more natural place for this rule is `registerRules`.
Treating this uniformly like other packages is complicated by it not
having any source code or a cabal file. However we can do a bit better
by reporting the dependency firstly in `PackageData` and then needing
the `.conf` file in the same place as every other package in
`configurePackage`.
This commit increases the `shakeVersion`, to provide backwards
compatibility to previous builds with different PackageData.
Fixes #25303
Co-authored-by: Sven Tennie <sven.tennie(a)gmail.com>
- - - - -
576987d0 by Simon Jakobi at 2026-06-02T04:53:36-04:00
compiler: use nubOrd from containers
Address #27103 by replacing GHC.Utils.Misc.ordNub[On] with
Data.Containers.ListUtils.nubOrd[On].
Note that nubOrd suffers from a small inefficiency, a fix for which
will be included in the next containers release:
https://github.com/haskell/containers/issues/1202
- - - - -
deea53c3 by David Eichmann at 2026-06-02T04:54:22-04:00
Hadrian: disable response files for GHC/Haddock builders on non-Windows
This makes debugging build errors easier on non-windows hosts.
See issue #27230
- - - - -
f2f5c6ba by Nikita Efremov at 2026-06-02T16:04:54+00:00
fix typo : compete with performance, not complete
- - - - -
5524ea0e by Wolfgang Jeltsch at 2026-06-03T08:01:26-04:00
Make the current `base` buildable with GHC 9.14
This comprises the following changes:
* Disable some imports into `GHC.Base` for GHC 9.14
* Disable some imports into `Prelude` for GHC 9.14
* Disable separate `ArrowLoop` import for GHC 9.14
* Disable `GHC.Internal.STM` import for GHC 9.14
* Disable `GHC.Internal.Unicode.Version` import for GHC 9.14
* Disable `GHC.Internal.TH.Monad` import for GHC 9.14
* Add alternative `fixIO` import for GHC 9.14
* Add alternative `unsafeCodeCoerce` import for GHC 9.14
* Disable hiding of imported SIMD operations for GHC 9.14
* Disable use of GHC 9.14’s `printToHandleFinalizerExceptionHandler`
* Enable use of `getFileHash` from `ghc-internal` for GHC 9.14
* Make `thenA` available for GHC 9.14
* Make `thenM` available for GHC 9.14
* Disable translation of `IoManagerFlagPoll` for GHC 9.14
* Add `hGetNewlineMode` for GHC 9.14
- - - - -
d3438055 by Enrico Maria De Angelis at 2026-06-03T08:02:17-04:00
Fix #27067 - Clarify haddocks on `minusNaturalMaybe`
- - - - -
f9bcfac2 by sheaf at 2026-06-03T14:47:19-04:00
Avoid mkTick in Core Prep breaking ANF
As discovered in #27182, mkTick can break ANF. This patch introduces a
variant of mkTick that skips the single optimisation that could break
ANF. This is preferrable over switching to the raw Tick constructor,
as the latter may introduce spurious cost centres in profiling reports.
This is a temporary measure until we more thoroughly refactor how
mkTick works (see #27141).
See Note [mkTick breaks ANF] in GHC.CoreToStg.Prep.
Fixes #27182
- - - - -
cf1fd661 by Artem Pelenitsyn at 2026-06-03T14:48:09-04:00
clarify comment for getSizeofMutableByteArray#: we get the size in bytes, not "elements"
- - - - -
a3b431f3 by David Eichmann at 2026-06-04T10:10:19+00:00
Hadrian: convert env variable ACLOCAL_PATH to unix paths.
Convert ACLOCAL_PATH to a unix style path when invoking autoreconf.
Autoreconf doesn't handle windows paths.
See Note [Autoreconf unix paths from ACLOCAL_PATH].
Fixes #27311
- - - - -
18f6138a by Simon Jakobi at 2026-06-04T20:20:31-04:00
testsuite: Deduplicate --only test names
config.only is assumed to be a set, but supplying --only overwrote it
with the (list) argparse result, which can contain duplicates. When a
test ran, config.only.remove(name) dropped only the first occurrence,
so a duplicated name lingered and was later misreported as a
"test not found" framework failure. Store it as a set instead.
Fixes #27322
Co-Authored-By: Claude Opus 4.7 <noreply(a)anthropic.com>
- - - - -
981f2369 by Teo Camarasu at 2026-06-07T16:38:30+01:00
Make Q abstract
This patch aims to clearly demarcate the internal and external interfaces
of Q.
In the past the `Quasi` typeclass was both part of the external,
public-facing interface, and was used to give the implementation of `Q`.
Now we separate out these two distinct roles. `Quasi` continues to exist
in the public interface, but we introduce a new `MetaHandlers` type,
which is equivalent to `Dict Quasi`.
`Q a` is now defined to be `MetaHandlers IO -> IO a`, and, crucially,
the constructor and the new `MetaHandlers` type are not exposed from the
public interface.
This gives us the ability to vary the interface on the GHC side without
forcing a breaking change on the `template-haskell` side.
Similarly `template-haskell` has more freedom to change the `Quasi`
typeclass without needing any changes in `lib:ghc`.
Implements https://github.com/ghc-proposals/ghc-proposals/pull/70
Resolves #27341
- - - - -
442 changed files:
- .gitmodules
- boot
- + changelog.d/AbstractQ
- + changelog.d/T26979
- + changelog.d/T27182.md
- + changelog.d/T27202
- + changelog.d/T27261
- + changelog.d/bump-process
- + changelog.d/dynamic-trace-flags
- + changelog.d/elem-via-foldr-27096
- + changelog.d/fix-blackhole-handling
- + changelog.d/ghc-api-epa-parens
- + changelog.d/ghc-pkg-faster-closure
- + changelog.d/hadrian-system-cxx-std-lib-25303
- + changelog.d/ipe-event-class
- + changelog.d/jobserver-leak-fix
- + changelog.d/lib-add-tuple-tyfam-27179
- + changelog.d/libdir-setting
- + changelog.d/module-graph-reuse-in-downsweep
- + changelog.d/more-efficient-home-unit-imports-finding
- + changelog.d/no-more-timer-signal
- + changelog.d/remove-bignum-check-backend
- + changelog.d/remove-bignum-ffi-backend
- + changelog.d/rts_symlinks.md
- + changelog.d/semaphore-v2
- + changelog.d/so_inline_is_a_predicate
- + changelog.d/wasm-fix-serviceworker
- + changelog.d/windows-rethrow-overlapped-exception
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/BlockLayout.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Core/Opt/FloatIn.hs
- compiler/GHC/Core/Opt/FloatOut.hs
- compiler/GHC/Core/Opt/Monad.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Data/IOEnv.hs
- compiler/GHC/Data/List/SetOps.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/Config.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Driver/Config/Interpreter.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/Driver/MakeAction.hs
- compiler/GHC/Driver/MakeSem.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Driver/Session/Units.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/HsToCore/Errors/Ppr.hs
- compiler/GHC/HsToCore/Errors/Types.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Binary.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Linker/Unit.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/Types.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Settings.hs
- compiler/GHC/Settings/Constants.hs
- compiler/GHC/Settings/IO.hs
- compiler/GHC/Stg/Pipeline.hs
- compiler/GHC/StgToJS/Ids.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Bind.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Gen/Splice.hs-boot
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Name/Cache.hs
- compiler/GHC/Types/Unique.hs
- compiler/GHC/Types/Unique/Supply.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Info.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Utils/Misc.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Decls/Foreign.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Type.hs
- configure.ac
- distrib/configure.ac.in
- docs/users_guide/exts/stolen_syntax.rst
- docs/users_guide/exts/template_haskell.rst
- docs/users_guide/javascript.rst
- docs/users_guide/profiling.rst
- docs/users_guide/runtime_control.rst
- docs/users_guide/using-warnings.rst
- docs/users_guide/using.rst
- ghc/GHCi/UI.hs
- ghc/Main.hs
- hadrian/README.md
- hadrian/cfg/default.host.target.in
- hadrian/cfg/default.target.in
- hadrian/doc/user-settings.md
- hadrian/src/Builder.hs
- hadrian/src/CommandLine.hs
- hadrian/src/Flavour.hs
- hadrian/src/Flavour/Type.hs
- hadrian/src/Hadrian/Haskell/Cabal/Parse.hs
- hadrian/src/Hadrian/Haskell/Cabal/Type.hs
- hadrian/src/Hadrian/Oracles/Path.hs
- hadrian/src/Hadrian/Utilities.hs
- hadrian/src/Main.hs
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Rules/Library.hs
- hadrian/src/Rules/Register.hs
- hadrian/src/Rules/Rts.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/RunTest.hs
- hadrian/src/Settings/Default.hs
- hadrian/src/Settings/Packages.hs
- libraries/base/changelog.md
- libraries/base/src/Control/Applicative.hs
- libraries/base/src/Control/Arrow.hs
- libraries/base/src/Control/Exception.hs
- libraries/base/src/Control/Monad.hs
- libraries/base/src/Control/Monad/IO/Class.hs
- libraries/base/src/Data/Array/Byte.hs
- libraries/base/src/Data/Data.hs
- libraries/base/src/Data/Fixed.hs
- libraries/base/src/Data/Functor/Classes.hs
- libraries/base/src/Data/Functor/Compose.hs
- libraries/base/src/Data/List/NonEmpty.hs
- libraries/base/src/Data/Version.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/ByteOrder.hs
- libraries/base/src/GHC/Conc.hs
- libraries/base/src/GHC/Conc/Sync.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/GHC/Fingerprint.hs
- libraries/base/src/GHC/IO/Handle.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/base/src/GHC/Unicode.hs
- libraries/base/src/GHC/Weak.hs
- libraries/base/src/GHC/Weak/Finalize.hs
- libraries/base/src/Numeric.hs
- libraries/base/src/Prelude.hs
- libraries/base/src/System/IO.hs
- libraries/base/src/System/Mem/Weak.hs
- libraries/base/src/System/Timeout.hs
- libraries/base/src/Text/Read.hs
- libraries/base/tests/perf/ElemNoFusion_O1.stderr
- libraries/base/tests/perf/ElemNoFusion_O2.stderr
- libraries/ghc-bignum/ghc-bignum.cabal
- + libraries/ghc-boot/GHC/Data/ShortByteString.hs
- libraries/ghc-boot/GHC/Settings/Utils.hs
- libraries/ghc-boot/ghc-boot.cabal.in
- libraries/ghc-experimental/src/Data/Sum/Experimental.hs
- libraries/ghc-experimental/src/Data/Tuple/Experimental.hs
- libraries/ghc-internal/bignum-backend.rst
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Base.hs
- libraries/ghc-internal/src/GHC/Internal/Bignum/Backend.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Check.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/FFI.hs
- libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Native.hs
- − libraries/ghc-internal/src/GHC/Internal/Bignum/Backend/Selected.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Windows.hsc
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/List.hs
- libraries/ghc-internal/src/GHC/Internal/Natural.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- − libraries/ghc-internal/src/GHC/Internal/Text/Read.hs
- libraries/ghc-internal/src/GHC/Internal/Types.hs
- libraries/ghci/GHCi/Coverage.hs
- libraries/ghci/GHCi/Run.hs
- libraries/ghci/GHCi/TH.hs
- libraries/process
- libraries/semaphore-compat
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- m4/find_llvm_prog.m4
- m4/fp_setup_windows_toolchain.m4
- m4/ghc_toolchain.m4
- m4/prep_target_file.m4
- rts/.gitignore
- rts/IPE.c
- rts/Messages.c
- rts/RtsFlags.c
- rts/RtsSymbols.c
- rts/ThreadPaused.c
- rts/Threads.c
- rts/Trace.c
- rts/Trace.h
- rts/Updates.h
- rts/include/rts/EventLogWriter.h
- rts/include/rts/Flags.h
- rts/include/rts/storage/ClosureMacros.h
- + rts/posix/FdWakeup.c
- + rts/posix/FdWakeup.h
- rts/posix/Ticker.c
- − rts/posix/ticker/Pthread.c
- − rts/posix/ticker/TimerFd.c
- rts/rts.cabal
- rts/sm/BlockAlloc.c
- rts/sm/MBlock.c
- rts/sm/NonMoving.c
- + rts/win32/libHSghc-internal.def.in
- testsuite/driver/runtests.py
- testsuite/tests/MiniQuickCheck.hs
- testsuite/tests/codeGen/should_compile/T25177.stderr
- + testsuite/tests/codeGen/should_gen_asm/aarch64-shl-subword.asm
- + testsuite/tests/codeGen/should_gen_asm/aarch64-shl-subword.hs
- + testsuite/tests/codeGen/should_gen_asm/aarch64-ushr-subword.asm
- + testsuite/tests/codeGen/should_gen_asm/aarch64-ushr-subword.hs
- testsuite/tests/codeGen/should_gen_asm/all.T
- + testsuite/tests/codeGen/should_run/aarch64-subword-ops.hs
- + testsuite/tests/codeGen/should_run/aarch64-subword-ops.stdout
- + testsuite/tests/codeGen/should_run/aarch64-ushr-subword-run.hs
- + testsuite/tests/codeGen/should_run/aarch64-ushr-subword-run.stdout
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/deSugar/should_compile/T13208.stdout
- testsuite/tests/diagnostic-codes/codes.stdout
- testsuite/tests/driver/fat-iface/fat014.stdout
- testsuite/tests/ffi/should_run/all.T
- + testsuite/tests/ghc-api/T24386.hs
- testsuite/tests/ghc-api/T25121_status.stdout
- + testsuite/tests/ghc-api/T27273.hs
- testsuite/tests/ghc-api/all.T
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/A.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/B.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/C.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/D.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/X.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Y.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Z.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.stdout
- testsuite/tests/ghc-api/downsweep/OldModLocation.hs
- testsuite/tests/ghc-api/downsweep/PartialDownsweep.hs
- testsuite/tests/ghc-api/downsweep/all.T
- testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
- + testsuite/tests/ghc-api/settings/LibDir.hs
- + testsuite/tests/ghc-api/settings/LibDir.stdout
- + testsuite/tests/ghc-api/settings/all.T
- + testsuite/tests/ghci/prog-mhu006/Makefile
- + testsuite/tests/ghci/prog-mhu006/a/A.hs
- + testsuite/tests/ghci/prog-mhu006/all.T
- + testsuite/tests/ghci/prog-mhu006/b/B.hs
- + testsuite/tests/ghci/prog-mhu006/prog-mhu006a.script
- + testsuite/tests/ghci/prog-mhu006/prog-mhu006a.stdout
- + testsuite/tests/ghci/prog-mhu006/unitA
- + testsuite/tests/ghci/prog-mhu006/unitB
- testsuite/tests/ghci/prog003/prog003.script
- testsuite/tests/ghci/prog018/prog018.stdout
- testsuite/tests/ghci/prog020/Makefile
- testsuite/tests/ghci/prog020/all.T
- testsuite/tests/ghci/prog020/ghci.prog020.script → testsuite/tests/ghci/prog020/ghci.prog020a.script
- testsuite/tests/ghci/prog020/ghci.prog020.stderr → testsuite/tests/ghci/prog020/ghci.prog020a.stderr
- testsuite/tests/ghci/prog020/ghci.prog020.stdout → testsuite/tests/ghci/prog020/ghci.prog020a.stdout
- + testsuite/tests/ghci/prog020/ghci.prog020b.script
- + testsuite/tests/ghci/prog020/ghci.prog020b.stderr
- + testsuite/tests/ghci/prog020/ghci.prog020b.stdout
- + testsuite/tests/ghci/prog023/Makefile
- + testsuite/tests/ghci/prog023/all.T
- + testsuite/tests/ghci/prog023/prog023a.script
- + testsuite/tests/ghci/prog023/prog023a.stdout
- + testsuite/tests/ghci/prog023/prog023b.script
- + testsuite/tests/ghci/prog023/prog023b.stdout
- + testsuite/tests/ghci/prog023/src/A.hs
- + testsuite/tests/ghci/prog024/Makefile
- + testsuite/tests/ghci/prog024/all.T
- + testsuite/tests/ghci/prog024/prog024a.script
- + testsuite/tests/ghci/prog024/prog024a.stdout
- + testsuite/tests/ghci/prog024/prog024b.script
- + testsuite/tests/ghci/prog024/prog024b.stdout
- + testsuite/tests/ghci/prog024/prog024c.script
- + testsuite/tests/ghci/prog024/prog024c.stderr
- + testsuite/tests/ghci/prog024/prog024c.stdout
- + testsuite/tests/ghci/prog024/prog024d.script
- + testsuite/tests/ghci/prog024/prog024d.stderr
- + testsuite/tests/ghci/prog024/prog024d.stdout
- + testsuite/tests/ghci/prog024/prog024e.script
- + testsuite/tests/ghci/prog024/prog024e.stdout
- + testsuite/tests/ghci/prog024/prog024f.script
- + testsuite/tests/ghci/prog024/prog024f.stdout
- + testsuite/tests/ghci/prog024/src/A.hs
- + testsuite/tests/ghci/prog024/src/B.hs
- + testsuite/tests/ghci/prog025/Makefile
- + testsuite/tests/ghci/prog025/a/A.hs
- + testsuite/tests/ghci/prog025/all.T
- + testsuite/tests/ghci/prog025/prog025a.script
- + testsuite/tests/ghci/prog025/prog025a.stdout
- + testsuite/tests/ghci/prog025/prog025b.script
- + testsuite/tests/ghci/prog025/prog025b.stdout
- + testsuite/tests/ghci/prog025/testpkg/Test.hs
- + testsuite/tests/ghci/prog025/testpkg/testpkg-0.1.0.0.pkg
- + testsuite/tests/ghci/prog025/testpkg/testpkg-0.2.0.0.pkg
- + testsuite/tests/ghci/prog025/unitA
- testsuite/tests/ghci/scripts/ListTuplePunsPprNoAbbrevTuple.stdout
- testsuite/tests/ghci/scripts/T13997.stdout
- testsuite/tests/ghci/scripts/T1914.stdout
- testsuite/tests/ghci/scripts/T20217.stdout
- testsuite/tests/ghci/scripts/T8042.stdout
- testsuite/tests/ghci/scripts/T8042recomp.stdout
- testsuite/tests/ghci/scripts/all.T
- testsuite/tests/ghci/should_run/T10920.stderr
- + testsuite/tests/interface-stability/.gitignore
- testsuite/tests/interface-stability/README.mkd
- 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
- + testsuite/tests/interface-stability/download-base-exports.sh
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- testsuite/tests/interface-stability/template-haskell-exports.stdout
- testsuite/tests/linters/notes.stdout
- testsuite/tests/numeric/should_compile/T15547.stderr
- testsuite/tests/numeric/should_compile/T20347.stderr
- testsuite/tests/numeric/should_compile/T20374.stderr
- testsuite/tests/numeric/should_compile/T20376.stderr
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/parser/should_compile/DumpParsedAst.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/KindSigs.stderr
- testsuite/tests/parser/should_compile/ListTuplePunsSuccess1.hs
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/parser/should_compile/all.T
- + testsuite/tests/parser/should_fail/ListTuplePunsFail6.hs
- + testsuite/tests/parser/should_fail/ListTuplePunsFail6.stderr
- testsuite/tests/parser/should_fail/all.T
- testsuite/tests/parser/should_run/ListTuplePunsConstraints.hs
- testsuite/tests/perf/compiler/Makefile
- + testsuite/tests/perf/compiler/T26989.hs
- + testsuite/tests/perf/compiler/T26989a.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/perf/compiler/genMultiComp.py
- + testsuite/tests/perf/should_run/T11226.hs
- + testsuite/tests/perf/should_run/T11226.stdout
- testsuite/tests/perf/should_run/all.T
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/PprModifiers.hs
- + testsuite/tests/printer/PprQualifiedStrings.hs
- testsuite/tests/printer/T18052a.stderr
- + testsuite/tests/printer/Test27291.hs
- testsuite/tests/printer/all.T
- + testsuite/tests/profiling/should_compile/T27182.hs
- testsuite/tests/profiling/should_compile/all.T
- testsuite/tests/profiling/should_run/callstack001.stdout
- + testsuite/tests/rts/T25275/DebugIpe.hs
- + testsuite/tests/rts/T25275/T25275_A.stdout
- + testsuite/tests/rts/T25275/T25275_B.stdout
- + testsuite/tests/rts/T25275/T25275_C.stdout
- + testsuite/tests/rts/T25275/T25275_D.stdout
- + testsuite/tests/rts/T25275/TraceIpe.hs
- + testsuite/tests/rts/T25275/all.T
- testsuite/tests/simplCore/should_compile/DsSpecPragmas.stderr
- testsuite/tests/simplCore/should_compile/RewriteHigherOrderPatterns.stderr
- testsuite/tests/simplCore/should_compile/T15205.stderr
- testsuite/tests/simplCore/should_compile/T18668.stderr
- testsuite/tests/simplCore/should_compile/T19246.stderr
- testsuite/tests/simplCore/should_compile/T19599.stderr
- testsuite/tests/simplCore/should_compile/T19599a.stderr
- testsuite/tests/simplCore/should_compile/T21917.stderr
- testsuite/tests/simplCore/should_compile/T23074.stderr
- testsuite/tests/simplCore/should_compile/T24359a.stderr
- testsuite/tests/simplCore/should_compile/T25160.stderr
- testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-32
- testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-64
- testsuite/tests/simplCore/should_compile/T26051.stderr
- testsuite/tests/simplCore/should_compile/T26116.stderr
- + testsuite/tests/simplCore/should_compile/T27261.hs
- + testsuite/tests/simplCore/should_compile/T27261_aux.hs
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/T8848a.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/simplCore/should_compile/spec004.stderr
- testsuite/tests/th/T24111.stdout
- testsuite/tests/typecheck/should_compile/T13032.stderr
- + testsuite/tests/typecheck/should_compile/T23135.hs
- testsuite/tests/typecheck/should_compile/all.T
- testsuite/tests/typecheck/should_compile/subsumption_sort_hole_fits.stderr
- testsuite/tests/typecheck/should_fail/T21130.stderr
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/ghc-pkg/Main.hs
- utils/ghc-toolchain/exe/Main.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Program.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Target.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Interface/RenameType.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/jsffi/prelude.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/44cc53feef363e4beeb5f3d70e008a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/44cc53feef363e4beeb5f3d70e008a…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/dcoutts/issue-27105-stopTicker] 12 commits: Promote HAVE_PREEMPTION from Timer.c to OSThreads.h
by Duncan Coutts (@dcoutts) 07 Jun '26
by Duncan Coutts (@dcoutts) 07 Jun '26
07 Jun '26
Duncan Coutts pushed to branch wip/dcoutts/issue-27105-stopTicker at Glasgow Haskell Compiler / GHC
Commits:
9421fe08 by Duncan Coutts at 2026-06-06T23:51:30+02:00
Promote HAVE_PREEMPTION from Timer.c to OSThreads.h
We will want to know about HAVE_PREEMPTION in more places.
HAVE_PREEMPTION tells us that we do have OS threads available,
irrespective of whether THREADED is defined. In particular,
HAVE_PREEMPTION is defined on all proper OSs, but not on WASM (and
hyopthetically may not be true on some other platforms like
micro-controllers, RTOSs, VM hypervisors etc).
- - - - -
542e0742 by Duncan Coutts at 2026-06-07T09:19:31+02:00
Define ACQUIRE_LOCK_ALWAYS and friends
Fix issue #27335
Like the atomic _ALWAYS variants, these lock actions are always defined,
rather than being dependent on whether we are in the THREADED case. All
the "normal" LOCK macros are defined to be no-ops when !THREADED.
The use case for the _ALWAYS variants is where we are using OS threads
even in the non-threaded RTS. This includes everything to do with the
timer/ticker thread, which is used in the non-threaded RTS too.
In particular, we will want to use this for eventlog things, because the
timer thread performs eventlogging concurrently with the main
capability, even in the non-threaded RTS.
- - - - -
5d90f476 by Duncan Coutts at 2026-06-07T09:19:31+02:00
Use ACQUIRE/RELEASE_LOCK_ALWAYS with eventBufMutex
Even in the non-threaded RTS the eventBufMutex is needed by both the
main capability and the timer/ticker thread, so always use the mutex.
This should fix #25165 which is about the main capability and the timer
thread posting events to the eventlog buffer concurrently and thereby
corrupting the buffer data.
- - - - -
233e6c16 by Duncan Coutts at 2026-06-07T09:19:31+02:00
Expose eventBufMutex in the EventLog interface/header
We will need it in forkProcess to ensure we don't write to the global
eventlog buffer concurrently with trying to flush eventlog buffers and
do the fork().
- - - - -
baba3e89 by Duncan Coutts at 2026-06-07T09:19:31+02:00
Split flushAllCapsEventsBufs into safe and unlocked version
Following the convention that unlocked versions have a trailing _
underscore in their name. This one requires the caller to hold the
eventlog global buffer mutex. We will need this in forkProcess.
- - - - -
57d166ae by Duncan Coutts at 2026-06-07T09:19:31+02:00
Remove redundant use of stopTimer in setNumCapabilities
Historically, the comment here was:
We must stop the interval timer while we are changing the
capabilities array lest handle_tick may try to context switch
an old capability. See #17289.
and
We must disable the timer while we do this since the tick handler may
call contextSwitchAllCapabilities, which may see the capabilities array
as we free it.
What this refers to is that historically, when changing the number of
capabilities, the array of capabilities was reallocated to a new size,
allocating new ones and freeing the old ones, thus invalidating all
existing capbility pointers.
Strangely, for good measure the code used to call stopTimer twice (hence
the two similar comments above).
However, since commit a3eccf06292dd666b24606251a52da2b466a9612, the
capabilities array is no longer reallocated. Instead the array is
allcoated once on RTS startup to the maximum size it could ever be
allowed to be, and then capabilities get enabled/disabled at runtime. So
the capability pointers never become invalid anymore. At worst, they may
point to capabilities that are disabled.
Thus we no longer need to stop the timer (twice) while we change the
number of enabled capabilities. This also partially solves issue #27105,
which notes that stopTimer is being used as if it were synchronous, when
it is not. At least for this case, the solution is that stopTimer is not
needed at all!
- - - - -
e2c8b108 by Duncan Coutts at 2026-06-07T09:19:31+02:00
Remove redundant use of stopTimer in forkProcess
but replace it with taking the eventlog buffer lock during the fork.
Fixes issue #27105
The original reason to block the timer during a fork was that
historically the timer was implemented using a periodic timer signal,
and the signal itself would interrupt the fork system call (returning
EINTR). For large processes (where fork() takes a while) this could
permanently livelock: the timer always would go off before the fork
could complete, which got retried in a loop forever.
The timer is no longer implemented as a unix signal, but uses threads.
Thus the original problem no longer exists. The only remaining reason to
block the timer tick is to prevent actions taken by the tick from
interfering with the delicate process involved in fork (taking a load of
locks and pausing everything).
The only thing we need to do is to prevent the eventlog from being
written to or flushed while the fork is taking place. To achieve this
all we need to do is hold the mutex for the global eventlog buffer.
This removes the last use of stopTimer that expects stopTimer to work
synchronously (which it was not) and thus solves issue #27105. To be
clear, we solve issue #27105 not by making stopTimer synchronous, but by
eliminating the use sites that expected it to be synchronous.
- - - - -
5a26a760 by Duncan Coutts at 2026-06-07T11:17:48+02:00
Add a test for thread scheduler fairness
It also tests that the interval timer and context switching works.
We also test that fairness is lost when the context switching interval
is too coarse for the duration of the test.
We add this test before doing surgery on the interval timer, so we have
decent coverage.
- - - - -
bcab4fff by Duncan Coutts at 2026-06-07T13:47:21+02:00
Improve and clarify ticker implementation(s)
We remove stop/startTicker and replace them with pause/unpauseTicker.
In the past the stop/startTicker actions were used incorrectly as if
they were synchronous, which they are not. See issue #27105. We now
document pause/unpackTicker as being async and not to be used for the
purpose of concurrency safety.
The existing stop/startTimer (note Timer not Ticker, the Timer calls the
Ticker!) are also exported from the RTS as a public API. This was
historically because the ticker used signals and it was important to
suspend the timer signel over a process fork. So these functions were
exported to be used by the process and unix libraries. This is no longer
necessary. Add a changelog entry to explain this.
We also take the opportunity to improve the ticker implementations
somewhat.
In the posix implementation, we take care to keep the tick action cheap.
Since pause/unpause are used very infrequently, we make them more
expensive and complicated to allow the normal hot path in the tick
action to be cheap. In particular we are able to eliminate the use of a
mutex in the tick action. We avoid locks and atomic memory ops in the
hot path. We use message passing via an eventfd or pipe.
In the win32 implementation, we continue to use the TimerQueue API, and
we make use of its ability to delete timers synchronously or
asynchronously. We improve the locking to ensure that it is safe to call
pause/unpause from any thread.
- - - - -
efa24f6a by Duncan Coutts at 2026-06-07T14:06:12+02:00
Make win32 ticker wait interval for initial tick too
There is no need to tick immediately. This is consistent with the
posix implementation.
- - - - -
55547c28 by Duncan Coutts at 2026-06-07T14:07:49+02:00
Remove now-unnecessary layer of RTS ticker enable/disable
There was an atomic variable used to block *part* of the actions of the
tick handler. This still did not make stopTimer synchronous, even for
the part of the the handle_tick actions it covered. It also added a more
expensive (sequentuially consistent) atomic operation in the hot path
for the handle_tick action, whereas our new design requires no atomic
ops at all.
Now that we have eliminate the need for synchronous stop/startTicker,
we don't need this not-quite-working-anyway atomic protocol. The new
pause/unpauseTicker is explicitly asynchronous and idempotent.
- - - - -
6a667450 by Duncan Coutts at 2026-06-07T14:12:09+02:00
Add TODOs about issue #27250: too much being done from handle_tick
The handle_tick should not perform I/O, block, perform long-running
operations or call arbitrary user code. Unfortunately, everything to
do with the eventlog (at the moment) falls into all those categories.
- - - - -
15 changed files:
- + changelog.d/T27105
- rts/Capability.c
- rts/RtsStartup.c
- rts/Schedule.c
- rts/Ticker.h
- rts/Timer.c
- rts/Timer.h
- rts/eventlog/EventLog.c
- rts/eventlog/EventLog.h
- rts/include/rts/OSThreads.h
- rts/include/rts/Timer.h
- rts/posix/Ticker.c
- rts/win32/Ticker.c
- + testsuite/tests/concurrent/should_run/T27105.hs
- testsuite/tests/concurrent/should_run/all.T
Changes:
=====================================
changelog.d/T27105
=====================================
@@ -0,0 +1,14 @@
+section: rts
+issues: #27105 #25165 #27335
+mrs: !16147 !16023
+synopsis: The RTS public APIs `stopTimer` and `startTimer` are now no-ops
+description: {
+ As a result of fixing some timer/ticker concurrency bugs, the exported RTS
+ APIs `stopTimer` and `startTimer` are now no-ops and are deprecated. They
+ were called at least by the process and unix libraries. No replacement is
+ needed.
+
+ They were used by libraries to temporarily block the RTS's use of the timer
+ signal. These functions no longer have a purpose since the RTS interval
+ timer no longer uses signals.
+}
=====================================
rts/Capability.c
=====================================
@@ -443,13 +443,6 @@ void
moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
{
#if defined(THREADED_RTS)
- // We must disable the timer while we do this since the tick handler may
- // call contextSwitchAllCapabilities, which may see the capabilities array
- // as we free it. The alternative would be to protect the capabilities
- // array with a lock but this seems more expensive than necessary.
- // See #17289.
- stopTimer();
-
if (to == 1) {
// THREADED_RTS must work on builds that don't have a mutable
// BaseReg (eg. unregisterised), so in this case
@@ -470,8 +463,6 @@ moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
}
debugTrace(DEBUG_sched, "allocated %d more capabilities", to - from);
-
- startTimer();
#endif
}
=====================================
rts/RtsStartup.c
=====================================
@@ -415,8 +415,8 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
traceInitEvent(dumpIPEToEventLog);
initHeapProfiling();
- /* start the virtual timer 'subsystem'. */
- startTimer();
+ /* start the timer (after initTimer above) */
+ unpauseTimer();
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
@@ -512,14 +512,12 @@ hs_exit_(bool wait_foreign)
}
#endif
- /* stop the ticker */
- stopTimer();
- /*
- * it is quite important that we wait here as some timer implementations
- * (e.g. pthread) may fire even after we exit, which may segfault as we've
- * already freed the capabilities.
+ /* We rely on the guarantee that exitTimer stops the timer synchronously,
+ * which ensures the timer handler does not get run again after this point.
+ * We are about to start freeing resources used by the timer handler (like
+ * the capabilities, eventlog and profiling data structures).
*/
- exitTimer(true);
+ exitTimer();
/*
* Dump the ticky counter definitions
=====================================
rts/Schedule.c
=====================================
@@ -37,6 +37,7 @@
#include "win32/AsyncWinIO.h"
#endif
#include "Trace.h"
+#include "eventlog/EventLog.h"
#include "RaiseAsync.h"
#include "Threads.h"
#include "Timer.h"
@@ -454,7 +455,7 @@ run_thread:
prev = setRecentActivity(ACTIVITY_YES);
if (prev == ACTIVITY_DONE_GC) {
#if !defined(PROFILING)
- startTimer();
+ unpauseTimer();
#endif
}
break;
@@ -1935,7 +1936,7 @@ delete_threads_and_gc:
// it will get re-enabled if we run any threads after the GC.
setRecentActivity(ACTIVITY_DONE_GC);
#if !defined(PROFILING)
- stopTimer();
+ pauseTimer();
#endif
break;
}
@@ -2100,24 +2101,31 @@ forkProcess(HsStablePtr *entry
ACQUIRE_LOCK(&all_tasks_mutex);
#endif
- stopTimer(); // See #4074
-
#if defined(TRACING)
- flushAllCapsEventsBufs(); // so that child won't inherit dirty file buffers
+#if defined(HAVE_PREEMPTION)
+ // We must hold the eventlog global mutex over the fork to prevent the
+ // timer thread from trying to post events. While holding the mutex we need
+ // to flush the eventlogs (global and per-cap) so that child won't inherit
+ // dirty eventlog buffers or file buffers.
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
+#endif
+ flushAllCapsEventsBufs_();
#endif
pid = fork();
if (pid) { // parent
- startTimer(); // #4074
-
RELEASE_LOCK(&sched_mutex);
RELEASE_LOCK(&sm_mutex);
RELEASE_LOCK(&stable_ptr_mutex);
RELEASE_LOCK(&stable_name_mutex);
RELEASE_LOCK(&task->lock);
+#if defined(TRACING) && defined(HAVE_PREEMPTION)
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
+#endif
+
#if defined(THREADED_RTS)
/* N.B. releaseCapability_ below may need to take all_tasks_mutex */
RELEASE_LOCK(&all_tasks_mutex);
@@ -2224,8 +2232,8 @@ forkProcess(HsStablePtr *entry
generations[g].threads = END_TSO_QUEUE;
}
- // On Unix, all timers are reset in the child, so we need to start
- // the timer again.
+ // The timer thread is not present in the child process, so we need
+ // to initialise the timer again.
initTimer();
// TODO: need to trace various other things in the child
@@ -2236,7 +2244,7 @@ forkProcess(HsStablePtr *entry
// start timer after the IOManager is initialized
// (the idle GC may wake up the IOManager)
- startTimer();
+ unpauseTimer();
// Install toplevel exception handlers, so interruption
// signal will be sent to the main thread.
@@ -2303,12 +2311,6 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
cap = rts_lock();
task = cap->running_task;
-
- // N.B. We must stop the interval timer while we are changing the
- // capabilities array lest handle_tick may try to context switch
- // an old capability. See #17289.
- stopTimer();
-
stopAllCapabilities(&cap, task);
if (new_n_capabilities < enabled_capabilities)
@@ -2364,9 +2366,7 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
tracingAddCapabilities(n_capabilities, new_n_capabilities);
#endif
- // Resize the capabilities array
- // NB. after this, capabilities points somewhere new. Any pointers
- // of type (Capability *) are now invalid.
+ // Allocate and initialise the extra capabilities
moreCapabilities(n_capabilities, new_n_capabilities);
// Resize and update storage manager data structures
@@ -2394,8 +2394,6 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
// Notify IO manager that the number of capabilities has changed.
notifyIOManagerCapabilitiesChanged(&cap);
- startTimer();
-
rts_unlock(cap);
#endif // THREADED_RTS
=====================================
rts/Ticker.h
=====================================
@@ -12,9 +12,44 @@
typedef void (*TickProc)(int);
-void initTicker (Time interval, TickProc handle_tick);
-void startTicker (void);
-void stopTicker (void);
-void exitTicker (bool wait);
+/* The ticker is initialised in a paused state. Use unpauseTicker to start. */
+void initTicker(Time interval, TickProc handle_tick);
+
+/* Stop and terminate the ticker. It does not need to be stopped first.
+ * The exitTicker action is *synchronous*. When it returns the caller is
+ * guaranteed that the tick action is blocked.
+ */
+void exitTicker(void);
+
+/* Pause and unpause (resume) the ticker.
+ *
+ * The pauseTicker and unpauseTicker actions are *asynchronous*. After calling
+ * pauseTicker, the ticker will pause eventually, but there may be another tick
+ * action before it does pause (and theoretically there could be several but
+ * in practice this is unlikely). Similarly, after calling unpauseTicker the
+ * ticker will start up again eventually, but there is an unspecified delay
+ * between the unpause and the next tick action (but in practice it is short).
+ *
+ * This should be used for the purpose of *efficiency*: to avoid unnecessary
+ * OS thread wakeups caused by the ticker.
+ *
+ * These should *not* be used for the purpose of *concurrency safety*: to
+ * prevent the tick action from running concurrently with some other critical
+ * section. The synchronous case is not provided because it is not currently
+ * needed (and proper locking is often a better solution anyway).
+ *
+ * The pairing of unpauseTicker and the handle_tick action form a
+ * synchonises-with relation: values written before unpauseTicker can be
+ * read from the resulting handle_tick action.
+ *
+ * It *is* safe to call these functions from within the tick handler itself.
+ *
+ * It is safe to use these functions concurrently from multiple threads, but
+ * note that they *are* idempotent. This means it is not appropriate to use
+ * paired pause/unpause calls concurrently. They can be used by threads based
+ * on consistent use of some shared state or observation.
+ */
+void pauseTicker(void);
+void unpauseTicker(void);
#include "EndPrivate.h"
=====================================
rts/Timer.c
=====================================
@@ -28,20 +28,6 @@
#include "RtsSignals.h"
#include "rts/EventLogWriter.h"
-// See Note [No timer on wasm32]
-#if !defined(wasm32_HOST_ARCH)
-#define HAVE_PREEMPTION
-#endif
-
-// This global counter is used to allow multiple threads to stop the
-// timer temporarily with a stopTimer()/startTimer() pair. If
-// timer_enabled == 0 timer is enabled
-// timer_disabled == N, N > 0 timer is disabled by N threads
-// When timer_enabled makes a transition to 0, we enable the timer,
-// and when it makes a transition to non-0 we disable it.
-
-static StgWord timer_disabled;
-
/* ticks left before next pre-emptive context switch */
static int ticks_to_ctxt_switch = 0;
@@ -112,9 +98,9 @@ static
void
handle_tick(int unused STG_UNUSED)
{
- handleProfTick();
- if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0
- && SEQ_CST_LOAD_ALWAYS(&timer_disabled) == 0)
+ handleProfTick(); // Bad or worse: see issue #27250.
+
+ if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0)
{
ticks_to_ctxt_switch--;
if (ticks_to_ctxt_switch <= 0) {
@@ -128,7 +114,7 @@ handle_tick(int unused STG_UNUSED)
ticks_to_eventlog_flush--;
if (ticks_to_eventlog_flush <= 0) {
ticks_to_eventlog_flush = RtsFlags.TraceFlags.eventlogFlushTicks;
- flushEventLog(NULL);
+ flushEventLog(NULL); // Bad or worse: see issue #27250.
}
}
#endif
@@ -153,7 +139,7 @@ handle_tick(int unused STG_UNUSED)
RtsFlags.MiscFlags.tickInterval;
#if defined(THREADED_RTS)
wakeUpRts();
- // The scheduler will call stopTimer() when it has done
+ // The scheduler will call pauseTimer() when it has done
// the GC.
#endif
} else {
@@ -165,10 +151,10 @@ handle_tick(int unused STG_UNUSED)
#if defined(PROFILING)
if (!(RtsFlags.ProfFlags.doHeapProfile
|| RtsFlags.CcFlags.doCostCentres)) {
- stopTimer();
+ pauseTimer();
}
#else
- stopTimer();
+ pauseTimer();
#endif
}
} else {
@@ -181,48 +167,49 @@ handle_tick(int unused STG_UNUSED)
}
}
-void
-initTimer(void)
+void initTimer(void)
{
#if defined(HAVE_PREEMPTION)
initProfTimer();
if (RtsFlags.MiscFlags.tickInterval != 0) {
initTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
}
- SEQ_CST_STORE_ALWAYS(&timer_disabled, 1);
#endif
}
-void
-startTimer(void)
+/* Deprecated exported functions. Now no-ops.
+ * Historically they were used by the process and unix libraries to disable
+ * the signal-based interval timer, since otherwise the timer signal would
+ * keep going off in the child process and confusing everything. The interval
+ * timer no longer uses signals, so there is no need any more for libraries to
+ * disable the timer. Also, the timer internal API has changed.
+ */
+void stopTimer(void) { /* no-op */ }
+void startTimer(void) { /* no-op */ }
+
+void pauseTimer(void)
{
#if defined(HAVE_PREEMPTION)
- if (SEQ_CST_SUB_ALWAYS(&timer_disabled, 1) == 0) {
- if (RtsFlags.MiscFlags.tickInterval != 0) {
- startTicker();
- }
+ if (RtsFlags.MiscFlags.tickInterval != 0) {
+ pauseTicker();
}
#endif
}
-void
-stopTimer(void)
+void unpauseTimer(void)
{
#if defined(HAVE_PREEMPTION)
- if (SEQ_CST_ADD_ALWAYS(&timer_disabled, 1) == 1) {
- if (RtsFlags.MiscFlags.tickInterval != 0) {
- stopTicker();
- }
+ if (RtsFlags.MiscFlags.tickInterval != 0) {
+ unpauseTicker();
}
#endif
}
-void
-exitTimer (bool wait)
+void exitTimer (void)
{
#if defined(HAVE_PREEMPTION)
if (RtsFlags.MiscFlags.tickInterval != 0) {
- exitTicker(wait);
+ exitTicker();
}
#endif
}
=====================================
rts/Timer.h
=====================================
@@ -8,5 +8,12 @@
#pragma once
-RTS_PRIVATE void initTimer (void);
-RTS_PRIVATE void exitTimer (bool wait);
+#include "BeginPrivate.h"
+
+void initTimer(void);
+void exitTimer(void);
+
+void pauseTimer(void);
+void unpauseTimer(void);
+
+#include "EndPrivate.h"
=====================================
rts/eventlog/EventLog.c
=====================================
@@ -129,8 +129,11 @@ typedef struct _EventsBuf {
static EventsBuf *capEventBuf; // one EventsBuf for each Capability
static EventsBuf eventBuf; // an EventsBuf not associated with any Capability
-#if defined(THREADED_RTS)
-static Mutex eventBufMutex; // protected by this mutex
+#if defined(HAVE_PREEMPTION)
+// Note that this mutex is used even in the non-threaded RTS, since the timer
+// thread posts events and flushes. So _all_ uses of this mutex must use
+// ACQUIRE_LOCK_ALWAYS/RELEASE_LOCK_ALWAYS.
+Mutex eventBufMutex; // protects eventBuf above
#endif
// Event type
@@ -393,8 +396,10 @@ initEventLogging(void)
moreCapEventBufs(0, get_n_capabilities());
initEventsBuf(&eventBuf, EVENT_LOG_SIZE, (EventCapNo)(-1));
-#if defined(THREADED_RTS)
+#if defined(HAVE_PREEMPTION)
initMutex(&eventBufMutex);
+#endif
+#if defined(THREADED_RTS)
initMutex(&state_change_mutex);
#endif
}
@@ -416,7 +421,7 @@ startEventLogging_(void)
{
initEventLogWriter();
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
postHeaderEvents();
/*
@@ -425,7 +430,7 @@ startEventLogging_(void)
*/
printAndClearEventBuf(&eventBuf);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
return true;
}
@@ -495,7 +500,7 @@ endEventLogging(void)
flushEventLog_(NULL);
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
// Mark end of events (data).
postEventTypeNum(&eventBuf, EVENT_DATA_END);
@@ -503,7 +508,7 @@ endEventLogging(void)
// Flush the end of data marker.
printAndClearEventBuf(&eventBuf);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
stopEventLogWriter();
event_log_writer = NULL;
@@ -666,7 +671,7 @@ void
postCapEvent (EventTypeNum tag,
EventCapNo capno)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, tag);
postEventHeader(&eventBuf, tag);
@@ -685,14 +690,14 @@ postCapEvent (EventTypeNum tag,
barf("postCapEvent: unknown event tag %d", tag);
}
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postCapsetEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord info)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, tag);
postEventHeader(&eventBuf, tag);
@@ -726,7 +731,7 @@ void postCapsetEvent (EventTypeNum tag,
barf("postCapsetEvent: unknown event tag %d", tag);
}
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postCapsetStrEvent (EventTypeNum tag,
@@ -740,14 +745,14 @@ void postCapsetStrEvent (EventTypeNum tag,
return;
}
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
if (!hasRoomForVariableEvent(&eventBuf, size)){
printAndClearEventBuf(&eventBuf);
if (!hasRoomForVariableEvent(&eventBuf, size)){
errorBelch("Event size exceeds buffer size, bail out");
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
return;
}
}
@@ -758,7 +763,7 @@ void postCapsetStrEvent (EventTypeNum tag,
postBuf(&eventBuf, (StgWord8*) msg, strsize);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postCapsetVecEvent (EventTypeNum tag,
@@ -783,14 +788,14 @@ void postCapsetVecEvent (EventTypeNum tag,
}
}
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
if (!hasRoomForVariableEvent(&eventBuf, size)){
printAndClearEventBuf(&eventBuf);
if(!hasRoomForVariableEvent(&eventBuf, size)){
errorBelch("Event size exceeds buffer size, bail out");
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
return;
}
}
@@ -804,7 +809,7 @@ void postCapsetVecEvent (EventTypeNum tag,
postBuf(&eventBuf, (StgWord8*) argv[i], 1 + strlen(argv[i]));
}
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postWallClockTime (EventCapsetID capset)
@@ -813,7 +818,7 @@ void postWallClockTime (EventCapsetID capset)
StgWord64 sec;
StgWord32 nsec;
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
/* The EVENT_WALL_CLOCK_TIME event is intended to allow programs
reading the eventlog to match up the event timestamps with wall
@@ -846,7 +851,7 @@ void postWallClockTime (EventCapsetID capset)
postWord64(&eventBuf, sec);
postWord32(&eventBuf, nsec);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
/*
@@ -885,7 +890,7 @@ void postEventHeapInfo (EventCapsetID heap_capset,
W_ mblockSize,
W_ blockSize)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_HEAP_INFO_GHC);
postEventHeader(&eventBuf, EVENT_HEAP_INFO_GHC);
@@ -899,7 +904,7 @@ void postEventHeapInfo (EventCapsetID heap_capset,
postWord64(&eventBuf, mblockSize);
postWord64(&eventBuf, blockSize);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postEventGcStats (Capability *cap,
@@ -952,7 +957,7 @@ void postTaskCreateEvent (EventTaskId taskId,
EventCapNo capno,
EventKernelThreadId tid)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_TASK_CREATE);
postEventHeader(&eventBuf, EVENT_TASK_CREATE);
@@ -961,14 +966,14 @@ void postTaskCreateEvent (EventTaskId taskId,
postCapNo(&eventBuf, capno);
postKernelThreadId(&eventBuf, tid);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postTaskMigrateEvent (EventTaskId taskId,
EventCapNo capno,
EventCapNo new_capno)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_TASK_MIGRATE);
postEventHeader(&eventBuf, EVENT_TASK_MIGRATE);
@@ -977,28 +982,28 @@ void postTaskMigrateEvent (EventTaskId taskId,
postCapNo(&eventBuf, capno);
postCapNo(&eventBuf, new_capno);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postTaskDeleteEvent (EventTaskId taskId)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_TASK_DELETE);
postEventHeader(&eventBuf, EVENT_TASK_DELETE);
/* EVENT_TASK_DELETE (taskID) */
postTaskId(&eventBuf, taskId);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void
postEventNoCap (EventTypeNum tag)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, tag);
postEventHeader(&eventBuf, tag);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void
@@ -1042,9 +1047,9 @@ void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap)
void postMsg(char *msg, va_list ap)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
postLogMsg(&eventBuf, EVENT_LOG_MSG, msg, ap);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postCapMsg(Capability *cap, char *msg, va_list ap)
@@ -1138,32 +1143,32 @@ void postConcUpdRemSetFlush(Capability *cap)
void postConcMarkEnd(StgWord32 marked_obj_count)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_CONC_MARK_END);
postEventHeader(&eventBuf, EVENT_CONC_MARK_END);
postWord32(&eventBuf, marked_obj_count);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postNonmovingHeapCensus(uint16_t blk_size,
const struct NonmovingAllocCensus *census)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
postEventHeader(&eventBuf, EVENT_NONMOVING_HEAP_CENSUS);
postWord16(&eventBuf, blk_size);
postWord32(&eventBuf, census->n_active_segs);
postWord32(&eventBuf, census->n_filled_segs);
postWord32(&eventBuf, census->n_live_blocks);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postNonmovingPrunedSegments(uint32_t pruned_segments, uint32_t free_segments)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
postEventHeader(&eventBuf, EVENT_NONMOVING_PRUNED_SEGMENTS);
postWord32(&eventBuf, pruned_segments);
postWord32(&eventBuf, free_segments);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void closeBlockMarker (EventsBuf *ebuf)
@@ -1224,7 +1229,7 @@ static HeapProfBreakdown getHeapProfBreakdown(void)
void postHeapProfBegin(void)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
PROFILING_FLAGS *flags = &RtsFlags.ProfFlags;
StgWord modSelector_len =
flags->modSelector ? strlen(flags->modSelector) : 0;
@@ -1258,42 +1263,42 @@ void postHeapProfBegin(void)
postStringLen(&eventBuf, flags->ccsSelector, ccsSelector_len);
postStringLen(&eventBuf, flags->retainerSelector, retainerSelector_len);
postStringLen(&eventBuf, flags->bioSelector, bioSelector_len);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postHeapProfSampleBegin(StgInt era)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
postWord64(&eventBuf, era);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postHeapBioProfSampleBegin(StgInt era, StgWord64 time)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
postEventHeader(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
postWord64(&eventBuf, era);
postWord64(&eventBuf, time);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postHeapProfSampleEnd(StgInt era)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
postWord64(&eventBuf, era);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postHeapProfSampleString(const char *label,
StgWord64 residency)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
StgWord label_len = strlen(label);
StgWord len = 1+8+label_len+1;
CHECK(!ensureRoomForVariableEvent(&eventBuf, len));
@@ -1303,7 +1308,7 @@ void postHeapProfSampleString(const char *label,
postWord8(&eventBuf, 0);
postWord64(&eventBuf, residency);
postStringLen(&eventBuf, label, label_len);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
#if defined(PROFILING)
@@ -1313,7 +1318,7 @@ void postHeapProfCostCentre(StgWord32 ccID,
const char *srcloc,
StgBool is_caf)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
StgWord label_len = strlen(label);
StgWord module_len = strlen(module);
StgWord srcloc_len = strlen(srcloc);
@@ -1326,13 +1331,13 @@ void postHeapProfCostCentre(StgWord32 ccID,
postStringLen(&eventBuf, module, module_len);
postStringLen(&eventBuf, srcloc, srcloc_len);
postWord8(&eventBuf, is_caf);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void postHeapProfSampleCostCentre(CostCentreStack *stack,
StgWord64 residency)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
StgWord depth = 0;
CostCentreStack *ccs;
for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
@@ -1351,7 +1356,7 @@ void postHeapProfSampleCostCentre(CostCentreStack *stack,
depth>0 && ccs != NULL && ccs != CCS_MAIN;
ccs = ccs->prevStack, depth--)
postWord32(&eventBuf, ccs->cc->ccID);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
@@ -1359,7 +1364,7 @@ void postProfSampleCostCentre(Capability *cap,
CostCentreStack *stack,
StgWord64 tick)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
StgWord depth = 0;
CostCentreStack *ccs;
for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
@@ -1377,7 +1382,7 @@ void postProfSampleCostCentre(Capability *cap,
depth>0 && ccs != NULL && ccs != CCS_MAIN;
ccs = ccs->prevStack, depth--)
postWord32(&eventBuf, ccs->cc->ccID);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
// This event is output at the start of profiling so the tick interval can
@@ -1385,11 +1390,11 @@ void postProfSampleCostCentre(Capability *cap,
// can be calculated from how many samples there are.
void postProfBegin(void)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
postEventHeader(&eventBuf, EVENT_PROF_BEGIN);
// The interval that each tick was sampled, in nanoseconds
postWord64(&eventBuf, TimeToNS(RtsFlags.MiscFlags.tickInterval));
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
#endif /* PROFILING */
@@ -1415,11 +1420,11 @@ static void postTickyCounterDef(EventsBuf *eb, StgEntCounter *p)
void postTickyCounterDefs(StgEntCounter *counters)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
for (StgEntCounter *p = counters; p != NULL; p = p->link) {
postTickyCounterDef(&eventBuf, p);
}
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
static void postTickyCounterSample(EventsBuf *eb, StgEntCounter *p)
@@ -1443,13 +1448,13 @@ static void postTickyCounterSample(EventsBuf *eb, StgEntCounter *p)
void postTickyCounterSamples(StgEntCounter *counters)
{
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
ensureRoomForEvent(&eventBuf, EVENT_TICKY_COUNTER_SAMPLE);
postEventHeader(&eventBuf, EVENT_TICKY_COUNTER_BEGIN_SAMPLE);
for (StgEntCounter *p = counters; p != NULL; p = p->link) {
postTickyCounterSample(&eventBuf, p);
}
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
#endif /* TICKY_TICKY */
void postIPE(const InfoProvEnt *ipe)
@@ -1459,7 +1464,7 @@ void postIPE(const InfoProvEnt *ipe)
// See Note [Maximum event length].
const StgWord MAX_IPE_STRING_LEN = 65535;
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
StgWord table_name_len = MIN(strlen(ipe->prov.table_name), MAX_IPE_STRING_LEN);
StgWord closure_desc_len = MIN(strlen(closure_desc_buf), MAX_IPE_STRING_LEN);
StgWord ty_desc_len = MIN(strlen(ipe->prov.ty_desc), MAX_IPE_STRING_LEN);
@@ -1489,7 +1494,7 @@ void postIPE(const InfoProvEnt *ipe)
postBuf(&eventBuf, &colon, 1);
postStringLen(&eventBuf, ipe->prov.src_span, src_span_len);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
}
void printAndClearEventBuf (EventsBuf *ebuf)
@@ -1601,14 +1606,21 @@ void flushLocalEventsBuf(Capability *cap)
// Flush all capabilities' event buffers when we already hold all capabilities.
// Used during forkProcess.
void flushAllCapsEventsBufs(void)
+{
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
+ flushAllCapsEventsBufs_();
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
+}
+
+// Unafe version that does not acquire/release eventBufMutex. You must
+// already hold the eventBufMutex, which you must do with ACQUIRE_LOCK_ALWAYS!
+void flushAllCapsEventsBufs_(void)
{
if (!event_log_writer) {
return;
}
- ACQUIRE_LOCK(&eventBufMutex);
printAndClearEventBuf(&eventBuf);
- RELEASE_LOCK(&eventBufMutex);
for (unsigned int i=0; i < getNumCapabilities(); i++) {
flushLocalEventsBuf(getCapability(i));
@@ -1641,9 +1653,9 @@ static void flushEventLog_(Capability **cap USED_IF_THREADS)
return;
}
- ACQUIRE_LOCK(&eventBufMutex);
+ ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
printAndClearEventBuf(&eventBuf);
- RELEASE_LOCK(&eventBufMutex);
+ RELEASE_LOCK_ALWAYS(&eventBufMutex);
#if defined(THREADED_RTS)
Task *task = newBoundTask();
=====================================
rts/eventlog/EventLog.h
=====================================
@@ -18,6 +18,13 @@
#if defined(TRACING)
extern bool eventlog_enabled;
+#if defined(HAVE_PREEMPTION)
+// Avoid using this mutex directly if at all possible. It is needed in the
+// implementation of forkProcess.
+//
+// All uses of this mutex must use ACQUIRE_LOCK_ALWAYS/RELEASE_LOCK_ALWAYS.
+extern Mutex eventBufMutex;
+#endif
void initEventLogging(void);
void restartEventLogging(void);
@@ -27,6 +34,7 @@ void abortEventLogging(void); // #4512 - after fork child needs to abort
void moreCapEventBufs (uint32_t from, uint32_t to);
void flushLocalEventsBuf(Capability *cap);
void flushAllCapsEventsBufs(void);
+void flushAllCapsEventsBufs_(void);
void flushAllEventsBufs(Capability *cap);
typedef void (*EventlogInitPost)(void);
=====================================
rts/include/rts/OSThreads.h
=====================================
@@ -14,6 +14,40 @@
#pragma once
+/* Note [Threads and preemption]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ All full-fat OSs that GHC works on have OS threads, and we use them even in
+ the non-threaded RTS for a few features:
+ * Haskell thread preemption;
+ * sample-based profiling;
+ * idle GC;
+ * periodic eventlog flushing.
+
+ We use defined(HAVE_PREEMPTION) to decide if these features are implemented
+ via OS threads.
+
+ On platforms like WASM/js we do not have OS threads in any conventional
+ sense, and the features above are either not available or are implemented
+ differently. See Note [No timer on wasm32].
+
+ In future if GHC is ported to platforms like bare-metal micro-controllers,
+ RTOSs or to run directly under hypervisors then such platforms may also not
+ have threads available and they should not define HAVE_PREEMPTION here. Or
+ for some micro-controller RTOSs like Zeypher one may have a choice about
+ whether to use threads or not (at a size cost). Here would be the right
+ place to control whether the feature list above is supported.
+ */
+#if defined(wasm32_HOST_ARCH)
+ // See Note [No timer on wasm32]
+ // To confuse matters, WASM _does_ have pthread.h but it doesnt work.
+#elif defined(HAVE_PTHREAD_H) || defined(HAVE_WINDOWS_H)
+#define HAVE_PREEMPTION
+#else
+#error Decide if this platform has threads and pre-emption or not.
+#endif
+// And JS does all of this differently, without using this bit of the RTS.
+
+
#if defined(HAVE_PTHREAD_H) && !defined(mingw32_HOST_OS)
#if defined(CMINUSMINUS)
@@ -210,9 +244,29 @@ extern bool timedWaitCondition ( Condition* pCond, Mutex* pMut, Time timeout)
//
// Mutexes
//
+// Even in the non-threaded RTS we use threads and mutexes! In particular the
+// timer/ticker is implemented using a thread. And using threads needs locks.
+// In particular we need locks for the data shared between the timer/ticker
+// thread and the thread running the main capability.
+#if defined(HAVE_PREEMPTION)
extern void initMutex ( Mutex* pMut );
extern void closeMutex ( Mutex* pMut );
+// The "always" variants do locking in the threaded and non-threaded RTS.
+// The normal variants below are no-ops in the non-threaded RTS.
+#define ACQUIRE_LOCK_ALWAYS(l) OS_ACQUIRE_LOCK(l)
+#define TRY_ACQUIRE_LOCK_ALWAYS(l) OS_TRY_ACQUIRE_LOCK(l)
+#define RELEASE_LOCK_ALWAYS(l) OS_RELEASE_LOCK(l)
+#define ASSERT_LOCK_HELD_ALWAYS(l) OS_ASSERT_LOCK_HELD(l)
+#else
+// And just to be a bit confusing, the always variants are still no-ops when we
+// do not HAVE_PREEMPTION, since then we don't have threads or mutexes at all.
+#define ACQUIRE_LOCK_ALWAYS(l)
+#define TRY_ACQUIRE_LOCK_ALWAYS(l) 0
+#define RELEASE_LOCK_ALWAYS(l)
+#define ASSERT_LOCK_HELD_ALWAYS(l)
+#endif
+
// Processors and affinity
void setThreadAffinity (uint32_t n, uint32_t m);
void setThreadNode (uint32_t node);
@@ -228,6 +282,7 @@ void releaseThreadNode (void);
#else
+// No-ops in the non-threaded RTS. See also the _ALWAYS variants above.
#define ACQUIRE_LOCK(l)
#define TRY_ACQUIRE_LOCK(l) 0
#define RELEASE_LOCK(l)
=====================================
rts/include/rts/Timer.h
=====================================
@@ -13,6 +13,6 @@
#pragma once
-void startTimer (void);
-void stopTimer (void);
+void startTimer (void); // Deprecated: see issue #27086
+void stopTimer (void); // Deprecated: see issue #27086
int rtsTimerSignal (void); // Deprecated: see issue #27073
=====================================
rts/posix/Ticker.c
=====================================
@@ -103,120 +103,139 @@
#include <unistd.h>
#include <fcntl.h>
-static Time itimer_interval = DEFAULT_TICK_INTERVAL;
+static Time ticker_interval = DEFAULT_TICK_INTERVAL;
-// Should we be firing ticks?
-// Writers to this must hold the mutex below.
-static bool stopped = false;
+// Atomic variable used by client threads to communicate that they want the
+// ticker thread to pause. This communication is one-way, with no
+// acknowledgement.
+static bool pause_request;
-// should the ticker thread exit?
-// This can be set without holding the mutex.
-static bool exited = true;
+// Atomic variable used by other threads to communicate that they want the
+// ticker thread to exit.
+static bool exit_request;
+// Used to wait for the ticker thread to terminate after asking it to exit.
+static OSThreadId ticker_thread_id;
-// Signaled when we want to (re)start the timer
-static Condition start_cond;
-static Mutex mutex;
-static OSThreadId thread;
+// Fds used with sendFdWakeup to notify the ticker thread that any of the
+// *_request variables above have been set.
+static int notifyfd_r = -1, notifyfd_w = -1;
-// fds for interrupting the ticker
-static int interruptfd_r = -1, interruptfd_w = -1;
-static void *itimer_thread_func(void *_handle_tick)
+// Asynchronous request. Idempotent.
+void pauseTicker(void)
{
- TickProc handle_tick = _handle_tick;
-
-#if defined(HAVE_DECL_PPOLL) && HAVE_DECL_PPOLL == 1
- struct pollfd pollfds[1];
+ RELEASE_STORE_ALWAYS(&pause_request, true);
+ sendFdWakeup(notifyfd_w);
+}
- pollfds[0].fd = interruptfd_r;
- pollfds[0].events = POLLIN;
+// Asynchronous request. Idempotent.
+void unpauseTicker(void)
+{
+ RELEASE_STORE_ALWAYS(&pause_request, false);
+ sendFdWakeup(notifyfd_w);
+}
- struct timespec ts = { .tv_sec = TimeToSeconds(itimer_interval)
- , .tv_nsec = TimeToNS(itimer_interval) % 1000000000
- };
-#else
- fd_set selectfds;
- FD_ZERO(&selectfds);
- FD_SET(interruptfd_r, &selectfds);
-
- struct timeval tv = { .tv_sec = TimeToSeconds(itimer_interval)
- /* convert remainder time in nanoseconds
- to microseconds, rounding up: */
- , .tv_usec = ((TimeToNS(itimer_interval) % 1000000000)
- + 999) / 1000
- };
-#endif
+// Synchronous. Not idempotent.
+// The ticker is guaranteed stopped after this.
+void exitTicker(void)
+{
+ ASSERT(!RELAXED_LOAD_ALWAYS(&exit_request));
+ RELEASE_STORE_ALWAYS(&exit_request, true);
+ sendFdWakeup(notifyfd_w);
- // Relaxed is sufficient: If we don't see that exited was set in one iteration we will
- // see it next time.
- while (!RELAXED_LOAD_ALWAYS(&exited)) {
+ // wait for ticker thread to terminate
+ if (pthread_join(ticker_thread_id, NULL)) {
+ sysErrorBelch("Ticker: Failed to join: %s", strerror(errno));
+ }
+ closeFdWakeup(notifyfd_r, notifyfd_w);
+}
#if defined(HAVE_DECL_PPOLL) && HAVE_DECL_PPOLL == 1
- int nfds = 1;
- int nready = ppoll(pollfds, nfds, &ts, NULL);
+typedef struct timespec timeout; // for ppoll()
+typedef struct { struct pollfd pollfds[1]; } fdset;
#else
- struct timeval tv_tmp = tv; // copy since select may change this value.
- int nfds = interruptfd_r+1;
- int nready = select(nfds, &selectfds, NULL, NULL, &tv_tmp);
+typedef struct timeval timeout; // for select()
+typedef struct { int fd; fd_set selectfds; } fdset; // need to stash fd
#endif
- // In either case (ppoll or select), the result nready is the number
- // of fds that are ready.
- if (RTS_LIKELY(nready == 0)) {
- // Timer expired, not interrupted, continue.
- } else if (nready > 0) {
- // We only monitor one fd (the interruptfd_r), so we know
- // it is that fd that is ready without any further checks.
- collectFdWakeup(interruptfd_r);
- // No further action needed, continue on to handling the final tick
- // and then stop.
-
- // Note that we rely on sendFdWakeup and select/poll to provide the
- // happens-before relation. So if 'exited' was set before calling
- // sendFdWakeup, then we should be able to reliably read it after.
- // And thus reading 'exited' in the while loop guard is ok.
+
+// local helpers, to hide the difference between ppoll() and select()
+static void poll_init_timeout(timeout *tv, Time t);
+static void poll_init_fdset(fdset *fds, int fd); // single fd only
+// These two return: >0 if fd ready, ==0 if timeout, <0 if error
+static int poll_no_timeout(fdset *fdset);
+static int poll_with_timeout(fdset *fdset, timeout *t);
+
+static void *ticker_thread_func(void *_handle_tick)
+{
+ TickProc handle_tick = _handle_tick;
+
+ // Thread-local view of our state. We compare these with the corresponding
+ // atomic shared variables used to request state changes.
+ bool paused = true; // updated from atomic shared var pause_request
+ bool exit = false; // updated from atomic shared var exit_request
+ // Note that we start paused.
+
+ timeout timeout;
+ fdset fdset;
+ poll_init_timeout(&timeout, ticker_interval);
+ poll_init_fdset(&fdset, notifyfd_r);
+
+ while (!exit) {
+
+ int notify;
+ if (paused) {
+ notify = poll_no_timeout(&fdset);
} else {
- // While the RTS attempts to mask signals, some foreign libraries
- // that rely on signal delivery may unmask them. Consequently we
- // may see EINTR. See #24610.
- if (errno != EINTR) {
- sysErrorBelch("Ticker: poll failed: %s", strerror(errno));
- }
+ notify = poll_with_timeout(&fdset, &timeout);
}
- // first try a cheap test
- if (RELAXED_LOAD_ALWAYS(&stopped)) {
- OS_ACQUIRE_LOCK(&mutex);
- // should we really stop?
- if (stopped) {
- waitCondition(&start_cond, &mutex);
- }
- OS_RELEASE_LOCK(&mutex);
- } else {
+ if (RTS_LIKELY(notify == 0)) {
+ // The time expired, no state change notification.
handle_tick(0);
+
+ } else if (notify > 0) {
+ // State change notification, check the request variables.
+
+ // We rely on sendFdWakeup and select/poll to provide the
+ // happens-before relation. So if the request variables are set
+ // before calling sendFdWakeup, then we should be able to reliably
+ // read them here afterwards.
+ collectFdWakeup(notifyfd_r);
+
+ paused = ACQUIRE_LOAD_ALWAYS(&pause_request);
+ exit = RELAXED_LOAD_ALWAYS(&exit_request);
+ } else if (errno != EINTR) {
+ // While the RTS attempts to mask signals, some foreign libraries
+ // that rely on signal delivery may unmask them. Consequently we
+ // may see EINTR. See #24610.
+ sysErrorBelch("Ticker: poll failed: %s", strerror(errno));
}
}
return NULL;
}
+/* Initialise the ticker on startup or re-initialise the ticker after a fork().
+ * In the fork case, the thread will not be present, but fds are inherited.
+ *
+ * The ticker is started in the paused state. Use unpauseTicker to continue.
+ */
void
initTicker (Time interval, TickProc handle_tick)
{
- itimer_interval = interval;
- stopped = true;
- exited = false;
+ ticker_interval = interval;
+ pause_request = true;
+ exit_request = false;
+
#if defined(HAVE_SIGNAL_H)
sigset_t mask, omask;
int sigret;
#endif
int ret;
- initCondition(&start_cond);
- initMutex(&mutex);
-
/* Open the interrupt fd synchronously.
*
- * We used to do it in itimer_thread_func (i.e. in the timer thread) but it
+ * We used to do it in ticker_thread_func (i.e. in the timer thread) but it
* meant that some user code could run before it and get confused by the
* allocation of the timerfd.
*
@@ -226,11 +245,11 @@ initTicker (Time interval, TickProc handle_tick)
* descriptor closed by the first call! (see #20618)
*/
- if (interruptfd_r != -1) {
+ if (notifyfd_r != -1) {
// don't leak the old file descriptors after a fork (#25280)
- closeFdWakeup(interruptfd_r, interruptfd_w);
+ closeFdWakeup(notifyfd_r, notifyfd_w);
}
- newFdWakeup(&interruptfd_r, &interruptfd_w);
+ newFdWakeup(¬ifyfd_r, ¬ifyfd_w);
/*
* Create the thread with all blockable signals blocked, leaving signal
@@ -242,7 +261,7 @@ initTicker (Time interval, TickProc handle_tick)
sigfillset(&mask);
sigret = pthread_sigmask(SIG_SETMASK, &mask, &omask);
#endif
- ret = createAttachedOSThread(&thread, "ghc_ticker", itimer_thread_func, (void*)handle_tick);
+ ret = createAttachedOSThread(&ticker_thread_id, "ghc_ticker", ticker_thread_func, (void*)handle_tick);
#if defined(HAVE_SIGNAL_H)
if (sigret == 0)
pthread_sigmask(SIG_SETMASK, &omask, NULL);
@@ -253,47 +272,65 @@ initTicker (Time interval, TickProc handle_tick)
}
}
-void
-startTicker(void)
+/* Implementation of the local helpers, to hide the difference between ppoll()
+ * and select().
+ */
+#if defined(HAVE_DECL_PPOLL) && HAVE_DECL_PPOLL == 1
+static void poll_init_timeout(timeout *tv, Time t)
{
- OS_ACQUIRE_LOCK(&mutex);
- RELAXED_STORE(&stopped, false);
- signalCondition(&start_cond);
- OS_RELEASE_LOCK(&mutex);
+ tv->tv_sec = TimeToSeconds(t);
+ tv->tv_nsec = TimeToNS(t) % 1000000000;
}
-/* There may be at most one additional tick fired after a call to this */
-void
-stopTicker(void)
+static void poll_init_fdset(fdset *fds, int fd)
{
- OS_ACQUIRE_LOCK(&mutex);
- RELAXED_STORE(&stopped, true);
- OS_RELEASE_LOCK(&mutex);
+ fds->pollfds[0].fd = fd;
+ fds->pollfds[0].events = POLLIN;
}
-/* There may be at most one additional tick fired after a call to this */
-void
-exitTicker (bool wait)
+static int poll_no_timeout(fdset *fds)
{
- ASSERT(!SEQ_CST_LOAD(&exited));
- SEQ_CST_STORE(&exited, true);
- // ensure that ticker wakes up if stopped
- startTicker();
- sendFdWakeup(interruptfd_w);
-
- // wait for ticker to terminate if necessary
- if (wait) {
- if (pthread_join(thread, NULL)) {
- sysErrorBelch("Ticker: Failed to join: %s", strerror(errno));
- }
- closeFdWakeup(interruptfd_r, interruptfd_w);
- closeMutex(&mutex);
- closeCondition(&start_cond);
- } else {
- pthread_detach(thread);
- }
+ int nfds = 1;
+ return ppoll(fds->pollfds, nfds, NULL, NULL);
+}
+
+static int poll_with_timeout(fdset *fds, timeout *ts)
+{
+ int nfds = 1;
+ return ppoll(fds->pollfds, nfds, ts, NULL);
}
+#else // select()
+
+static void poll_init_timeout(timeout *tv, Time t)
+{
+ tv->tv_sec = TimeToSeconds(t);
+ /* convert remainder time in nanoseconds to microseconds, rounding up: */
+ tv->tv_usec = ((TimeToNS(t) % 1000000000) + 999) / 1000;
+}
+
+static void poll_init_fdset(fdset *fds, int fd)
+{
+ FD_ZERO(&fds->selectfds);
+ FD_SET(fd, &fds->selectfds);
+ fds->fd = fd;
+}
+
+static int poll_no_timeout(fdset *fds)
+{
+ int nfds = fds->fd+1;
+ return select(nfds, &fds->selectfds, NULL, NULL, NULL);
+}
+
+static int poll_with_timeout(fdset *fds, timeout *tv)
+{
+ struct timeval tv_tmp = *tv; // copy since select may change this value.
+ int nfds = fds->fd+1;
+ return select(nfds, &fds->selectfds, NULL, NULL, &tv_tmp);
+}
+#endif
+
+/* This is obsolete, but is used in the unix package for now */
int
rtsTimerSignal(void)
{
=====================================
rts/win32/Ticker.c
=====================================
@@ -9,10 +9,13 @@
#include <stdio.h>
#include <process.h>
+static Time tick_interval = 0;
static TickProc tick_proc = NULL;
+
+static Mutex lock; // To protect the timer and state vars below
static HANDLE timer_queue = NULL;
static HANDLE timer = NULL;
-static Time tick_interval = 0;
+static bool paused;
static VOID CALLBACK tick_callback(
PVOID lpParameter STG_UNUSED,
@@ -39,9 +42,12 @@ static VOID CALLBACK tick_callback(
void
initTicker (Time interval, TickProc handle_tick)
{
+ ASSERT(timer_queue == NULL);
tick_interval = interval;
tick_proc = handle_tick;
+ OS_INIT_LOCK(&lock);
+ paused = true; // starts paused
timer_queue = CreateTimerQueue();
if (timer_queue == NULL) {
sysErrorBelch("CreateTimerQueue");
@@ -49,39 +55,78 @@ initTicker (Time interval, TickProc handle_tick)
}
}
-void
-startTicker(void)
-{
- BOOL r;
-
- r = CreateTimerQueueTimer(&timer,
- timer_queue,
- tick_callback,
- 0,
- 0,
- TimeToMS(tick_interval), // ms
- WT_EXECUTEINTIMERTHREAD);
+static void startTicker(void) {
+ ASSERT(timer_queue != NULL && timer == NULL);
+ DWORD interval = TimeToMS(tick_interval); // ms
+ BOOL r = CreateTimerQueueTimer(&timer,
+ timer_queue,
+ tick_callback,
+ NULL, // callback param
+ interval, // inital interval
+ interval, // recurrant interval
+ WT_EXECUTEINTIMERTHREAD);
+ //TODO: using WT_EXECUTEINTIMERTHREAD is fine for context switching, and
+ // plausibly also ok for profile sampling but is way out for eventlog
+ // flushing. The eventlog flush does a global synchronisation of all
+ // capabilities and I/O! And with eventlog providers, it calls arbitrary
+ // user code. This is not ok! See issue #27250.
if (r == 0) {
sysErrorBelch("CreateTimerQueueTimer");
stg_exit(EXIT_FAILURE);
}
+ ASSERT(timer != NULL);
}
-void
-stopTicker(void)
+static void stopTicker(bool synchronous) {
+ ASSERT(timer_queue != NULL && timer != NULL);
+ // From the docs for DeleteTimerQueueTimer:
+ // If this parameter is INVALID_HANDLE_VALUE, the function waits for any
+ // running timer callback functions to complete before returning.
+ HANDLE completion = synchronous ? INVALID_HANDLE_VALUE : NULL;
+ DeleteTimerQueueTimer(timer_queue, timer, completion);
+ timer = NULL;
+}
+
+// Asynchronous. Idempotent.
+void pauseTicker(void)
{
- if (timer_queue != NULL && timer != NULL) {
- DeleteTimerQueueTimer(timer_queue, timer, NULL);
- timer = NULL;
+ OS_ACQUIRE_LOCK(&lock);
+ if (!paused) {
+ /* pauseTicker is called from within the handle_tick, so stopping
+ * the ticker here /must/ be asynchronous or we will deadlock! */
+ stopTicker(false /* asynchronous */);
}
+ paused = true;
+ OS_RELEASE_LOCK(&lock);
}
-void
-exitTicker (bool wait)
+// Asynchronous. Idempotent.
+void unpauseTicker(void)
+{
+ OS_ACQUIRE_LOCK(&lock);
+ if (paused) {
+ startTicker();
+ }
+ paused = false;
+ OS_RELEASE_LOCK(&lock);
+}
+
+void exitTicker(void)
{
- stopTicker();
- if (timer_queue != NULL) {
- DeleteTimerQueueEx(timer_queue, wait ? INVALID_HANDLE_VALUE : NULL);
- timer_queue = NULL;
+ ASSERT(timer_queue != NULL);
+
+ OS_ACQUIRE_LOCK(&lock);
+ if (!paused) {
+ stopTicker(true /* synchronous */);
}
+ OS_RELEASE_LOCK(&lock);
+
+ // From the docs for DeleteTimerQueueEx:
+ // If this parameter is INVALID_HANDLE_VALUE, the function waits
+ // for all callback functions to complete before returning.
+ // This is a belt-and-braces approach to ensuring exitTicker is synchronous,
+ // since stopTicker(true) is already synchronous and there's only one timer.
+ HANDLE completion = INVALID_HANDLE_VALUE;
+ DeleteTimerQueueEx(timer_queue, completion);
+ timer_queue = NULL;
}
=====================================
testsuite/tests/concurrent/should_run/T27105.hs
=====================================
@@ -0,0 +1,114 @@
+{-# OPTIONS_GHC -fno-omit-yields #-}
+
+import Control.Monad
+import Control.Monad.ST
+import Control.Concurrent
+import Control.Exception
+import System.Exit
+import System.Mem
+import GHC.Arr
+import Prelude hiding (init)
+
+-- Test thread fairness:
+-- run two cpu-bound threads concurrently for a second,
+-- each counts how many operations it can perform until signaled to stop
+-- expect a balance between the two with no more than a 75% imperfection.
+-- Yes, 75%! On the CI machines we occasionally observe extraordinary levels
+-- of unfairness: nearly 60% in some cases. We don't want this to become a
+-- fragile test that is ignored, so we use an extreme bound. This should still
+-- catch gross breakage.
+--
+-- This _should_ detect if the interval timer is not working, or if thread
+-- context switching is messed up. We can expect failure if we force a
+-- contex switch interval of more than half the test time, i.e. more than 0.5s
+--
+-- We run the test twice, with allocating and non-allocating worker threads.
+-- The -fno-omit-yields above is crucial for worker_nonalloc below, or it never
+-- gets interrupted and thus no context switches.
+
+main :: IO ()
+main = do
+ test worker_alloc
+ performMajorGC
+ test worker_nonalloc
+
+test :: Worker -> IO ()
+test worker = do
+ stop <- newEmptyMVar
+ res1 <- newEmptyMVar
+ res2 <- newEmptyMVar
+ _ <- forkIO (worker stop >>= putMVar res1)
+ _ <- forkIO (worker stop >>= putMVar res2)
+ threadDelay 300_000
+ -- Let them run for 300ms. The default context switch interval is 20ms.
+ -- This gives time for 15 context switches, so this _should_ be enough
+ -- to get less than 10% unfairness. And on most platforms it is enough.
+ -- But OSX! Oh OSX! How do I loath thee? Let me count++ the ways.
+ -- To avoid a fragile test, we use a 75% unfairness threshold.
+ putMVar stop ()
+ count1 <- takeMVar res1
+ count2 <- takeMVar res2
+ let balance :: Double
+ balance = abs ((fromIntegral count1 - fromIntegral count2)
+ / fromIntegral count2)
+ when (balance > 0.75) $ do
+ putStrLn "Schedule fairness more than 75% tolerance:"
+ putStrLn $ "imperfection: " ++ show (balance * 100) ++ "%"
+ putStrLn $ "work counts: " ++ show (count1, count2)
+ exitFailure
+
+type Worker = MVar () -> IO Int
+
+-- count how many iterations we can calculate until we're signaled to stop
+worker_template :: IO a -> (a -> IO ()) -> MVar () -> IO Int
+worker_template init iter stop = do
+ a <- init
+ go a 0
+ where
+ go a !count = do
+ ok <- tryReadMVar stop
+ case ok of
+ Just () -> return count
+ Nothing -> do
+ iter a
+ go a (count + 1)
+
+
+-- the allocating worker
+{-# NOINLINE worker_alloc #-}
+worker_alloc :: Worker
+worker_alloc =
+ worker_template
+ (return 18)
+ (\n -> evaluate (fib n) >> return ())
+
+-- by forcing this to be Integer we cause lots of allocation!
+fib :: Integer -> Integer
+fib 0 = 0
+fib 1 = 1
+fib n = fib (n-1) + fib (n-2)
+
+
+-- the non-allocating worker
+{-# NOINLINE worker_nonalloc #-}
+worker_nonalloc :: Worker
+worker_nonalloc =
+ worker_template
+ (stToIO $ newSTArray (0,50_000) 42)
+ (\arr -> stToIO $ arrrev arr)
+
+arrrev :: STArray s Int Int -> ST s ()
+arrrev arr =
+ let (i,j) = boundsSTArray arr
+ in arrrev_go arr i j
+
+{-# NOINLINE arrrev_go #-}
+arrrev_go :: STArray s Int Int -> Int -> Int -> ST s ()
+arrrev_go !_ !i !j | i >= j = return ()
+arrrev_go !arr !i !j = do
+ x <- readSTArray arr i
+ y <- readSTArray arr j
+ writeSTArray arr i y
+ writeSTArray arr j x
+ arrrev_go arr (i+1) (j-1)
+
=====================================
testsuite/tests/concurrent/should_run/all.T
=====================================
@@ -325,3 +325,15 @@ test('T26341b'
# test uses pipe operations which are not supported by the JS/wasm backends
, when(arch('wasm32') or arch('javascript'), skip)
, compile_and_run, ['-package process'])
+
+# Scheduler (very rough) fairness
+test('T27105',
+ [when(arch('wasm32'), skip), # same reason as T367_letnoescape
+ run_timeout_multiplier(0.05)], # we expect this to run for ~2s
+ compile_and_run, [''])
+test('T27105_fail',
+ [when(arch('wasm32'), skip),
+ # And we can expect it to fail if we context switch too coarsely
+ extra_run_opts('+RTS -C0.2 -RTS'), expect_fail,
+ run_timeout_multiplier(0.05)],
+ multimod_compile_and_run, ['T27105.hs', ''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/fd599caf29868ac3dc39b01dd32dd0…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/fd599caf29868ac3dc39b01dd32dd0…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/sjakobi/T26964] 2 commits: StgToCmm: store the current primop name as a FastString
by Simon Jakobi (@sjakobi2) 07 Jun '26
by Simon Jakobi (@sjakobi2) 07 Jun '26
07 Jun '26
Simon Jakobi pushed to branch wip/sjakobi/T26964 at Glasgow Haskell Compiler / GHC
Commits:
e403294f by Simon Jakobi at 2026-06-07T13:51:08+02:00
StgToCmm: store the current primop name as a FastString
fcs_prim_op now holds a Maybe FastString rather than a Maybe String. The
name comes straight from occNameFS (primOpOcc primop) — an already-interned
FastString — and is emitted via newByteStringCLit (bytesFS name), avoiding
the previous unpackFS/BS8.pack round-trip on every bounds-checked primop.
Also shortens the emitBoundsCheckFailed doc comment.
- - - - -
d841fc91 by Simon Jakobi at 2026-06-07T13:59:21+02:00
StgToCmm: build the module-name CLit straight from its FastString
getCurrentModuleCLit now reads the bare module name via
moduleNameFS (moduleName mod) and emits it with newByteStringCLit (bytesFS …),
dropping the ppr/renderWithContext/getContext pretty-printer round-trip and the
String repack. The module being reported is always stgToCmmThisModule (the home
module), which ppr never qualifies, so the rendered text is unchanged.
- - - - -
2 changed files:
- compiler/GHC/StgToCmm/Monad.hs
- compiler/GHC/StgToCmm/Prim.hs
Changes:
=====================================
compiler/GHC/StgToCmm/Monad.hs
=====================================
@@ -305,7 +305,7 @@ data FCodeState =
-- See Note [Self-recursive tail calls] in GHC.StgToCmm.Expr
, fcs_ticky :: !CLabel -- ^ Destination for ticky counts
, fcs_tickscope :: !CmmTickScope -- ^ Tick scope for new blocks & ticks
- , fcs_prim_op :: Maybe String -- ^ Source name of the primop currently being
+ , fcs_prim_op :: Maybe FastString -- ^ Source name of the primop currently being
-- compiled, used by -fcheck-prim-bounds error
-- messages.
}
@@ -531,10 +531,10 @@ setTickyCtrLabel ticky code = do
-- | The source name of the primop currently being compiled (e.g.
-- @"writeArray#"@), if any. Used to produce informative @-fcheck-prim-bounds@
-- error messages.
-getCurrentPrimOpName :: FCode (Maybe String)
+getCurrentPrimOpName :: FCode (Maybe FastString)
getCurrentPrimOpName = fcs_prim_op <$> getFCodeState
-withCurrentPrimOpName :: String -> FCode a -> FCode a
+withCurrentPrimOpName :: FastString -> FCode a -> FCode a
withCurrentPrimOpName name code = do
fstate <- getFCodeState
withFCodeState code (fstate {fcs_prim_op = Just name})
=====================================
compiler/GHC/StgToCmm/Prim.hs
=====================================
@@ -25,19 +25,19 @@ import GHC.StgToCmm.Layout
import GHC.StgToCmm.Foreign
import GHC.StgToCmm.Monad
import GHC.StgToCmm.Utils
-import GHC.StgToCmm.Lit ( newStringCLit )
+import GHC.StgToCmm.Lit ( newByteStringCLit )
import GHC.StgToCmm.Ticky
import GHC.StgToCmm.Heap
import GHC.StgToCmm.Prof ( costCentreFrom )
import GHC.Types.Basic
-import GHC.Types.Name.Occurrence ( occNameString )
+import GHC.Types.Name.Occurrence ( occNameFS )
import GHC.Types.Literal.Floating
import GHC.Cmm.BlockId
import GHC.Cmm.Graph
import GHC.Stg.Syntax
import GHC.Cmm
-import GHC.Unit ( rtsUnit )
+import GHC.Unit ( rtsUnit, moduleName, moduleNameFS )
import GHC.Core.Type ( Type, tyConAppTyCon_maybe )
import GHC.Core.TyCon
import GHC.Cmm.CLabel
@@ -101,7 +101,7 @@ cmmPrimOpApp cfg primop cmm_args mres_ty = do
-- error message. Guarded by the flag so that the common (unchecked) case pays
-- nothing: no name thunk, no FCodeState update.
if stgToCmmDoBoundsCheck cfg
- then withCurrentPrimOpName (occNameString (primOpOcc primop)) (f res_ty)
+ then withCurrentPrimOpName (occNameFS (primOpOcc primop)) (f res_ty)
else f res_ty
externalPrimop :: PrimOp -> [CmmExpr] -> PrimopCmmEmit
@@ -3623,8 +3623,8 @@ emitCheckedMemcpyCall dst src n align = do
emitMemcpyCall dst src n align
where
doCheck platform = do
- name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
- nameLbl <- newStringCLit name
+ name <- fromMaybe (fsLit "<unknown primop>") <$> getCurrentPrimOpName
+ nameLbl <- newByteStringCLit (bytesFS name)
modLbl <- getCurrentModuleCLit
overlapCheckFailed <- getCode $
emitCCallNeverReturns []
@@ -3742,13 +3742,12 @@ whenCheckBounds a = do
False -> pure ()
True -> a
--- | Render the module currently being code-generated as a string literal, for
--- use in @-fcheck-prim-bounds@ failure diagnostics.
+-- | The bare name of the module currently being code-generated, as a string
+-- literal, for use in @-fcheck-prim-bounds@ failure diagnostics.
getCurrentModuleCLit :: FCode CmmLit
getCurrentModuleCLit = do
mod <- getModuleName
- ctx <- getContext
- newStringCLit (renderWithContext ctx (ppr mod))
+ newByteStringCLit (bytesFS (moduleNameFS (moduleName mod)))
-- | Emit a call to the RTS @rtsOutOfBoundsAccess@ bounds-check failure
-- handler, passing the offending index, element count, array size, primop name
@@ -3758,8 +3757,8 @@ emitBoundsCheckFailed :: CmmExpr -- ^ accessed index
-> CmmExpr -- ^ array size (in elements)
-> FCode ()
emitBoundsCheckFailed idx count sz = do
- name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
- nameLbl <- newStringCLit name
+ name <- fromMaybe (fsLit "<unknown primop>") <$> getCurrentPrimOpName
+ nameLbl <- newByteStringCLit (bytesFS name)
modLbl <- getCurrentModuleCLit
emitCCallNeverReturns []
(mkLblExpr mkOutOfBoundsAccessLabel)
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/31e87195be4ca01845dfd4f91cee81…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/31e87195be4ca01845dfd4f91cee81…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/sjakobi/T26964] Report the module in -fcheck-prim-bounds failures
by Simon Jakobi (@sjakobi2) 07 Jun '26
by Simon Jakobi (@sjakobi2) 07 Jun '26
07 Jun '26
Simon Jakobi pushed to branch wip/sjakobi/T26964 at Glasgow Haskell Compiler / GHC
Commits:
31e87195 by Simon Jakobi at 2026-06-07T13:24:59+02:00
Report the module in -fcheck-prim-bounds failures
A failing bounds-checked primop now reports the Haskell module being
compiled alongside the primop name and access details, e.g.
readSmallArray#: array access out of bounds in module Main:
index -1 is not within [0, 5).
The module string is rendered in StgToCmm from stgToCmmThisModule and
passed as an extra argument to the rtsOutOfBoundsAccess and
rtsMemcpyRangeOverlap RTS helpers. The DEBUG ASSERT_IN_BOUNDS path in
PrimOps.cmm has no user module and passes "<RTS>".
Adds a cross-module regression test (T26964Module) asserting the module
reported is the one containing the failing primop, not its caller.
- - - - -
10 changed files:
- compiler/GHC/StgToCmm/Prim.hs
- rts/PrimOps.cmm
- rts/RtsMessages.c
- rts/include/rts/Messages.h
- testsuite/tests/codeGen/should_fail/T26964.stderr
- + testsuite/tests/codeGen/should_fail/T26964Module.hs
- + testsuite/tests/codeGen/should_fail/T26964Module.stderr
- + testsuite/tests/codeGen/should_fail/T26964ModuleA.hs
- testsuite/tests/codeGen/should_fail/T26964b.stderr
- testsuite/tests/codeGen/should_fail/all.T
Changes:
=====================================
compiler/GHC/StgToCmm/Prim.hs
=====================================
@@ -3625,10 +3625,12 @@ emitCheckedMemcpyCall dst src n align = do
doCheck platform = do
name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
nameLbl <- newStringCLit name
+ modLbl <- getCurrentModuleCLit
overlapCheckFailed <- getCode $
emitCCallNeverReturns []
(mkLblExpr mkMemcpyRangeOverlapLabel)
- [ (CmmLit nameLbl, AddrHint) ]
+ [ (CmmLit nameLbl, AddrHint)
+ , (CmmLit modLbl, AddrHint) ]
emit =<< mkCmmIfThen' rangesOverlap overlapCheckFailed (Just False)
where
rangesOverlap = (checkDiff dst src `or` checkDiff src dst) `ne` zero
@@ -3740,11 +3742,17 @@ whenCheckBounds a = do
False -> pure ()
True -> a
+-- | Render the module currently being code-generated as a string literal, for
+-- use in @-fcheck-prim-bounds@ failure diagnostics.
+getCurrentModuleCLit :: FCode CmmLit
+getCurrentModuleCLit = do
+ mod <- getModuleName
+ ctx <- getContext
+ newStringCLit (renderWithContext ctx (ppr mod))
+
-- | Emit a call to the RTS @rtsOutOfBoundsAccess@ bounds-check failure
--- handler, passing the offending index, the number of accessed elements and
--- the array size, so that the runtime can produce an informative error
--- message. The name of the offending primop is read from the code generator
--- environment (see 'withCurrentPrimOpName').
+-- handler, passing the offending index, element count, array size, primop name
+-- (see 'withCurrentPrimOpName') and the module being compiled.
emitBoundsCheckFailed :: CmmExpr -- ^ accessed index
-> CmmExpr -- ^ number of accessed elements
-> CmmExpr -- ^ array size (in elements)
@@ -3752,12 +3760,14 @@ emitBoundsCheckFailed :: CmmExpr -- ^ accessed index
emitBoundsCheckFailed idx count sz = do
name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
nameLbl <- newStringCLit name
+ modLbl <- getCurrentModuleCLit
emitCCallNeverReturns []
(mkLblExpr mkOutOfBoundsAccessLabel)
[ (idx, NoHint)
, (count, NoHint)
, (sz, NoHint)
- , (CmmLit nameLbl, AddrHint) ]
+ , (CmmLit nameLbl, AddrHint)
+ , (CmmLit modLbl, AddrHint) ]
emitBoundsCheck :: CmmExpr -- ^ accessed index
-> CmmExpr -- ^ array size (in elements)
=====================================
rts/PrimOps.cmm
=====================================
@@ -93,7 +93,7 @@ import CLOSURE ghc_hs_iface;
// the index reported here may be in bytes. count is 1 since these checks cover
// a single access.
#define ASSERT_IN_BOUNDS(op, ind, sz) \
- if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op); }
+ if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op, "<RTS>"); }
#else
#define ASSERT_IN_BOUNDS(op, ind, sz)
#endif
=====================================
rts/RtsMessages.c
=====================================
@@ -352,32 +352,31 @@ rtsBadAlignmentBarf(void)
}
void
-rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op)
+rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module)
{
if (count <= 1) {
- errorBelch("%s: array access out of bounds:\n"
+ errorBelch("%s: array access out of bounds in module %s:\n"
" index %" FMT_Int " is not within [0, %" FMT_Word ").\n"
"This is usually caused by incorrect use of unsafe primops "
"in user or library code.",
- op, index, size);
+ op, module, index, size);
} else {
- errorBelch("%s: array access out of bounds:\n"
+ errorBelch("%s: array access out of bounds in module %s:\n"
" range of %" FMT_Word " elements starting at index %" FMT_Int
" is not within [0, %" FMT_Word ").\n"
"This is usually caused by incorrect use of unsafe primops "
"in user or library code.",
- op, count, index, size);
+ op, module, count, index, size);
}
stg_exit(EXIT_FAILURE);
}
void
-rtsMemcpyRangeOverlap(const char *op)
+rtsMemcpyRangeOverlap(const char *op, const char *module)
{
- errorBelch("%s: overlapping source and destination ranges in a "
- "memcpy-using operation.\n"
+ errorBelch("%s: overlapping source and destination ranges in module %s.\n"
"This is usually caused by incorrect use of unsafe primops "
"in user or library code.",
- op);
+ op, module);
stg_exit(EXIT_FAILURE);
}
=====================================
rts/include/rts/Messages.h
=====================================
@@ -108,5 +108,5 @@ extern RtsMsgFunction rtsSysErrorMsgFn;
/* Used by code generator */
void rtsBadAlignmentBarf(void) STG_NORETURN;
-void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op) STG_NORETURN;
-void rtsMemcpyRangeOverlap(const char *op) STG_NORETURN;
+void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module) STG_NORETURN;
+void rtsMemcpyRangeOverlap(const char *op, const char *module) STG_NORETURN;
=====================================
testsuite/tests/codeGen/should_fail/T26964.stderr
=====================================
@@ -1,3 +1,3 @@
-readSmallArray#: array access out of bounds:
+readSmallArray#: array access out of bounds in module Main:
index -1 is not within [0, 5).
This is usually caused by incorrect use of unsafe primops in user or library code.
=====================================
testsuite/tests/codeGen/should_fail/T26964Module.hs
=====================================
@@ -0,0 +1,6 @@
+module Main where
+
+import T26964ModuleA (bad)
+
+main :: IO ()
+main = bad
=====================================
testsuite/tests/codeGen/should_fail/T26964Module.stderr
=====================================
@@ -0,0 +1,3 @@
+readSmallArray#: array access out of bounds in module T26964ModuleA:
+ index -1 is not within [0, 5).
+This is usually caused by incorrect use of unsafe primops in user or library code.
=====================================
testsuite/tests/codeGen/should_fail/T26964ModuleA.hs
=====================================
@@ -0,0 +1,17 @@
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE MagicHash #-}
+
+-- The failing -fcheck-prim-bounds primop is emitted while code-generating this
+-- helper module, so the runtime diagnostic should report T26964ModuleA, not the
+-- Main module that merely calls 'bad'.
+
+module T26964ModuleA (bad) where
+
+import GHC.Exts
+import GHC.IO
+
+{-# NOINLINE bad #-}
+bad :: IO ()
+bad = IO $ \s0 ->
+ case newSmallArray# 5# () s0 of
+ (# s1, marr #) -> readSmallArray# marr (-1#) s1
=====================================
testsuite/tests/codeGen/should_fail/T26964b.stderr
=====================================
@@ -1,3 +1,3 @@
-copyMutableByteArray#: array access out of bounds:
+copyMutableByteArray#: array access out of bounds in module Main:
range of 4 elements starting at index 6 is not within [0, 8).
This is usually caused by incorrect use of unsafe primops in user or library code.
=====================================
testsuite/tests/codeGen/should_fail/all.T
=====================================
@@ -42,3 +42,9 @@ test('T26964',
test('T26964b',
[omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix)],
compile_and_run, ['-fcheck-prim-bounds'])
+# T26964Module checks that the reported module is the one containing the failing
+# primop (the helper T26964ModuleA), not the Main module that calls it.
+test('T26964Module',
+ [omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix),
+ extra_files(['T26964ModuleA.hs'])],
+ multimod_compile_and_run, ['T26964Module', '-fcheck-prim-bounds'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/31e87195be4ca01845dfd4f91cee810…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/31e87195be4ca01845dfd4f91cee810…
You're receiving this email because of your account on gitlab.haskell.org.
1
0