[Git][ghc/ghc][wip/T27737] Work in progress on modifying the Simplifier's FloatBinds
by Simon Peyton Jones (@simonpj) 08 Oct '26
by Simon Peyton Jones (@simonpj) 08 Oct '26
08 Oct '26
Simon Peyton Jones pushed to branch wip/T27737 at Glasgow Haskell Compiler / GHC
Commits:
c42c8498 by Simon Peyton Jones at 2026-10-08T16:17:13+01:00
Work in progress on modifying the Simplifier's FloatBinds
...in collaboration with Claude
- - - - -
2 changed files:
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Simplify/Env.hs
=====================================
@@ -45,7 +45,7 @@ module GHC.Core.Opt.Simplify.Env (
-- * LetFloats
LetFloats, FloatEnable(..), letFloatBinds, emptyLetFloats, unitLetFloat,
- addLetFlts, mapLetFloats,
+ unitCaseFloat, addLetFlts, mapLetFloats,
-- * JoinFloats
JoinFloat, JoinFloats, emptyJoinFloats,
@@ -65,7 +65,8 @@ import GHC.Core.Subst( substExprSC )
import GHC.Core.Unfold
import GHC.Core.TyCo.Subst (emptyIdSubstEnv, mkSubst)
import GHC.Core.Multiplicity( Scaled(..), mkMultMul )
-import GHC.Core.Make ( mkWildValBinder, mkCoreLet )
+import GHC.Core.Make ( mkWildValBinder )
+import qualified GHC.Core.Make
import GHC.Core.Type hiding ( substTy, substTyVar, substTyVarBndr, substCo
, extendTvSubst, extendCvSubst )
import qualified GHC.Core.Coercion as Coercion
@@ -760,10 +761,46 @@ Examples
NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy let-can-float invariant
NonRec x# (f y) FltCareful -- Might diverge; does not satisfy let-can-float invariant
+
+A binding that does not satisfy the let-can-float invariant (the last two
+examples above) is represented by a FloatCase, not a FloatLet:
+ FloatCase (a /# b) x# DEFAULT []
+That is done once and for all by `unitLetFloat`, so a FloatLet in a LetFloats
+is always a valid let-binding, and `wrapFloats` does not need to check.
+Such bindings can arise from `makeTrivial`, because an argument need not
+satisfy the let-can-float invariant. They also arise because
+exprOkForSpeculation is conservative: e.g. it says False for (# s, x #)
+where x is lifted, because it checks the arguments against the
+(representation-polymorphic) type of the unboxed-tuple worker.
+
+However, a FloatLet can still be FltCareful: the first FltCareful example
+above, NonRec x* (f y), where x* is lifted but has a strict demand
+(isStrUsedDmd). That is a perfectly valid (lazy) let-binding, but its demand
+info is valid only where it is. If we floated it out of the RHS of a lazy
+binding
+ let v = let x* = f y in x*+1 in body
+ ==> let x* = f y; v = x*+1 in body
+then x's demand info would be a lie, and CorePrep, which case-binds a let
+whose binder has a strict demand, would evaluate (f y) eagerly. Hence
+FltCareful, which doFloatFromRhs allows to float only out of a strict binding.
+
+As well as let-bindings, a LetFloats can contain single-alternative case
+floats (FloatCase), for example
+ case e of b { (# a, c #) -> <hole> }
+These are classified just like a strict binding:
+
+ FloatCase (y +# 3) b DEFAULT [] FltOkSpec -- Scrutinee ok-for-speculation
+ FloatCase (f y) b (# a,c #) [a,c] FltCareful -- Might fail or diverge
+
+Being strict they are never FltLifted, so they never float to top level or into
+a recursive group.
+
+Currently, we never put a FloatTick in a LetFloats.
-}
-data LetFloats = LetFloats (OrdList OutBind) FloatFlag
+data LetFloats = LetFloats FloatBinds FloatFlag
-- See Note [LetFloats]
+ -- Contains only FloatLet and FloatCase; never FloatTick
type JoinFloat = OutBind
type JoinFloats = OrdList JoinFloat
@@ -864,17 +901,35 @@ isEmptyJoinFloats = isNilOL
unitLetFloat :: OutBind -> LetFloats
-- This key function constructs a singleton float with the right form
+-- If the binding does not satisfy the let-can-float invariant, it
+-- makes a FloatCase. See Note [LetFloats]
unitLetFloat bind = assert (all (not . isJoinId) (bindersOf bind)) $
- LetFloats (unitOL bind) (flag bind)
+ mk_float bind
where
- flag (Rec {}) = FltLifted
- flag (NonRec bndr rhs)
- | not (isStrictId bndr) = FltLifted
- | exprIsTickedString rhs = FltLifted
+ mk_float bind@(Rec {}) = let_float FltLifted bind
+ mk_float bind@(NonRec bndr rhs)
+ | not (isStrictId bndr) = let_float FltLifted bind
+ | exprIsTickedString rhs = let_float FltLifted bind
-- String literals can be floated freely.
-- See Note [Core top-level string literals] in GHC.Core.
- | exprOkForSpeculation rhs = FltOkSpec -- Unlifted, and lifted but ok-for-spec (eg HNF)
- | otherwise = FltCareful
+ | exprOkForSpeculation rhs = let_float FltOkSpec bind -- Unlifted, and lifted but ok-for-spec (eg HNF)
+ | needsCaseBinding (idType bndr) rhs
+ = pprTrace "TMP-unitLetFloat-case" (ppr bind) $
+ LetFloats (unitOL (FloatCase rhs bndr DEFAULT [])) FltCareful
+ -- Unlifted, and not ok-for-spec: does not satisfy let-can-float invariant
+ | otherwise = let_float FltCareful bind
+
+ let_float flag bind = LetFloats (unitOL (FloatLet bind)) flag
+
+unitCaseFloat :: OutExpr -> OutId -> AltCon -> [OutVar] -> LetFloats
+-- Constructs a singleton single-alternative case float
+-- case scrut of bndr { con bndrs -> <hole> }
+-- See Note [LetFloats]
+unitCaseFloat scrut bndr con bndrs
+ = LetFloats (unitOL (FloatCase scrut bndr con bndrs)) flag
+ where
+ flag | exprOkForSpeculation scrut = FltOkSpec
+ | otherwise = FltCareful
unitJoinFloat :: OutBind -> JoinFloats
unitJoinFloat bind = assert (all isJoinId (bindersOf bind)) $
@@ -929,7 +984,11 @@ addLetFloats floats let_floats
extendInScopeFromLF :: InScopeSet -> LetFloats -> InScopeSet
extendInScopeFromLF in_scope (LetFloats binds _)
- = foldlOL extendInScopeSetBind in_scope binds
+ = foldlOL extend in_scope binds
+ where
+ extend in_scope (FloatLet bind) = in_scope `extendInScopeSetBind` bind
+ extend in_scope (FloatCase _ b _ bs) = in_scope `extendInScopeSetList` (b:bs)
+ extend in_scope (FloatTick {}) = in_scope
addJoinFloats :: SimplFloats -> JoinFloats -> SimplFloats
addJoinFloats floats join_floats
@@ -952,7 +1011,12 @@ addLetFlts (LetFloats bs1 l1) (LetFloats bs2 l2)
= LetFloats (bs1 `appOL` bs2) (l1 `andFF` l2)
letFloatBinds :: LetFloats -> [CoreBind]
-letFloatBinds (LetFloats bs _) = fromOL bs
+-- Precondition: there are no case-floats
+-- True, for example, if the FloatFlag is FltLifted
+letFloatBinds (LetFloats bs _) = map get_bind (fromOL bs)
+ where
+ get_bind (FloatLet bind) = bind
+ get_bind flt = pprPanic "letFloatBinds" (ppr flt)
addJoinFlts :: JoinFloats -> JoinFloats -> JoinFloats
addJoinFlts = appOL
@@ -960,7 +1024,7 @@ addJoinFlts = appOL
mkRecFloats :: SimplFloats -> SimplFloats
-- Flattens the floats into a single Rec group,
-- They must either all be lifted LetFloats or all JoinFloats
-mkRecFloats floats@(SimplFloats { sfLetFloats = LetFloats bs _ff
+mkRecFloats floats@(SimplFloats { sfLetFloats = lfs@(LetFloats bs _ff)
, sfJoinFloats = jbs
, sfInScope = in_scope })
= assertPpr (isNilOL bs || isNilOL jbs) (ppr floats) $
@@ -970,20 +1034,19 @@ mkRecFloats floats@(SimplFloats { sfLetFloats = LetFloats bs _ff
where
-- See Note [Bangs in the Simplifier]
!floats' | isNilOL bs = emptyLetFloats
- | otherwise = unitLetFloat (Rec (flattenBinds (fromOL bs)))
+ | otherwise = unitLetFloat (Rec (flattenBinds (letFloatBinds lfs)))
!jfloats' | isNilOL jbs = emptyJoinFloats
| otherwise = unitJoinFloat (Rec (flattenBinds (fromOL jbs)))
wrapFloats :: SimplFloats -> OutExpr -> OutExpr
-- Wrap the floats around the expression
-wrapFloats (SimplFloats { sfLetFloats = LetFloats bs flag
+wrapFloats (SimplFloats { sfLetFloats = LetFloats bs _
, sfJoinFloats = jbs }) body
- = foldrOL mk_let (wrapJoinFloats jbs body) bs
+ = GHC.Core.Make.wrapFloats bs (wrapJoinFloats jbs body)
-- Note: Always safe to put the joins on the inside
-- since the values can't refer to them
- where
- mk_let | FltCareful <- flag = mkCoreLet -- need to enforce let-can-float-invariant
- | otherwise = Let -- let-can-float invariant hold
+ -- No need to worry about the let-can-float invariant: unitLetFloat
+ -- has made a FloatCase for any binding that does not satisfy it
wrapJoinFloatsX :: SimplFloats -> OutExpr -> (SimplFloats, OutExpr)
-- Wrap the sfJoinFloats of the env around the expression,
@@ -1009,8 +1072,10 @@ mapLetFloats :: LetFloats -> ((Id,CoreExpr) -> (Id,CoreExpr)) -> LetFloats
mapLetFloats (LetFloats fs ff) fun
= LetFloats fs1 ff
where
- app (NonRec b e) = case fun (b,e) of (b',e') -> NonRec b' e'
- app (Rec bs) = Rec (strictMap fun bs)
+ app (FloatLet (NonRec b e)) = case fun (b,e) of (b',e') -> FloatLet (NonRec b' e')
+ app (FloatLet (Rec bs)) = FloatLet (Rec (strictMap fun bs))
+ app (FloatCase e b con bs) = case fun (b,e) of (b',e') -> FloatCase e' b' con bs
+ app flt@(FloatTick {}) = pprPanic "mapLetFloats" (ppr flt)
!fs1 = (mapOL' app fs) -- See Note [Bangs in the Simplifier]
{-
=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -256,6 +256,8 @@ simplRecBind env0 bind_cxt pairs0
; let new_bndrs = map sndOf3 triples
; (rec_floats, env2) <- enterRecGroupRHSs env1 new_bndrs $ \env ->
go env triples
+
+ -- In rec_floats, all the `sfLetFloats` bindings are `FltLifted`
; return (mkRecFloats rec_floats, env2) }
where
add_rules :: SimplEnv -> (InBndr,InExpr) -> SimplM (SimplEnv, (InBndr, OutBndr, InExpr))
@@ -284,7 +286,8 @@ simplRecOrTopPair :: SimplEnv
-> BindContext
-> InId -> OutBndr -> InExpr -- Binder and rhs
-> SimplM (SimplFloats, SimplEnv)
-
+-- Invariant: in the returned SimplFloats,
+-- all the `sfLetFloats` bindings are `FltLifted`
simplRecOrTopPair env bind_cxt old_bndr new_bndr rhs
| Just env' <- preInlineUnconditionally env (bindContextLevel bind_cxt)
old_bndr (UnSimplified env) rhs MRefl
@@ -3399,15 +3402,57 @@ doCaseToLet scrut case_bndr
reallyRebuildCase (saf,env) scrut case_bndr alts cont
= do { (floats, env', cont') <- mkDupableCaseCont env alts cont
- ; case_expr <- simplAlts (saf,env') scrut
- (scaleIdBy holeScaling case_bndr)
- (scaleAltsBy holeScaling alts)
- cont'
- ; return (floats, case_expr) }
+ ; traceSmpl "reallyRebuildCase" (vcat [ ppr case_bndr
+ , text "cont':" <+> ppr cont'
+ , text "in_scope" <+> ppr (seInScope env') ])
+ ; (alt_env, scrut', case_bndr', imposs_deflt_cons, in_alts)
+ <- prepareCase (saf,env') scrut (scaleIdBy holeScaling case_bndr)
+ (scaleAltsBy holeScaling alts)
+ ; case in_alts of
+ [in_alt] -> do { (alt_floats, alt') <- simplAlt (saf,alt_env) (Just scrut')
+ imposs_deflt_cons case_bndr'
+ bndr_swap cont' in_alt
+ ; (case_floats, res) <- rebuildSingleAltCase env' scrut' case_bndr'
+ cont' alt_floats alt'
+ ; return (floats `addFloats` case_floats, res) }
+
+ _ -> do { case_expr <- simplAlts (saf,alt_env) scrut' case_bndr'
+ imposs_deflt_cons bndr_swap cont' in_alts
+ ; return (floats, case_expr) } }
where
holeScaling = contHoleScaling cont
-- Note [Scaling in case-of-case]
+ bndr_swap = scrutOkForBinderSwap scrut
+
+rebuildSingleAltCase :: SimplEnv -> OutExpr -> OutId -> SimplCont
+ -> SimplFloats -> OutAlt
+ -> SimplM (SimplFloats, OutExpr)
+-- Build a single-alternative case; but return it as a FloatCase float, so that
+-- the floats from its RHS are not trapped inside it.
+-- See Note [Floating single-alternative cases]
+rebuildSingleAltCase env scrut case_bndr cont alt_floats (Alt con bs rhs)
+ = do { let alts_ty = contResultType cont
+ -- See Note [Avoiding space leaks in OutType]
+ ; case_expr <- seqType alts_ty `seq`
+ mkCase (seMode env) scrut case_bndr alts_ty
+ [Alt con bs (wrapFloats alt_floats rhs)]
+ -- wrapFloats: lazily; see (FSC1)
+ ; case case_expr of
+ Case scrut2 bndr2 _ [Alt con2 bs2 rhs2]
+ | not (noFloats alt_floats)
+ , bndr2 == case_bndr -- mkCase has not changed the case; see (FSC1)
+ -> return (case_float `addFloats` alt_floats, rhs)
+ | otherwise
+ -> return (case_float, rhs2)
+ where
+ case_float = emptyFloats env `addLetFloats`
+ unitCaseFloat scrut2 bndr2 con2 bs2
+ _ -> return (emptyFloats env, case_expr) }
+ where
+ noFloats (SimplFloats { sfLetFloats = lfs, sfJoinFloats = jfs })
+ = isEmptyLetFloats lfs && isEmptyJoinFloats jfs
+
{-
simplCaseBinder checks whether the scrutinee is a variable, v. If so,
try to eliminate uses of v in the RHSs in favour of case_bndr; that
@@ -3540,17 +3585,16 @@ scale the entire case we are simplifying, by a scaling factor which can be
computed in the continuation (with function `contHoleScaling`).
-}
-simplAlts :: (SimplAltFlag, SimplEnv)
- -> OutExpr -- Scrutinee
- -> InId -> [InAlt] -- Alts (non-empty)
- -> SimplCont
- -> SimplM OutExpr -- Returns the complete simplified case expression
-
-simplAlts (saf,env0) scrut case_bndr alts cont'
- = do { traceSmpl "simplAlts" (vcat [ ppr case_bndr
- , text "cont':" <+> ppr cont'
- , text "in_scope" <+> ppr (seInScope env0) ])
- ; (env1, case_bndr1) <- simplAltIdBinder (saf,env0) case_bndr
+prepareCase :: (SimplAltFlag, SimplEnv)
+ -> OutExpr -- Scrutinee
+ -> InId -> [InAlt] -- Case binder and alts (non-empty)
+ -> SimplM ( SimplEnv -- For the alternatives
+ , OutExpr -- Scrutinee, perhaps improved by improveSeq
+ , OutId -- Case binder
+ , [AltCon] -- Constructors impossible in the DEFAULT alt
+ , [InAlt] ) -- Alternatives, from prepareAlts
+prepareCase (saf,env0) scrut case_bndr alts
+ = do { (env1, case_bndr1) <- simplAltIdBinder (saf,env0) case_bndr
; let case_bndr2 = case_bndr1 `setIdUnfolding` evaldUnfolding
env2 = modifyInScope env1 case_bndr2
-- See Note [Case binder evaluated-ness]
@@ -3565,16 +3609,61 @@ simplAlts (saf,env0) scrut case_bndr alts cont'
-- NB: pass case_bndr::InId, not case_bndr' :: OutId, to prepareAlts
-- See Note [Shadowing in prepareAlts] in GHC.Core.Opt.Simplify.Utils
- ; alts' <- forM in_alts $
- simplAlt (saf,alt_env') (Just scrut') imposs_deflt_cons
- case_bndr' (scrutOkForBinderSwap scrut) cont'
+ ; return (alt_env', scrut', case_bndr', imposs_deflt_cons, in_alts) }
+
+simplAlts :: (SimplAltFlag, SimplEnv)
+ -> OutExpr -> OutId -- Scrutinee and case binder
+ -> [AltCon] -- Constructors impossible in the DEFAULT alt
+ -> BinderSwapDecision
+ -> SimplCont
+ -> [InAlt]
+ -> SimplM OutExpr -- Returns the complete simplified case expression
+-- The arguments are prepared by prepareCase
+simplAlts (saf,env) scrut' case_bndr' imposs_deflt_cons bndr_swap cont' in_alts
+ = do { alts' <- forM in_alts $
+ simplAltC (saf,env) (Just scrut') imposs_deflt_cons
+ case_bndr' bndr_swap cont'
; let alts_ty' = contResultType cont'
-- See Note [Avoiding space leaks in OutType]
; seqType alts_ty' `seq`
- mkCase (seMode env0) scrut' case_bndr' alts_ty' alts' }
+ mkCase (seMode env) scrut' case_bndr' alts_ty' alts' }
+{- Note [Floating single-alternative cases]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When reallyRebuildCase finds a single-alternative case (after prepareAlts)
+ case e of b { (# a, c #) -> let x1 = .. in ... let xn = .. in (# e1, e2 #) }
+it does not return the case expression; instead it returns
+ * floats: [FloatCase e b (# a,c #) [a,c], x1 = .., ..., xn = ..]
+ * result: (# e1, e2 #)
+This is done by rebuildSingleAltCase. See Note [LetFloats] in GHC.Core.Opt.Simplify.Env.
+
+Why? Because a caller (notably rebuildWithFloats, when case-of-case is
+switched off) may want to do case-of-known-constructor on the result. If we
+returned the whole case, exprIsConApp_maybe would have to walk all the way
+down through the case and the lets, which can be quadratic (#27737, T18223).
+
+This is not restricted to the no-case-of-case path: when case-of-case is on,
+the continuation has already been pushed into the alternative, and the
+floats are simply wrapped around the result, or floated further out of a
+strict let (which a StrictBind continuation would do anyway). The
+FloatFlag (FltCareful or FltOkSpec) stops a case-float from floating out of
+a lazy let, or to top level; see doFloatFromRhs.
+
+Wrinkles:
+
+(FSC1) mkCase may transform the case, e.g. by case-merging, identity-case
+ elimination, or caseRules (mkCase2), which renames the case binder and
+ wraps (let b = ..) around the RHS. So we call mkCase on the alternative
+ with its floats wrapped (lazily: mkCase inspects only the top of the RHS),
+ and then:
+ - If the alternative has floats, and mkCase has left the case binder
+ unchanged, mkCase cannot have done anything to the RHS (which starts
+ with a let), so we return (case-float + alt-floats, unwrapped RHS).
+ - Otherwise we return the case-float with whatever RHS mkCase produced.
+-}
+
------------------------------------
improveSeq :: (FamInstEnv, FamInstEnv)
-> (SimplAltFlag, SimplEnv)
@@ -3594,6 +3683,15 @@ improveSeq _ (_,env) scrut _ case_bndr1 _
------------------------------------
+simplAltC :: (SimplAltFlag, SimplEnv) -> Maybe OutExpr -> [AltCon] -> OutId
+ -> BinderSwapDecision -> SimplCont -> InAlt
+ -> SimplM OutAlt
+-- Like simplAlt, but wraps the floats around the RHS
+simplAltC env scrut' imposs_deflt_cons case_bndr' bndr_swap' cont' alt
+ = do { (floats, Alt con bs rhs) <- simplAlt env scrut' imposs_deflt_cons
+ case_bndr' bndr_swap' cont' alt
+ ; return (Alt con bs (wrapFloats floats rhs)) }
+
simplAlt :: (SimplAltFlag, SimplEnv)
-> Maybe OutExpr -- The scrutinee
-> [AltCon] -- These constructors can't be present when
@@ -3603,19 +3701,21 @@ simplAlt :: (SimplAltFlag, SimplEnv)
-- add unfolding `v :-> bndr |> sym co`
-> SimplCont
-> InAlt
- -> SimplM OutAlt
+ -> SimplM (SimplFloats, OutAlt)
+ -- The floats scope over the RHS only, and may mention the
+ -- binders of the alternative
simplAlt (saf,env) _scrut' imposs_deflt_cons case_bndr' bndr_swap' cont' (Alt DEFAULT bndrs rhs)
= assert (null bndrs) $
do { let env' = addDefaultUnfoldings env case_bndr' bndr_swap' imposs_deflt_cons
- ; rhs' <- simplAltExprC (saf,env') rhs cont'
- ; return (Alt DEFAULT [] rhs') }
+ ; (floats, rhs') <- simplAltExprF (saf,env') rhs cont'
+ ; return (floats, Alt DEFAULT [] rhs') }
simplAlt (saf,env) _scrut' _ case_bndr' bndr_swap' cont' (Alt (LitAlt lit) bndrs rhs)
= assert (null bndrs) $
do { let env' = addAltUnfoldings env case_bndr' bndr_swap' (Lit lit)
- ; rhs' <- simplAltExprC (saf,env') rhs cont'
- ; return (Alt (LitAlt lit) [] rhs') }
+ ; (floats, rhs') <- simplAltExprF (saf,env') rhs cont'
+ ; return (floats, Alt (LitAlt lit) [] rhs') }
simplAlt (saf,env) scrut' _ case_bndr' bndr_swap' cont' (Alt (DataAlt con) vs rhs)
= do { -- See Note [Adding evaluatedness info to pattern-bound variables]
@@ -3633,8 +3733,8 @@ simplAlt (saf,env) scrut' _ case_bndr' bndr_swap' cont' (Alt (DataAlt con) vs rh
con_app = mkConApp2 con inst_tys' vs'
env'' = addAltUnfoldings env' case_bndr' bndr_swap' con_app
- ; rhs' <- simplAltExprC (saf,env'') rhs cont'
- ; return (Alt (DataAlt con) vs' rhs') }
+ ; (floats, rhs') <- simplAltExprF (saf,env'') rhs cont'
+ ; return (floats, Alt (DataAlt con) vs' rhs') }
{- Note [Adding evaluatedness info to pattern-bound variables]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3815,11 +3915,6 @@ simplAltExprF (saf,env) expr cont
SAF_Out -> simplOutExpr env expr cont
SAF_In -> simplExprF env expr cont
-simplAltExprC :: (SimplAltFlag, SimplEnv) -> CoreExpr -> SimplCont -> SimplM OutExpr
-simplAltExprC env expr cont
- = do { (floats, expr') <- simplAltExprF env expr cont
- ; return (wrapFloats floats expr') }
-
{- Note [Case binder evaluated-ness]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -4338,7 +4433,7 @@ mkDupableContWithDmds env _
scaleIdBy cont_scaling case_bndr
; alts' <- forM (scaleAltsBy cont_scaling alts) $
- simplAlt (saf,alt_env1) Nothing [] case_bndr' NoBinderSwap alt_cont
+ simplAltC (saf,alt_env1) Nothing [] case_bndr' NoBinderSwap alt_cont
-- Safe to say that there are no handled-cons for the DEFAULT case
-- NB: simplBinder does not zap deadness occ-info, so
-- a dead case_bndr' will still advertise its deadness
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c42c84984525e8c9cd722ce6b58f9c3…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c42c84984525e8c9cd722ce6b58f9c3…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 3 commits: ci: move hadrian/ghci into the lint category so it can be picked up by more runners
by Marge Bot (@marge-bot) 08 Oct '26
by Marge Bot (@marge-bot) 08 Oct '26
08 Oct '26
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
d94a7a81 by mangoiv at 2026-10-08T10:34:39-04:00
ci: move hadrian/ghci into the lint category so it can be picked up by more runners
Fixes #27817
- - - - -
b4d54576 by mangoiv at 2026-10-08T10:34:39-04:00
ci: make lint-adjacent jobs into platform independent
- move lint jobs into lint-anyarch tag
- unify lint jobs under the same platform independent container
- - - - -
f959dcd8 by Zubin Duggal at 2026-10-08T10:34:40-04:00
DmdAnal: Make AbsDmd neutral in maxDmd
fixes #27845
- - - - -
10 changed files:
- .gitlab-ci.yml
- + changelog.d/27845
- compiler/GHC/Types/Demand.hs
- + testsuite/tests/dmdanal/should_run/T27845.hs
- + testsuite/tests/dmdanal/should_run/T27845.stdout
- + testsuite/tests/dmdanal/should_run/T27845_Lib.hs
- + testsuite/tests/dmdanal/should_run/T27845b.hs
- + testsuite/tests/dmdanal/should_run/T27845b.stdout
- + testsuite/tests/dmdanal/should_run/T27845b_Lib.hs
- testsuite/tests/dmdanal/should_run/all.T
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -137,15 +137,37 @@ workflow:
.lint:
stage: tool-lint
tags:
- - lint
- before_script:
- # Allow Git to read from the runner-owned checkout. This is needed
- # for example by the lint-author job.
- - git config --global --add safe.directory "$CI_PROJECT_DIR"
+ - lint-anyarch
+ image: debian:13
rules:
- *drafts-can-fail-lint
- when: always
+.install-ghc-toolchain: &install-ghc-toolchain
+ - apt update
+ - apt install -qy build-essential curl libffi-dev libffi8 libgmp-dev libgmp10 libncurses-dev libncurses6 libtinfo6 pkg-config python3 cmake git happy alex autoconf automake python3 libgmp-dev libnuma-dev libncurses-dev
+ - curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
+ - source /root/.ghcup/env
+ - ghcup --no-verbose install ghc --set --install-targets 'install_bin install_lib update_package_db' '9.10'
+ - ghcup --no-verbose install cabal --set
+ - ghc --info
+ - cabal --version
+
+# linting but we need a boot toolchain
+.lint-ghc-toolchain:
+ extends: .lint
+ before_script:
+ - *install-ghc-toolchain
+ - git config --global --add safe.directory "$CI_PROJECT_DIR"
+
+# linting but we need python
+.lint-python:
+ extends: .lint
+ before_script:
+ - apt update
+ - apt install -qy python3 mypy shellcheck git
+ - git config --global --add safe.directory "$CI_PROJECT_DIR"
+
.nightly: &nightly
variables:
XZ_OPT: "-9"
@@ -217,11 +239,11 @@ not-interruptible:
stage: not-interruptible
script: "true"
interruptible: false
- image: "debian:13"
+ image: debian:13
variables:
GIT_STRATEGY: none
tags:
- - lint
+ - lint-anyarch
rules:
# - if: '$CI_COMMIT_BRANCH == "master"'
# when: always
@@ -242,7 +264,6 @@ include: '.gitlab/jobs.yaml'
ghc-linters:
stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint-params
variables:
BUILD_FLAVOUR: default
@@ -258,16 +279,11 @@ ghc-linters:
# Skipped if the MR has the ~"no-changelog" label.
lint-changelog:
stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-ghc-toolchain
variables:
CHANGELOG_EXPECT_MR: "$CI_MERGE_REQUEST_IID"
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- .gitlab/ci.sh lint_changelog
dependencies: []
@@ -279,42 +295,30 @@ lint-changelog:
# Run mypy Python typechecker on linter scripts.
lint-linters:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- mypy testsuite/tests/linters/regex-linters/*.py
dependencies: []
# Check that .T files all parse by listing broken tests.
lint-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-ghc-toolchain
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- - make -Ctestsuite list_broken TEST_HC=$GHC
+ - make -Ctestsuite list_broken TEST_HC=$(which ghc)
dependencies: []
# Run mypy Python typechecker on testsuite driver
typecheck-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- mypy testsuite/driver/runtests.py
dependencies: []
@@ -323,7 +327,6 @@ typecheck-testsuite:
# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
# Marge jobs.
.lint-submods:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint-params
variables:
BUILD_FLAVOUR: default
@@ -341,13 +344,9 @@ typecheck-testsuite:
# Check that commits in an MR were not authored with the identity that CI uses
# when it needs to create commits itself. This only needs Git history.
lint-author:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
@@ -425,12 +424,9 @@ lint-submods-branch:
.lint-params:
needs: []
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint
before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
+ - *install-ghc-toolchain
- .gitlab/ci.sh setup
after_script:
- .gitlab/ci.sh save_cache
@@ -448,18 +444,13 @@ lint-submods-branch:
hadrian-ghc-in-ghci:
stage: quick-build
+ extends: .lint-ghc-toolchain
needs:
- job: lint-linters
- job: lint-submods
optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
variables:
GHC_FLAGS: -Werror -Wwarn=unused-imports
- tags:
- - x86_64-linux
script:
- git clean -xdf && git submodule foreach git clean -xdf
- . .gitlab/ci.sh setup
@@ -544,6 +535,7 @@ stack-hadrian-build:
extends: hadrian-ghc-in-ghci
stage: quick-build
script:
+ - ghcup --no-verbose install stack --set
- . .gitlab/ci.sh setup
- . .gitlab/ci.sh configure
- hadrian/build-stack --version
=====================================
changelog.d/27845
=====================================
@@ -0,0 +1,5 @@
+section: compiler
+synopsis: Fix a bug where an argument used lazily only by a function's stable
+ unfolding could be treated as strict in its fields.
+mrs: !16746
+issues: #27845
=====================================
compiler/GHC/Types/Demand.hs
=====================================
@@ -924,6 +924,8 @@ maxCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
maxDmd :: Demand -> Demand -> Demand
maxDmd BotDmd dmd2 = dmd2
maxDmd dmd1 BotDmd = dmd1
+maxDmd AbsDmd dmd2 = dmd2
+maxDmd dmd1 AbsDmd = dmd1
maxDmd (n1 :* sd1) (n2 :* sd2) =
maxCard n1 n2 :* maxSubDmd sd1 sd2
=====================================
testsuite/tests/dmdanal/should_run/T27845.hs
=====================================
@@ -0,0 +1,14 @@
+module Main where
+import T27845_Lib (f)
+import System.Environment (getArgs)
+
+{-# NOINLINE mkArg #-}
+mkArg :: Int -> Int
+mkArg n | n < 0 = n
+ | otherwise = error ("boom " ++ show n)
+
+main :: IO ()
+main = do
+ n <- length <$> getArgs
+ let x = mkArg n
+ print (length (f (x, x) n))
=====================================
testsuite/tests/dmdanal/should_run/T27845.stdout
=====================================
@@ -0,0 +1 @@
+0
=====================================
testsuite/tests/dmdanal/should_run/T27845_Lib.hs
=====================================
@@ -0,0 +1,11 @@
+module T27845_Lib where
+
+{-# INLINABLE [2] f #-}
+f :: a -> Int -> [a]
+f p x = lazyUse p x ++ lazyUse p (x + 1) ++ lazyUse p (x + 2)
+
+{-# NOINLINE lazyUse #-}
+lazyUse :: a -> Int -> [a]
+lazyUse p x = p `seq` replicate x p
+
+{-# RULES "lazyUse" [1] forall p x. lazyUse p x = [] #-}
=====================================
testsuite/tests/dmdanal/should_run/T27845b.hs
=====================================
@@ -0,0 +1,14 @@
+module Main where
+import T27845b_Lib (outer)
+import System.Environment (getArgs)
+
+{-# NOINLINE mkArg #-}
+mkArg :: Int -> Int
+mkArg n | n < 0 = n
+ | otherwise = error ("boom " ++ show n)
+
+main :: IO ()
+main = do
+ n <- length <$> getArgs
+ let x = mkArg n
+ print (length (outer (x, x) n))
=====================================
testsuite/tests/dmdanal/should_run/T27845b.stdout
=====================================
@@ -0,0 +1 @@
+0
=====================================
testsuite/tests/dmdanal/should_run/T27845b_Lib.hs
=====================================
@@ -0,0 +1,14 @@
+module T27845b_Lib where
+
+outer :: a -> Int -> [a]
+outer a n =
+ let {-# INLINABLE [2] g #-}
+ g x = lazyUse a (x + 0) ++ lazyUse a (x + 1) ++ lazyUse a (x + 2)
+ in g n ++ g (n + 1) ++ g (n + 2)
+{-# NOINLINE outer #-}
+
+{-# NOINLINE lazyUse #-}
+lazyUse :: a -> Int -> [a]
+lazyUse p x = p `seq` replicate x p
+
+{-# RULES "lazyUse" [1] forall p x. lazyUse p x = [] #-}
=====================================
testsuite/tests/dmdanal/should_run/all.T
=====================================
@@ -37,3 +37,5 @@ test('T25439', normal, compile_and_run, [''])
test('T26748', normal, compile_and_run, [''])
test('T26416', [extra_files(['M1.hs'])], multimod_compile_and_run, ['T26416','M1.hs'])
test('T27626', [extra_files(['M2.hs'])], multimod_compile_and_run, ['T27626','M2.hs'])
+test('T27845', [extra_files(['T27845_Lib.hs'])], multimod_compile_and_run, ['T27845','T27845_Lib.hs'])
+test('T27845b', [extra_files(['T27845b_Lib.hs'])], multimod_compile_and_run, ['T27845b','T27845b_Lib.hs'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/5f2203620d63124583cf0bf4ecbcaa…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/5f2203620d63124583cf0bf4ecbcaa…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc] Pushed new branch wip/davide/windows-dlls_sysm-test_master
by David Eichmann (@DavidEichmann) 08 Oct '26
by David Eichmann (@DavidEichmann) 08 Oct '26
08 Oct '26
David Eichmann pushed new branch wip/davide/windows-dlls_sysm-test_master at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/davide/windows-dlls_sysm-test…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/27323] 82 commits: Add -Wimplicit-field-strictness (#16836)
by Sasha Bogicevic (@Bogicevic) 08 Oct '26
by Sasha Bogicevic (@Bogicevic) 08 Oct '26
08 Oct '26
Sasha Bogicevic pushed to branch wip/27323 at Glasgow Haskell Compiler / GHC
Commits:
9e7739ab by Simon Jakobi at 2026-09-03T13:45:43-04:00
Add -Wimplicit-field-strictness (#16836)
This opt-in warning fires when a data constructor field lacks an
explicit strictness annotation (`!` or `~`). It complements the
LazyFieldAnnotations extension (4762a8bf30f) from GHC proposal 752,
which makes `~` annotations available for this purpose.
Deciding which fields to report requires their levity, so the check
runs after typechecking. To keep the noise down, the diagnostic is
emitted once per data declaration, grouped by constructor.
Closes #16836.
Assisted-by: Claude Fable 5
- - - - -
6a44d591 by mangoiv at 2026-09-03T13:46:22-04:00
simplifier: remove a bogus `assert` in `rebuild_app'` in `GHC.CoreToStg.Prep.cpeApp`.
Prior to this commit
commit 08bc245be70d95801bc1138804ed1de9474fbdc0
Author: sheaf <sam.derbyshire(a)gmail.com>
Date: Sat Feb 28 16:30:43 2026 +0100
Clean up join points, casts & ticks
This commit shores up the logic dealing with casts and ticks occurring
in between a join point binding and a jump
any `PlaceRuntime` ticks we observed were profiling ticks, even though that
isn't necessary.
The more liberal rules in the above commit allow e.g. breakpoint ticks
(which are valid PlaceRuntime ticks) to legitimately appear in an argument
position.
Fixes #27556
- - - - -
eaa95a6f by Andrei Borzenkov at 2026-09-04T08:08:40-04:00
Parentheses in prefix GADT constructors (#27423)
Updated `splitLHsGadtTy` to allow looking
through the parentheses for inner binders. General example
of a code pattern that's allowed now:
data S a where
MkS :: (forall a. S a)
That should work now with any combination of nested
foralls and parentheses.
We don't perform parenthesis unwrapping for record
GADT constructors in accordance with GHC Proposal #402.
To this end `con_inner_bndrs` no longer stores plain forall
telescopes: `[HsForAllTelescope pass]` is replaced with
`[LHsGadtTelescope pass]`, a new `HsArg`-style type whose
`HsGadtForAll` holds an inner telescope and whose `HsGadtPar`
holds a pair of parentheses. The parentheses carry no meaning
for renaming or type checking; the only reason to record them
is exact-printing.
Updated `pprConDecl` to improve the `parse == parse . ppr . parse`
property of GADT pretty-printing.
The pretty printer can now output code that's similar to this:
data T a where
MkT1 :: (forall a. T a)
MkT2 :: forall . forall a. T a
These are special cases of inner forall binders
for prefix GADT constructors, when we have either
implicit or zero explicit outer binders.
- - - - -
639456a8 by Evgeny Malyshev at 2026-09-04T08:09:25-04:00
HsPat: Add spacing to unary tuple patterns
Use hsep when printing unary boxed TuplePat applications so that the
MkSolo constructor is separated from its argument. The old hcat rendered
wildcard and parenthesized arguments as MkSolo_ and MkSolo().
Add T27034 to exercise the HsPat splice-dump path with wildcard and
variable arguments, and update existing affected golden output.
Fixes #27034
Assisted-By: OpenAI Codex
- - - - -
2908ab36 by Simon Jakobi at 2026-09-05T07:22:17-04:00
X86 NCG: use btr/bts/btc for single-bit operations
Previously the Cmm patterns
x & ~(1 << i)
x | (1 << i)
x ^ (1 << i)
compiled to mov/shl/not/and-style sequences of 3-4 instructions. Now
they compile to a single btr, bts or btc, matching what C compilers
produce.
When the bit index is a literal, constant folding has already collapsed
these patterns into ones with a literal mask, such as
x & 0xfffffeffffffffff for x & ~(1 << 40). Such masks are now also
compiled to a bit-test instruction when they don't fit in an imm32 and
would otherwise have to be loaded into a register first.
For a variable bit index, this applies only when the shift is unchecked
(uncheckedShiftL#, Data.Bits.unsafeShiftL): the bounds-checked shiftL
used by e.g. the default clearBit/setBit/complementBit implementations
wraps the shift in a bounds mask that this optimisation does not see
through. With a literal index, the bounds mask is constant-folded away,
so the checked operations benefit too.
See Note [Bit-test instructions] in GHC.CmmToAsm.X86.CodeGen.
Fixes #25233.
Assisted-by: Claude Fable 5
- - - - -
c673ecf0 by Simon Peyton Jones at 2026-09-05T07:22:59-04:00
Move HsStatic free-var test to typechecker
A `static` form should have no free *term* variables, but it
can have free *type* variables. Alas, the renamer does not really know what
is a term variable and what is a type variable, because of required type
arguments. This patch moves the test to the typechecker, which does know.
Addresses #27664
- - - - -
5939ceaf by sheaf at 2026-09-05T22:06:18-04:00
Windows: enforce path convention in ./configure
As detailed in Note [MSYS paths] in Hadrian.Utilities, the standing
convention (using Windows-style paths with forward slashes) is now
enforced in ./configure instead of within Hadrian, removing the need for
'cygpath' calls within Hadrian.
Fixes #26683
- - - - -
a6061455 by sheaf at 2026-09-05T22:06:18-04:00
Hadrian: introduce ExeSpawnPath
Specific details about the filepath used to specify the executable to
spawn with CreateProcess matters on Windows: whether we use forward or
backward slashes, a leading ./, or an absolute path changes how the
executable is found.
This commit introduces 'ExeSpawnPath' which is a path that is guaranteed
to be found when spawning a process. All command invocations now go
through this type to ensure the path has been properly sanitised.
See Note [NeedCurrentDirectoryForExePath] in Hadrian.Utilities.
The same treatment is applied to hsc2hs. Updates hsc2hs submodule.
- - - - -
e28313e3 by sheaf at 2026-09-05T22:07:06-04:00
Preserve tick ordering in 'tickTickedExpr'
'GHC.Core.Utils.tickTickedExpr' tries to combine a tick 't1' into an
existing stack of ticks 't2s'. There are two situations:
1. 't1' is subsumed by a tick in 't2s': drop it.
2. A tick in 't2s' is subsumed by 't1', say 't2'.
This commit ensures that in case (2) we keep 't1' on the outside instead
of replacing 't2' at its position in the stack. This avoids re-ordering
source notes (which was the cause of #27749).
This fixes a regression introduced in 2dadf3b0d05.
Fixes #27749
- - - - -
3172f557 by sheaf at 2026-09-05T22:07:06-04:00
Consistently prefer local source note ticks
GHC.Cmm.DebugBlock.cmmDebugGen (DWARF annotations) and
GHC.Stg.Debug.quickSourcePos (-finfo-table-map) both contained logic to
prioritise source note ticks from the current module.
This commit commons up this logic and propagates it to a third consumer:
IPE stack frames, in GHC.Driver.GenerateCgIPEStub.
See the new function GHC.Types.Tickish.bestSourceNote.
- - - - -
192be0b6 by Luite Stegeman at 2026-09-07T19:43:36-04:00
rts: fix ctoi_tuple_spill_words getting out of sync
Fix a few places that were not updating ctoi_tuple_spill_words
correctly, leading to corruption/crashes when dealing with large
unboxed tuples in bytecode:
- captureContinuationAndAbort
- findRetryFrameHelper/findAtomicallyFrameHelper
- interpretBCO bci_BRK_FUN
fixes #27633
- - - - -
604eb43c by Simon Jakobi at 2026-09-07T19:44:15-04:00
Hadrian: don't capture the testsuite driver's output (#27780)
a6061455d54 switched the Testsuite RunTest case from Shake's cmd to the
cmd' wrapper. cmd' always captures stdout and stderr, and since the
caller asks for Exit, it returns without dumping what it captured. As a
result the testsuite output no longer appears in CI job logs: failures,
performance metrics and the summary were lost with the job.
Use cmdExe, the uncaptured cmd, as the other plain-cmd sites in that
commit do.
Fixes #27780.
Assisted-by: Claude Fable 5.1
- - - - -
06eee015 by Luite Stegeman at 2026-09-08T06:03:06+02:00
rts: Fix missing memory barrier in eval_thunk_selector (#27477)
unchain_thunk_selectors() was missing an ACQUIRE_LOAD for the
indirectee, leading to segfaults and corruption during GC on
weakly-ordered architectures.
Fixes #27477
- - - - -
f8b2bd8f by Alan Zimmerman at 2026-09-08T09:39:12-04:00
EPA Fix HsCmdDo exact print with comments
Exact printing of HsCmdDo was ignoring the location for the do
statements, and this is an annotation that can have comments in it.
Update it so we print the statements as a unit, including any
comments.
Also add the result of auditing that we capture comments in all needed
places, noting that the remaining Anno SrcSpan instances are benign.
- - - - -
430967ab by Duncan Coutts at 2026-09-09T11:07:01+01:00
Reorder cmm decls in HeapStackCheck for a better logical grouping
And put more section headers in to deliniate the groups.
We're about to add more here, so better to organise it first.
- - - - -
344080fd by Duncan Coutts at 2026-09-09T11:07:01+01:00
Add raisePrimIOException and add it to RTS<->ghc-internal API
The raisePrimIOException is a new helper function that I/O primops will
use to help them report I/O errors. This is implemented in Haskell
(since that's a lot easier), but has a calling convention that is
easy(ish) to use from Cmm in the I/O primops.
So we add it to the RTS API struct, and since we'll use it from Cmm we
also need a field accessor macro for cmm (in deriveConstants).
See the Note about how we cannot have nice things due to async
exceptions and thunks preventing us from using catch.
- - - - -
cfdb3399 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Add new blocking functions for I/O primops
See the Note [Thread blocking for new I/O primops],
and the Note [Calling convention for raisePrimIOException].
The point is, it will allow us to report synchronous exceptions from I/O
primops, and do so much more flexibly.
Previously the I/O managers could only report async exceptions and only
nullary exceptions. This was OK historically, but no good as we add
more I/O managers and expand the range of I/O operations we support.
- - - - -
f09c09d8 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Change the encoding of results from the I/O manager to I/O primops
Previously we just had async continue or heap overflow.
We now extend what we can report with synchronous success, and
synchronous failure with an errno.
See Note [Encoding of result of I/O manager operations]
We don't use these two new cases yet, but we will. In particular an
epoll I/O manager needs to be able to report synchronous success or
failure for waitRead#/waitWrite#.
- - - - -
30f074d9 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Switch waitRead/Write# to use new blocking return frames
and update the I/O managers to set the result before resuming the
blocked threads.
This makes it possible for I/O managers to report synchronous exceptions
from the I/O primops, but that will be done in a subsequent commit.
- - - - -
a8786ced by Duncan Coutts at 2026-09-09T11:07:01+01:00
Switch Poll and Select I/O managers to report sync exceptions
rather than using raiseAsync with blockedOnBadFD_closure.
This uses the new mechanism in the blocking frame return code to report
synchronous exceptions.
- - - - -
7a9df79a by Duncan Coutts at 2026-09-09T11:07:01+01:00
Remove now-unused blockedOnBadFD
It was previously thrown by the select and poll I/O managers, but now
they use raisePrimIOException (with an EBADF errno).
- - - - -
6b0424e3 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Improve the docs for delay# waitRead# and waitWrite#
Document that the waitRead/Write# can throw exceptions (this was true
before too), and that all of them are async exception cancellation
points.
- - - - -
afeb2c30 by Duncan Coutts at 2026-09-09T20:08:58-04:00
Enable printf warnings for trace functions and fix resulting warnings
Most of the existing printf-style functions are annotated with
attributes to enable gcc/clang warnings for the printf format string,
but several trace functions in Trace.h were missing this annotation.
Enable them, and fix the resulting warnings.
- - - - -
9a442c93 by Alan Zimmerman at 2026-09-09T20:09:36-04:00
EPA: Exact print ConDeclGADT without custom enterAnn
!16321 brought in explicit capture of parens in a ConDeclGADT.
The ExactPrint update introduced a modification of the fundamental
function in exact printing, `enterAnn`, by splitting it into a version
allowing injection of functionality normally handled by the
ExactPrint class methods.
This commit refactors that code, to restore the prior `enterAnn`
version, by following the convention in ExactPrint of introducing a
helper data structure with its own `ExactPrint` instance to achieve
the same effect.
- - - - -
4e9297ea by Simon Jakobi at 2026-09-11T08:32:45-04:00
ci: Actually pass --ignore-perf-failures to the testsuite driver
684c0018d9 changed the IGNORE_PERF_FAILURES handling to append to
RUNTEST_ARGS with bash array syntax, but the three use sites still
expand RUNTEST_ARGS as a scalar, which yields only the first array
element. The appended flag was therefore dropped in every job, so
perf improvements kept failing Marge Bot batches and master pipelines,
contrary to #19562.
Append as a string instead, matching the existing --force-colors
append in test_hadrian.
Fixes #27563.
Assisted-by: Claude Fable 5.1
- - - - -
4f78dfdf by Simon Jakobi at 2026-09-11T08:33:24-04:00
testsuite: Give T26537 a 1.5x compile timeout
Its -fregs-graph compile step tends to time out in unoptimized builds
(#27188, #27776).
Assisted-by: Claude Fable 5.1
- - - - -
130286e3 by Alan Zimmerman at 2026-09-11T08:34:08-04:00
EPA: Remove ListBanana / ListParens from AnnListBrackets
This is a step towards making AnnList only represent
lists of items which can have either braces or layout.
- - - - -
a9827d13 by Simon Jakobi at 2026-09-11T18:53:32-04:00
Reject ~, UNPACK and multiplicity annotations on type data fields
Only `!` was rejected so far. `~`, UNPACK and multiplicity annotations
were silently accepted. None of them make sense at the type level, so
restriction (R3) of Note [Type data declarations] now covers all of
them.
Fixes #27732.
Assisted-by: Claude Fable 5.1
- - - - -
c71d5e23 by Alan Zimmerman at 2026-09-11T18:54:11-04:00
EPA: Add a Note for the exact print main loop
- - - - -
7a108e43 by Simon Jakobi at 2026-09-12T18:35:59-04:00
FastString: Drop mkFastStringWith's constructor callback
All three callers passed the same callback, a partial application of
mkNewFastStringShortByteString to the string being interned. That
partial application is allocated as a closure before the table lookup,
on the common hit path too, although the callback is needed only after
a miss.
Drop the parameter and call mkNewFastStringShortByteString directly
after a miss. Since nothing is passed "with" anymore, rename the
function to internSB.
Suggested by Simon PJ in #27528:
https://gitlab.haskell.org/ghc/ghc/-/work_items/27528#note_687031
Assisted-by: Claude Fable 5
- - - - -
82c73b22 by Alan Zimmerman at 2026-09-12T18:36:38-04:00
EPA: More targeted HsDo exact print annotation
HsDo is multi-purpose, as encoded in its HsDoFlavour field. Some of
these are in a layout context (DoExpr, MDoExpr), others are not
(ListComp, MonadComp).
We are moving towards using AnnList only in layout contexts, so we
switch the HsDo TTG annotation from holding an AnnList for this, to
holding
Either (EpToken "[", EpToken "]") AnnList
This also allows us to trim down AnnListBrackets to only have braces
or None, thereby opening the door for unification with the existing
layout context data type EpLayout.
- - - - -
749d2448 by Luite Stegeman at 2026-09-15T14:07:01-04:00
rts: handle large CONSTR closures in compacting GC
The function update_fwd_large in the compacting GC could run into
an unexpected object with the following error:
internal error: update_fwd_large: unknown/strange object 1
Closure type 1 is CONSTR. This patch adds cases for CONSTR and
CONSTR_NOCAF.
This is the same problem as #27434 (large AP closures, fixed by
cca0d58963), which missed this case.
Fixes #27649
- - - - -
177d6155 by Luite Stegeman at 2026-09-15T14:07:02-04:00
testsuite: fix T27434 test with compacting GC
Ensure that the interpreter is actually run with the compacting GC
- - - - -
5796aa63 by Luite Stegeman at 2026-09-15T14:07:49-04:00
rts: initialise the stack frame header for mask_frame and apply_mask_frame
We must leave the stack in consistent state before jumping to
mask_frame or apply_mask_frame because they may result. Failing
to do so could lead to a crash if there were waiting exceptions.
Fixes #27651
- - - - -
2486cc92 by Simon Peyton Jones at 2026-09-15T14:08:36-04:00
Re-introduce the "weird SpecDict" case
In this commit
commit f80375dd4945350a1d784e436975b48b9c736eaf
Author: Simon Peyton Jones <simon.peytonjones(a)gmail.com>
Date: Sun Jun 29 15:26:58 2025 +0100
Refactor of Specialise.hs
I removed a test for a dictionary with unbound type variables. This
turned out to be wrong; see #27629.
So this MR re-introduces it.
- - - - -
8e09a46f by Duncan Coutts at 2026-09-15T20:11:35-04:00
Refactor (and rename) removeFromQueues, to simplify I/O managers
Rename it to unblockAndAppendToRunQueue which better reflects what it is
intended to do.
The post-condition for unblockAndAppendToRunQueue is that the TSO is on
the run queue or it is in the process of migrating to another cap.
Previously it achieved that by always directly adding the TSO to the run
queue itself.
But this actually made things more complicated for the I/O managers,
because it meant they needed a separate code path for notifying for
cancellation compared to notifying for completion. The general
notification code would always add the TSO to the run queue itself.
So the improvement is to allow different cases in
unblockAndAppendToRunQueue to achieve the same outcome in different
ways: either directly adding to the run queue or calling helper
functions that do so themselves.
This then allows the new I/O managers to share code between the sync and
async cancellation, and to reuse their notifyIOCompletion helpers for
cancellation. This avoids a source of bugs where the completion path may
be updated but the cancellation path may be forgotten, or similarly in
future for sync/async operations.
Update all the existing in-RTS I/O managers, and the posix timeout code.
- - - - -
d668782c by Duncan Coutts at 2026-09-15T20:11:35-04:00
Document that awaitCompletedTimeoutsOrIO expects an empty run queue
This was true before but implicit and not relied on much. It's better to
be explicit, and allow things to depend on it.
- - - - -
11d938bb by Duncan Coutts at 2026-09-15T20:11:35-04:00
Store the I/O opcode and fd in the StgAsyncIOOp
This will be useful in several I/O managers and it is handy for logging
and debugging.
It also doesn't increase the size of the StgAsyncIOOp structure. There
was enough spare padding space already.
Update the poll I/O manager to set the new fields.
Add a helper function to convert the enum IOReadOrWrite into the enum
IOOpCode. Also change IOReadOrWrite to be an enum without a typedef, for
consistency with other enumerations in IOManager.h
- - - - -
bfa87882 by Duncan Coutts at 2026-09-15T20:11:36-04:00
Add a new I/O manager based on select()
Yes, this is the second such I/O manager, but it is a modern
re-implementation based on the new in-RTS I/O manager infrastructure. So
it is cleaner and faster than the old select I/O manager.
Why do we need another I/O manager based on select? Why isn't the poll()
one good enough as a baseline portable unix I/O manager? Because macOS.
Apple Inc. is why we cannot have nice things.
The man page for poll on macOS documents the fact that it does not work.
At least, it does not work for all files. Specifically, it does not work
for device files. Whereas macOS select() does work for device files.
Aaaaarg!
We _do_ want to deprecate and remove the old select I/O manager, but due to
macOS we cannot do that until we have a replacement. This is that
replacement. Until of course a nice new k-queue I/O manager arrives,
which could become the new default for macOS and FreeBSD.
Interestingly, this select I/O manager is actually faster than the poll
one, on Linix, in some circumstances: specifically when many Haskell
threads are waiting on the same fd. The poll I/O manager does O(n) work
for n threads waiting on I/O, whereas the select one does O(fds) work
for the number of fds that threads are waiting on. Usually this is 1:1,
so it's not noticable, but one can concoct extreme benchmarks to show
the difference.
- - - - -
8e9de15a by Duncan Coutts at 2026-09-15T20:11:36-04:00
Minor updates in the poll I/O manager to keep in sync with select
This keeps it in sync with select one. The changes are based on code review
while implementing the new select I/O manager. The two I/O managers are so
similar in structure that it makes sense to try to minimise the diff between
them. This should aid understanding, and fixes to both in future.
- - - - -
222668bb by Duncan Coutts at 2026-09-15T20:11:36-04:00
Document the new select I/O manager in the user guide
in the RTS section about I/O managers.
And add a changelog entry.
- - - - -
0f48735b by Cheng Shao at 2026-09-15T20:12:23-04:00
Revert "wasm: workaround WebKit bug in dyld"
This reverts commit c9b8465c2c338176fcab9d197e9d31f4aee11f68. The
underlying webkit bug has been fixed in
https://commits.webkit.org/314219@main. Closes #27564.
- - - - -
809294f1 by Luite Stegeman at 2026-09-15T20:13:08-04:00
rts: make stg_threadLabelzh return a valid pointer for unlabeled threads.
This fixes a segfault in the GC caused by stg_threadLabelzh returning
a 0 pointer in a GC pointer field.
stg_threadLabelzh returns a tuple of type (# Int#, ByteArray# #). If a
thread has no label, the second field is unused. We must still return
a valid heap object pointer.
Instead of returning 0, we now return stg_DEAD_SLOT_closure.
fixes #27618
- - - - -
e2d57026 by Luite Stegeman at 2026-09-15T20:13:54-04:00
JS: fix selector thunk handling
fix a bug where entering a selector thunk could lead to a crash
if the selected field was still a thunk.
fixes #27788
- - - - -
1b4a622f by sheaf at 2026-09-17T02:39:13-04:00
Improvements to type/data family handling
This commit makes several improvements to the treatment of type and data
families in GHC:
- We consistently use "type family" instead of "type synonym family"
to avoid a confusion with type synonyms. For example:
- OpenSynFamilyTyCon ==> OpenTypeFamilyTyCon
- ClosedSynFamilyTyCon => ClosedTypeFamilyTyCon
- Various functions that were specific to data families have been
renamed to make this clear. For example:
- tyConFamInst_maybe ==> tyConDataFamInst_maybe
- isFamInstTyCon ==> isDataFamInstTyCon
- 'FamTyConFlav' has been refactored so that all closed type families
share a single 'ClosedTypeFamilyTyCon' constructor.
The corresponding 'IfaceFamTyConFlav' type was updated similarly.
This is then used to tidy up the implementation of
GHC.Core.FamInstEnv.reduceTyFamApp_maybe.
- - - - -
c5aa9098 by sheaf at 2026-09-17T02:39:13-04:00
Small refactor of lookupFamInstEnv
This commit reworks the code for looking up family instances in
GHC.Core.FamInstEnv, reducing duplication a little bit.
No change in behaviour.
- - - - -
a3ad4588 by sheaf at 2026-09-17T02:39:14-04:00
Use a type family for boxing unboxed types
This commit overhauls the way in which unboxed types are boxed, as per
the updated Note [Boxing constructors] in GHC.Builtin.WiredIn.Types.Box.
The main change is to allow boxing to be parametrised by representation,
e.g. making 'Box ty' a valid type. We achieve this by implementing 'Box'
using a closed type family:
newtype Box (a :: TYPE r) = Box (BoxTF r)
type BoxTF :: RuntimeRep -> Type
type family BoxTF r where
BoxTF IntRep = BoxInt
BoxTF Int8Rep = BoxInt8
BoxTF WordRep = BoxWord
BoxTF LiftedRep = Any @Type
BoxTF (TupleRep [r1, r2]) = (BoxTF r1, BoxTF r2)
...
BoxTF (SumRep rs) = BoxSum rs
This new design solves the following problems:
- It allows boxing a type whose 'RuntimeRep' has not yet been
determined (e.g. because we only learn the 'RuntimeRep' after
constraint solving). That is, 'Box @r a' is a perfectly valid type
even if 'r' is an unfilled metavariable. This is a requirement
to fix #25065 (in which we need to box a type whose 'RuntimeRep'
is only filled in during constraint solving).
- It handles boxing of unboxed tuples and unboxed sums, via recursive
boxing. See Note [Boxing TupleRep and SumRep] in
GHC.Builtin.WiredIn.Types.Box.
'Box', 'BoxTF' and all of the boxing data constructors are defined in
a new 'ghc-internal' module, 'GHC.Internal.Box'. This module contains
nothing but wired-in declarations, and GHC never loads its interface on
account of a wired-in thing (GHC.Builtin.Modules.isWiredInOnlyModule);
see Note [Loading instances for wired-in things] in GHC.Iface.Load.
The individual boxing data constructors are deliberately left as an
internal implementation detail, and not exported. The intended API is
via the two new magic 'Id's:
box :: forall {r} (a :: TYPE r). a -> Box a
unbox :: forall {r} (a :: TYPE r). Box a -> a
exported from 'GHC.PrimOps' (in 'ghc-experimental'). The old boxing
data types (IntBox, WordBox, FloatBox, DoubleBox, DictBox) are no longer
exported from base (CLC proposal #421).
We use this new design to consistently desugar:
- parallel comprehensions (GHC.HsToCore.ListComp.{deListComp,dsMcStmt})
- then/group/using statements (GHC.HsToCore.ListComp.{dsTransStmt,dsMcStmt})
- recursive do blocks (mdo/rec) (GHC.HsToCore.Expr.dsDo)
- arrows (GHC.HsToCore.Arrows)
by consistently using 'box'/'unbox' to deal with unboxed types being put
into big tuples. We also adapt 'GHC.Tc.Gen.Match.{tcMcStmt,tcDoStmt}'
to create fresh /representation-polymorphic/ type variables for the
binders that we are going to put into a big tuple (previously, GHC only
allowed lifted types in that position).
These desugaring of box and unbox is explained in
Note [Desugaring box & unbox] in GHC.Core.Make.Box. Roughly speaking,
the desugaring looks like:
box @r @ty e ==> K e
unbox @r @ty e ==> case e of K x -> x
where 'K' is the boxing data constructor at RuntimeRep 'r'. It's
slightly more complicated than that in practice: we first need to
insert a cast (see Note [The canonical type of a RuntimeRep]) using the
new 'CanonicalProv' 'UnivCoProvenance', and unboxed tuples/sums need
recursive logic explained in Note [box/unbox for unboxed tuples and sums],
including a specific 'BoxSum' datatypes for unboxed sum (which also
needed a wired-in type-level list indexing type family (!!)).
The desugaring happens in two ways:
- Occurrences of 'box'/'unbox' emitted by the typechecker are
eliminated in the 'ds_app_var' case of GHC.HsToCore.Expr.
- Other code that needs to box/unbox emits the appropriate code inline.
This includes the big tuple machinery of GHC.Core.Make used by the
desugarer (GHC.HsToCore.{Utils,Binds,Arrows,ListComp}) as well as
the float-out pass (GHC.Core.Opt.SetLevels).
Core Lint checks that no occurrence of 'box'/'unbox' survives desugaring.
On the way, we overhaul the litany of big tuple functions by introducing
data BigTupleLayout = BoxedElements | BareElements
to distinguish the two kinds of "big tuples" that GHC routinely deals
with; for example 'mkBigCoreVarTupSolo' becomes 'mkBigCoreVarTup BareElements'.
All of this code is moved to the new module GHC.Core.Make.BigTuple.
Fixes #20864 #22336 #22473 #25065 #27331
-------------------------
Metric Decrease:
T9872a
-------------------------
- - - - -
4cf7628a by Evgeny Malyshev at 2026-09-17T02:39:56-04:00
Fix the CompactionFailed documentation link to compact
The old Haddock reference links into base instead of ghc-compact.
Use an explicit URL because ghc-compact depends on base, not vice versa.
Fixes #27558
Assisted-By: OpenAI Codex
- - - - -
098bba70 by Facundo Domínguez at 2026-09-17T14:57:41-04:00
Remove the call to hoistFlag from processCmdLineP
This call was undesirable because it was causing a reconstruction
of the list of flag processors.
Even relying on list fusion would not be sufficient because we want
to replace the list with a data structure with faster lookups to
address #25763.
The removal is done in two moves:
* We move CmdLineP to CmdLine.hs
* Then we move the effect of hoisting to processArgs via a new function
hoistEwM
- - - - -
e01799c7 by Facundo Domínguez at 2026-09-17T14:57:42-04:00
Do not create duplicate flag processors for the -W flag
This makes simpler implementing the command line parser with a trie map
holding flag processors. If we were to allow duplicate flag processors
for any flag, the trie map would need to be a multimap.
- - - - -
3875b257 by Facundo Domínguez at 2026-09-17T14:57:42-04:00
Replace the list of flag processors with a trie map in `processArgs`
Previously `GHC.Driver.CmdLine.findArg` was called for each
command-line argument, doing a linear search on the list of flag
processors each time. This was somewhat costly as the list of flag
processor has near 2000 elements.
A lookup with a trie map is faster in general, but the speed up is
only noticeable when calling `GHC.Driver.CmdLine.processArgs` sufficient
times, so the amount of lookups piles up. This could happen in large
projects with many units each having many dependencies. If only a
module needs to be recompiled, the user still needs to wait for all of
the flag parsing to complete.
The benchmark at testsuite/tests/perf/compiler/cmdline-parser shows a
10x speed up when using the trie.
The trie map is implemented in `GHC.Data.StringTrie`.
The design is explained in Note [Processing command line argument fast]
in GHC.Driver.Session.
The commit also:
* adds two property-based tests for trie map operations,
* adds a benchmark of the command line parser, and
* renames the predicate `arg_ok` to `valid_flag_suffix` to decide what
flag processor should be used when there are multiple matching
prefixes on a flag.
Fixes #25763.
- - - - -
5236634a by Andreas Klebinger at 2026-09-17T14:58:24-04:00
Compile Word64{Map,Set} with -O2 always.
This is the hottest code and even if we build GHC with -O0 otherwise -O2
pays off for these modules.
Fixes #27814.
- - - - -
545fd4fb by ARATA Mizuki at 2026-09-22T15:03:24-04:00
Change the C types of hs_{bitrev,bswap}{16,32} to match the Haskell types
bitReverse{16,32}# and byteSwap{16,32}# have the type
Word# -> Word#, but their C correspondents took and
returned StgWord{16,32}.
The mismatch on bitReverse16# led to the problem reported
in #27299. Although no similar issue is reported for
bitReverse32# and byteSwap{16,32}#, it seemed wise to
change them proactively.
This commit fixes the mismatch by changing the C type.
Fixes #27299
- - - - -
bf17f289 by fendor at 2026-09-22T15:04:05-04:00
Don't lose instances from shadowed imported modules with the same name
When we look for instances below the current module, we need to check
the unit id as well when we check for whether the module is the current
module, otherwise we ignore modules we import that have the same name as
the import module.
Adds regression test.
- - - - -
53eead15 by Wolfgang Jeltsch at 2026-09-24T20:12:03-04:00
Correct the documentation of `explicitUnits`
Resolves #27787.
- - - - -
35bf6f4b by Simon Jakobi at 2026-09-24T20:12:49-04:00
Remove stale specHeader bullet from Note [Don't make fillers for constraint types]
The Note said that Specialise.specHeader also calls mkAbsentFiller.
abfc224a27c removed that call: the specialiser no longer drops dead
arguments at all, see Note [Do not drop dead args from specialisations]
in GHC.Core.Opt.Specialise.
Assisted-by: Claude Fable 5.1
- - - - -
1abef1ef by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Improve the `mhu-closure` makefile
- - - - -
a79a68ea by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Make `ghci-multi` hide all unneeded packages
- - - - -
d6e72450 by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Improve the definition of the home unit closure property
- - - - -
c9a2766d by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Re-implement the home unit closure check
Compared to the previous implementation, the new one has the following
advantages:
* It is correct.
- It distinguishes between units that have the same unit ID but
different ABI hashes.
- When `-hide-all-packages` is not used, it considers as home unit
dependencies also units that are made implicitly available
because they are in the package database.
* It seems to be faster in usual settings.
- In particular, it does not have a preparation phase in which it
merges the dependency information from all home units, so that
its running time does not grow linearly with the size of the
package database in normal Cabal scenarios.
* It is (hopefully) clearer.
* It is better documented.
- - - - -
fa96acf8 by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Remove erroneous GHC flag in `hadrian-multi`
The flag was `-Werror=-Wno-error=incomplete-record-selectors`. Its
purpose was to permit incomplete record selectors, but because of the
illegal combination of `-Werror=` and `-Wno-error` it was ignored,
without any negative consequences.
- - - - -
9f48a5b9 by Alan Zimmerman at 2026-09-25T17:02:50-04:00
EPA: Add specific layout field to AnnList
Up to now AnnList has effectively served to represent lists of things
having layout, regardless of whether they do or not.
In Haskell, layout is optional in many places, as there is also an
alternative syntax using braces and semi-colons, which is free-form.
This commit introduces AnnListLayout, a data structure capturing this
distinction.
It is deliberately set up similarly to EpLayout, so that these two can
be merged in time.
The transition is done mechanically, where AnnListBraces is not used
yet, the original Nothing case maps to AnnListNoLayout, and the Just
case to AnnListLayout.
Later commits will fine tune these against the actual parser layout.
- - - - -
234bab08 by Vladislav Zavialov at 2026-09-29T17:22:54-04:00
Add regression test for #7803
Commit 2effe18ab5, first shipped with GHC 8.2.1, fixed #7803 "Superclass
methods are left unspecialized".
This change turns the example from the ticket description into a regression
test, checking that foo1 is fully specialised at Double, with no calls to the
overloaded exp5Tail.
Closes #7803
Assisted-by: Claude Opus 5
- - - - -
c406135c by Andreas Klebinger at 2026-10-01T06:57:28-04:00
RTS: Update flag parsing/handling:
Using 0 as argument to any of these flags now resets the flags setting to default:
- ``-n0`` disables nursery chunking.
- ``-K0`` (or a bare ``-K``) removes the stack size limit.
- ``-M0`` removes the heap size limit.
- ``-H0`` resets the suggested heap size, including the nursery scaling set by ``-H``.
- ``-AL0`` makes the large object allocation limit follow ``-A`` again.
GC Generations are now limited to 64.
-n larger than -A now emits a warning and disables chunking.
Fixes #27830 #27829
- - - - -
984ee82b by Andreas Klebinger at 2026-10-01T06:58:10-04:00
Fix MultiLayerModules timeout multiplier.
We accidentally used the compile multiplier for ghci commands which
use the run timeout setting to set the timeout.
Fixes #26263 and #27796.
- - - - -
50a9cf26 by Andreas Klebinger at 2026-10-01T06:58:10-04:00
testsuite: Include runtime in JUnit report.
- - - - -
e358619f by Alan Zimmerman at 2026-10-01T06:59:01-04:00
EPA: Use EpaLocation in EpVirtualBraces
Haddock processing uses EpLayout.EpVirtualBraces to record the current
layout column, for allocating haddock comments correctly.
For exact printing, we need the line as well as the col, so we know
how many lines to skip when the indented code block starts.
This commit updates EpLayout.EpVirtualBraces so that it carries an
EpaLocation instead of just the Int column, to allow it to be used for
both purposes.
It is a simple mechanical change, with no other impact, but it allows
us to use EpLayout instead of AnnListLayout in AnnList, in the next
commit in this series.
- - - - -
1d2a26ee by Andrew Lelechenko at 2026-10-01T20:22:04-04:00
Remove bitSize from MINIMAL pragma of class Bits
Cf. https://github.com/haskell/core-libraries-committee/issues/441
The function is deprecated for 12 years and has a default implementation,
yet it was never removed from the MINIMAL pragma, putting library authors
in a very awkward position. Let's finally remove bitSize from MINIMAL.
- - - - -
3cc21e4c by Hannes Siebenhandl at 2026-10-01T20:22:59-04:00
Add regression test for #27641
- - - - -
c35096f5 by Hannes Siebenhandl at 2026-10-01T20:23:00-04:00
Don't `:add` modules the loader will reject
Only home modules can be actually added to the loader context, thus we
only accept the module if it belongs to a home unit.
- - - - -
a563cb27 by Simon Jakobi at 2026-10-02T17:37:36-04:00
ci: accept modified changelog.d entries in lint-changelog
The changelog guide says to extend an existing entry rather than add a
new one when the feature is already documented. lint_changelog only
counted added files, so such MRs failed before the validator ran.
Fixes #27779.
Assisted-by: Claude Fable 5.1
- - - - -
03082cd4 by Simon Jakobi at 2026-10-02T17:38:17-04:00
changelog.d: Fix warning flag name in the semaphore-v2 entry
The entry refers to -Wsemaphore-version-mismatch, which does not exist.
The warning GHC emits when it cannot use a -jsem semaphore, including
on a protocol version mismatch, is -Wsemaphore-open-failure.
Context: !15729, #25087
Assisted-by: Claude Fable 5.1
- - - - -
a93705ee by Simon Jakobi at 2026-10-02T17:38:17-04:00
changelog.d: Fix the CLC proposal link in the T27455 entry
The entry used the Sphinx :ref: role with a URL as its target. :ref:
resolves only internal labels, so the generated release notes would
show the proposal name without a link. Use the plain hyperlink form
like the other entries.
Context: !16274, #27455
Assisted-by: Claude Fable 5.1
- - - - -
54381079 by Hannes Siebenhandl at 2026-10-02T17:39:01-04:00
Extend the `TrustOverlay` for wired-in units
The TrustOverlay only contained the `UnitId` of all on-disk units.
However, wired-in units are referred to by their wired-in unit id, which
is not the same as the on-disk unit id.
Thus, trust checks for wired-in units failed because the lookup was
using the wired-in unit, which wasn't present in the `TrustOverlay`.
We fix #27834, by copying the trust info for wired-in unit ids.
- - - - -
f8cfb1a5 by Hécate Kleidukos at 2026-10-04T19:36:39+02:00
[CLC 341] Strict variants of mutable types
This commit is the implementation of CLC Proposal 341
https://github.com/haskell/core-libraries-committee/issues/341
- - - - -
575c4bc6 by Rodrigo Mesquita at 2026-10-05T12:32:02-04:00
ttg: HsModuleName in the AST, ModuleName in GHC
This commit makes the AST fully independent from GHC by parsing a
"module name" as an `HsModuleName (= HText)` rather than constructing an
`ModuleName (= FastString)` straight away.
In the GHC side, everything remains as a `ModuleName`. We turn AST
`HsModuleName`s into fast strings with the cheap `mkFastStringShortText`
when we process the AST for manipulation within the compiler.
There are no performance regressions introduced by this approach.
This is the final piece of #21592
Alternative plans were discussed in
gitlab.haskell.org/ghc/ghc/-/merge_requests/16546#note_694647,
but the Simon suggested one won in simplicity and performance when
compared against my attempt at implementing my original plan of having
a family `ModuleNameP`.
- - - - -
b3b89d32 by mangoiv at 2026-10-05T22:03:32-04:00
hadrian: Persist the used flavour name in the build root (#20650)
This executes the idea proposed in #20650, teaching Hadrian to persist
the flavour used to build a build root. This both makes use of multiple
build roots more ergonomic (as the user no longer needs to repeat
themselves) and avoids a tiresome foot-gun (forgetting to specify a
flavour, often wholly invalidating a build root).
Closes #20650.
Co-authored-by: Sylvain Henry <sylvain(a)haskus.fr>
- - - - -
f977837b by mangoiv at 2026-10-05T22:04:21-04:00
configure: fix sed script and subst tooldir script
Fixes #27672
Adds sanity checking for SUBST_TOOLDIR
Metric Decrease:
LinkableUsage01
MultiLayerModulesTH_OneShot
T10547
T12234
T12425
T13035
T13820
T18140
T18730
T18923
T9198
TcPlugin_RewritePerf
mhu-perf
- - - - -
f1cb08be by Hannes Siebenhandl at 2026-10-05T22:05:03-04:00
Prepend in-memory unit database for backpack
The packageDbFlags are stored in reverse order. Thus, prepending will
ensure that the in-memory unit database is the last item on the unit
database stack.
Further, the in-memory unit database needs to be able to shadow units
from earlier unit databases in the unit database stack.
Moreover, a `-clear-package-db` would remove the in-memory database if
it weren't the last item on the stack.
Closes #27835
- - - - -
8d49ed42 by Kazu Yamamoto at 2026-10-06T19:37:25-04:00
Do not leave standard file descriptors free at startup (#24450)
A process may be started with stdout closed -- `prog >&-` from a shell does
exactly that. Nothing then reserves descriptor 1, and open(), pipe() and
socket() hand out the lowest free descriptor, so the next descriptor the
runtime creates for itself takes it: the ticker's pipe, or a capability's IO
manager control pipe.
'GHC.Internal.IO.StdHandles.stdout' is a CAF, built the first time the program
writes to stdout, which is long after that has happened. It builds a 'Handle'
over descriptor 1, which now belongs to the runtime, and nothing reports an
error because the descriptor is perfectly good. The program then writes its
output into the runtime's own plumbing.
What that looks like from the outside is a hang. The descriptor the Handle has
taken over is the read end of a pipe, so poll() for POLLOUT on it never says
yes and epoll_ctl() accepts a registration for it; the thread waiting to write
blocks for ever. Closing the Handle at exit closes the runtime's descriptor,
which is worse: the ticker then fails on every tick.
'hs_init_ghc' now opens /dev/null onto whichever of descriptors 0, 1 and 2 are
closed, before the runtime creates any descriptor of its own. Each is opened
for the access that descriptor would normally have, read-only for 0 and
write-only for 1 and 2, so that writing to 'stdin' or reading from 'stdout'
still fails rather than quietly succeeding against /dev/null. See
Note [Standard file descriptors must be open].
Moving only the descriptors the runtime opens would not do: the first file the
program itself opened would land on the free number instead. The fix has to
leave no free number. A program run this way therefore finds stdout connected
to /dev/null rather than failing with EBADF on the first write, which is what
such a program would get from most other language runtimes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply(a)anthropic.com>
- - - - -
65bcf9e9 by Simon Jakobi at 2026-10-06T19:38:09-04:00
changelog: Repair the sentence describing #27477
The description read "programs using could crash", the object of
"using" having been lost. The synopsis already says which programs are
affected, so drop the dangling word.
Assisted-by: Claude Fable 5.1
- - - - -
e0e4c1b0 by Sasha Bogicevic at 2026-10-08T15:49:53+02:00
Don't report -XStrict-generated bangs under -Wredundant-bang-patterns
With -XStrict, decideBangHood inserts bang patterns on binders. When
such a bang cannot force anything (e.g. on a binder of unlifted type),
-Wredundant-bang-patterns reported it, even though there is no bang in
the source to remove.
The desugarer now tracks whether it is desugaring compiler-generated
code, mirroring tcl_in_gen_code in the typechecker:
* decideBangHood places the bangs it inserts at a generatedSrcSpan.
* DsLclEnv gains a dsl_in_generated_code field, maintained solely by
putSrcSpanDs: a real span clears it, a generated span sets it.
* The pattern-match checker's desugaring (desugarLPat) pushes each
pattern's location, and on a bang in generated code emits a PmBang
with no SrcInfo: it is still divergence-checked (so inaccessible-RHS
warnings under -XStrict survive, #21761), but never reported as
redundant.
See Note [Desugaring -XStrict matches in Pmc] in GHC.HsToCore.Pmc.Desugar.
Making these bangs proper expanded patterns instead is tracked as #27677.
- - - - -
496 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- + changelog.d/24450
- + changelog.d/25763-cmdline-opt
- + changelog.d/26610
- + changelog.d/27556
- + changelog.d/27641
- + changelog.d/27732
- + changelog.d/T27323
- changelog.d/T27455
- + changelog.d/T27629
- + changelog.d/T27749
- + changelog.d/T27764
- + changelog.d/T27788-js-selector
- + changelog.d/T27830-rts-flag-bounds
- + changelog.d/allow-gadt-prefix-con-parens
- + changelog.d/boxing-family
- + changelog.d/clc-341-strict-mutable-data-types
- + changelog.d/clc-421
- + changelog.d/fix-compacting-gc-constr-27649
- + changelog.d/fix-control0-mask-trampoline
- + changelog.d/fix-parallel-gc-selector-race-27477
- + changelog.d/fix-threadlabel-segfault-27618
- + changelog.d/hadrian-persist-flavour
- + changelog.d/implicit-field-strictness-warning
- changelog.d/lazy-field-annotations
- + changelog.d/ncg-x86-bit-test-instructions
- + changelog.d/select-io-manager
- changelog.d/semaphore-v2
- changelog.d/unit-index
- compiler/GHC.hs
- compiler/GHC/Builtin.hs
- compiler/GHC/Builtin/KnownKeys.hs
- compiler/GHC/Builtin/Modules.hs
- compiler/GHC/Builtin/Uniques.hs
- compiler/GHC/Builtin/WiredIn/Ids.hs
- compiler/GHC/Builtin/WiredIn/Prim.hs
- compiler/GHC/Builtin/WiredIn/TypeLits.hs
- compiler/GHC/Builtin/WiredIn/Types.hs
- + compiler/GHC/Builtin/WiredIn/Types/Box.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Show.hs
- compiler/GHC/Cmm/DebugBlock.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion/Axiom.hs
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/FamInstEnv.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- + compiler/GHC/Core/Make/BigTuple.hs
- + compiler/GHC/Core/Make/Box.hs
- compiler/GHC/Core/Opt/CallerCC/Types.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Opt/WorkWrap/Utils.hs
- compiler/GHC/Core/TyCo/Ppr.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/AddImplicitBinds.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Data/FastString.hs
- + compiler/GHC/Data/StringTrie.hs
- compiler/GHC/Data/Word64Map/Internal.hs
- compiler/GHC/Data/Word64Map/Strict/Internal.hs
- compiler/GHC/Data/Word64Set/Internal.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/CmdLine.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Env.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/GenerateCgIPEStub.hs
- compiler/GHC/Driver/Main/Compile.hs
- compiler/GHC/Driver/Main/Passes.hs
- compiler/GHC/Driver/Pipeline.hs-boot
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Pipeline/Phases.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Extension/Pass.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Lit.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Arrows.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/ListComp.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Types.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/Iface/Decl.hs
- compiler/GHC/Iface/Errors/Types.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Ext/Debug.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/Header.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Parser/String.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Unbound.hs
- compiler/GHC/Stg/Debug.hs
- compiler/GHC/Stg/Lint.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/CodeGen.hs
- compiler/GHC/StgToJS/Linker/Linker.hs
- compiler/GHC/StgToJS/Symbols.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Generate.hs
- compiler/GHC/Tc/Deriv/Generics.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Match.hs
- compiler/GHC/Tc/Gen/Pat.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Instance/Family.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Solver/Default.hs
- compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Types/ErrCtxt.hs
- compiler/GHC/Tc/Utils/Backpack.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/CompleteMatch.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Types/TyThing.hs
- compiler/GHC/Types/TyThing/Ppr.hs
- compiler/GHC/Types/Unique.hs
- compiler/GHC/Types/UnresolvedImport.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/External/Wired.hs
- compiler/GHC/Unit/Home.hs
- compiler/GHC/Unit/Module.hs
- compiler/GHC/Unit/Module/Env.hs
- + compiler/GHC/Unit/Module/Name.hs
- compiler/GHC/Unit/Parser.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Unit/Types.hs
- compiler/GHC/Unit/Types.hs-boot
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Outputable.hs
- compiler/Language/Haskell/Syntax.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- compiler/Language/Haskell/Syntax/ImpExp.hs
- compiler/Language/Haskell/Syntax/Lit.hs
- compiler/Language/Haskell/Syntax/Module/Name.hs
- compiler/Language/Haskell/Syntax/Text.hs
- compiler/Language/Haskell/Syntax/Type.hs
- compiler/ghc.cabal.in
- configure.ac
- distrib/configure.ac.in
- docs/users_guide/exts/gadt_syntax.rst
- docs/users_guide/exts/strict.rst
- docs/users_guide/exts/type_data.rst
- docs/users_guide/runtime_control.rst
- docs/users_guide/using-warnings.rst
- ghc/GHC/Driver/Session/Mode.hs
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Info.hs
- hadrian/doc/flavours.md
- hadrian/ghci-multi-cabal.in
- hadrian/src/Base.hs
- hadrian/src/Builder.hs
- hadrian/src/Hadrian/Builder.hs
- hadrian/src/Hadrian/Builder/Ar.hs
- hadrian/src/Hadrian/Oracles/Path.hs
- hadrian/src/Hadrian/Utilities.hs
- hadrian/src/Oracles/Setting.hs
- hadrian/src/Oracles/TestSettings.hs
- hadrian/src/Rules.hs
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Rules/Changelog.hs
- hadrian/src/Rules/Codes.hs
- hadrian/src/Rules/Lint.hs
- hadrian/src/Rules/Nofib.hs
- hadrian/src/Rules/Test.hs
- hadrian/src/Settings.hs
- libraries/base/base.cabal.in
- libraries/base/changelog.md
- libraries/base/src/Control/Concurrent/Chan.hs
- + libraries/base/src/Control/Concurrent/Chan/Strict.hs
- libraries/base/src/Control/Concurrent/MVar.hs
- + libraries/base/src/Control/Concurrent/MVar/Strict.hs
- libraries/base/src/Data/IORef.hs
- + libraries/base/src/Data/IORef/Strict.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/include/RtsIfaceSymbols.h
- libraries/ghc-internal/src/GHC/Internal/Bits.hs
- + libraries/ghc-internal/src/GHC/Internal/Box.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/TypeNats.hs
- libraries/ghc-internal/src/GHC/Internal/Types.hs
- linters/lint-codes/LintCodes/Static.hs
- m4/find_python.m4
- + m4/fp_canonicalise_win_path.m4
- m4/fp_find_nm.m4
- m4/fp_find_root.m4
- m4/fp_prog_ar.m4
- m4/fp_prog_ar_args.m4
- m4/fp_prog_sh.m4
- m4/fptools_alex.m4
- m4/fptools_happy.m4
- m4/subst_tooldir.m4
- rts/Capability.c
- rts/Continuation.c
- rts/ContinuationOps.cmm
- rts/HeapStackCheck.cmm
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/Interpreter.c
- rts/Messages.c
- rts/Prelude.h
- rts/PrimOps.cmm
- rts/Printer.c
- rts/RaiseAsync.c
- rts/RtsFlags.c
- rts/RtsStartup.c
- rts/STM.c
- rts/Schedule.c
- rts/Sparks.c
- rts/StableName.c
- rts/StgMiscClosures.cmm
- rts/ThreadPaused.c
- rts/Threads.c
- rts/Trace.h
- rts/configure.ac
- rts/include/rts/Flags.h
- rts/include/rts/RtsToHsIface.h
- rts/include/rts/storage/Closures.h
- rts/include/rts/storage/GC.h
- rts/include/stg/MiscClosures.h
- rts/include/stg/Prim.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- + rts/posix/SelectBis.c
- + rts/posix/SelectBis.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/prim/bitrev.c
- rts/prim/bswap.c
- rts/rts.cabal
- rts/sm/Compact.c
- rts/sm/Evac.c
- rts/sm/GC.c
- rts/sm/GCUtils.c
- rts/sm/MBlock.c
- rts/sm/NonMoving.c
- rts/sm/NonMovingMark.c
- rts/sm/Storage.c
- rts/sm/Sweep.c
- testsuite/driver/junit.py
- testsuite/driver/testglobals.py
- testsuite/driver/testlib.py
- testsuite/tests/MiniQuickCheck.hs
- testsuite/tests/arrows/should_run/all.T
- + testsuite/tests/arrows/should_run/arrowrun005.hs
- + testsuite/tests/arrows/should_run/arrowrun005.stdout
- + testsuite/tests/backpack/should_compile/T27835.bkp
- + testsuite/tests/backpack/should_compile/T27835.stderr
- testsuite/tests/backpack/should_compile/all.T
- + testsuite/tests/bytecode/T27633/Obj.hs
- + testsuite/tests/bytecode/T27633/T27633a.hs
- + testsuite/tests/bytecode/T27633/T27633a.stdout
- + testsuite/tests/bytecode/T27633/T27633b.hs
- + testsuite/tests/bytecode/T27633/T27633b.stdout
- + testsuite/tests/bytecode/T27633/all.T
- + testsuite/tests/codeGen/should_gen_asm/T25233.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233.hs
- + testsuite/tests/codeGen/should_gen_asm/T25233b.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233b.cmm
- testsuite/tests/codeGen/should_gen_asm/all.T
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/deSugar/should_compile/T25065a.hs
- testsuite/tests/deSugar/should_compile/all.T
- + testsuite/tests/deSugar/should_run/T20864.hs
- + testsuite/tests/deSugar/should_run/T20864.stdout
- + testsuite/tests/deSugar/should_run/T25065b.hs
- + testsuite/tests/deSugar/should_run/T25065b.stdout
- testsuite/tests/deSugar/should_run/all.T
- testsuite/tests/driver/all.T
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/Makefile
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/mhu-closure.stderr
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/mhu-closure.stdout
- + testsuite/tests/driver/stringtrie.hs
- + testsuite/tests/driver/stringtrie.stdout
- − testsuite/tests/gadt/T14320.stderr
- testsuite/tests/gadt/T18191.hs
- testsuite/tests/gadt/T18191.stderr
- + testsuite/tests/gadt/T27423a.hs
- + testsuite/tests/gadt/T27423b.hs
- + testsuite/tests/gadt/T27423b.stderr
- testsuite/tests/gadt/all.T
- testsuite/tests/ghc-api/T25121_status.stdout
- testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.hs
- testsuite/tests/ghc-api/exactprint/T22919.stderr
- testsuite/tests/ghc-api/exactprint/Test20239.stderr
- testsuite/tests/ghc-api/exactprint/ZeroWidthSemi.stderr
- + testsuite/tests/ghci.debugger/scripts/T27633c.hs
- + testsuite/tests/ghci.debugger/scripts/T27633c.script
- + testsuite/tests/ghci.debugger/scripts/T27633c.stdout
- + testsuite/tests/ghci.debugger/scripts/T27633c_obj.hs
- testsuite/tests/ghci.debugger/scripts/all.T
- + testsuite/tests/ghci/prog-mhu008/Makefile
- + testsuite/tests/ghci/prog-mhu008/a/M.hs
- + testsuite/tests/ghci/prog-mhu008/all.T
- + testsuite/tests/ghci/prog-mhu008/b/M.hs
- + testsuite/tests/ghci/prog-mhu008/prog-mhu008.script
- + testsuite/tests/ghci/prog-mhu008/prog-mhu008.stdout
- + testsuite/tests/ghci/prog-mhu008/unitA
- + testsuite/tests/ghci/prog-mhu008/unitB
- + testsuite/tests/ghci/scripts/T27641.script
- + testsuite/tests/ghci/scripts/T27641.stderr
- + testsuite/tests/ghci/scripts/T27641.stdout
- + testsuite/tests/ghci/scripts/T27834.hs
- + testsuite/tests/ghci/scripts/T27834.script
- + testsuite/tests/ghci/scripts/T27834.stdout
- testsuite/tests/ghci/scripts/all.T
- 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/hiefile/should_run/T24544.hs
- + testsuite/tests/indexed-types/should_run/T27331.hs
- + testsuite/tests/indexed-types/should_run/T27331.stdout
- + testsuite/tests/indexed-types/should_run/T27331b.hs
- + testsuite/tests/indexed-types/should_run/T27331b.stdout
- + testsuite/tests/indexed-types/should_run/T27331b_Plugin.hs
- testsuite/tests/indexed-types/should_run/all.T
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/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/javascript/T27788.hs
- + testsuite/tests/javascript/T27788.stdout
- testsuite/tests/javascript/all.T
- testsuite/tests/linters/notes.stdout
- 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/T15279.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/perf/compiler/T25763.stderr
- testsuite/tests/perf/compiler/all.T
- + testsuite/tests/pmcheck/should_compile/T27323.hs
- testsuite/tests/pmcheck/should_compile/all.T
- + testsuite/tests/primops/should_run/T27299.hs
- + testsuite/tests/primops/should_run/T27299.stdout
- testsuite/tests/primops/should_run/all.T
- testsuite/tests/printer/AnnotationNoListTuplePuns.stdout
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/T18791.stderr
- + testsuite/tests/printer/T27423c.hs
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/printer/Test24533.stdout
- testsuite/tests/printer/all.T
- testsuite/tests/profiling/should_run/caller-cc/CallerCcParser.hs
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- testsuite/tests/rename/should_fail/T26545.stderr
- + testsuite/tests/rts/T24450.hs
- + testsuite/tests/rts/T24450.stderr
- + testsuite/tests/rts/T27477.hs
- + testsuite/tests/rts/T27477.stdout
- + testsuite/tests/rts/T27618.hs
- + testsuite/tests/rts/T27618.stdout
- + testsuite/tests/rts/T27649.hs
- + testsuite/tests/rts/T27649.stdout
- testsuite/tests/rts/all.T
- + testsuite/tests/rts/continuations/T27651.hs
- + testsuite/tests/rts/continuations/T27651.stdout
- testsuite/tests/rts/continuations/all.T
- testsuite/tests/rts/rtsflags001.stderr-ws-32
- testsuite/tests/rts/rtsflags001.stderr-ws-64
- testsuite/tests/simplCore/should_compile/Makefile
- + testsuite/tests/simplCore/should_compile/T27556.hs
- + testsuite/tests/simplCore/should_compile/T27556.script
- + testsuite/tests/simplCore/should_compile/T27629.hs
- + testsuite/tests/simplCore/should_compile/T27629.stderr
- + testsuite/tests/simplCore/should_compile/T27629Plugin.hs
- + testsuite/tests/simplCore/should_compile/T27749.hs
- + testsuite/tests/simplCore/should_compile/T27749.stderr
- + testsuite/tests/simplCore/should_compile/T7803.hs
- + testsuite/tests/simplCore/should_compile/T7803.stderr
- + testsuite/tests/simplCore/should_compile/T7803a.hs
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/th/T17380.stderr
- testsuite/tests/th/T18612.stderr
- + testsuite/tests/th/T27034.hs
- + testsuite/tests/th/T27034.stderr
- testsuite/tests/th/T8761.stderr
- testsuite/tests/th/all.T
- + testsuite/tests/type-data/should_fail/T27732a.hs
- + testsuite/tests/type-data/should_fail/T27732a.stderr
- + testsuite/tests/type-data/should_fail/T27732b.hs
- + testsuite/tests/type-data/should_fail/T27732b.stderr
- + testsuite/tests/type-data/should_fail/T27732c.hs
- + testsuite/tests/type-data/should_fail/T27732c.stderr
- + testsuite/tests/type-data/should_fail/T27732d.hs
- + testsuite/tests/type-data/should_fail/T27732d.stderr
- + testsuite/tests/type-data/should_fail/T27732e.hs
- + testsuite/tests/type-data/should_fail/T27732e.stderr
- + testsuite/tests/type-data/should_fail/T27732f.hs
- + testsuite/tests/type-data/should_fail/T27732f.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessGADT.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessH98.stderr
- testsuite/tests/type-data/should_fail/all.T
- + testsuite/tests/typecheck/should_compile/T27664.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/warnings/should_compile/T16836a.hs
- + testsuite/tests/warnings/should_compile/T16836a.stderr
- + testsuite/tests/warnings/should_compile/T16836b.hs
- + testsuite/tests/warnings/should_compile/T16836c.hs
- + testsuite/tests/warnings/should_compile/T16836c.stderr
- + testsuite/tests/warnings/should_compile/T16836d.hs
- + testsuite/tests/warnings/should_compile/T16836d.stderr
- testsuite/tests/warnings/should_compile/all.T
- + testsuite/tests/warnings/should_fail/WExpectedNoArgError.stderr
- testsuite/tests/warnings/should_fail/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Transform.hs
- utils/check-exact/Utils.hs
- utils/deriveConstants/Main.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/hsc2hs
- utils/jsffi/dyld.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c311fd902beeab760f920c653ad91c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c311fd902beeab760f920c653ad91c…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/T27737] Attempt to deal with the perf issue in T18223 [skip ci]
by Simon Peyton Jones (@simonpj) 08 Oct '26
by Simon Peyton Jones (@simonpj) 08 Oct '26
08 Oct '26
Simon Peyton Jones pushed to branch wip/T27737 at Glasgow Haskell Compiler / GHC
Commits:
936e9884 by Simon Peyton Jones at 2026-10-08T14:21:30+01:00
Attempt to deal with the perf issue in T18223 [skip ci]
see `rebuildWithFloats`
- - - - -
1 changed file:
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -66,6 +66,7 @@ import GHC.Builtin.WiredIn.Ids( seqId )
import qualified GHC.Data.List.Infinite as Inf
import GHC.Data.Maybe ( isNothing, orElse, mapMaybe )
import GHC.Data.FastString
+import GHC.Data.OrdList ( fromOL ) -- TMP
import GHC.Unit.Module ( moduleName )
import GHC.Utils.Outputable
import GHC.Utils.Panic
@@ -1285,8 +1286,8 @@ simplExprF1 env expr@(Lam {}) cont
simplExprF1 env expr@(Case scrut bndr _ alts) cont
| Just (inner, outer) <- splitContForNoCaseCase env cont
-- See (COC-INV) in Note [sm_case_case: switching off case continuations]
- = do { expr' <- simplExprC env expr inner
- ; rebuild env expr' outer }
+ = do { (floats, expr') <- simplExprF env expr inner
+ ; rebuildWithFloats env floats expr' outer }
| otherwise
= {-#SCC "simplExprF1-Case" #-}
@@ -1312,8 +1313,9 @@ simplExprF1 env (Let (NonRec bndr rhs) body) cont
simplExprF1 env expr@(Let {}) cont
| Just (inner, outer) <- splitContForNoCaseCase env cont
- = do { expr' <- simplExprC env expr inner
- ; rebuild env expr' outer }
+ -- See (COC-INV) in Note [sm_case_case: switching off case continuations]
+ = do { (floats, expr') <- simplExprF env expr inner
+ ; rebuildWithFloats env floats expr' outer }
-- Now check for a join point. It's better to do the preInlineUnconditionally
-- test first, because joinPointBinding_maybe has to eta-expand, so a trivial
@@ -1626,6 +1628,22 @@ simplTick env tickish expr cont
rebuild :: SimplEnv -> OutExpr -> SimplCont -> SimplM (SimplFloats, OutExpr)
rebuild env expr cont = rebuild_go (zapSubstEnv env) expr cont
+rebuildWithFloats :: SimplEnv -> SimplFloats -> OutExpr -> SimplCont
+ -> SimplM (SimplFloats, OutExpr)
+-- (rebuildWithFloats env floats expr cont) rebuilds (let floats in expr)
+-- with continuation `cont`. Used only when seCaseCase is off.
+-- See (COC3) in Note [sm_case_case: switching off case continuations]
+rebuildWithFloats env floats expr cont
+ | Select { sc_bndr = bndr, sc_alts = alts, sc_env = se, sc_cont = cont' } <- cont
+ , isEmptyJoinFloats (sfJoinFloats floats)
+ , let env1 = zapSubstEnv env `setInScopeFromF` floats
+ , Just do_it <- knownConCase_maybe (mkAltEnv env1 se) expr bndr alts cont'
+ = do { (floats2, res) <- do_it
+ ; return (floats `addFloats` floats2, res) }
+
+ | otherwise
+ = rebuild env (wrapFloats floats expr) cont
+
rebuild_go :: HasDebugCallStack
=> SimplEnvIS -> OutExpr -> SimplCont -> SimplM (SimplFloats, OutExpr)
-- SimplEnvIS: at this point the substitution in the SimplEnv is irrelevant;
@@ -3287,41 +3305,9 @@ rebuildCase, reallyRebuildCase
-- 1. Eliminate the case if there's a known constructor
--------------------------------------------------
-rebuildCase (saf,env) scrut case_bndr alts cont
- | Lit lit <- scrut -- No need for same treatment as constructors
- -- because literals are inlined more vigorously
- , not (litIsLifted lit)
- = do { tick (KnownBranch case_bndr)
- ; case findAlt (LitAlt lit) alts of
- Nothing -> missingAlt env case_bndr alts cont
- Just (Alt _ bs rhs) -> simpl_rhs env scrut bs rhs }
-
- | Just (in_scope', wfloats, con, ty_args, other_args)
- <- exprIsConApp_maybe (getUnfoldingInRuleMatch env) scrut
- -- Works when the scrutinee is a variable with a known unfolding
- -- as well as when it's an explicit constructor application
- , let env0 = setInScopeSet env in_scope'
- = do { tick (KnownBranch case_bndr)
- ; let -- case_bndr_unf: see Note [Do not duplicate constructor applications]
- case_bndr_rhs | exprIsTrivial scrut = scrut
- | otherwise = con_app
- con_app = Var (dataConWorkId con) `mkTyApps` ty_args
- `mkApps` other_args
- ; wrapDataConFloats env wfloats case_bndr cont $
- case findAlt (DataAlt con) alts of
- Nothing -> missingAlt env0 case_bndr alts cont
- Just (Alt DEFAULT bs rhs) -> simpl_rhs env0 case_bndr_rhs bs rhs
- Just (Alt _ bs rhs) -> knownCon env0 scrut con other_args
- case_bndr bs rhs cont
- }
- where
- simpl_rhs env case_bndr_rhs bs rhs
- = assert (null bs) $
- do { (floats1, env') <- simplAuxBind (saf,env) case_bndr case_bndr_rhs
- -- scrut is a constructor application,
- -- hence satisfies let-can-float invariant
- ; (floats2, expr') <- simplExprF env' rhs cont
- ; return (floats1 `addFloats` floats2, expr') }
+rebuildCase saf_env scrut case_bndr alts cont
+ | Just do_it <- knownConCase_maybe saf_env scrut case_bndr alts cont
+ = do_it
--------------------------------------------------
-- 2. Eliminate the case if scrutinee is evaluated
@@ -3928,6 +3914,58 @@ let binders, so we could float them). But the need for the extra
complication is not clear.
-}
+knownConCase_maybe :: (SimplAltFlag, SimplEnv)
+ -> OutExpr -- Scrutinee
+ -> InId -- Case binder
+ -> [InAlt] -- Alternatives (increasing order)
+ -> SimplCont
+ -> Maybe (SimplM (SimplFloats, OutExpr))
+-- Case-of-known-constructor: returns Just if the scrutinee is a literal
+-- or (via exprIsConApp_maybe) a constructor application
+knownConCase_maybe (saf,env) scrut case_bndr alts cont
+ | Lit lit <- scrut -- No need for same treatment as constructors
+ -- because literals are inlined more vigorously
+ , not (litIsLifted lit)
+ = Just $
+ do { tick (KnownBranch case_bndr)
+ ; case findAlt (LitAlt lit) alts of
+ Nothing -> missingAlt env case_bndr alts cont
+ Just (Alt _ bs rhs) -> simpl_rhs env scrut bs rhs }
+
+ | Just (in_scope', wfloats, con, ty_args, other_args)
+ <- exprIsConApp_maybe (getUnfoldingInRuleMatch env) scrut
+ -- Works when the scrutinee is a variable with a known unfolding
+ -- as well as when it's an explicit constructor application
+ , let env0 = setInScopeSet env in_scope'
+ = Just $
+ (if isEmptyFloatBinds wfloats then id else
+ pprTrace "TMP-knownCon" (vcat [ text "nfloats" <+> ppr (length (fromOL wfloats))
+ , text "scrut" <+> ppr scrut ])) $
+ do { tick (KnownBranch case_bndr)
+ ; let -- case_bndr_unf: see Note [Do not duplicate constructor applications]
+ case_bndr_rhs | exprIsTrivial scrut = scrut
+ | otherwise = con_app
+ con_app = Var (dataConWorkId con) `mkTyApps` ty_args
+ `mkApps` other_args
+ ; wrapDataConFloats env wfloats case_bndr cont $
+ case findAlt (DataAlt con) alts of
+ Nothing -> missingAlt env0 case_bndr alts cont
+ Just (Alt DEFAULT bs rhs) -> simpl_rhs env0 case_bndr_rhs bs rhs
+ Just (Alt _ bs rhs) -> knownCon env0 scrut con other_args
+ case_bndr bs rhs cont
+ }
+
+ | otherwise
+ = Nothing
+ where
+ simpl_rhs env case_bndr_rhs bs rhs
+ = assert (null bs) $
+ do { (floats1, env') <- simplAuxBind (saf,env) case_bndr case_bndr_rhs
+ -- scrut is a constructor application,
+ -- hence satisfies let-can-float invariant
+ ; (floats2, expr') <- simplExprF env' rhs cont
+ ; return (floats1 `addFloats` floats2, expr') }
+
wrapDataConFloats :: SimplEnv -> FloatBinds -> InId -> SimplCont
-> SimplM (SimplFloats, OutExpr)
-> SimplM (SimplFloats, OutExpr)
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/936e98842424a6f0278a3ba2630be9d…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/936e98842424a6f0278a3ba2630be9d…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/substitution-via-mapper] 2 commits: Remove the Eq and Ord instances for ForAllTyFlag
by Simon Peyton Jones (@simonpj) 08 Oct '26
by Simon Peyton Jones (@simonpj) 08 Oct '26
08 Oct '26
Simon Peyton Jones pushed to branch wip/substitution-via-mapper at Glasgow Haskell Compiler / GHC
Commits:
a38ff2f0 by Simon Peyton Jones at 2026-10-07T15:40:53+01:00
Remove the Eq and Ord instances for ForAllTyFlag
In Note [Comparing visibility] in GHC.Core.TyCo.Compare we read that
"we always compare ForAllTyFlags with `eqForAllVis` or `cmpForAllVis`"
But alas there was an Eq and Ord instance for ForAllTyFlag, which made it
impossible to check this claim. So I made these changes:
* Move the definition of ForAllTyFlag and its related functions from
L.H.S.Specificity (where it did not belong, since L.H.S didn't use it)
into GHC.Types.Var.
* Remove the Eq and Ord instances for ForAllTyFlag
* Deal with the fallout, by using `eqForAllVis` or related functions.
* In interface files we use IfaceType as a key for a de-deduplication map
See Note [Deduplication during iface binary serialisation]
in GHC.Iface.Binary. For this we need /exact/ comparison, so we use a
newtype wrapper for IfaceForAllTyFlag, and give use `cmpForAllTyFlagExactly`
to implement its Ord instance. Tiresome but easy.
* Rename `toIfaceForAllBndrs` to `toIfaceForAllTyBndrs`
- - - - -
bc48ff7f by Simon Peyton Jones at 2026-10-07T17:55:32+01:00
Refactor type and coercion substitution
This MR refactors type and coercion substitution so that they use
TyCoMapper, rather than hand-rolled code. Fundamentally it's a simple
idea, but I had to do quite a bit of refactoring to make it fly.
I got Claude to help me this this refactoring, but I paid careful
attention to every line of code.
Main changes:
* New module GHC.Core.TyCo.Make which defines TyCoMapper, and a bunch of other
simple "smart constructors" for types and coercions. See
GHC.Core.TyCo.Rep Note [The Type-related module hierarchy], esp (TRM1)
* The new TyCoMapper has new fields `tcm_tcapp_ty` and `tcm_tcapp_co` to handle
type-constructor applications. These replace `tcm_tycon`.
* Rewrite GHC.Core.TyCo.Subst to use TyCoMapper
* Rewrite GHC.Core.Type.expandTypeSynonyms to use TyCoMapper.
* Implement `seqType` and `seqCo` with TyCoFolder. To to this I had to add
a `tcf_lit` field to TyCoFolder.
* A new module GHC.Utils.StrictIdentity to define a strict identity monad,
which itself is used for
substTyCoMapper :: TyCoMapper Subst StrictIdentity
Refactoring `seq` functions
* In GHC.Core.Seq, redefine `seqOneShot`, `seqRuleInfo`, and friends to return
`SeqResult`, a new type defined in GHC.Types.Baseic, rather than `()`. We
can define a Monoid instance for `SeqResult` that does the right thing.
* This has knock-on effects across the compiler.
- - - - -
58 changed files:
- compiler/GHC/Builtin/WiredIn/Prim.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion.hs-boot
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Reduction.hs
- compiler/GHC/Core/Seq.hs
- compiler/GHC/Core/TyCo/Compare.hs
- compiler/GHC/Core/TyCo/FVs.hs
- + compiler/GHC/Core/TyCo/Make.hs
- + compiler/GHC/Core/TyCo/Make.hs-boot
- compiler/GHC/Core/TyCo/Ppr.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCo/Rep.hs-boot
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Type.hs-boot
- compiler/GHC/Core/Unify.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/CoreToIface.hs-boot
- compiler/GHC/Driver/Main/Compile.hs
- compiler/GHC/Iface/Decl.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/Iface/Type.hs-boot
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Stg/EnforceEpt/TagSig.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Tc/Zonk/TcType.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/GHC/Types/Arity.hs
- compiler/GHC/Types/Basic.hs
- compiler/GHC/Types/Cpr.hs
- compiler/GHC/Types/Demand.hs
- compiler/GHC/Types/Name/Env.hs
- compiler/GHC/Types/Name/Occurrence.hs
- compiler/GHC/Types/Unique/FM.hs
- compiler/GHC/Types/Unique/Map.hs
- compiler/GHC/Types/Unique/Set.hs
- compiler/GHC/Types/Var.hs
- compiler/GHC/Types/Var.hs-boot
- compiler/GHC/Types/Var/Set.hs
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Outputable.hs
- + compiler/GHC/Utils/StrictIdentity.hs
- compiler/Language/Haskell/Syntax/Specificity.hs
- compiler/ghc.cabal.in
- testsuite/tests/count-deps/CountDepsParser.stdout
- utils/haddock/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f9ef07750bb5836e8342396c0eb2e1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f9ef07750bb5836e8342396c0eb2e1…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/dcoutts/foreign-label-source-refactoring] 43 commits: Correct the documentation of `explicitUnits`
by Duncan Coutts (@dcoutts) 08 Oct '26
by Duncan Coutts (@dcoutts) 08 Oct '26
08 Oct '26
Duncan Coutts pushed to branch wip/dcoutts/foreign-label-source-refactoring at Glasgow Haskell Compiler / GHC
Commits:
53eead15 by Wolfgang Jeltsch at 2026-09-24T20:12:03-04:00
Correct the documentation of `explicitUnits`
Resolves #27787.
- - - - -
35bf6f4b by Simon Jakobi at 2026-09-24T20:12:49-04:00
Remove stale specHeader bullet from Note [Don't make fillers for constraint types]
The Note said that Specialise.specHeader also calls mkAbsentFiller.
abfc224a27c removed that call: the specialiser no longer drops dead
arguments at all, see Note [Do not drop dead args from specialisations]
in GHC.Core.Opt.Specialise.
Assisted-by: Claude Fable 5.1
- - - - -
1abef1ef by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Improve the `mhu-closure` makefile
- - - - -
a79a68ea by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Make `ghci-multi` hide all unneeded packages
- - - - -
d6e72450 by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Improve the definition of the home unit closure property
- - - - -
c9a2766d by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Re-implement the home unit closure check
Compared to the previous implementation, the new one has the following
advantages:
* It is correct.
- It distinguishes between units that have the same unit ID but
different ABI hashes.
- When `-hide-all-packages` is not used, it considers as home unit
dependencies also units that are made implicitly available
because they are in the package database.
* It seems to be faster in usual settings.
- In particular, it does not have a preparation phase in which it
merges the dependency information from all home units, so that
its running time does not grow linearly with the size of the
package database in normal Cabal scenarios.
* It is (hopefully) clearer.
* It is better documented.
- - - - -
fa96acf8 by Wolfgang Jeltsch at 2026-09-25T17:02:07-04:00
Remove erroneous GHC flag in `hadrian-multi`
The flag was `-Werror=-Wno-error=incomplete-record-selectors`. Its
purpose was to permit incomplete record selectors, but because of the
illegal combination of `-Werror=` and `-Wno-error` it was ignored,
without any negative consequences.
- - - - -
9f48a5b9 by Alan Zimmerman at 2026-09-25T17:02:50-04:00
EPA: Add specific layout field to AnnList
Up to now AnnList has effectively served to represent lists of things
having layout, regardless of whether they do or not.
In Haskell, layout is optional in many places, as there is also an
alternative syntax using braces and semi-colons, which is free-form.
This commit introduces AnnListLayout, a data structure capturing this
distinction.
It is deliberately set up similarly to EpLayout, so that these two can
be merged in time.
The transition is done mechanically, where AnnListBraces is not used
yet, the original Nothing case maps to AnnListNoLayout, and the Just
case to AnnListLayout.
Later commits will fine tune these against the actual parser layout.
- - - - -
234bab08 by Vladislav Zavialov at 2026-09-29T17:22:54-04:00
Add regression test for #7803
Commit 2effe18ab5, first shipped with GHC 8.2.1, fixed #7803 "Superclass
methods are left unspecialized".
This change turns the example from the ticket description into a regression
test, checking that foo1 is fully specialised at Double, with no calls to the
overloaded exp5Tail.
Closes #7803
Assisted-by: Claude Opus 5
- - - - -
c406135c by Andreas Klebinger at 2026-10-01T06:57:28-04:00
RTS: Update flag parsing/handling:
Using 0 as argument to any of these flags now resets the flags setting to default:
- ``-n0`` disables nursery chunking.
- ``-K0`` (or a bare ``-K``) removes the stack size limit.
- ``-M0`` removes the heap size limit.
- ``-H0`` resets the suggested heap size, including the nursery scaling set by ``-H``.
- ``-AL0`` makes the large object allocation limit follow ``-A`` again.
GC Generations are now limited to 64.
-n larger than -A now emits a warning and disables chunking.
Fixes #27830 #27829
- - - - -
984ee82b by Andreas Klebinger at 2026-10-01T06:58:10-04:00
Fix MultiLayerModules timeout multiplier.
We accidentally used the compile multiplier for ghci commands which
use the run timeout setting to set the timeout.
Fixes #26263 and #27796.
- - - - -
50a9cf26 by Andreas Klebinger at 2026-10-01T06:58:10-04:00
testsuite: Include runtime in JUnit report.
- - - - -
e358619f by Alan Zimmerman at 2026-10-01T06:59:01-04:00
EPA: Use EpaLocation in EpVirtualBraces
Haddock processing uses EpLayout.EpVirtualBraces to record the current
layout column, for allocating haddock comments correctly.
For exact printing, we need the line as well as the col, so we know
how many lines to skip when the indented code block starts.
This commit updates EpLayout.EpVirtualBraces so that it carries an
EpaLocation instead of just the Int column, to allow it to be used for
both purposes.
It is a simple mechanical change, with no other impact, but it allows
us to use EpLayout instead of AnnListLayout in AnnList, in the next
commit in this series.
- - - - -
1d2a26ee by Andrew Lelechenko at 2026-10-01T20:22:04-04:00
Remove bitSize from MINIMAL pragma of class Bits
Cf. https://github.com/haskell/core-libraries-committee/issues/441
The function is deprecated for 12 years and has a default implementation,
yet it was never removed from the MINIMAL pragma, putting library authors
in a very awkward position. Let's finally remove bitSize from MINIMAL.
- - - - -
3cc21e4c by Hannes Siebenhandl at 2026-10-01T20:22:59-04:00
Add regression test for #27641
- - - - -
c35096f5 by Hannes Siebenhandl at 2026-10-01T20:23:00-04:00
Don't `:add` modules the loader will reject
Only home modules can be actually added to the loader context, thus we
only accept the module if it belongs to a home unit.
- - - - -
a563cb27 by Simon Jakobi at 2026-10-02T17:37:36-04:00
ci: accept modified changelog.d entries in lint-changelog
The changelog guide says to extend an existing entry rather than add a
new one when the feature is already documented. lint_changelog only
counted added files, so such MRs failed before the validator ran.
Fixes #27779.
Assisted-by: Claude Fable 5.1
- - - - -
03082cd4 by Simon Jakobi at 2026-10-02T17:38:17-04:00
changelog.d: Fix warning flag name in the semaphore-v2 entry
The entry refers to -Wsemaphore-version-mismatch, which does not exist.
The warning GHC emits when it cannot use a -jsem semaphore, including
on a protocol version mismatch, is -Wsemaphore-open-failure.
Context: !15729, #25087
Assisted-by: Claude Fable 5.1
- - - - -
a93705ee by Simon Jakobi at 2026-10-02T17:38:17-04:00
changelog.d: Fix the CLC proposal link in the T27455 entry
The entry used the Sphinx :ref: role with a URL as its target. :ref:
resolves only internal labels, so the generated release notes would
show the proposal name without a link. Use the plain hyperlink form
like the other entries.
Context: !16274, #27455
Assisted-by: Claude Fable 5.1
- - - - -
54381079 by Hannes Siebenhandl at 2026-10-02T17:39:01-04:00
Extend the `TrustOverlay` for wired-in units
The TrustOverlay only contained the `UnitId` of all on-disk units.
However, wired-in units are referred to by their wired-in unit id, which
is not the same as the on-disk unit id.
Thus, trust checks for wired-in units failed because the lookup was
using the wired-in unit, which wasn't present in the `TrustOverlay`.
We fix #27834, by copying the trust info for wired-in unit ids.
- - - - -
c159372f by Duncan Coutts at 2026-10-06T14:46:51+01:00
Move data FunctionOrData from GHC.Types.Basic to .ForeignCall
It makes more sense here, and we will soon use it in other related types
in this module.
Adjust all the other imports.
- - - - -
fcb0f581 by Duncan Coutts at 2026-10-06T14:46:51+01:00
Rename type FunctionOrData to ForeignLabelIsFunctionOrData
And its constructors from IsFunction | IsData to
ForeignLabelIsFunction | ForeignLabelIsData
This name better fits the names of the related types that it is used
with.
- - - - -
3fc95aae by Duncan Coutts at 2026-10-06T14:46:51+01:00
Change dsCCall to take a CCallSpec
and change callers as appropriate. There should be no semantic change.
It's just moving the CCallSpec construction into the two callers.
It is currently only used by the C & JS functions that generate code for
the foreign import wrapper constructs (in the call to createAdjustor).
- - - - -
c1bb9828 by Duncan Coutts at 2026-10-06T14:46:52+01:00
Change calls to createAdjustor to specify that it comes from the rts
Previously it said TargetIsInThisUnit, meaning that createAdjustor lives
in the local library. This is false since createAdjustor is defined in
the RTS.
In practice, this false source information did not matter because the
source information is not used (yet). However in future it will be, for
better Windows DLL support (which does care about such distinctions).
It doesn't really matter that we say it's the RTS (though that is
actually true), what's important is that it will always be external to
the current shared library.
- - - - -
5a8aec6b by Duncan Coutts at 2026-10-06T14:46:52+01:00
Remove unused TargetIsInThisUnit case from CCallStaticTargetUnit
The CCallStaticTargetUnit infortmation in the XStaticTarget (TTG
exstension point) is actually pretty dubious.
Historically it was a (Maybe Unit) and the comments say that it is only
used by out-of-line primop calls on Windows. Indeed it is only used on
Windows for the dynamic way, when each unit is built as a separate DLL
(which we currently do not support). And even in that hypothetical
situation, the information that actually gets filled in is completely
bogus.
It _could_ be used in the windows dll case to correctly distinguish
making an out-of-line call to a cmm primop that is defined in the
current dll or in an external dll. But the information gets filled in in
the renaming phase with the _current_ unit. This is blatently wrong.
Many out-of-line primops are defined in the rts, which is obviously not
the current unit. It _could_ be a reasonable default, that cmm primops
are expected to be in the current dll, but we would have to have support
to specify a different location, i.e. the rts.
Furthermore, in addition to TargetIsInThisUnit being unused (after the
previous patch) it should never be used because it uses an implicit
"this" which will be wrong as soon as the information is inlined across
units. Instead of an implicit unit, it should use an explicit unit which
can be initialised to the defining unit and then be compared later to
the current unit. This will work correctly when looking at unfoldings
across unit boundaries.
- - - - -
0536471b by Duncan Coutts at 2026-10-07T14:13:13+01:00
Rename CCallStaticTargetUnit to CLabelTargetLibrary
And the constructor TargetIsInThat to CLabelTargetInUnit.
We will end up using this type both for calls and for labels/addresses
(used in core literals), so adjust the name to be about C names/labels
rather than about calls specifically.
Also improve related code docs. And introduce a conversion function from
CLabelTargetLibrary to ForeignLabelSource. We will extend this
conversion when we add more constructors to CLabelTargetLibrary.
- - - - -
53592d0a by Duncan Coutts at 2026-10-07T14:13:13+01:00
Change data PrimOp to use a UnitId rather than Unit
This simplifies the conversions slightly, but more importantly in a
later change we are going to want to specify a unit where we will only
have a UnitId to hand, not a Unit.
- - - - -
34a74091 by Duncan Coutts at 2026-10-07T16:20:32+01:00
Extend 'foreign import prim' syntax to allow specifying the source package
that is: the package where the cmm entity comes from.
The package name is stashed in the "header" field for the FFI call, and
then the renamer resolves the package name to a unit id (with a new
ghc error for the failure of the package name resolution).
Fixes issue #27206
Adds test case T27206
- - - - -
2bf19f2d by Duncan Coutts at 2026-10-07T16:20:32+01:00
Use new package name syntax for primops from the RTS
foreign import prim "rts stg_thething"
Most uses of foreign import prim in the libraries are for primops
defined in .cmm files local to that library, but some import primops
defined in the rts. These cases should use the new syntax to specify the
package name in the ffi entity string.
- - - - -
de9c32f0 by Duncan Coutts at 2026-10-08T11:27:22+01:00
Change labelDynamic to labelLinkerUnit and refine the question it answers
Previously asked a very vague question:
-- | Does a 'CLabel' need dynamic linkage?
given the plethora of platforms and linking schemes, this is not a
question with a yes/no answer in general.
Instead we change the question to this:
-- | Does the target entity of a 'CLabel' live in the same linker unit
-- as the given module?
This _does_ have a clear meaning across platforms. (The notion of what
a linker unit is is platform dependent it is relatively consistent).
We also change the answer from Bool to a new type:
data LabelLinkerUnit = LinkerUnitLocal
| LinkerUnitExternal
In a subsequent change we will extend this type to admit a third answer:
unknown, could be either local or external. This is the case arising
from all user-written FFI declarations.
Update the callers: SRT generation and PIC.howToAccessLabel
The latter will need more work to do nicely, which we'll do in a
subsequent patch.
- - - - -
019e09b4 by Duncan Coutts at 2026-10-08T11:27:22+01:00
Extend LabelLinkerUnit with a third case: unknown
For user-written FFI calls, we never know where the target of the label
lives: it could live in the local linker unit or it could be external.
This case was not accounted for in the old labelDynamic function.
Callers need to decide if they want to know about all three cases, or
just want to know for sure that something is local, or for sure that
something is external and thus they can bundle the unknown case into the
negative.
- - - - -
b6c9d3de by Duncan Coutts at 2026-10-08T11:27:22+01:00
Update use of labelLinkerUnit in howToAccessLabel for unknown case
Since "is it external or local" is not a yes/no question anymore, due to
the "dunno, could be either" case, we update all the uses of
labelLinkerUnit in howToAccessLabel so that should do the right thing
for the unknown case.
In practice, the unknown case doesn't _yet_ reach howToAccessLabel for
non-win32 platforms because for the one case where it will occurr -- in
foreign calls -- labelLinkerUnit defines this always to be
LinkerUnitExternal for all platforms other than OSMinGW32.
But nevertheless, this brings us a step closer to accuracy in
howToAccessLabel, should we want to be more precise for foreign calls.
- - - - -
683dd6ec by Duncan Coutts at 2026-10-08T11:27:22+01:00
Extend ForeignLabelSource with ForeignLabelInUnknownPackage case
Initially this is treated the same way as ForeignLabelInExternalPackage.
Later we will extend this for Windows/PE to support building each
Haskell unit as a separate DLL, to support this unknown case
specifically.
- - - - -
d590f9cf by Duncan Coutts at 2026-10-08T11:27:22+01:00
Extend CLabelTargetLibrary with CLabelTargetUnknown case
Initially unused, but this will become the typical case, because in fact
when Haskell code uses ffi imports, we do not know where the name comes
from: we do not know if the named entity is defined in the current
shared lib or in another one. Knowing where C entities come from is the
exception rather than the rule.
- - - - -
e55790cd by Duncan Coutts at 2026-10-08T11:27:22+01:00
Extend LitLabel with CLabelTargetLibrary
Bundle the three fields of LitLabel into a new data CLabelSpec, defined
in GHC.Types.ForeignCall
Apart from the binary format, this should not change behaviour.
Behaviour changes are in the next patch
- - - - -
5dc9e552 by Duncan Coutts at 2026-10-08T11:27:22+01:00
Reorder and group related declarations in ForeignCall module
It was all a bit of a jumble.
- - - - -
ed813c32 by Duncan Coutts at 2026-10-08T11:27:22+01:00
Remove redundant util ccallConvAttribute and unused defaultCCallConv
Historically, the stdcall calling convention required special treatment
when constructing calls in the via-C backend, to declare the C prototype
with the right attributes to tell the C compiler what call convention to
use.
We no longer support stdcall. Now ccallConvAttribute returns empty for
every calling convention, or panics. So it is no longer useful.
The defaultCCallConv was unused.
- - - - -
ca2ade4b by Duncan Coutts at 2026-10-08T12:13:07+01:00
Add Note [Tracking labels' target libraries] and [Tracking labels' target type]
and reference these notes elsewhere.
- - - - -
71a632dd by Duncan Coutts at 2026-10-08T12:13:07+01:00
Change FFI imports to use CLabelTargetUnknown
We never know the target for normal foreign imports.
Historically, this information was only actually used for
"foreign import prim", and only on Windows when building with one DLL
per unit (which bitrotted). The previous default of using the current
package as the source was wrong, even for the limited case of Windows
DLLs, because many of the imports are for primops defined in the RTS,
which is certainly not the current package.
- - - - -
69cf70c4 by Duncan Coutts at 2026-10-08T12:13:07+01:00
Pass through the label source in stg->cmm conversion
Previously we had to hard code the (often incorrect) source
ForeignLabelInThisPackage. Now the Core label literal representation
carries the source, so we just convert that and pass it down.
As a consequence, if the source will now be either
ForeignLabelInUnknownPackage or ForeignLabelInPackage. The typical
value will be ForeignLabelInUnknownPackage, since that's what we get
for FFI imports of addresses.
In practice is not an immediate change of behaviour, because the only
user of this information is on Windows when building each Haskell unit
as a separate DLl, which isn't (yet) supported.
- - - - -
baeb2fbf by Duncan Coutts at 2026-10-08T12:13:07+01:00
Fix source for generated C name for 'foreign import "wrapper"'
For a 'foreign import "wrapper"' construct we generate a local wrapper
C function. We need to refer to the name of this local C function. We
_know_ that this function lives in the local shared lib, because it is
compiled into the same library. Thus we set the label source to be
CLabelTargetInUnit.
- - - - -
f18df396 by Duncan Coutts at 2026-10-08T12:13:07+01:00
Fix source for generated C name for 'foreign import capi'
For a 'foreign import capi' we generate a local wrapper function and
then call that. We need to refer to the name of this local C function.
We _know_ that this function lives in the local shared lib, because it
is compiled into the same library. Thus we set the label source to be
CLabelTargetInUnit.
- - - - -
9f6328ae by David Eichmann at 2026-10-08T13:12:54+01:00
Documentation: foreign imports of Cmm code must now specify source package
but the current package is the default.
- - - - -
120 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- + changelog.d/27641
- changelog.d/T27455
- + changelog.d/T27830-rts-flag-bounds
- + changelog.d/foreign-import-prim-with-package.md
- changelog.d/semaphore-v2
- changelog.d/unit-index
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/Cmm/CLabel.hs
- compiler/GHC/Cmm/Info/Build.hs
- compiler/GHC/Cmm/Node.hs
- compiler/GHC/Cmm/Parser.y
- compiler/GHC/Cmm/ThreadSanitizer.hs
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/LA64/CodeGen.hs
- compiler/GHC/CmmToAsm/PIC.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/RV64/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/Core/Opt/WorkWrap/Utils.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/HsToCore/Foreign/Call.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Foreign/Wasm.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Bind.hs
- compiler/GHC/StgToCmm/Foreign.hs
- compiler/GHC/StgToCmm/Lit.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/FFI.hs
- compiler/GHC/StgToJS/Literal.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Types/Basic.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/ForeignCall.hs
- compiler/GHC/Types/Literal.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/External/Wired.hs
- compiler/GHC/Unit/State.hs
- docs/users_guide/exts/ffi.rst
- docs/users_guide/runtime_control.rst
- ghc/GHCi/UI.hs
- hadrian/ghci-multi-cabal.in
- libraries/base/changelog.md
- libraries/ghc-internal/src/GHC/Internal/AllocationLimitHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/Prim/Ext.hs
- libraries/ghc-internal/src/GHC/Internal/Prim/Panic.hs
- rts/RtsFlags.c
- rts/include/rts/Flags.h
- rts/include/rts/storage/GC.h
- rts/sm/GC.c
- rts/sm/Storage.c
- testsuite/driver/junit.py
- testsuite/driver/testglobals.py
- testsuite/driver/testlib.py
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/Makefile
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/mhu-closure.stderr
- testsuite/tests/driver/multipleHomeUnits/mhu-closure/mhu-closure.stdout
- testsuite/tests/ghc-api/exactprint/T22919.stderr
- testsuite/tests/ghc-api/exactprint/Test20239.stderr
- testsuite/tests/ghc-api/exactprint/ZeroWidthSemi.stderr
- + testsuite/tests/ghci/scripts/T27641.script
- + testsuite/tests/ghci/scripts/T27641.stderr
- + testsuite/tests/ghci/scripts/T27641.stdout
- + testsuite/tests/ghci/scripts/T27834.hs
- + testsuite/tests/ghci/scripts/T27834.script
- + testsuite/tests/ghci/scripts/T27834.stdout
- testsuite/tests/ghci/scripts/all.T
- 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/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/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/T15279.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/perf/compiler/all.T
- testsuite/tests/printer/AnnotationNoListTuplePuns.stdout
- testsuite/tests/printer/T18791.stderr
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/printer/Test24533.stdout
- + testsuite/tests/rename/should_fail/T27206.hs
- + testsuite/tests/rename/should_fail/T27206.stderr
- testsuite/tests/rename/should_fail/all.T
- testsuite/tests/rts/all.T
- testsuite/tests/rts/rtsflags001.stderr-ws-32
- testsuite/tests/rts/rtsflags001.stderr-ws-64
- testsuite/tests/simplCore/should_compile/T16122.stderr
- + testsuite/tests/simplCore/should_compile/T7803.hs
- + testsuite/tests/simplCore/should_compile/T7803.stderr
- + testsuite/tests/simplCore/should_compile/T7803a.hs
- testsuite/tests/simplCore/should_compile/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Transform.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ea588929ed5e8617f7b1a8a59d88e7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ea588929ed5e8617f7b1a8a59d88e7…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 5 commits: Do not leave standard file descriptors free at startup (#24450)
by Marge Bot (@marge-bot) 08 Oct '26
by Marge Bot (@marge-bot) 08 Oct '26
08 Oct '26
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
8d49ed42 by Kazu Yamamoto at 2026-10-06T19:37:25-04:00
Do not leave standard file descriptors free at startup (#24450)
A process may be started with stdout closed -- `prog >&-` from a shell does
exactly that. Nothing then reserves descriptor 1, and open(), pipe() and
socket() hand out the lowest free descriptor, so the next descriptor the
runtime creates for itself takes it: the ticker's pipe, or a capability's IO
manager control pipe.
'GHC.Internal.IO.StdHandles.stdout' is a CAF, built the first time the program
writes to stdout, which is long after that has happened. It builds a 'Handle'
over descriptor 1, which now belongs to the runtime, and nothing reports an
error because the descriptor is perfectly good. The program then writes its
output into the runtime's own plumbing.
What that looks like from the outside is a hang. The descriptor the Handle has
taken over is the read end of a pipe, so poll() for POLLOUT on it never says
yes and epoll_ctl() accepts a registration for it; the thread waiting to write
blocks for ever. Closing the Handle at exit closes the runtime's descriptor,
which is worse: the ticker then fails on every tick.
'hs_init_ghc' now opens /dev/null onto whichever of descriptors 0, 1 and 2 are
closed, before the runtime creates any descriptor of its own. Each is opened
for the access that descriptor would normally have, read-only for 0 and
write-only for 1 and 2, so that writing to 'stdin' or reading from 'stdout'
still fails rather than quietly succeeding against /dev/null. See
Note [Standard file descriptors must be open].
Moving only the descriptors the runtime opens would not do: the first file the
program itself opened would land on the free number instead. The fix has to
leave no free number. A program run this way therefore finds stdout connected
to /dev/null rather than failing with EBADF on the first write, which is what
such a program would get from most other language runtimes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply(a)anthropic.com>
- - - - -
65bcf9e9 by Simon Jakobi at 2026-10-06T19:38:09-04:00
changelog: Repair the sentence describing #27477
The description read "programs using could crash", the object of
"using" having been lost. The synopsis already says which programs are
affected, so drop the dangling word.
Assisted-by: Claude Fable 5.1
- - - - -
b9582136 by mangoiv at 2026-10-08T08:19:21-04:00
ci: move hadrian/ghci into the lint category so it can be picked up by more runners
Fixes #27817
- - - - -
a6722e24 by mangoiv at 2026-10-08T08:19:21-04:00
ci: make lint-adjacent jobs into platform independent
- move lint jobs into lint-anyarch tag
- unify lint jobs under the same platform independent container
- - - - -
5f220362 by Zubin Duggal at 2026-10-08T08:19:22-04:00
DmdAnal: Make AbsDmd neutral in maxDmd
fixes #27845
- - - - -
16 changed files:
- .gitlab-ci.yml
- + changelog.d/24450
- + changelog.d/27845
- changelog.d/fix-parallel-gc-selector-race-27477
- compiler/GHC/Types/Demand.hs
- rts/RtsStartup.c
- + testsuite/tests/dmdanal/should_run/T27845.hs
- + testsuite/tests/dmdanal/should_run/T27845.stdout
- + testsuite/tests/dmdanal/should_run/T27845_Lib.hs
- + testsuite/tests/dmdanal/should_run/T27845b.hs
- + testsuite/tests/dmdanal/should_run/T27845b.stdout
- + testsuite/tests/dmdanal/should_run/T27845b_Lib.hs
- testsuite/tests/dmdanal/should_run/all.T
- + testsuite/tests/rts/T24450.hs
- + testsuite/tests/rts/T24450.stderr
- testsuite/tests/rts/all.T
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -137,15 +137,37 @@ workflow:
.lint:
stage: tool-lint
tags:
- - lint
- before_script:
- # Allow Git to read from the runner-owned checkout. This is needed
- # for example by the lint-author job.
- - git config --global --add safe.directory "$CI_PROJECT_DIR"
+ - lint-anyarch
+ image: debian:13
rules:
- *drafts-can-fail-lint
- when: always
+.install-ghc-toolchain: &install-ghc-toolchain
+ - apt update
+ - apt install -qy build-essential curl libffi-dev libffi8 libgmp-dev libgmp10 libncurses-dev libncurses6 libtinfo6 pkg-config python3 cmake git happy alex autoconf automake python3 libgmp-dev libnuma-dev libncurses-dev
+ - curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
+ - source /root/.ghcup/env
+ - ghcup --no-verbose install ghc --set --install-targets 'install_bin install_lib update_package_db' '9.10'
+ - ghcup --no-verbose install cabal --set
+ - ghc --info
+ - cabal --version
+
+# linting but we need a boot toolchain
+.lint-ghc-toolchain:
+ extends: .lint
+ before_script:
+ - *install-ghc-toolchain
+ - git config --global --add safe.directory "$CI_PROJECT_DIR"
+
+# linting but we need python
+.lint-python:
+ extends: .lint
+ before_script:
+ - apt update
+ - apt install -qy python3 mypy shellcheck git
+ - git config --global --add safe.directory "$CI_PROJECT_DIR"
+
.nightly: &nightly
variables:
XZ_OPT: "-9"
@@ -217,11 +239,11 @@ not-interruptible:
stage: not-interruptible
script: "true"
interruptible: false
- image: "debian:13"
+ image: debian:13
variables:
GIT_STRATEGY: none
tags:
- - lint
+ - lint-anyarch
rules:
# - if: '$CI_COMMIT_BRANCH == "master"'
# when: always
@@ -242,7 +264,6 @@ include: '.gitlab/jobs.yaml'
ghc-linters:
stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint-params
variables:
BUILD_FLAVOUR: default
@@ -258,16 +279,11 @@ ghc-linters:
# Skipped if the MR has the ~"no-changelog" label.
lint-changelog:
stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-ghc-toolchain
variables:
CHANGELOG_EXPECT_MR: "$CI_MERGE_REQUEST_IID"
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- .gitlab/ci.sh lint_changelog
dependencies: []
@@ -279,42 +295,30 @@ lint-changelog:
# Run mypy Python typechecker on linter scripts.
lint-linters:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- mypy testsuite/tests/linters/regex-linters/*.py
dependencies: []
# Check that .T files all parse by listing broken tests.
lint-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-ghc-toolchain
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- - make -Ctestsuite list_broken TEST_HC=$GHC
+ - make -Ctestsuite list_broken TEST_HC=$(which ghc)
dependencies: []
# Run mypy Python typechecker on testsuite driver
typecheck-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- mypy testsuite/driver/runtests.py
dependencies: []
@@ -323,7 +327,6 @@ typecheck-testsuite:
# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
# Marge jobs.
.lint-submods:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint-params
variables:
BUILD_FLAVOUR: default
@@ -341,13 +344,9 @@ typecheck-testsuite:
# Check that commits in an MR were not authored with the identity that CI uses
# when it needs to create commits itself. This only needs Git history.
lint-author:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
+ extends: .lint-python
variables:
GIT_SUBMODULE_STRATEGY: none
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
script:
- git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
@@ -425,12 +424,9 @@ lint-submods-branch:
.lint-params:
needs: []
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
extends: .lint
before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
+ - *install-ghc-toolchain
- .gitlab/ci.sh setup
after_script:
- .gitlab/ci.sh save_cache
@@ -448,18 +444,13 @@ lint-submods-branch:
hadrian-ghc-in-ghci:
stage: quick-build
+ extends: .lint-ghc-toolchain
needs:
- job: lint-linters
- job: lint-submods
optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
variables:
GHC_FLAGS: -Werror -Wwarn=unused-imports
- tags:
- - x86_64-linux
script:
- git clean -xdf && git submodule foreach git clean -xdf
- . .gitlab/ci.sh setup
@@ -544,6 +535,7 @@ stack-hadrian-build:
extends: hadrian-ghc-in-ghci
stage: quick-build
script:
+ - ghcup --no-verbose install stack --set
- . .gitlab/ci.sh setup
- . .gitlab/ci.sh configure
- hadrian/build-stack --version
=====================================
changelog.d/24450
=====================================
@@ -0,0 +1,14 @@
+section: rts
+synopsis:
+ Fix a hang when a program is started with a standard file descriptor closed
+description:
+ A process started with stdout or stderr closed -- ``prog >&-`` from a shell
+ does exactly that -- left that descriptor number free for the runtime to
+ take for its own use. The ``Handle`` for the stream, built later when the
+ program first wrote to it, then took over a descriptor belonging to the
+ runtime: the program wrote its output into the runtime's own plumbing and
+ hung, with no error reported anywhere. The runtime now opens ``/dev/null``
+ onto whichever of the descriptors 0, 1 and 2 are closed when it starts, so
+ such a stream is connected to ``/dev/null`` instead.
+mrs: !16710
+issues: #24450
=====================================
changelog.d/27845
=====================================
@@ -0,0 +1,5 @@
+section: compiler
+synopsis: Fix a bug where an argument used lazily only by a function's stable
+ unfolding could be treated as strict in its fields.
+mrs: !16746
+issues: #27845
=====================================
changelog.d/fix-parallel-gc-selector-race-27477
=====================================
@@ -1,7 +1,7 @@
section: rts
synopsis: Fix a parallel GC race on weakly-ordered architectures (AArch64) that could crash or silently corrupt the heap
description:
- On weakly-ordered architectures such as AArch64 programs using
+ On weakly-ordered architectures such as AArch64, programs
could crash during parallel garbage collection (segmentation fault
or ``internal error: eval_thunk_selector: strange selectee <n>``) or
continue running with silently corrupted heap data, due to a missing
=====================================
compiler/GHC/Types/Demand.hs
=====================================
@@ -924,6 +924,8 @@ maxCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
maxDmd :: Demand -> Demand -> Demand
maxDmd BotDmd dmd2 = dmd2
maxDmd dmd1 BotDmd = dmd1
+maxDmd AbsDmd dmd2 = dmd2
+maxDmd dmd1 AbsDmd = dmd1
maxDmd (n1 :* sd1) (n2 :* sd2) =
maxCard n1 n2 :* maxSubDmd sd1 sd2
=====================================
rts/RtsStartup.c
=====================================
@@ -69,6 +69,10 @@
#if defined(HAVE_LOCALE_H)
#include <locale.h>
#endif
+#if !defined(mingw32_HOST_OS)
+#include <errno.h>
+#include <fcntl.h>
+#endif
// Count of how many outstanding hs_init()s there have been.
static StgWord hs_init_count = 0;
@@ -81,6 +85,10 @@ static int64_t __codePage = -1;
static void flushStdHandles(void);
+#if !defined(mingw32_HOST_OS)
+static void sanitiseStandardFds(void);
+#endif
+
/* -----------------------------------------------------------------------------
Initialise floating point unit on x86 (currently disabled; See Note
[x86 Floating point precision] in compiler/GHC/CmmToAsm/X86/Instr.hs)
@@ -238,6 +246,82 @@ hs_init_with_rtsopts(int *argc, char **argv[])
void init_ghc_hs_iface(void);
+#if !defined(mingw32_HOST_OS)
+/* See Note [Standard file descriptors must be open]. */
+static void sanitiseStandardFds(void)
+{
+ // The access mode each descriptor would have had, had the process been
+ // started with it open.
+ static const int access_mode[3] = { O_RDONLY, O_WRONLY, O_WRONLY };
+
+ for (int fd = 0; fd <= 2; fd++) {
+ if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
+ continue; // already open
+ }
+
+ int nullfd;
+ do {
+ nullfd = open("/dev/null", access_mode[fd]);
+ } while (nullfd == -1 && errno == EINTR);
+
+ if (nullfd == -1) {
+ // No /dev/null to be had. There is nothing better to do than
+ // carry on; the hazard the Note describes is then still there,
+ // but refusing to start would be worse.
+ return;
+ }
+ if (nullfd != fd) {
+ // open() hands out the lowest free descriptor, so this cannot
+ // happen unless something in this process is opening descriptors
+ // concurrently. Do not shuffle its descriptor around.
+ close(nullfd);
+ return;
+ }
+ }
+}
+
+/*
+ * Note [Standard file descriptors must be open]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * A process may be started with any of file descriptors 0, 1 and 2 closed --
+ * from a shell, `prog >&-` does exactly that. Nothing then reserves those
+ * numbers, and open(), pipe() and socket() hand out the lowest free
+ * descriptor, so the next descriptor the runtime creates for itself takes one
+ * of them: the ticker's pipe, or a capability's IO manager control pipe.
+ *
+ * Nothing warns anybody. 'GHC.Internal.IO.StdHandles.stdout' is a CAF, so it
+ * is built the first time the program writes to stdout, which is long after
+ * that has happened, and it builds a 'Handle' over descriptor 1 -- which now
+ * belongs to the runtime. The program then writes its output into the
+ * runtime's own plumbing, and at exit closes it.
+ *
+ * What this looks like from the outside is a hang, because the descriptor the
+ * Handle has taken over is the read end of a pipe. It is a perfectly good
+ * descriptor, so nothing reports an error: poll() for POLLOUT on it simply
+ * never says yes, epoll_ctl() accepts a registration for it, and the thread
+ * waiting to write blocks for ever. See #24450, where this is `prog >&-`
+ * hanging after main has finished.
+ *
+ * Closing those descriptors is legal, so the runtime cannot refuse them; and
+ * moving only the descriptors the runtime opens would not help, since the
+ * first file the program itself opens would land on the free number instead.
+ * The fix is to leave no free number: open /dev/null onto whichever of 0, 1
+ * and 2 are closed, before the runtime creates any descriptor of its own.
+ * Other runtimes do the same, and for the same reason.
+ *
+ * A program run this way therefore finds stdout connected to /dev/null rather
+ * than failing with EBADF on the first write. That is the price of the fix,
+ * and it is the behaviour such a program would get from most other language
+ * runtimes.
+ *
+ * Each substitute is opened for the access the descriptor would normally have:
+ * read-only for 0, write-only for 1 and 2. Opening all three for both would
+ * make the substitute something a real stdin or stdout is not, and writing to
+ * 'stdin' or reading from 'stdout' would then quietly succeed instead of
+ * failing with EBADF.
+ */
+#endif
+
void
hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
{
@@ -252,6 +336,12 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
stg_exit(1);
}
+#if !defined(mingw32_HOST_OS)
+ /* Before anything here opens a file descriptor of its own.
+ See Note [Standard file descriptors must be open]. */
+ sanitiseStandardFds();
+#endif
+
#if defined(wasm32_HOST_ARCH)
char *pwd = getenv("PWD");
if (pwd != NULL) {
=====================================
testsuite/tests/dmdanal/should_run/T27845.hs
=====================================
@@ -0,0 +1,14 @@
+module Main where
+import T27845_Lib (f)
+import System.Environment (getArgs)
+
+{-# NOINLINE mkArg #-}
+mkArg :: Int -> Int
+mkArg n | n < 0 = n
+ | otherwise = error ("boom " ++ show n)
+
+main :: IO ()
+main = do
+ n <- length <$> getArgs
+ let x = mkArg n
+ print (length (f (x, x) n))
=====================================
testsuite/tests/dmdanal/should_run/T27845.stdout
=====================================
@@ -0,0 +1 @@
+0
=====================================
testsuite/tests/dmdanal/should_run/T27845_Lib.hs
=====================================
@@ -0,0 +1,11 @@
+module T27845_Lib where
+
+{-# INLINABLE [2] f #-}
+f :: a -> Int -> [a]
+f p x = lazyUse p x ++ lazyUse p (x + 1) ++ lazyUse p (x + 2)
+
+{-# NOINLINE lazyUse #-}
+lazyUse :: a -> Int -> [a]
+lazyUse p x = p `seq` replicate x p
+
+{-# RULES "lazyUse" [1] forall p x. lazyUse p x = [] #-}
=====================================
testsuite/tests/dmdanal/should_run/T27845b.hs
=====================================
@@ -0,0 +1,14 @@
+module Main where
+import T27845b_Lib (outer)
+import System.Environment (getArgs)
+
+{-# NOINLINE mkArg #-}
+mkArg :: Int -> Int
+mkArg n | n < 0 = n
+ | otherwise = error ("boom " ++ show n)
+
+main :: IO ()
+main = do
+ n <- length <$> getArgs
+ let x = mkArg n
+ print (length (outer (x, x) n))
=====================================
testsuite/tests/dmdanal/should_run/T27845b.stdout
=====================================
@@ -0,0 +1 @@
+0
=====================================
testsuite/tests/dmdanal/should_run/T27845b_Lib.hs
=====================================
@@ -0,0 +1,14 @@
+module T27845b_Lib where
+
+outer :: a -> Int -> [a]
+outer a n =
+ let {-# INLINABLE [2] g #-}
+ g x = lazyUse a (x + 0) ++ lazyUse a (x + 1) ++ lazyUse a (x + 2)
+ in g n ++ g (n + 1) ++ g (n + 2)
+{-# NOINLINE outer #-}
+
+{-# NOINLINE lazyUse #-}
+lazyUse :: a -> Int -> [a]
+lazyUse p x = p `seq` replicate x p
+
+{-# RULES "lazyUse" [1] forall p x. lazyUse p x = [] #-}
=====================================
testsuite/tests/dmdanal/should_run/all.T
=====================================
@@ -37,3 +37,5 @@ test('T25439', normal, compile_and_run, [''])
test('T26748', normal, compile_and_run, [''])
test('T26416', [extra_files(['M1.hs'])], multimod_compile_and_run, ['T26416','M1.hs'])
test('T27626', [extra_files(['M2.hs'])], multimod_compile_and_run, ['T27626','M2.hs'])
+test('T27845', [extra_files(['T27845_Lib.hs'])], multimod_compile_and_run, ['T27845','T27845_Lib.hs'])
+test('T27845b', [extra_files(['T27845b_Lib.hs'])], multimod_compile_and_run, ['T27845b','T27845b_Lib.hs'])
=====================================
testsuite/tests/rts/T24450.hs
=====================================
@@ -0,0 +1,41 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+-- A process may be started with stdout closed -- `prog >&-` from a shell does
+-- exactly that. Nothing then reserves descriptor 1, so the next descriptor
+-- the runtime opens for itself takes it, and the 'Handle' for stdout, built
+-- later when the program first writes, takes over a descriptor belonging to
+-- the runtime. The write then goes into the runtime's own plumbing, and what
+-- this looks like from the outside is a hang. See #24450 and
+-- Note [Standard file descriptors must be open] in rts/RtsStartup.c.
+--
+-- This test is run with its stdin and stdout closed, so what it has to say
+-- goes to stderr. The four writes are the reproducer from the ticket and must
+-- simply finish. The lines after them are what tell the two outcomes apart:
+-- the descriptors the runtime opens for itself are pipes, so finding a pipe on
+-- descriptor 0 or 1 means it was handed to the runtime.
+module Main (main) where
+
+import Control.Exception (IOException, try)
+import System.IO
+import System.Posix.Files (getFdStatus, isCharacterDevice, isNamedPipe)
+import System.Posix.Types (Fd (..))
+
+main :: IO ()
+main = do
+ hPutChar stderr 'A' -- unbuffered
+ hPutChar stdout 'X' -- buffered; this is the one that used to hang
+ hPutChar stderr 'Z' -- unbuffered
+ hPutChar stderr '\n' -- unbuffered
+ mapM_ (\fd -> hPutStrLn stderr =<< describeFd fd) [0, 1]
+
+describeFd :: Fd -> IO String
+describeFd fd = do
+ r <- try (getFdStatus fd)
+ return $ "fd " ++ show fd ++ ": " ++ case r of
+ Left (_ :: IOException) -> "closed"
+ Right st
+ -- What the fix arranges: /dev/null, opened onto the free number
+ -- before the runtime could take it.
+ | isCharacterDevice st -> "character device"
+ -- What #24450 is: the runtime's ticker or control pipe.
+ | isNamedPipe st -> "pipe"
+ | otherwise -> "something else"
=====================================
testsuite/tests/rts/T24450.stderr
=====================================
@@ -0,0 +1,3 @@
+AZ
+fd 0: character device
+fd 1: character device
=====================================
testsuite/tests/rts/all.T
=====================================
@@ -408,6 +408,18 @@ test('T10590', [ ignore_stderr
, req_process
], compile_and_run, [''])
+# Run with stdin and stdout closed -- that is what leaves those descriptors
+# free for the runtime to take, which is the whole of #24450. What the test
+# has to say therefore goes to stderr and is checked against T24450.stderr.
+test('T24450',
+ [ when(opsys('mingw32'), skip) # POSIX only
+ , js_skip # JS backend has its own runtime
+ # The wrapper below would close the stdout of the wasm runtime rather
+ # than that of the program running under it, which tests nothing.
+ , when(arch('wasm32'), skip)
+ , cmd_wrapper(lambda c: c + ' <&- >&-')
+ ], compile_and_run, [''])
+
# 20000 was easily enough to trigger the bug with 7.10
test('T10904', [ extra_run_opts('20000'), req_c ],
compile_and_run, ['T10904lib.c'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f20e7d949c703152133e0c6147073a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f20e7d949c703152133e0c6147073a…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc] Pushed new branch wip/sjakobi/hadrian-readme-tool-args
by Simon Jakobi (@sjakobi) 08 Oct '26
by Simon Jakobi (@sjakobi) 08 Oct '26
08 Oct '26
Simon Jakobi pushed new branch wip/sjakobi/hadrian-readme-tool-args at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/sjakobi/hadrian-readme-tool-a…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc] Pushed new branch wip/sjakobi/hadrian-readme-tool-args
by Simon Jakobi (@sjakobi) 08 Oct '26
by Simon Jakobi (@sjakobi) 08 Oct '26
08 Oct '26
Simon Jakobi pushed new branch wip/sjakobi/hadrian-readme-tool-args at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/sjakobi/hadrian-readme-tool-a…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0