Add -fno-safe-haskell flag
authorMatthew Pickering <matthewtpickering@gmail.com>
Sat, 8 Dec 2018 04:25:20 +0000 (23:25 -0500)
committerBen Gamari <ben@smart-cactus.org>
Sat, 8 Dec 2018 04:25:30 +0000 (23:25 -0500)
This flag can be set to turn off the Safe Haskell checks.

Whether a module is marked Safe/Unsafe/Trustworthy is ignored when
this flag to set.

Reviewers: bgamari, tdammers

Reviewed By: tdammers

Subscribers: rwbarton, carter

GHC Trac Issues: #15920

Differential Revision: https://phabricator.haskell.org/D5360

compiler/main/DynFlags.hs
compiler/main/HscMain.hs
compiler/main/HscTypes.hs
docs/users_guide/safe_haskell.rst
testsuite/tests/safeHaskell/flags/SafeIgnore.hs [new file with mode: 0644]
testsuite/tests/safeHaskell/flags/SafeIgnoreA.hs [new file with mode: 0644]
testsuite/tests/safeHaskell/flags/all.T

index b574ba9..3fb3874 100644 (file)
@@ -74,7 +74,8 @@ module DynFlags (
 
         -- ** Safe Haskell
         SafeHaskellMode(..),
-        safeHaskellOn, safeImportsOn, safeLanguageOn, safeInferOn,
+        safeHaskellOn, safeHaskellModeEnabled,
+        safeImportsOn, safeLanguageOn, safeInferOn,
         packageTrustOn,
         safeDirectImpsReq, safeImplicitImpsReq,
         unsafeFlags, unsafeFlagsForInfer,
@@ -844,6 +845,7 @@ data SafeHaskellMode
    | Sf_Unsafe
    | Sf_Trustworthy
    | Sf_Safe
+   | Sf_Ignore
    deriving (Eq)
 
 instance Show SafeHaskellMode where
@@ -851,6 +853,7 @@ instance Show SafeHaskellMode where
     show Sf_Unsafe       = "Unsafe"
     show Sf_Trustworthy  = "Trustworthy"
     show Sf_Safe         = "Safe"
+    show Sf_Ignore       = "Ignore"
 
 instance Outputable SafeHaskellMode where
     ppr = text . show
@@ -2391,7 +2394,12 @@ packageTrustOn = gopt Opt_PackageTrust
 
 -- | Is Safe Haskell on in some way (including inference mode)
 safeHaskellOn :: DynFlags -> Bool
-safeHaskellOn dflags = safeHaskell dflags /= Sf_None || safeInferOn dflags
+safeHaskellOn dflags = safeHaskellModeEnabled dflags || safeInferOn dflags
+
+safeHaskellModeEnabled :: DynFlags -> Bool
+safeHaskellModeEnabled dflags = safeHaskell dflags `elem` [Sf_Unsafe, Sf_Trustworthy
+                                                   , Sf_Safe ]
+
 
 -- | Is the Safe Haskell safe language in use
 safeLanguageOn :: DynFlags -> Bool
@@ -2440,6 +2448,7 @@ safeImplicitImpsReq d = safeLanguageOn d
 combineSafeFlags :: SafeHaskellMode -> SafeHaskellMode -> DynP SafeHaskellMode
 combineSafeFlags a b | a == Sf_None         = return b
                      | b == Sf_None         = return a
+                     | a == Sf_Ignore || b == Sf_Ignore = return Sf_Ignore
                      | a == b               = return a
                      | otherwise            = addErr errm >> pure a
     where errm = "Incompatible Safe Haskell flags! ("
@@ -2776,7 +2785,7 @@ safeFlagCheck cmdl dflags =
     -- dynflags and warn for when -fpackage-trust by itself with no safe
     -- haskell flag
     (dflags', warn)
-      | safeHaskell dflags == Sf_None && not cmdl && packageTrustOn dflags
+      | not (safeHaskellModeEnabled dflags) && not cmdl && packageTrustOn dflags
       = (gopt_unset dflags Opt_PackageTrust, pkgWarnMsg)
       | otherwise = (dflags, [])
 
@@ -3643,6 +3652,7 @@ dynamic_flags_deps = [
   , make_ord_flag defFlag "fpackage-trust"   (NoArg setPackageTrust)
   , make_ord_flag defFlag "fno-safe-infer"   (noArg (\d ->
                                                     d { safeInfer = False }))
+  , make_ord_flag defFlag "fno-safe-haskell" (NoArg (setSafeHaskell Sf_Ignore))
   , 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))
index 5102fa0..9b9edf7 100644 (file)
@@ -1002,7 +1002,7 @@ checkSafeImports tcg_env
     pkgTrustReqs :: DynFlags -> Set InstalledUnitId -> Set InstalledUnitId ->
           Bool -> ImportAvails
     pkgTrustReqs dflags req inf infPassed | safeInferOn dflags
-                                  && safeHaskell dflags == Sf_None && infPassed
+                                  && not (safeHaskellModeEnabled dflags) && infPassed
                                    = emptyImportAvails {
                                        imp_trust_pkgs = req `S.union` inf
                                    }
@@ -1095,6 +1095,7 @@ hscCheckSafe' m l = do
     -- otherwise we check the package trust flag.
     packageTrusted :: DynFlags -> SafeHaskellMode -> Bool -> Module -> Bool
     packageTrusted _ Sf_None      _ _ = False -- shouldn't hit these cases
+    packageTrusted _ Sf_Ignore    _ _ = False -- shouldn't hit these cases
     packageTrusted _ Sf_Unsafe    _ _ = False -- prefer for completeness.
     packageTrusted dflags _ _ _
         | not (packageTrustOn dflags) = True
@@ -1163,7 +1164,7 @@ markUnsafeInfer tcg_env whyUnsafe = do
     -- NOTE: Only wipe trust when not in an explicitly safe haskell mode. Other
     -- times inference may be on but we are in Trustworthy mode -- so we want
     -- to record safe-inference failed but not wipe the trust dependencies.
-    case safeHaskell dflags == Sf_None of
+    case not (safeHaskellModeEnabled dflags) of
       True  -> return $ tcg_env { tcg_imports = wiped_trust }
       False -> return tcg_env
 
index d57d69b..d0cf7e0 100644 (file)
@@ -2920,6 +2920,7 @@ trustInfoToNum it
             Sf_Unsafe       -> 1
             Sf_Trustworthy  -> 2
             Sf_Safe         -> 3
+            Sf_Ignore       -> 0
 
 numToTrustInfo :: Word8 -> IfaceTrustInfo
 numToTrustInfo 0 = setSafeMode Sf_None
@@ -2933,6 +2934,7 @@ numToTrustInfo n = error $ "numToTrustInfo: bad input number! (" ++ show n ++ ")
 
 instance Outputable IfaceTrustInfo where
     ppr (TrustInfo Sf_None)          = text "none"
+    ppr (TrustInfo Sf_Ignore)        = text "none"
     ppr (TrustInfo Sf_Unsafe)        = text "unsafe"
     ppr (TrustInfo Sf_Trustworthy)   = text "trustworthy"
     ppr (TrustInfo Sf_Safe)          = text "safe"
index adf70d2..6772d6a 100644 (file)
@@ -206,6 +206,11 @@ run the plugin, it calls ``RIO.runRIO Danger.runMe`` within the ``IO``
 monad. The application is safe in the knowledge that the only ``IO`` to
 ensue will be to files whose paths were approved by the ``pathOK`` test.
 
+The Safe Haskell checks can be disabled for a module by passing the
+:ghc-flag:`-fno-safe-haskell` flag. This is useful in particular when compiling
+with source plugins as running a plugin marks the module as unsafe and can then
+cause downstream modules to fail the safety checks.
+
 .. _safe-language:
 
 Safe Language
@@ -710,6 +715,18 @@ In summary, Safe Haskell consists of the following three language flags:
     - *Imported Modules* — Under control of module author which ones must be
       trusted.
 
+A flag to disable Safe Haskell checks:
+
+.. ghc-flag:: -fno-safe-haskell
+    :shortdesc: Disable :ref:`Safe Haskell <safe-haskell>`
+    :type: dynamic
+
+    This flag can be enabled to override any declared safety property of the
+    module (Safe, Unsafe, Trustworthy) so compilation proceeds as if none of
+    these flags were specified. This is particularly useful when compiling
+    using plugins, which usually results in the compiled modules being marked
+    as unsafe.
+
 And one general flag:
 
 .. ghc-flag:: -fpackage-trust
diff --git a/testsuite/tests/safeHaskell/flags/SafeIgnore.hs b/testsuite/tests/safeHaskell/flags/SafeIgnore.hs
new file mode 100644 (file)
index 0000000..8c2ee88
--- /dev/null
@@ -0,0 +1,6 @@
+{-# LANGUAGE Safe #-}
+module SafeIgnore where
+
+import SafeIgnoreA
+
+foo = ()
diff --git a/testsuite/tests/safeHaskell/flags/SafeIgnoreA.hs b/testsuite/tests/safeHaskell/flags/SafeIgnoreA.hs
new file mode 100644 (file)
index 0000000..52ed719
--- /dev/null
@@ -0,0 +1,4 @@
+{-# LANGUAGE Unsafe #-}
+module SafeIgnoreA where
+
+qux = ()
index 0fa30e5..8b1ea97 100644 (file)
@@ -63,3 +63,5 @@ test('Flags01', normal, compile, ['-XSafe'])
 test('Flags02', normal, compile, ['-XSafe'])
 
 test('SafeFlags30', normal, compile_fail, [''])
+
+test('SafeIgnore', [], multimod_compile, ['SafeIgnore', '-v0 -fno-safe-haskell'])