Commit a863c44f authored by Oleg Grenrus's avatar Oleg Grenrus Committed by Ben Gamari

Add -Winferred-safe-imports warning

This commit partly reverts e69619e9
commit by reintroducing Sf_SafeInferred SafeHaskellMode.

We preserve whether module was declared or inferred Safe.  When
declared-Safe module imports inferred-Safe, we warn.  This inferred
status is volatile, often enough it's a happy coincidence, something
which cannot be relied upon. However, explicitly Safe or Trustworthy
packages won't accidentally become Unsafe.

Updates haddock submodule.
parent 5c3f2080
......@@ -912,6 +912,8 @@ data WarningFlag =
| Opt_WarnMissingDerivingStrategies -- Since 8.8
| Opt_WarnPrepositiveQualifiedModule -- Since TBD
| Opt_WarnUnusedPackages -- Since 8.10
| Opt_WarnInferredSafeImports -- Since 8.10
| Opt_WarnMissingSafeHaskellMode -- Since 8.10
deriving (Eq, Show, Enum)
data Language = Haskell98 | Haskell2010
......@@ -922,11 +924,12 @@ instance Outputable Language where
-- | The various Safe Haskell modes
data SafeHaskellMode
= Sf_None
| Sf_Unsafe
| Sf_Trustworthy
| Sf_Safe
| Sf_Ignore
= Sf_None -- ^ inferred unsafe
| Sf_Unsafe -- ^ declared and checked
| Sf_Trustworthy -- ^ declared and checked
| Sf_Safe -- ^ declared and checked
| Sf_SafeInferred -- ^ inferred as safe
| Sf_Ignore -- ^ @-fno-safe-haskell@ state
deriving (Eq)
instance Show SafeHaskellMode where
......@@ -934,6 +937,7 @@ instance Show SafeHaskellMode where
show Sf_Unsafe = "Unsafe"
show Sf_Trustworthy = "Trustworthy"
show Sf_Safe = "Safe"
show Sf_SafeInferred = "Safe-Inferred"
show Sf_Ignore = "Ignore"
instance Outputable SafeHaskellMode where
......@@ -3758,6 +3762,8 @@ dynamic_flags_deps = [
, make_ord_flag defFlag "fno-safe-infer" (noArg (\d ->
d { safeInfer = False }))
, make_ord_flag defFlag "fno-safe-haskell" (NoArg (setSafeHaskell Sf_Ignore))
------ position independent flags ----------------------------------
, make_ord_flag defGhcFlag "fPIC" (NoArg (setGeneralFlag Opt_PIC))
, make_ord_flag defGhcFlag "fno-PIC" (NoArg (unSetGeneralFlag Opt_PIC))
, make_ord_flag defGhcFlag "fPIE" (NoArg (setGeneralFlag Opt_PIC))
......@@ -4076,6 +4082,8 @@ wWarningFlagsDeps = [
flagSpec "all-missed-specializations" Opt_WarnAllMissedSpecs,
flagSpec' "safe" Opt_WarnSafe setWarnSafe,
flagSpec "trustworthy-safe" Opt_WarnTrustworthySafe,
flagSpec "inferred-safe-imports" Opt_WarnInferredSafeImports,
flagSpec "missing-safe-haskell-mode" Opt_WarnMissingSafeHaskellMode,
flagSpec "tabs" Opt_WarnTabs,
flagSpec "type-defaults" Opt_WarnTypeDefaults,
flagSpec "typed-holes" Opt_WarnTypedHoles,
......
......@@ -1109,21 +1109,36 @@ hscCheckSafe' m l = do
let trust = getSafeMode $ mi_trust iface'
trust_own_pkg = mi_trust_pkg iface'
-- check module is trusted
safeM = trust `elem` [Sf_Safe, Sf_Trustworthy]
safeM = trust `elem` [Sf_Safe, Sf_SafeInferred, Sf_Trustworthy]
-- check package is trusted
safeP = packageTrusted dflags trust trust_own_pkg m
-- pkg trust reqs
pkgRs = S.fromList . map fst $ filter snd $ dep_pkgs $ mi_deps iface'
-- warn if Safe module imports Safe-Inferred module.
warns = if wopt Opt_WarnInferredSafeImports dflags
&& safeLanguageOn dflags
&& trust == Sf_SafeInferred
then inferredImportWarn
else emptyBag
-- General errors we throw but Safe errors we log
errs = case (safeM, safeP) of
(True, True ) -> emptyBag
(True, False) -> pkgTrustErr
(False, _ ) -> modTrustErr
in do
logWarnings warns
logWarnings errs
return (trust == Sf_Trustworthy, pkgRs)
where
inferredImportWarn = unitBag
$ makeIntoWarning (Reason Opt_WarnInferredSafeImports)
$ mkErrMsg dflags l (pkgQual dflags)
$ sep
[ text "Importing Safe-Inferred module "
<> ppr (moduleName m)
<> text " from explicitly Safe module"
]
pkgTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $
sep [ ppr (moduleName m)
<> text ": Can't be safely imported!"
......@@ -1146,6 +1161,7 @@ hscCheckSafe' m l = do
packageTrusted dflags _ _ _
| not (packageTrustOn dflags) = True
packageTrusted _ Sf_Safe False _ = True
packageTrusted _ Sf_SafeInferred False _ = True
packageTrusted dflags _ _ m
| isHomePkg dflags m = True
| otherwise = trusted $ getPackageDetails dflags (moduleUnitId m)
......
......@@ -2948,6 +2948,7 @@ trustInfoToNum it
Sf_Unsafe -> 1
Sf_Trustworthy -> 2
Sf_Safe -> 3
Sf_SafeInferred -> 4
Sf_Ignore -> 0
numToTrustInfo :: Word8 -> IfaceTrustInfo
......@@ -2955,9 +2956,7 @@ numToTrustInfo 0 = setSafeMode Sf_None
numToTrustInfo 1 = setSafeMode Sf_Unsafe
numToTrustInfo 2 = setSafeMode Sf_Trustworthy
numToTrustInfo 3 = setSafeMode Sf_Safe
numToTrustInfo 4 = setSafeMode Sf_Safe -- retained for backwards compat, used
-- to be Sf_SafeInfered but we no longer
-- differentiate.
numToTrustInfo 4 = setSafeMode Sf_SafeInferred
numToTrustInfo n = error $ "numToTrustInfo: bad input number! (" ++ show n ++ ")"
instance Outputable IfaceTrustInfo where
......@@ -2966,6 +2965,7 @@ instance Outputable IfaceTrustInfo where
ppr (TrustInfo Sf_Unsafe) = text "unsafe"
ppr (TrustInfo Sf_Trustworthy) = text "trustworthy"
ppr (TrustInfo Sf_Safe) = text "safe"
ppr (TrustInfo Sf_SafeInferred) = text "safe-inferred"
instance Binary IfaceTrustInfo where
put_ bh iftrust = putByte bh $ trustInfoToNum iftrust
......
......@@ -1835,13 +1835,13 @@ finalSafeMode :: DynFlags -> TcGblEnv -> IO SafeHaskellMode
finalSafeMode dflags tcg_env = do
safeInf <- fst <$> readIORef (tcg_safeInfer tcg_env)
return $ case safeHaskell dflags of
Sf_None | safeInferOn dflags && safeInf -> Sf_Safe
Sf_None | safeInferOn dflags && safeInf -> Sf_SafeInferred
| otherwise -> Sf_None
s -> s
-- | Switch instances to safe instances if we're in Safe mode.
fixSafeInstances :: SafeHaskellMode -> [ClsInst] -> [ClsInst]
fixSafeInstances sfMode | sfMode /= Sf_Safe = id
fixSafeInstances sfMode | sfMode /= Sf_Safe && sfMode /= Sf_SafeInferred = id
fixSafeInstances _ = map fixSafe
where fixSafe inst = let new_flag = (is_flag inst) { isSafeOverlap = True }
in inst { is_flag = new_flag }
......
......@@ -740,7 +740,7 @@ And one general flag:
requiring the package that ``M`` resides in be considered trusted, for ``M``
to be considered trusted.
And three warning flags:
And four warning flags:
.. ghc-flag:: -Wunsafe
:shortdesc: warn if the module being compiled is regarded to be unsafe.
......@@ -777,6 +777,39 @@ And three warning flags:
-XSafe , a more informative bound. Can be used to detect once a Safe Haskell
bound can be improved as dependencies are updated.
.. ghc-flag:: -Winferred-safe-imports
:shortdesc: warn when an explicitly Safe Haskell module imports a Safe-Inferred one
:type: dynamic
:reverse: -Wno-inferred-safe-imports
:category:
:since: 8.10.1
.. index::
single: safe haskell imports, warning
The module ``A`` below is annotated to be explictly ``Safe``, but it imports
``Safe-Inferred`` module.
{-# LANGUAGE Safe #-}
module A where
import B (double)
quad :: Int -> Int
quad = double . double
module B where
double :: Int -> Int
double n = n + n
The inferred status is volatile: if an unsafe import is added to the module
``B``, it will cause compilation error of ``A``. When
:ghc-flag:`-Winferred-safe-imports` is enabled, the compiler will emit a
warning about this.
.. _safe-compilation:
Safe Compilation
......
......@@ -4,42 +4,42 @@ pdb.safePkg01/local.db
trusted: False
M_SafePkg
package dependencies: base-4.12.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: base-4.13.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe
require own pkg trusted: False
M_SafePkg2
package dependencies: base-4.12.0.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: base-4.13.0.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: trustworthy
require own pkg trusted: False
M_SafePkg3
package dependencies: base-4.12.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: base-4.13.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe
require own pkg trusted: True
M_SafePkg4
package dependencies: base-4.12.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: base-4.13.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe
require own pkg trusted: True
M_SafePkg5
package dependencies: base-4.12.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe
package dependencies: base-4.13.0.0* ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe-inferred
require own pkg trusted: True
M_SafePkg6
package dependencies: array-0.5.2.0 base-4.12.0.0* bytestring-0.10.8.2* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: array-0.5.4.0 base-4.13.0.0* bytestring-0.10.9.0* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: trustworthy
require own pkg trusted: False
M_SafePkg7
package dependencies: array-0.5.2.0 base-4.12.0.0* bytestring-0.10.8.2* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: array-0.5.4.0 base-4.13.0.0* bytestring-0.10.9.0* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: safe
require own pkg trusted: False
M_SafePkg8
package dependencies: array-0.5.2.0 base-4.12.0.0 bytestring-0.10.8.2* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
package dependencies: array-0.5.4.0 base-4.13.0.0 bytestring-0.10.9.0* deepseq-1.4.4.0 ghc-prim-0.6.1 integer-gmp-1.0.2.0
trusted: trustworthy
require own pkg trusted: False
......
Subproject commit 83bb9870a117f9426e6f6cff6fec3bb6e93a7c18
Subproject commit 5e333bad752b9c048ad5400b7159e32f4d3d65bd
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment