Simon Jakobi pushed to branch wip/sjakobi/T27628-rebox-warning at Glasgow Haskell Compiler / GHC

Commits:

23 changed files:

Changes:

  • compiler/GHC/Core/Opt/SetLevels.hs
    ... ... @@ -108,8 +108,8 @@ import GHC.Types.Var.Env
    108 108
     import GHC.Types.Literal      ( litIsTrivial )
    
    109 109
     import GHC.Types.Demand       ( DmdSig, prependArgsDmdSig )
    
    110 110
     import GHC.Types.Cpr          ( CprSig, prependArgsCprSig )
    
    111
    -import GHC.Types.Name         ( getOccName )
    
    112
    -import GHC.Types.Name.Occurrence ( occNameFS )
    
    111
    +import GHC.Types.Name         ( getOccName, getSrcSpan, mkSystemNameAt )
    
    112
    +import GHC.Types.Name.Occurrence ( occNameFS, mkVarOccFS )
    
    113 113
     import GHC.Types.Unique       ( hasKey )
    
    114 114
     import GHC.Types.Tickish      ( tickishIsCode )
    
    115 115
     import GHC.Types.Unique.Supply
    
    ... ... @@ -1872,7 +1872,10 @@ newPolyBndrs dest_lvl
    1872 1872
     
    
    1873 1873
         mk_poly_bndr bndr uniq = transferPolyIdInfo bndr abs_vars $ -- Note [transferPolyIdInfo] in GHC.Types.Id
    
    1874 1874
                                  transfer_join_info bndr $
    
    1875
    -                             mkSysLocal str uniq (idMult bndr) poly_ty
    
    1875
    +                             -- Keep bndr's srcspan so that diagnostics can
    
    1876
    +                             -- still point at the original definition
    
    1877
    +                             mkLocalId (mkSystemNameAt uniq (mkVarOccFS str) (getSrcSpan bndr))
    
    1878
    +                                       (idMult bndr) poly_ty
    
    1876 1879
                                where
    
    1877 1880
                                  str     = fsLit "poly_" `appendFS` occNameFS (getOccName bndr)
    
    1878 1881
                                  poly_ty = mkLamTypes abs_vars (substTyUnchecked subst (idType bndr))
    

  • compiler/GHC/Core/Opt/SpecConstr.hs
    ... ... @@ -36,6 +36,9 @@ import GHC.Core.Coercion hiding( substCo )
    36 36
     import GHC.Core.Rules
    
    37 37
     import GHC.Core.Predicate ( scopedSort, typeDeterminesValue )
    
    38 38
     import GHC.Core.Type     hiding ( substTy )
    
    39
    +import GHC.Core.TyCo.Compare ( eqType )
    
    40
    +import GHC.Core.TyCo.Ppr ( pprSigmaType )
    
    41
    +import GHC.Core.TyCo.Tidy ( tidyTopType )
    
    39 42
     import GHC.Core.TyCon   (TyCon, tyConName )
    
    40 43
     import GHC.Core.Multiplicity
    
    41 44
     import GHC.Core.Ppr     ( pprParendExpr )
    
    ... ... @@ -45,12 +48,13 @@ import GHC.Unit.Module.ModGuts
    45 48
     
    
    46 49
     import GHC.Types.InlinePragma
    
    47 50
     import GHC.Types.Error (DiagnosticReason(..))
    
    48
    -import GHC.Types.Literal ( litIsLifted )
    
    51
    +import GHC.Types.Literal ( Literal, litIsLifted )
    
    49 52
     import GHC.Types.Id
    
    50 53
     import GHC.Types.Id.Info ( IdDetails(..) )
    
    51 54
     import GHC.Types.Var.Env
    
    52 55
     import GHC.Types.Var.Set
    
    53 56
     import GHC.Types.Name
    
    57
    +import GHC.Types.SrcLoc ( isGoodSrcSpan )
    
    54 58
     import GHC.Types.Tickish
    
    55 59
     import GHC.Types.Basic
    
    56 60
     import GHC.Types.Demand
    
    ... ... @@ -75,7 +79,7 @@ import GHC.Exts( SpecConstrAnnotation(..) )
    75 79
     import GHC.Serialized   ( deserializeWithData )
    
    76 80
     
    
    77 81
     import Control.Monad
    
    78
    -import Data.List ( sortBy, partition, dropWhileEnd, mapAccumL, nub, unzip4 )
    
    82
    +import Data.List ( sortBy, partition, dropWhileEnd, mapAccumL, nub, nubBy, unzip4 )
    
    79 83
     import Data.List.NonEmpty ( NonEmpty (..) )
    
    80 84
     import Data.Maybe( mapMaybe )
    
    81 85
     import Data.Ord( comparing )
    
    ... ... @@ -790,8 +794,8 @@ specConstrProgram guts
    790 794
                  is_rebox _                = False
    
    791 795
     
    
    792 796
            ; when (not (null forced_ws)) $ diagnostic WarningWithoutFlag (forced_msg forced_ws)
    
    793
    -       ; when (not (null rebox_ws)) $ diagnostic (WarningWithFlag Opt_WarnSpecConstrReboxing)
    
    794
    -                                                 (rebox_msg (nub rebox_ws))
    
    797
    +       ; mapM_ (diagnostic (WarningWithFlag Opt_WarnSpecConstrReboxing) . rebox_msg)
    
    798
    +               (aggregateRebox rebox_ws)
    
    795 799
     
    
    796 800
            ; return (guts { mg_binds = binds' }) }
    
    797 801
     
    
    ... ... @@ -802,15 +806,137 @@ specConstrProgram guts
    802 806
                             nest 2 (vcat (map ppr warnings)) $$
    
    803 807
                             (text "If this is expected you might want to increase -fmax-forced-spec-args to force specialization anyway.")
    
    804 808
     
    
    809
    +    -- One warning per specialised function (all its patterns listed),
    
    810
    +    -- then warnings that would render identically merged too; see
    
    811
    +    -- Note [Reboxing warning]
    
    812
    +    aggregateRebox :: SpecConstrWarnings -> SpecConstrWarnings
    
    813
    +    aggregateRebox = mergeBy same_render . mergeBy same_fn
    
    814
    +      where
    
    815
    +        mergeBy eq ws
    
    816
    +          = [ SpecReboxed fn ty parent recur (nubBy same_pat (concat patss)) (nub (concat callerss))
    
    817
    +            | w@(SpecReboxed fn ty parent recur _ _) <- nubBy eq ws
    
    818
    +            , let (patss, callerss) = unzip [ (pats, callers)
    
    819
    +                                            | w'@(SpecReboxed _ _ _ _ pats callers) <- ws
    
    820
    +                                            , eq w w' ] ]
    
    821
    +
    
    822
    +        -- Also compare the parents: the fn Name alone is ambiguous
    
    823
    +        -- between top-level bindings; see Note [Reboxing warning]
    
    824
    +        same_fn (SpecReboxed fn1 _ p1 _ _ _) (SpecReboxed fn2 _ p2 _ _ _)
    
    825
    +          = fn1 == fn2 && p1 == p2
    
    826
    +        same_fn _ _ = False
    
    827
    +
    
    828
    +        -- Merge warnings that would render identically: same occurrence
    
    829
    +        -- name, type, parent, displayed location, recursivity, and
    
    830
    +        -- patterns. The reader could not tell them apart, so printing
    
    831
    +        -- both is noise; see Note [Reboxing warning].  Callers are
    
    832
    +        -- aggregated, not compared.
    
    833
    +        same_render (SpecReboxed fn1 ty1 p1 r1 pats1 _) (SpecReboxed fn2 ty2 p2 r2 pats2 _)
    
    834
    +          = getOccName fn1 == getOccName fn2 && p1 == p2
    
    835
    +            && nameSrcSpan (rebox_loc_name fn1 p1) == nameSrcSpan (rebox_loc_name fn2 p2)
    
    836
    +            && ty1 `eqType` ty2
    
    837
    +            && r1 `same_recur` r2
    
    838
    +            && equalLength pats1 pats2
    
    839
    +            && and (zipWith same_pat (sortBy cmpReboxedPat pats1)
    
    840
    +                                     (sortBy cmpReboxedPat pats2))
    
    841
    +        same_render _ _ = False
    
    842
    +
    
    843
    +        same_pat p1 p2 = cmpReboxedPat p1 p2 == EQ
    
    844
    +
    
    845
    +        -- Recursivity as displayed: siblings compare by occurrence name,
    
    846
    +        -- so span-less copies of one mutual group still merge
    
    847
    +        same_recur ReboxSelfRec        ReboxSelfRec        = True
    
    848
    +        same_recur (ReboxNonRec j1)    (ReboxNonRec j2)    = j1 == j2
    
    849
    +        same_recur (ReboxMutualRec s1) (ReboxMutualRec s2)
    
    850
    +          = map getOccName (sortBy stableNameCmp s1)
    
    851
    +            == map getOccName (sortBy stableNameCmp s2)
    
    852
    +        same_recur _ _ = False
    
    853
    +
    
    854
    +    -- The definition site shown in a reboxing warning: the fn's own when
    
    855
    +    -- known, otherwise the parent's (e.g. for simplifier-made join points)
    
    856
    +    rebox_loc_name :: Name -> Maybe Name -> Name
    
    857
    +    rebox_loc_name fn (Just parent)
    
    858
    +      | not (isGoodSrcSpan (nameSrcSpan fn)) = parent
    
    859
    +    rebox_loc_name fn _ = fn
    
    860
    +
    
    805 861
         -- See Note [Reboxing warning]
    
    806
    -    rebox_msg :: SpecConstrWarnings -> SDoc
    
    807
    -    rebox_msg warnings = text "SpecConstr specialised the following function(s) on a constructor argument that is also used boxed:" $$
    
    808
    -                         nest 2 (vcat (map ppr warnings)) $$
    
    809
    -                         text "The specialised code allocates a fresh constructor at each such use (\"reboxing\")," $$
    
    810
    -                         text "which can increase allocation and defeat pointer-equality-based sharing." $$
    
    811
    -                         text "Possible remedies: exclude the type with an {-# ANN type T NoSpecConstr #-} pragma," $$
    
    812
    -                         text "hide the constructor from SpecConstr by wrapping the call-site argument in GHC.Exts.lazy," $$
    
    813
    -                         text "or use -fno-spec-constr."
    
    862
    +    rebox_msg :: SpecConstrWarning -> SDoc
    
    863
    +    rebox_msg w@(SpecFailForcedArgCount {}) = pprPanic "rebox_msg" (ppr w)
    
    864
    +    rebox_msg (SpecReboxed fn ty mb_parent recur pats callers)
    
    865
    +      = vcat [ hang (text "SpecConstr specialised") 2
    
    866
    +                    (quotes (ppr fn <+> dcolon <+> pp_ty))
    
    867
    +             , nest 2 $ vcat $ catMaybes
    
    868
    +                 [ Just (fact "source:" pp_source)
    
    869
    +                 , Just (fact "recursivity:" pp_recur)
    
    870
    +                 , fact "called from:" <$> pp_callers
    
    871
    +                 , Just (fact pats_label pp_pats) ]
    
    872
    +             , pp_trailer
    
    873
    +             , text "See -Wspec-constr-reboxing in the users guide for possible remedies." ]
    
    874
    +      where
    
    875
    +        -- Aligned label column; $$ overlaps, so a multi-line value keeps
    
    876
    +        -- its lines aligned under the first
    
    877
    +        fact l v = text l $$ nest 23 v
    
    878
    +
    
    879
    +        -- Truncate only pathologically large types
    
    880
    +        pp_ty = sdocWithContext $ \ctx ->
    
    881
    +                  case splitAt 10000 (showSDocOneLine ctx pp_tidy) of
    
    882
    +                    (_, [])        -> pp_tidy
    
    883
    +                    (prefix, _)    -> text prefix <> text "..."
    
    884
    +          where pp_tidy = pprSigmaType (tidyTopType ty)
    
    885
    +                -- pprSigmaType: suppress the printed forall
    
    886
    +
    
    887
    +        -- A name with no source span reached this module in an interface
    
    888
    +        -- unfolding: iface files record no spans for local binders
    
    889
    +        pp_source = case (mb_parent, isGoodSrcSpan (nameSrcSpan loc_name)) of
    
    890
    +          (Nothing, True)  -> pp_loc
    
    891
    +          (Just p,  True)  -> quotes (ppr p) <+> text "at" <+> pp_loc
    
    892
    +          (Just p,  False) -> quotes (ppr p) <> comma <+> pp_no_loc
    
    893
    +          (Nothing, False) -> pp_no_loc
    
    894
    +          where
    
    895
    +            loc_name  = rebox_loc_name fn mb_parent
    
    896
    +            pp_loc    = ppr (nameSrcLoc loc_name)
    
    897
    +            pp_no_loc = text "inlined from another module (no source location)"
    
    898
    +
    
    899
    +        pp_recur = case recur of
    
    900
    +          ReboxSelfRec        -> text "self-recursive"
    
    901
    +          ReboxNonRec True    -> text "non-recursive (a join point)"
    
    902
    +          ReboxNonRec False   -> text "non-recursive"
    
    903
    +          ReboxMutualRec sibs
    
    904
    +            -> text "mutually recursive with"
    
    905
    +               <+> pprWithCommas (quotes . ppr) named <> pp_rest
    
    906
    +            where
    
    907
    +              (named, rest) = splitAt 3 (sortBy stableNameCmp sibs)
    
    908
    +              pp_rest = case length rest of
    
    909
    +                0 -> empty
    
    910
    +                1 -> text " and 1 other"
    
    911
    +                n -> text " and" <+> int n <+> text "others"
    
    912
    +
    
    913
    +        pp_callers = case sortBy stableNameCmp callers of
    
    914
    +          [] -> Nothing
    
    915
    +          cs -> Just (pprWithCommas (quotes . ppr) cs)
    
    916
    +
    
    917
    +        pats_label = case pats of
    
    918
    +          [_] -> "call pattern:"
    
    919
    +          _   -> "call patterns:"
    
    920
    +
    
    921
    +        pp_pats = vcat (map pp_pat (sortBy cmpReboxedPat pats))
    
    922
    +
    
    923
    +        pp_pat (ReboxedPat shapes cons)
    
    924
    +          = hang (hang (ppr fn) 2 (fsep (map pprPatShape shapes))) 2
    
    925
    +                 (text "-- reboxes" <+>
    
    926
    +                  pprWithCommas pp_con (sortBy stableNameCmp cons))
    
    927
    +
    
    928
    +        -- Qualify imported constructors: they identify the package to
    
    929
    +        -- follow up with when the function itself has no location
    
    930
    +        pp_con con
    
    931
    +          | Just m <- nameModule_maybe con, m /= mg_module guts
    
    932
    +          = quotes (ppr m <> dot <> ppr con)
    
    933
    +          | otherwise = quotes (ppr con)
    
    934
    +
    
    935
    +        all_cons = nub [ con | ReboxedPat _ cons <- pats, con <- cons ]
    
    936
    +
    
    937
    +        pp_trailer = fsep $ map text $ words $ case all_cons of
    
    938
    +          [_] -> "This constructor argument is also used boxed, so the specialisation may increase allocation and defeat pointer-equality-based sharing."
    
    939
    +          _   -> "These constructor arguments are also used boxed, so the specialisations may increase allocation and defeat pointer-equality-based sharing."
    
    814 940
     scTopBinds :: ScEnv -> [InBind] -> UniqSM (ScUsage, [OutBind], [SpecConstrWarning])
    
    815 941
     scTopBinds _env []     = return (nullUsage, [], [])
    
    816 942
     scTopBinds env  (b:bs) = do { (usg, b', bs', warnings) <- scBind TopLevel env b $
    
    ... ... @@ -975,7 +1101,12 @@ data ScEnv = SCE { sc_opts :: !SpecConstrOpts,
    975 1101
                             -- Domain is OutIds (*after* applying the substitution)
    
    976 1102
                             -- Used even for top-level bindings (but not imported ones)
    
    977 1103
     
    
    978
    -                   sc_annotations :: UniqFM Name SpecConstrAnnotation
    
    1104
    +                   sc_annotations :: UniqFM Name SpecConstrAnnotation,
    
    1105
    +
    
    1106
    +                   sc_top_fn    :: Maybe Name
    
    1107
    +                        -- The top-level binder whose RHS we are inside,
    
    1108
    +                        -- used to attribute warnings about local functions
    
    1109
    +                        -- See Note [Reboxing warning]
    
    979 1110
                  }
    
    980 1111
     
    
    981 1112
     ---------------------
    
    ... ... @@ -1025,7 +1156,8 @@ initScEnv guts
    1025 1156
                            sc_subst       = init_subst,
    
    1026 1157
                            sc_how_bound   = emptyVarEnv,
    
    1027 1158
                            sc_vals        = emptyVarEnv,
    
    1028
    -                       sc_annotations = anns }) }
    
    1159
    +                       sc_annotations = anns,
    
    1160
    +                       sc_top_fn      = Nothing }) }
    
    1029 1161
       where
    
    1030 1162
         init_subst = mkEmptySubst $ mkInScopeSetBndrs (mg_binds guts)
    
    1031 1163
             -- Acccount for top-level bindings that are not in dependency order;
    
    ... ... @@ -1046,6 +1178,11 @@ instance Outputable HowBound where
    1046 1178
     scForce :: ScEnv -> Bool -> ScEnv
    
    1047 1179
     scForce env b = env { sc_force = b }
    
    1048 1180
     
    
    1181
    +-- Keeps the outermost binder; see Note [Reboxing warning]
    
    1182
    +setTopFn :: ScEnv -> OutId -> ScEnv
    
    1183
    +setTopFn env@(SCE { sc_top_fn = Nothing }) bndr = env { sc_top_fn = Just (idName bndr) }
    
    1184
    +setTopFn env _ = env
    
    1185
    +
    
    1049 1186
     lookupHowBound :: ScEnv -> OutId -> Maybe HowBound
    
    1050 1187
     lookupHowBound env id = lookupVarEnv (sc_how_bound env) id
    
    1051 1188
     
    
    ... ... @@ -1286,9 +1423,11 @@ data ScUsage
    1286 1423
          }                                  -- The domain is OutIds
    
    1287 1424
     
    
    1288 1425
     type CallEnv = IdEnv [Call]  -- Domain is OutIds
    
    1289
    -data Call    = Call OutId [CoreArg] ValueEnv
    
    1426
    +data Call    = Call OutId [CoreArg] ValueEnv (Maybe Name)
    
    1290 1427
             -- The arguments of the call, together with the
    
    1291 1428
             -- env giving the constructor bindings at the call site
    
    1429
    +        -- and the enclosing top-level binder of the call site
    
    1430
    +        -- (sc_top_fn, for reboxing warnings)
    
    1292 1431
             -- We keep the function mainly for debug output
    
    1293 1432
             --
    
    1294 1433
             -- The call is not necessarily saturated; we just put
    
    ... ... @@ -1300,7 +1439,7 @@ instance Outputable ScUsage where
    1300 1439
                                      , text "occs =" <+> ppr occs ])
    
    1301 1440
     
    
    1302 1441
     instance Outputable Call where
    
    1303
    -  ppr (Call fn args _) = ppr fn <+> fsep (map pprParendExpr args)
    
    1442
    +  ppr (Call fn args _ _) = ppr fn <+> fsep (map pprParendExpr args)
    
    1304 1443
     
    
    1305 1444
     nullUsage :: ScUsage
    
    1306 1445
     nullUsage = SCU { scu_calls = emptyVarEnv, scu_occs = emptyVarEnv }
    
    ... ... @@ -1443,6 +1582,73 @@ that decision bites, without changing which specialisations are made:
    1443 1582
       SpecReboxed warnings, which specConstrProgram emits under
    
    1444 1583
       -Wspec-constr-reboxing (off by default).
    
    1445 1584
     
    
    1585
    +* One warning per function, listing each call pattern the function was
    
    1586
    +  specialised for — the constructor skeletons of the call's arguments,
    
    1587
    +  e.g. `go (_ : _) (BMap _) -- reboxes ‘BMap’` — alongside that
    
    1588
    +  pattern's reboxed constructors.  The shapes show where in the
    
    1589
    +  argument each reboxed constructor sits, and picture what SpecConstr
    
    1590
    +  did: it made a copy of
    
    1591
    +  the function for calls of exactly that shape.  The warning also shows
    
    1592
    +  the function's type: names like `go1` say nothing, and for span-less
    
    1593
    +  functions (last bullet below) the type is the main identifying clue.
    
    1594
    +
    
    1595
    +  "Per function" means per (parent, function) *pair*: the function's
    
    1596
    +  Name alone is ambiguous, because distinct top-level bindings can bind
    
    1597
    +  distinct locals that share a unique.  That happens when several
    
    1598
    +  bindings inline one stable unfolding (e.g. a class's default-method
    
    1599
    +  template): each copy keeps the template's uniques, and the simplifier
    
    1600
    +  only freshens a binder on an in-scope clash, which cannot arise
    
    1601
    +  between sibling top-level RHSs.
    
    1602
    +
    
    1603
    +  Warnings that would render identically — same name, type, parent,
    
    1604
    +  definition site, recursivity, and patterns — are merged too: the
    
    1605
    +  reader could not tell them apart, so printing both is noise.  For
    
    1606
    +  located functions the merged warnings are simplifier-made copies of one
    
    1607
    +  binding, addressed by a single source-level remedy; span-less loops
    
    1608
    +  inlined from other modules can in principle merge across different
    
    1609
    +  origins, but sharing name and type they are almost certainly copies of
    
    1610
    +  one function.
    
    1611
    +
    
    1612
    +* The warning classifies how the specialised function recurses
    
    1613
    +  ("recursivity"), taken from the binding SpecConstr saw: a Rec group of
    
    1614
    +  one is self-recursive (the occurrence analyser demotes non-recursive
    
    1615
    +  singletons to NonRec), a larger group is mutually recursive and the
    
    1616
    +  siblings are named, and a nested NonRec binding — typically a join
    
    1617
    +  point, see Note [Specialising local let bindings] — is non-recursive.
    
    1618
    +  This reflects the post-optimisation program, whose shape can differ
    
    1619
    +  from the source's.
    
    1620
    +
    
    1621
    +* Nullary constructors are exempt: "reboxing" a nullary constructor just
    
    1622
    +  references its shared static closure, so it costs no allocation and even
    
    1623
    +  preserves pointer identity.  Such patterns are common (Nil, [], Nothing,
    
    1624
    +  ...) and warning about them would be pure noise.
    
    1625
    +
    
    1626
    +* Warnings about local functions (join points, local workers) name the
    
    1627
    +  enclosing top-level binder too: locals often have meaningless names,
    
    1628
    +  and any remedy is applied at the enclosing function anyway.
    
    1629
    +  sc_top_fn tracks that binder, set when entering a top-level RHS (or a
    
    1630
    +  specialised copy of one) and kept unchanged below that.  The location
    
    1631
    +  shown is the local's own definition site, so same-named locals can be
    
    1632
    +  told apart; only when that is missing (e.g. for simplifier-made join
    
    1633
    +  points) does the warning fall back to the parent's location.
    
    1634
    +
    
    1635
    +* The warning lists the top-level binders containing the specialised
    
    1636
    +  calls ("called from"); each Call records the sc_top_fn of its call
    
    1637
    +  site for this purpose.  Self-calls of a top-level loop are dropped as
    
    1638
    +  uninformative (in callToPat); a *local* loop's self-calls record its
    
    1639
    +  parent, indistinguishable from the parent's entry call, so the parent
    
    1640
    +  appears among the callers.
    
    1641
    +
    
    1642
    +* A function with no source span and no parent reached this module in an
    
    1643
    +  interface unfolding: iface files record no spans for local binders, and
    
    1644
    +  such loops typically float to top level in the consuming module.  The
    
    1645
    +  warning says "inlined from another module" instead of showing an
    
    1646
    +  unhelpful span.  Imported constructors are shown qualified — with the
    
    1647
    +  function anonymous, they are what identifies the package to report the
    
    1648
    +  reboxing to.  For such a warning the call sites ("called from") are the
    
    1649
    +  only located code to point at: following the inlining from one of them
    
    1650
    +  identifies the reboxed loop.
    
    1651
    +
    
    1446 1652
     Why BoxPassAlong does not warn: if the callee is specialised at that argument
    
    1447 1653
     position, its RULE rewrites the constructor-shaped call in the specialised
    
    1448 1654
     body and no box is ever rebuilt.  That is exactly the good case that
    
    ... ... @@ -1534,7 +1740,7 @@ scBind top_lvl env (NonRec bndr rhs) do_body
    1534 1740
         --
    
    1535 1741
         -- I tried always specialising non-recursive top-level bindings too,
    
    1536 1742
         -- but found some regressions (see !8135).  So I backed off.
    
    1537
    -  = do { (rhs_usage, rhs', ws_rhs)   <- scExpr env rhs
    
    1743
    +  = do { (rhs_usage, rhs', ws_rhs)   <- scExpr (setTopFn env bndr) rhs
    
    1538 1744
     
    
    1539 1745
            -- At top level, we've already put all binders into scope; see initScEnv
    
    1540 1746
            -- Hence no need to call `extendBndr`. But we still want to
    
    ... ... @@ -1554,7 +1760,8 @@ scBind top_lvl env (Rec prs) do_body
    1554 1760
         --       why it only applies at top level. But that's the way it has been
    
    1555 1761
         --       for a while. See #21456.
    
    1556 1762
         do  { (body_usg, body', warnings_body) <- do_body rhs_env2
    
    1557
    -        ; (rhs_usgs, rhss', rhs_ws) <- mapAndUnzip3M (scExpr env) rhss
    
    1763
    +        ; (rhs_usgs, rhss', rhs_ws) <- mapAndUnzip3M (\(b,r) -> scExpr (setTopFn env b) r)
    
    1764
    +                                                     (bndrs' `zip` rhss)
    
    1558 1765
             ; let all_usg = (combineUsages rhs_usgs `combineUsage` body_usg)
    
    1559 1766
                             `delCallsFor` bndrs'
    
    1560 1767
                   bind'   = Rec (bndrs' `zip` rhss')
    
    ... ... @@ -1799,7 +2006,7 @@ markPassAlongArg _env _other usg = usg
    1799 2006
     mkVarUsage :: ScEnv -> Id -> [CoreExpr] -> ScUsage
    
    1800 2007
     mkVarUsage env fn args
    
    1801 2008
       = case lookupHowBound env fn of
    
    1802
    -        Just RecFun -> SCU { scu_calls = unitVarEnv fn [Call fn args (sc_vals env)]
    
    2009
    +        Just RecFun -> SCU { scu_calls = unitVarEnv fn [Call fn args (sc_vals env) (sc_top_fn env)]
    
    1803 2010
                                , scu_occs  = emptyVarEnv }
    
    1804 2011
             Just RecArg -> SCU { scu_calls = emptyVarEnv
    
    1805 2012
                                , scu_occs  = unitVarEnv fn arg_occ }
    
    ... ... @@ -1812,7 +2019,7 @@ mkVarUsage env fn args
    1812 2019
     scRecRhs :: ScEnv -> (OutId, InExpr) -> UniqSM (RhsInfo, SpecConstrWarnings)
    
    1813 2020
     scRecRhs env (bndr,rhs)
    
    1814 2021
       = do  { let (arg_bndrs,body)       = collectBinders rhs
    
    1815
    -              (body_env, arg_bndrs') = extendBndrsWith RecArg env arg_bndrs
    
    2022
    +              (body_env, arg_bndrs') = extendBndrsWith RecArg (setTopFn env bndr) arg_bndrs
    
    1816 2023
             ; (body_usg, body', body_ws)         <- scExpr body_env body
    
    1817 2024
             ; let (rhs_usg, arg_occs)    = lookupOccs body_usg arg_bndrs'
    
    1818 2025
             ; return (RI { ri_rhs_usg = rhs_usg
    
    ... ... @@ -1891,7 +2098,9 @@ specNonRec :: ScEnv
    1891 2098
                                                    --     plus details of specialisations
    
    1892 2099
     
    
    1893 2100
     specNonRec env body_calls rhs_info
    
    1894
    -  = specialise env body_calls rhs_info (initSpecInfo rhs_info)
    
    2101
    +  = specialise env recur body_calls rhs_info (initSpecInfo rhs_info)
    
    2102
    +  where
    
    2103
    +    recur = ReboxNonRec (isJoinId (ri_fn rhs_info))
    
    1895 2104
     
    
    1896 2105
     ----------------------
    
    1897 2106
     specRec :: ScEnv
    
    ... ... @@ -1911,6 +2120,13 @@ specRec env body_calls rhs_infos
    1911 2120
       where
    
    1912 2121
         opts = sc_opts env
    
    1913 2122
     
    
    2123
    +    -- A Rec group of one is genuinely self-recursive: the occurrence
    
    2124
    +    -- analyser demotes non-recursive singletons to NonRec
    
    2125
    +    recur ri = case rhs_infos of
    
    2126
    +      [_] -> ReboxSelfRec
    
    2127
    +      _   -> ReboxMutualRec [ idName (ri_fn ri') | ri' <- rhs_infos
    
    2128
    +                            , ri_fn ri' /= ri_fn ri ]
    
    2129
    +
    
    1914 2130
         -- Loop, specialising, until you get no new specialisations
    
    1915 2131
         go, go_again :: Int   -- Which iteration of the "until no new specialisations"
    
    1916 2132
                               -- loop we are on; first iteration is 1
    
    ... ... @@ -1925,7 +2141,8 @@ specRec env body_calls rhs_infos
    1925 2141
             --                           , text "iteration" <+> int n_iter
    
    1926 2142
             --                           , text "spec_infos" <+> ppr (map (map os_pat . si_specs) spec_infos)
    
    1927 2143
             --                    ]) $
    
    1928
    -        do  { specs_w_usg <- zipWithM (specialise env seed_calls) rhs_infos spec_infos
    
    2144
    +        do  { specs_w_usg <- zipWithM (\ri si -> specialise env (recur ri) seed_calls ri si)
    
    2145
    +                                      rhs_infos spec_infos
    
    1929 2146
     
    
    1930 2147
                 ; let (extra_usg_s, all_spec_infos, extra_ws ) = unzip3 specs_w_usg
    
    1931 2148
                       extra_usg = combineUsages extra_usg_s
    
    ... ... @@ -1963,6 +2180,7 @@ specRec env body_calls rhs_infos
    1963 2180
     ----------------------
    
    1964 2181
     specialise
    
    1965 2182
        :: ScEnv
    
    2183
    +   -> ReboxRecursivity            -- How the function recurses, for warnings
    
    1966 2184
        -> CallEnv                     -- Info on newly-discovered calls to this function
    
    1967 2185
        -> RhsInfo
    
    1968 2186
        -> SpecInfo                    -- Original RHS plus patterns dealt with
    
    ... ... @@ -1977,8 +2195,8 @@ specialise
    1977 2195
     -- So when we make a specialised copy of the RHS, we're starting
    
    1978 2196
     -- from an RHS whose nested functions have been optimised already.
    
    1979 2197
     
    
    1980
    -specialise env bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs
    
    1981
    -                              , ri_lam_body = body, ri_arg_occs = arg_occs })
    
    2198
    +specialise env recur bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs
    
    2199
    +                                    , ri_lam_body = body, ri_arg_occs = arg_occs })
    
    1982 2200
                    spec_info@(SI { si_specs = specs, si_n_specs = spec_count
    
    1983 2201
                                  , si_mb_unspec = mb_unspec })
    
    1984 2202
       | isDeadEndId fn  -- Note [Do not specialise diverging functions]
    
    ... ... @@ -2001,7 +2219,9 @@ specialise env bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs
    2001 2219
             ; let n_pats = length new_pats
    
    2002 2220
                   -- Warn about committed specialisations that will rebox;
    
    2003 2221
                   -- see Note [Reboxing warning]
    
    2004
    -              rebox_ws = [ SpecReboxed (idName fn) (cp_rebox p)
    
    2222
    +              rebox_ws = [ SpecReboxed (idName fn) (idType fn) (sc_top_fn env)
    
    2223
    +                                       recur [ReboxedPat (patShapes p) (cp_rebox p)]
    
    2224
    +                                       (cp_callers p)
    
    2005 2225
                              | p <- new_pats, not (null (cp_rebox p)) ]
    
    2006 2226
     --        ; when (not (null new_pats) || isJust mb_unspec) $
    
    2007 2227
     --          pprTraceM "specialise" (vcat [ ppr fn <+> text "with" <+> int n_pats <+> text "good patterns"
    
    ... ... @@ -2013,7 +2233,9 @@ specialise env bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs
    2013 2233
     --                                       , text "arg_occs" <+> ppr arg_occs
    
    2014 2234
     --                                       , text "new_pats" <+> ppr new_pats])
    
    2015 2235
     
    
    2016
    -        ; let spec_env = decreaseSpecCount env n_pats
    
    2236
    +        ; let spec_env = setTopFn (decreaseSpecCount env n_pats) fn
    
    2237
    +                -- setTopFn: attribute warnings from re-analysing the
    
    2238
    +                -- specialised copies of a top-level fn's body to fn
    
    2017 2239
             ; (spec_usgs, new_specs, new_wss) <- mapAndUnzip3M (spec_one spec_env fn arg_bndrs body)
    
    2018 2240
                                                      (new_pats `zip` [spec_count..])
    
    2019 2241
                     -- See Note [Specialise original body]
    
    ... ... @@ -2565,30 +2787,127 @@ data CallPat = CP { cp_qvars :: [Var] -- Quantified variables
    2565 2787
                       , cp_args  :: [CoreExpr]      -- Arguments
    
    2566 2788
                       , cp_strict_args :: [Var]     -- Arguments we want to pass unlifted even if they are boxed
    
    2567 2789
                                                     -- See Note [SpecConstr and strict fields]
    
    2568
    -                  , cp_rebox :: [Name] }        -- Constructors matched by this pattern whose box
    
    2790
    +                  , cp_rebox :: [Name]          -- Constructors matched by this pattern whose box
    
    2569 2791
                                                     -- is also used; see Note [Reboxing warning]
    
    2792
    +                  , cp_callers :: [Name] }      -- Enclosing top-level binders of the calls this
    
    2793
    +                                                -- pattern came from; see Note [Reboxing warning]
    
    2570 2794
     
    
    2571 2795
          -- See Note [SpecConstr call patterns]
    
    2572 2796
     
    
    2573 2797
     instance Outputable CallPat where
    
    2574
    -  ppr (CP { cp_qvars = qvars, cp_args = args, cp_strict_args = strict, cp_rebox = rebox })
    
    2798
    +  ppr (CP { cp_qvars = qvars, cp_args = args, cp_strict_args = strict, cp_rebox = rebox
    
    2799
    +          , cp_callers = callers })
    
    2575 2800
         = text "CP" <> braces (sep [ text "cp_qvars =" <+> ppr qvars <> comma
    
    2576 2801
                                    , text "cp_args =" <+> ppr args
    
    2577 2802
                                    , text "cp_strict_args = " <> ppr strict
    
    2578
    -                               , text "cp_rebox = " <> ppr rebox ])
    
    2803
    +                               , text "cp_rebox = " <> ppr rebox
    
    2804
    +                               , text "cp_callers = " <> ppr callers ])
    
    2805
    +
    
    2806
    +-- | One call pattern as displayed by the reboxing warning: the shapes of
    
    2807
    +-- the pattern's arguments, and the reboxed constructors among them.
    
    2808
    +-- See Note [Reboxing warning]
    
    2809
    +data ReboxedPat = ReboxedPat [PatShape] [Name]
    
    2810
    +
    
    2811
    +-- | The constructor skeleton of one call-pattern argument, as displayed
    
    2812
    +-- by the reboxing warning
    
    2813
    +data PatShape = ShapeWild
    
    2814
    +              | ShapeLit Literal
    
    2815
    +              | ShapeCon DataCon [PatShape]
    
    2816
    +
    
    2817
    +-- | The displayed shapes of a pattern's value arguments
    
    2818
    +patShapes :: CallPat -> [PatShape]
    
    2819
    +patShapes (CP { cp_args = args }) = mapMaybe arg_shape args
    
    2820
    +  where
    
    2821
    +    arg_shape (Type {})     = Nothing
    
    2822
    +    arg_shape (Coercion {}) = Nothing
    
    2823
    +    arg_shape (Cast e _)    = arg_shape e
    
    2824
    +    arg_shape (Tick _ e)    = arg_shape e
    
    2825
    +    arg_shape (Lit l)       = Just (ShapeLit l)
    
    2826
    +    arg_shape e
    
    2827
    +      | (Var f, f_args) <- collectArgs e
    
    2828
    +      , Just dc <- isDataConWorkId_maybe f
    
    2829
    +      = Just (ShapeCon dc (mapMaybe arg_shape f_args))
    
    2830
    +      | otherwise
    
    2831
    +      = Just ShapeWild
    
    2832
    +
    
    2833
    +-- | Stable comparison, used both to merge identically-rendering warnings
    
    2834
    +-- and to order a warning's patterns deterministically
    
    2835
    +cmpReboxedPat :: ReboxedPat -> ReboxedPat -> Ordering
    
    2836
    +cmpReboxedPat (ReboxedPat ss1 cs1) (ReboxedPat ss2 cs2)
    
    2837
    +  = cmpListBy cmpShape ss1 ss2
    
    2838
    +    `mappend` cmpListBy stableNameCmp (sortBy stableNameCmp cs1)
    
    2839
    +                                      (sortBy stableNameCmp cs2)
    
    2840
    +
    
    2841
    +cmpShape :: PatShape -> PatShape -> Ordering
    
    2842
    +cmpShape ShapeWild        ShapeWild        = EQ
    
    2843
    +cmpShape ShapeWild        _                = LT
    
    2844
    +cmpShape _                ShapeWild        = GT
    
    2845
    +cmpShape (ShapeLit l1)    (ShapeLit l2)    = compare l1 l2
    
    2846
    +cmpShape (ShapeLit _)     _                = LT
    
    2847
    +cmpShape _                (ShapeLit _)     = GT
    
    2848
    +cmpShape (ShapeCon c1 a1) (ShapeCon c2 a2)
    
    2849
    +  = stableNameCmp (dataConName c1) (dataConName c2)
    
    2850
    +    `mappend` cmpListBy cmpShape a1 a2
    
    2851
    +
    
    2852
    +cmpListBy :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering
    
    2853
    +cmpListBy _   []       []       = EQ
    
    2854
    +cmpListBy _   []       _        = LT
    
    2855
    +cmpListBy _   _        []       = GT
    
    2856
    +cmpListBy cmp (x1:xs1) (x2:xs2) = cmp x1 x2 `mappend` cmpListBy cmp xs1 xs2
    
    2857
    +
    
    2858
    +-- Constructors are shown by bare occurrence name: shapes illustrate,
    
    2859
    +-- while the warning's "reboxes" list identifies (with qualification)
    
    2860
    +pprPatShape :: PatShape -> SDoc
    
    2861
    +pprPatShape = go (10 :: Int)   -- Depth cap against pathological patterns
    
    2862
    +  where
    
    2863
    +    go _ ShapeWild        = underscore
    
    2864
    +    go _ (ShapeLit l)     = ppr l
    
    2865
    +    go _ (ShapeCon dc []) = ppr (getOccName dc)
    
    2866
    +    go 0 (ShapeCon {})    = text "..."
    
    2867
    +    go d (ShapeCon dc args)
    
    2868
    +      | isTupleDataCon dc
    
    2869
    +      = parens (pprWithCommas (go d') args)
    
    2870
    +      | isUnboxedTupleDataCon dc
    
    2871
    +      = text "(#" <+> pprWithCommas (go d') args <+> text "#)"
    
    2872
    +      | dataConIsInfix dc, [a1, a2] <- args
    
    2873
    +      = parens (go d' a1 <+> pprInfixOcc (getOccName dc) <+> go d' a2)
    
    2874
    +      | otherwise
    
    2875
    +      = parens (pprPrefixOcc (getOccName dc) <+> sep (map (go d') args))
    
    2876
    +      where d' = d - 1
    
    2877
    +
    
    2878
    +-- | How the function that SpecConstr specialised recurses, as bound in
    
    2879
    +-- the post-optimisation program.  See Note [Reboxing warning]
    
    2880
    +data ReboxRecursivity
    
    2881
    +  = ReboxSelfRec
    
    2882
    +  | ReboxMutualRec [Name]  -- The sibling binders of its Rec group
    
    2883
    +  | ReboxNonRec Bool       -- True <=> a join point
    
    2579 2884
     
    
    2580 2885
     data SpecConstrWarning
    
    2581 2886
       = SpecFailForcedArgCount { spec_failed_fun_name :: Name }
    
    2582 2887
       | SpecReboxed { spec_rebox_fun_name :: Name    -- The specialised function
    
    2583
    -                , spec_rebox_cons :: [Name] }    -- The reboxed constructor(s)
    
    2888
    +                , spec_rebox_fun_ty :: Type      -- Its type: often the only clue
    
    2889
    +                                                 -- to a span-less function's identity
    
    2890
    +                , spec_rebox_parent :: Maybe Name -- Its enclosing top-level
    
    2891
    +                                                  -- binder, if fn is local
    
    2892
    +                , spec_rebox_recur :: ReboxRecursivity
    
    2893
    +                , spec_rebox_pats :: [ReboxedPat] -- The patterns that rebox
    
    2894
    +                , spec_rebox_callers :: [Name] } -- Top-level binders containing
    
    2895
    +                                                 -- the specialised calls
    
    2584 2896
         -- See Note [Reboxing warning]
    
    2585
    -  deriving Eq
    
    2586 2897
     
    
    2587 2898
     type SpecConstrWarnings = [SpecConstrWarning]
    
    2588 2899
     
    
    2589 2900
     instance Outputable SpecConstrWarning where
    
    2590 2901
       ppr (SpecFailForcedArgCount name) = ppr name <+> pprDefinedAt name
    
    2591
    -  ppr (SpecReboxed fn dcs) = ppr fn <+> parens (pprWithCommas ppr dcs) <+> pprDefinedAt fn
    
    2902
    +  ppr (SpecReboxed fn _ty mb_parent _recur pats _callers)
    
    2903
    +    = ppr fn <+> parens (pprWithCommas ppr dcs) <+> pp_defn
    
    2904
    +    where
    
    2905
    +      dcs = [ dc | ReboxedPat _ cons <- pats, dc <- cons ]
    
    2906
    +      -- A local fn often has no useful location; point at its
    
    2907
    +      -- enclosing top-level binder instead
    
    2908
    +      pp_defn = case mb_parent of
    
    2909
    +        Just parent -> text "in" <+> ppr parent <> comma <+> pprDefinedAt parent
    
    2910
    +        Nothing     -> pprDefinedAt fn
    
    2592 2911
     
    
    2593 2912
     combineSpecWarning :: SpecConstrWarnings -> SpecConstrWarnings -> SpecConstrWarnings
    
    2594 2913
     combineSpecWarning = (++)
    
    ... ... @@ -2735,7 +3054,7 @@ callToPat :: ScEnv -> [ArgOcc] -> Call -> UniqSM (Maybe CallPat)
    2735 3054
             --      Type variables come first, since they may scope
    
    2736 3055
             --      over the following term variables
    
    2737 3056
             -- The [CoreExpr] are the argument patterns for the rule
    
    2738
    -callToPat env bndr_occs call@(Call fn args con_env)
    
    3057
    +callToPat env bndr_occs call@(Call fn args con_env mb_caller)
    
    2739 3058
       = do  { let in_scope = substInScopeSet (sc_subst env)
    
    2740 3059
     
    
    2741 3060
             ; arg_quads <- zipWith3M (argToPat env in_scope con_env) args bndr_occs (map (const NotMarkedStrict) args)
    
    ... ... @@ -2784,7 +3103,11 @@ callToPat env bndr_occs call@(Call fn args con_env)
    2784 3103
               if interesting && null bad_covars
    
    2785 3104
               then do { let cp_res = CP { cp_qvars = qvars', cp_args = pats
    
    2786 3105
                                         , cp_strict_args = concat cbv_ids
    
    2787
    -                                    , cp_rebox = concat rebox_cons }
    
    3106
    +                                    , cp_rebox = concat rebox_cons
    
    3107
    +                                      -- Self-recursive calls are no clue
    
    3108
    +                                      -- to the function's identity
    
    3109
    +                                    , cp_callers = [ c | Just c <- [mb_caller]
    
    3110
    +                                                       , c /= idName fn ] }
    
    2788 3111
     --                  ; pprTraceM "callToPatOut" $
    
    2789 3112
     --                    vcat [ text "fn:" <+> ppr fn
    
    2790 3113
     --                         , text "args:" <+> ppr args
    
    ... ... @@ -2888,8 +3211,10 @@ argToPat1 env in_scope val_env arg arg_occ _arg_str
    2888 3211
            ; let args'        = [ p    | (_, p, _, _)   <- prs ] :: [CoreArg]
    
    2889 3212
                  cbvs         = concat [ cbv | (_, _, cbv, _) <- prs ]
    
    2890 3213
                  rebox_nested = concat [ rbs | (_, _, _, rbs) <- prs ]
    
    2891
    -             -- rebox_here: see Note [Reboxing warning]
    
    2892
    -             rebox_here   = [ dataConName dc | box_use == BoxOther ]
    
    3214
    +             -- rebox_here: see Note [Reboxing warning]; nullary
    
    3215
    +             -- constructors rebox for free, so don't warn about them
    
    3216
    +             rebox_here   = [ dataConName dc
    
    3217
    +                            | box_use == BoxOther, dataConRepArity dc > 0 ]
    
    2893 3218
            ; assertPpr (length con_str == length (filter isRuntimeArg rest_args))
    
    2894 3219
                 ( ppr con_str $$ ppr rest_args $$
    
    2895 3220
                   ppr (length con_str) $$ ppr (length rest_args)
    

  • docs/users_guide/using-warnings.rst
    ... ... @@ -534,6 +534,35 @@ of ``-W(no-)*``.
    534 534
         the call-pattern analysis by wrapping the argument in ``GHC.Exts.lazy``
    
    535 535
         at the call site, or :ghc-flag:`-fno-spec-constr`.
    
    536 536
     
    
    537
    +    The warning shows the specialised function's type, which is often the
    
    538
    +    clearest clue to its identity when its name carries no meaning,
    
    539
    +    followed by a block of labelled facts: ``source:`` — the function's
    
    540
    +    definition site (for a local function, also the enclosing top-level
    
    541
    +    binding); ``recursivity:`` — whether the function is self-recursive,
    
    542
    +    mutually recursive (naming the other functions of its recursive
    
    543
    +    group), or non-recursive (for example a join point), as bound in the
    
    544
    +    optimised program, whose shape can differ from the source's;
    
    545
    +    ``called from:`` — the top-level bindings containing the specialised
    
    546
    +    calls; ``call patterns:`` — the calls the function was specialised
    
    547
    +    for, shown as the constructor skeletons of their arguments, each
    
    548
    +    alongside the constructors that the specialisation reboxes (for
    
    549
    +    example ``go (_ : _) (Bin _ _ _) -- reboxes ‘Bin’``). One warning is emitted per
    
    550
    +    specialised function, and warnings that would read identically are
    
    551
    +    merged into one. Specialisations on nullary constructors are not
    
    552
    +    reported, since "reboxing" a nullary constructor simply references
    
    553
    +    its shared static closure.
    
    554
    +
    
    555
    +    A ``source:`` reading ``inlined from another module (no source
    
    556
    +    location)`` concerns a function that reached the module being compiled
    
    557
    +    through another module's unfolding; interface files record no source
    
    558
    +    locations for local functions. Such reboxing cannot be addressed in
    
    559
    +    the module being compiled — consider reporting it against the package
    
    560
    +    defining the inlined code. Constructors imported from other modules
    
    561
    +    are shown qualified with their defining module as a hint to where that
    
    562
    +    is. For such a warning the ``called from:`` sites are the only located
    
    563
    +    code — following the inlining from one of them identifies the reboxed
    
    564
    +    code.
    
    565
    +
    
    537 566
         The analysis behind this warning is approximate: it can both miss genuine
    
    538 567
         reboxing and report reboxing that later optimisations eliminate or that
    
    539 568
         only occurs on cold code paths.
    

  • testsuite/tests/simplCore/should_compile/T27628.stderr
    1 1
     T27628.hs: warning: [-Wspec-constr-reboxing]
    
    2
    -    SpecConstr specialised the following function(s) on a constructor argument that is also used boxed:
    
    3
    -      $wgo (LC) Defined at T27628.hs:17:1
    
    4
    -    The specialised code allocates a fresh constructor at each such use ("reboxing"),
    
    5
    -    which can increase allocation and defeat pointer-equality-based sharing.
    
    6
    -    Possible remedies: exclude the type with an {-# ANN type T NoSpecConstr #-} pragma,
    
    7
    -    hide the constructor from SpecConstr by wrapping the call-site argument in GHC.Exts.lazy,
    
    8
    -    or use -fno-spec-constr.
    
    2
    +    SpecConstr specialised
    
    3
    +      ‘$wgo :: LC
    
    4
    +               -> GHC.Internal.Prim.Int#
    
    5
    +               -> GHC.Internal.Prim.Int#
    
    6
    +               -> GHC.Internal.Prim.Int#’
    
    7
    +      source:                T27628.hs:17:1
    
    8
    +      recursivity:           self-recursive
    
    9
    +      called from:           ‘f’
    
    10
    +      call pattern:          $wgo (LC _ _) -- reboxes ‘LC’
    
    11
    +    This constructor argument is also used boxed, so the specialisation
    
    12
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    13
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    9 14
     

  • testsuite/tests/simplCore/should_compile/T27628b.stderr
    1 1
     T27628b.hs: warning: [-Wspec-constr-reboxing]
    
    2
    -    SpecConstr specialised the following function(s) on a constructor argument that is also used boxed:
    
    3
    -      merge (Bin) Defined at T27628b.hs:10:1
    
    4
    -    The specialised code allocates a fresh constructor at each such use ("reboxing"),
    
    5
    -    which can increase allocation and defeat pointer-equality-based sharing.
    
    6
    -    Possible remedies: exclude the type with an {-# ANN type T NoSpecConstr #-} pragma,
    
    7
    -    hide the constructor from SpecConstr by wrapping the call-site argument in GHC.Exts.lazy,
    
    8
    -    or use -fno-spec-constr.
    
    2
    +    SpecConstr specialised ‘merge :: T -> T -> T’
    
    3
    +      source:                T27628b.hs:10:1
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘f’
    
    6
    +      call pattern:          merge (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    9 10
     

  • testsuite/tests/simplCore/should_compile/T27628e.hs
    1
    +-- Like T27628b, but the specialisation pattern is the *nullary*
    
    2
    +-- constructor Tip (the call passes Tip; the box is also returned).
    
    3
    +-- Reboxing a nullary constructor is free (it is a shared static
    
    4
    +-- closure), so no warning should be emitted.
    
    5
    +module T27628e where
    
    6
    +
    
    7
    +data T = Tip | Bin Int T T
    
    8
    +
    
    9
    +merge :: T -> T -> T
    
    10
    +merge Tip t2 = t2
    
    11
    +merge t1@(Bin k l r) t2 =
    
    12
    +  case t2 of
    
    13
    +    Tip         -> t1
    
    14
    +    Bin _ l2 r2 -> Bin k (merge l l2) (merge r r2)
    
    15
    +
    
    16
    +g :: T -> T
    
    17
    +g t = merge t Tip

  • testsuite/tests/simplCore/should_compile/T27628f.hs
    1
    +-- Like T27628b, but the specialised function is a *local* worker.
    
    2
    +-- The warning should attribute it to the enclosing top-level binder f.
    
    3
    +-- (merge captures n so that it is not floated to the top level.)
    
    4
    +module T27628f where
    
    5
    +
    
    6
    +data T = Tip | Bin Int T T
    
    7
    +
    
    8
    +f :: Int -> T -> T
    
    9
    +f n t0 = merge (Bin n Tip Tip) t0
    
    10
    +  where
    
    11
    +    merge :: T -> T -> T
    
    12
    +    merge Tip _ = Tip
    
    13
    +    merge t1@(Bin k l r) t2 =
    
    14
    +      case t2 of
    
    15
    +        Tip         -> t1
    
    16
    +        Bin _ l2 r2 -> Bin (k + n) (merge l l2) (merge r r2)

  • testsuite/tests/simplCore/should_compile/T27628f.stderr
    1
    +T27628f.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘merge :: T -> T -> T’
    
    3
    +      source:                ‘f’ at T27628f.hs:12:5
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘f’
    
    6
    +      call pattern:          merge (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    10
    +

  • testsuite/tests/simplCore/should_compile/T27628g.hs
    1
    +module T27628g where
    
    2
    +
    
    3
    +data T a = Tip | Bin a (T a) (T a)
    
    4
    +
    
    5
    +-- merge has no free value variables, so the float-out pass lifts it to
    
    6
    +-- top level as poly_merge, abstracted over 'a'. The reboxing warning
    
    7
    +-- should still point at merge's definition site.
    
    8
    +f :: a -> T a -> T a
    
    9
    +f x t = merge (Bin x Tip Tip) t
    
    10
    +  where
    
    11
    +    merge Tip t2 = t2
    
    12
    +    merge t1@(Bin k l r) t2 =
    
    13
    +      case t2 of
    
    14
    +        Tip         -> t1
    
    15
    +        Bin _ l2 r2 -> Bin k (merge l l2) (merge r r2)

  • testsuite/tests/simplCore/should_compile/T27628g.stderr
    1
    +T27628g.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘poly_merge :: T a -> T a -> T a’
    
    3
    +      source:                T27628g.hs:11:5
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘f’
    
    6
    +      call pattern:          poly_merge (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    10
    +

  • testsuite/tests/simplCore/should_compile/T27628h.hs
    1
    +-- Specialising the span-less copy of T27628h_M.merge must warn with the
    
    2
    +-- "inlined from another module" wording and a module-qualified constructor.
    
    3
    +module T27628h where
    
    4
    +
    
    5
    +import T27628h_M
    
    6
    +
    
    7
    +g :: Int -> T Int -> T Int
    
    8
    +g x t = f x (f x t)

  • testsuite/tests/simplCore/should_compile/T27628h.stderr
    1
    +./T27628h_M.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘poly_merge :: T a -> T a -> T a’
    
    3
    +      source:                T27628h_M.hs:11:5
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘f’
    
    6
    +      call pattern:          poly_merge (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    10
    +
    
    11
    +T27628h.hs: warning: [-Wspec-constr-reboxing]
    
    12
    +    SpecConstr specialised ‘merge :: T Int -> T Int -> T Int’
    
    13
    +      source:                inlined from another module (no source location)
    
    14
    +      recursivity:           self-recursive
    
    15
    +      called from:           ‘g’
    
    16
    +      call pattern:          merge (Bin _ _ _) -- reboxes ‘T27628h_M.Bin’
    
    17
    +    This constructor argument is also used boxed, so the specialisation
    
    18
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    19
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    20
    +

  • testsuite/tests/simplCore/should_compile/T27628h_M.hs
    1
    +-- The INLINE unfolding of f carries the local loop 'merge' into importing
    
    2
    +-- modules, where it is specialised without a source span: iface unfoldings
    
    3
    +-- record no spans for local binders.
    
    4
    +module T27628h_M where
    
    5
    +
    
    6
    +data T a = Tip | Bin a (T a) (T a)
    
    7
    +
    
    8
    +f :: a -> T a -> T a
    
    9
    +f x t = merge (Bin x Tip Tip) t
    
    10
    +  where
    
    11
    +    merge Tip t2 = t2
    
    12
    +    merge t1@(Bin k l r) t2 =
    
    13
    +      case t2 of
    
    14
    +        Tip         -> t1
    
    15
    +        Bin _ l2 r2 -> Bin k (merge l l2) (merge r r2)
    
    16
    +{-# INLINE f #-}

  • testsuite/tests/simplCore/should_compile/T27628i.hs
    1
    +-- The span-less copies of f1's and f3's 'merge' render identically, so
    
    2
    +-- one warning covers both; f2's 'merge' differs in type and gets its
    
    3
    +-- own warning.
    
    4
    +module T27628i where
    
    5
    +
    
    6
    +import T27628i_M
    
    7
    +
    
    8
    +g1 :: Int -> T Int -> T Int
    
    9
    +g1 x t = f1 x (f1 x t)
    
    10
    +
    
    11
    +g2 :: Int -> S Int -> S Int
    
    12
    +g2 x t = f2 x (f2 x t)
    
    13
    +
    
    14
    +g3 :: Int -> T Int -> T Int
    
    15
    +g3 x t = f3 x (f3 x t)

  • testsuite/tests/simplCore/should_compile/T27628i.stderr
    1
    +./T27628i_M.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘poly_merge :: T a -> T a -> T a’
    
    3
    +      source:                T27628i_M.hs:36:5
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘f3’
    
    6
    +      call pattern:          poly_merge (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    10
    +
    
    11
    +./T27628i_M.hs: warning: [-Wspec-constr-reboxing]
    
    12
    +    SpecConstr specialised ‘poly_merge :: S a -> S a -> S a’
    
    13
    +      source:                T27628i_M.hs:24:5
    
    14
    +      recursivity:           self-recursive
    
    15
    +      called from:           ‘f2’
    
    16
    +      call pattern:          poly_merge (Node _ _ _) -- reboxes ‘Node’
    
    17
    +    This constructor argument is also used boxed, so the specialisation
    
    18
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    19
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    20
    +
    
    21
    +./T27628i_M.hs: warning: [-Wspec-constr-reboxing]
    
    22
    +    SpecConstr specialised ‘poly_merge :: T a -> T a -> T a’
    
    23
    +      source:                T27628i_M.hs:14:5
    
    24
    +      recursivity:           self-recursive
    
    25
    +      called from:           ‘f1’
    
    26
    +      call pattern:          poly_merge (Bin _ _ _) -- reboxes ‘Bin’
    
    27
    +    This constructor argument is also used boxed, so the specialisation
    
    28
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    29
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    30
    +
    
    31
    +T27628i.hs: warning: [-Wspec-constr-reboxing]
    
    32
    +    SpecConstr specialised ‘merge :: T Int -> T Int -> T Int’
    
    33
    +      source:                inlined from another module (no source location)
    
    34
    +      recursivity:           self-recursive
    
    35
    +      called from:           ‘g1’, ‘g3’
    
    36
    +      call pattern:          merge (Bin _ _ _) -- reboxes ‘T27628i_M.Bin’
    
    37
    +    This constructor argument is also used boxed, so the specialisation
    
    38
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    39
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    40
    +
    
    41
    +T27628i.hs: warning: [-Wspec-constr-reboxing]
    
    42
    +    SpecConstr specialised ‘merge :: S Int -> S Int -> S Int’
    
    43
    +      source:                inlined from another module (no source location)
    
    44
    +      recursivity:           self-recursive
    
    45
    +      called from:           ‘g2’
    
    46
    +      call pattern:          merge (Node _ _ _)
    
    47
    +                               -- reboxes ‘T27628i_M.Node’
    
    48
    +    This constructor argument is also used boxed, so the specialisation
    
    49
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    50
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    51
    +

  • testsuite/tests/simplCore/should_compile/T27628i_M.hs
    1
    +-- Three INLINE functions with local loops named 'merge': f1 and f3 over
    
    2
    +-- T, f2 over S. In an importing module all three loops arrive span-less
    
    3
    +-- (iface unfoldings record no spans for local binders). f1's and f3's
    
    4
    +-- copies render identically (same name and type) and must merge into
    
    5
    +-- one warning; f2's differs in type and must stay separate.
    
    6
    +module T27628i_M where
    
    7
    +
    
    8
    +data T a = Tip | Bin a (T a) (T a)
    
    9
    +data S a = Leaf | Node a (S a) (S a)
    
    10
    +
    
    11
    +f1 :: a -> T a -> T a
    
    12
    +f1 x t = merge (Bin x Tip Tip) t
    
    13
    +  where
    
    14
    +    merge Tip t2 = t2
    
    15
    +    merge t1@(Bin k l r) t2 =
    
    16
    +      case t2 of
    
    17
    +        Tip         -> t1
    
    18
    +        Bin _ l2 r2 -> Bin k (merge l l2) (merge r r2)
    
    19
    +{-# INLINE f1 #-}
    
    20
    +
    
    21
    +f2 :: a -> S a -> S a
    
    22
    +f2 x t = merge (Node x Leaf Leaf) t
    
    23
    +  where
    
    24
    +    merge Leaf t2 = t2
    
    25
    +    merge t1@(Node k l r) t2 =
    
    26
    +      case t2 of
    
    27
    +        Leaf         -> t1
    
    28
    +        Node _ l2 r2 -> Node k (merge l l2) (merge r r2)
    
    29
    +{-# INLINE f2 #-}
    
    30
    +
    
    31
    +-- Like f1 but recursing with the children swapped, so the two loops
    
    32
    +-- stay distinct functions while their warnings render the same
    
    33
    +f3 :: a -> T a -> T a
    
    34
    +f3 x t = merge (Bin x Tip Tip) t
    
    35
    +  where
    
    36
    +    merge Tip t2 = t2
    
    37
    +    merge t1@(Bin k l r) t2 =
    
    38
    +      case t2 of
    
    39
    +        Tip         -> t1
    
    40
    +        Bin _ l2 r2 -> Bin k (merge r r2) (merge l l2)
    
    41
    +{-# INLINE f3 #-}

  • testsuite/tests/simplCore/should_compile/T27628j.hs
    1
    +-- A mutually recursive pair in the style of T27628b. g calls both
    
    2
    +-- functions with a constructor argument: the non-loop-breaker inlines
    
    3
    +-- into g, but the loop breaker's call survives to SpecConstr, whose
    
    4
    +-- warning classifies it as mutually recursive and names the sibling.
    
    5
    +module T27628j where
    
    6
    +
    
    7
    +data T = Tip | Bin Int T T
    
    8
    +
    
    9
    +mergeA :: T -> T -> T
    
    10
    +mergeA Tip t2 = t2
    
    11
    +mergeA t1@(Bin k l r) t2 =
    
    12
    +  case t2 of
    
    13
    +    Tip         -> t1
    
    14
    +    Bin _ l2 r2 -> Bin k (mergeB l l2) (mergeB r r2)
    
    15
    +
    
    16
    +mergeB :: T -> T -> T
    
    17
    +mergeB Tip t2 = t2
    
    18
    +mergeB t1@(Bin k l r) t2 =
    
    19
    +  case t2 of
    
    20
    +    Tip         -> t1
    
    21
    +    Bin _ l2 r2 -> Bin k (mergeA r r2) (mergeA l l2)
    
    22
    +
    
    23
    +g :: Int -> T -> T
    
    24
    +g x t = mergeA (Bin x Tip Tip) (mergeB (Bin x Tip Tip) t)

  • testsuite/tests/simplCore/should_compile/T27628j.stderr
    1
    +T27628j.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘mergeB :: T -> T -> T’
    
    3
    +      source:                T27628j.hs:17:1
    
    4
    +      recursivity:           mutually recursive with ‘mergeA’
    
    5
    +      called from:           ‘g’
    
    6
    +      call pattern:          mergeB (Bin _ _ _) -- reboxes ‘Bin’
    
    7
    +    This constructor argument is also used boxed, so the specialisation
    
    8
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    9
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    10
    +

  • testsuite/tests/simplCore/should_compile/T27628k.hs
    1
    +-- 'go' is specialised for two different call patterns, A and B, and
    
    2
    +-- both rebox (t is scrutinised but also passed whole to 'sink').
    
    3
    +-- Expect one warning for 'go' listing both call patterns.
    
    4
    +module T27628k where
    
    5
    +
    
    6
    +data T = A Int | B Int | C
    
    7
    +
    
    8
    +-- The guard makes the use of 't' lazy, so boxity analysis keeps the
    
    9
    +-- box: $wsink wants it.
    
    10
    +sink :: T -> Int -> Int
    
    11
    +sink t k
    
    12
    +  | k < 0     = k
    
    13
    +  | otherwise = case t of A n -> n; B n -> n; C -> 0
    
    14
    +{-# NOINLINE sink #-}
    
    15
    +
    
    16
    +go :: T -> Int -> Int
    
    17
    +go t k = case t of
    
    18
    +  A n -> if k == 0 then sink t k else go (B n) (k - 1)
    
    19
    +  B n -> if k == 0 then sink t k else go (A n) (k - 1)
    
    20
    +  C   -> 0

  • testsuite/tests/simplCore/should_compile/T27628k.stderr
    1
    +T27628k.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘go :: T -> Int -> Int’
    
    3
    +      source:                T27628k.hs:17:1
    
    4
    +      recursivity:           self-recursive
    
    5
    +      call patterns:         go (A _) (I# _) -- reboxes ‘A’
    
    6
    +                             go (B _) (I# _) -- reboxes ‘B’
    
    7
    +    These constructor arguments are also used boxed, so the
    
    8
    +    specialisations may increase allocation and defeat
    
    9
    +    pointer-equality-based sharing.
    
    10
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    11
    +

  • testsuite/tests/simplCore/should_compile/T27628l.hs
    1
    +-- Max and Min (mimicking GHC.Internal.Data.Functor.Utils) both inline
    
    2
    +-- base's foldl' and stimes templates, so each instance's methods bind
    
    3
    +-- local loops with the SAME uniques as the other's.  The warnings must
    
    4
    +-- stay separate per instance (keyed on (parent, function)), not be
    
    5
    +-- fused into one with doubled callers; see Note [Reboxing warning].
    
    6
    +module T27628l where
    
    7
    +
    
    8
    +import Data.List (foldl')
    
    9
    +
    
    10
    +newtype Max a = Max (Maybe a)
    
    11
    +
    
    12
    +instance Ord a => Semigroup (Max a) where
    
    13
    +    {-# INLINE (<>) #-}
    
    14
    +    m <> Max Nothing = m
    
    15
    +    Max Nothing <> n = n
    
    16
    +    (Max m@(Just x)) <> (Max n@(Just y))
    
    17
    +      | x >= y    = Max m
    
    18
    +      | otherwise = Max n
    
    19
    +
    
    20
    +instance Ord a => Monoid (Max a) where
    
    21
    +    mempty = Max Nothing
    
    22
    +    mconcat = foldl' (<>) mempty
    
    23
    +    {-# INLINE mconcat #-}
    
    24
    +
    
    25
    +newtype Min a = Min (Maybe a)
    
    26
    +
    
    27
    +instance Ord a => Semigroup (Min a) where
    
    28
    +    {-# INLINE (<>) #-}
    
    29
    +    m <> Min Nothing = m
    
    30
    +    Min Nothing <> n = n
    
    31
    +    (Min m@(Just x)) <> (Min n@(Just y))
    
    32
    +      | x <= y    = Min m
    
    33
    +      | otherwise = Min n
    
    34
    +
    
    35
    +instance Ord a => Monoid (Min a) where
    
    36
    +    mempty = Min Nothing
    
    37
    +    mconcat = foldl' (<>) mempty
    
    38
    +    {-# INLINE mconcat #-}

  • testsuite/tests/simplCore/should_compile/T27628l.stderr
    1
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    2
    +    SpecConstr specialised ‘go1 :: [Max a] -> Max a -> Max a’
    
    3
    +      source:                ‘$cmconcat’ at T27628l.hs:22:5
    
    4
    +      recursivity:           self-recursive
    
    5
    +      called from:           ‘$cmconcat’
    
    6
    +      call pattern:          go1 _ (Just _)
    
    7
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    8
    +    This constructor argument is also used boxed, so the specialisation
    
    9
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    10
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    11
    +
    
    12
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    13
    +    SpecConstr specialised ‘exit :: Max a -> b -> Max a’
    
    14
    +      source:                ‘$cstimes’ at T27628l.hs:12:10
    
    15
    +      recursivity:           non-recursive (a join point)
    
    16
    +      called from:           ‘$cstimes’
    
    17
    +      call pattern:          exit (Just _) _
    
    18
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    19
    +    This constructor argument is also used boxed, so the specialisation
    
    20
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    21
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    22
    +
    
    23
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    24
    +    SpecConstr specialised ‘g :: Max a -> b -> Max a -> Max a’
    
    25
    +      source:                ‘$cstimes’ at T27628l.hs:12:10
    
    26
    +      recursivity:           self-recursive
    
    27
    +      called from:           ‘$cstimes’
    
    28
    +      call pattern:          g (Just _) _ _
    
    29
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    30
    +    This constructor argument is also used boxed, so the specialisation
    
    31
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    32
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    33
    +
    
    34
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    35
    +    SpecConstr specialised ‘go1 :: [Min a] -> Min a -> Min a’
    
    36
    +      source:                ‘$cmconcat’ at T27628l.hs:37:5
    
    37
    +      recursivity:           self-recursive
    
    38
    +      called from:           ‘$cmconcat’
    
    39
    +      call pattern:          go1 _ (Just _)
    
    40
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    41
    +    This constructor argument is also used boxed, so the specialisation
    
    42
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    43
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    44
    +
    
    45
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    46
    +    SpecConstr specialised ‘exit :: Min a -> b -> Min a’
    
    47
    +      source:                ‘$cstimes’ at T27628l.hs:27:10
    
    48
    +      recursivity:           non-recursive (a join point)
    
    49
    +      called from:           ‘$cstimes’
    
    50
    +      call pattern:          exit (Just _) _
    
    51
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    52
    +    This constructor argument is also used boxed, so the specialisation
    
    53
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    54
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    55
    +
    
    56
    +T27628l.hs: warning: [-Wspec-constr-reboxing]
    
    57
    +    SpecConstr specialised ‘g :: Min a -> b -> Min a -> Min a’
    
    58
    +      source:                ‘$cstimes’ at T27628l.hs:27:10
    
    59
    +      recursivity:           self-recursive
    
    60
    +      called from:           ‘$cstimes’
    
    61
    +      call pattern:          g (Just _) _ _
    
    62
    +                               -- reboxes ‘GHC.Internal.Maybe.Just’
    
    63
    +    This constructor argument is also used boxed, so the specialisation
    
    64
    +    may increase allocation and defeat pointer-equality-based sharing.
    
    65
    +    See -Wspec-constr-reboxing in the users guide for possible remedies.
    
    66
    +

  • testsuite/tests/simplCore/should_compile/all.T
    ... ... @@ -617,3 +617,11 @@ test('T27628', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    617 617
     test('T27628b', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    618 618
     test('T27628c', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    619 619
     test('T27628d', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    620
    +test('T27628e', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    621
    +test('T27628f', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    622
    +test('T27628g', normal, compile, ['-O2 -Wspec-constr-reboxing -dsuppress-uniques'])
    
    623
    +test('T27628h', [extra_files(['T27628h_M.hs'])], multimod_compile, ['T27628h', '-v0 -O2 -Wspec-constr-reboxing -dsuppress-uniques'])
    
    624
    +test('T27628i', [extra_files(['T27628i_M.hs'])], multimod_compile, ['T27628i', '-v0 -O2 -Wspec-constr-reboxing -dsuppress-uniques'])
    
    625
    +test('T27628j', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    626
    +test('T27628k', normal, compile, ['-O2 -Wspec-constr-reboxing'])
    
    627
    +test('T27628l', normal, compile, ['-O2 -Wspec-constr-reboxing -dsuppress-uniques'])