`-fno-omit-interface-pragmas` causes an unsilenceable warning about optimizations in GHCi
Summary
Calling ghci
with -fno-omit-interface-pragmas
causes GHCi to issue a warning.
If -Werror
is also enabled, then ghci
exits entirely without booting.
It is possible to work around this issue by providing -O0
explicitly, but the call to -O0
must be after - calling it before has no effect.
Steps to reproduce
$ ghci -fno-omit-interface-pragmas
when making flags consistent: warning:
Optimization flags conflict with --interactive; optimization flags ignored.
GHCi, version 9.4.2: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/matt/.dotfiles/haskell/ghci.symlink
λ>
To work around, you must provide -O0
explicitly.
$ ghci -fno-omit-interface-pragmas -O0
GHCi, version 9.4.2: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/matt/.dotfiles/haskell/ghci.symlink
λ>
Calling with -Werror
also causes a problem:
$ ghci -fno-omit-interface-pragmas -Werror
when making flags consistent: error: [-Werror]
Optimization flags conflict with --interactive; optimization flags ignored.
$
The work around does not work if -O0
is provided before -fno-omit-interface-pragmas
:
$ ghci -O0 -fno-omit-interface-pragmas -Werror
when making flags consistent: error: [-Werror]
Optimization flags conflict with --interactive; optimization flags ignored.
$
Expected behavior
I'd expect the order of providing -O0
to not matter. I'd prefer a clearer error message, as well - calling cabal repl --verbose
and seeing a command like ghc --interactive -O0 (lots of stuff here ...)
and then it complains about "Optimization flags conflict with --interactive" is really hard to diagnose.
There are a few upstream fixes that would be nice here:
-
Give the warning a name so I can write
-Wno-optimizer-flags-conflict
or-Wwarn=optimizer-flags-conflict
and prevent it from breaking in the presence of -Werror
-
The warning appears to come from this part of the code:
-- compiler/GHC/Driver/Session.hs
| backendForcesOptimization0 (backend dflags)
, let (dflags', changed) = updOptLevelChanged 0 dflags
, changed
= loop dflags' ("Optimization flags are incompatible with the " ++
backendDescription (backend dflags) ++
"; optimization flags ignored.")
updOptLevelChanged
is here:
updOptLevelChanged :: Int -> DynFlags -> (DynFlags, Bool)
-- ^ Sets the 'DynFlags' to be appropriate to the optimisation level and signals if any changes took place
updOptLevelChanged n dfs
= (dfs3, changed1 || changed2 || changed3)
where
final_n = max 0 (min 2 n) -- Clamp to 0 <= n <= 2
(dfs1, changed1) = foldr unset (dfs , False) remove_gopts
(dfs2, changed2) = foldr set (dfs1, False) extra_gopts
(dfs3, changed3) = setLlvmOptLevel dfs2
extra_gopts = [ f | (ns,f) <- optLevelFlags, final_n `elem` ns ]
remove_gopts = [ f | (ns,f) <- optLevelFlags, final_n `notElem` ns ]
set f (dfs, changed)
| gopt f dfs = (dfs, changed)
| otherwise = (gopt_set dfs f, True)
unset f (dfs, changed)
| not (gopt f dfs) = (dfs, changed)
| otherwise = (gopt_unset dfs f, True)
setLlvmOptLevel dfs
| llvmOptLevel dfs /= final_n = (dfs{ llvmOptLevel = final_n }, True)
| otherwise = (dfs, False)
optLevelFlags
has this entry:
, ([0], Opt_OmitInterfacePragmas)
Opt_OmitInterfacePragmas
is included in the default [GeneralFlag]
since it has a 0
- O0
implies the flag.
defaultFlags :: Settings -> [GeneralFlag]
defaultFlags settings
{- snip -}
++ [f | (ns,f) <- optLevelFlags, 0 `elem` ns]
-- The default -O0 options
{- snip -}
So, -fno-omit-interface-pragmas
causes GHC to create the EnumSet
containing the Opt_OmitInterfacePragmas
. Then, extra_gopts
looks at optLevelFlags
and pulls all the flags with elem 0 ns
- this gets Opt_OmitInterfacePragmas
. When folding over the options, set
is called, which checks if gopt Opt_OmitInterfacePragmas dfs
is set. -fno-omit-interface-pragmas
was passed, so this returns False
, and set
flips the Changed switch to True
and does a gopt_set dfs Opt_OmitInterfacePragmas
.
Condensing:
- GHC has
-fomit-interface-pragmas
on by default - Calling
-fno-omit-interface-pragmas
removes that setting from theDynFlags
- When checking for compatibility with
Interactive
(or forcing optimization 0 inHEAD
), it forces-O0
and sees if anything changes. - Because forcing to
-O0
re-enables the flag, this counts as a change, and GHC issues a warning.
Reasoning
We use -fno-omit-interface-pragmas
so that we can get build warnings on irrelevant pragmas. The specific case that came up was:
data X = X {-# UNBOX #-} !Int
which passed CI fine (building with -O0
) but failed when deploying (due to -Werror -O2
). So we have -fno-omit-interface-pragmas
even when building locally with -O0
.
However, for the developers that have done cabal configure --ghc-options="-Werror"
, they can't get into a cabal repl
or ghcid
.
Environment
- GHC version used: 9.4.2, 9.4.3
Optional:
- Operating System:
- System Architecture: