diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# 1.2.5.3 August 2022
+
+* Tested with GHC 7.0 - 9.4.1.
+* Remove remnants of GHC 6.x support.
+* Silence incomplete pattern matching warning, refactor code.
+* Add section about limitations to README.
+
 # 1.2.5.2 November 2021
 
 * Tested with GHC 7.0 - 9.2.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -28,3 +28,12 @@
  captured: wookies!
  returned: 123
 ```
+
+## Limitations
+
+Capturing/silencing might not work as expected if the action uses the FFI
+or conceals output under `unsafePerformIO` or similar unsafe operations.
+
+Examples:
+- FFI: https://github.com/hspec/silently/issues/3
+- `unsafePerformIO`: https://github.com/bos/filemanip/issues/22
diff --git a/silently.cabal b/silently.cabal
--- a/silently.cabal
+++ b/silently.cabal
@@ -1,6 +1,6 @@
-name: silently
-version: 1.2.5.2
 cabal-version: >= 1.10
+name: silently
+version: 1.2.5.3
 build-type: Simple
 license: BSD3
 license-file: LICENSE
@@ -13,21 +13,23 @@
 description: Prevent or capture writing to stdout, stderr, and other handles.
 category: System, Testing
 author: Trystan Spangler
+
 tested-with:
-  GHC == 7.0.4
-  GHC == 7.2.2
-  GHC == 7.4.2
-  GHC == 7.6.3
-  GHC == 7.8.4
-  GHC == 7.10.3
-  GHC == 8.0.2
-  GHC == 8.2.2
-  GHC == 8.4.4
-  GHC == 8.6.5
-  GHC == 8.8.4
+  GHC == 9.4.1
+  GHC == 9.2.4
+  GHC == 9.0.2
   GHC == 8.10.7
-  GHC == 9.0.1
-  GHC == 9.2.1
+  GHC == 8.8.4
+  GHC == 8.6.5
+  GHC == 8.4.4
+  GHC == 8.2.2
+  GHC == 8.0.2
+  GHC == 7.10.3
+  GHC == 7.8.4
+  GHC == 7.6.3
+  GHC == 7.4.2
+  GHC == 7.2.2
+  GHC == 7.0.4
 
 extra-source-files:
   CHANGELOG.md
@@ -46,7 +48,7 @@
       System.IO.Silently
 
   build-depends:
-      base >=4 && <=5
+      base >= 4.3 && < 5
     , directory
     , deepseq
 
@@ -54,6 +56,12 @@
     cpp-options: -DWINDOWS
   if os(linux) || os(osx) || os(freebsd) || os(openbsd) || os(netbsd)
     cpp-options: -DUNIX
+
+  ghc-options:
+    -Wall
+  if impl(ghc >= 8)
+    ghc-options:
+      -Wcompat
 
 -- This tests the platform specific implementation.
 --
diff --git a/src/System/IO/Silently.hs b/src/System/IO/Silently.hs
--- a/src/System/IO/Silently.hs
+++ b/src/System/IO/Silently.hs
@@ -1,29 +1,32 @@
 {-# LANGUAGE CPP #-}
--- | Need to prevent output to the terminal, a file, or stderr? Need to capture it and use it for
--- your own means? Now you can, with 'silence' and 'capture'.
+{-# LANGUAGE ScopedTypeVariables #-}
 
-module System.IO.Silently (
-  silence,
-  hSilence,
-  capture,
-  capture_,
-  hCapture,
-  hCapture_,
-) where
+-- | Need to prevent output to the terminal, a file, or stderr?
+--   Need to capture it and use it for your own means?
+--   Now you can, with 'silence' and 'capture'.
 
-import Prelude
+module System.IO.Silently
+  ( silence, hSilence
+  , capture, capture_, hCapture, hCapture_
+  ) where
 
-#if __GLASGOW_HASKELL__ >= 612
-import GHC.IO.Handle (hDuplicate, hDuplicateTo)
-#else
-import GHC.Handle (hDuplicate, hDuplicateTo)
-#endif
+import Prelude
 
-import System.IO
 import qualified Control.Exception as E
 import Control.DeepSeq
-import System.Directory (removeFile,getTemporaryDirectory)
+  ( deepseq )
 
+import GHC.IO.Handle
+  ( hDuplicate, hDuplicateTo )
+
+import System.Directory
+  ( getTemporaryDirectory, removeFile )
+import System.IO
+  ( Handle, IOMode(AppendMode), SeekMode(AbsoluteSeek)
+  , hClose, hFlush, hGetBuffering, hGetContents, hSeek, hSetBuffering
+  , openFile, openTempFile, stdout
+  )
+
 mNullDevice :: Maybe FilePath
 #ifdef WINDOWS
 mNullDevice = Just "\\\\.\\NUL"
@@ -38,27 +41,34 @@
 silence = hSilence [stdout]
 
 -- | Run an IO action while preventing all output to the given handles.
-hSilence :: [Handle] -> IO a -> IO a
-hSilence handles action = case mNullDevice of
-  Just nullDevice -> E.bracket (openFile nullDevice AppendMode)
-                             hClose
-                             prepareAndRun
+hSilence :: forall a. [Handle] -> IO a -> IO a
+hSilence handles action =
+  case mNullDevice of
+    Just nullDevice ->
+      E.bracket (openFile nullDevice AppendMode)
+                hClose
+                prepareAndRun
+    Nothing -> withTempFile "silence" prepareAndRun
+  where
+    prepareAndRun :: Handle -> IO a
+    prepareAndRun tmpHandle = go handles
+      where
+        go []     = action
+        go (h:hs) = goBracket go tmpHandle h hs
 
-  Nothing -> do
-    tmpDir <- getTempOrCurrentDirectory
-    E.bracket (openTempFile tmpDir "silence")
-                               cleanup
-                               (prepareAndRun . snd)
 
- where
-  cleanup (tmpFile,tmpHandle) = do
-    hClose tmpHandle
-    removeFile tmpFile
-  prepareAndRun tmpHandle = go handles
-    where
-      go [] = action
-      go hs = goBracket go tmpHandle hs
-
+-- Provide a tempfile for the given action and remove it afterwards.
+withTempFile :: String -> (Handle -> IO a) -> IO a
+withTempFile tmpName action = do
+  tmpDir <- getTempOrCurrentDirectory
+  E.bracket (openTempFile tmpDir tmpName)
+            cleanup
+            (action . snd)
+  where
+    cleanup :: (FilePath, Handle) -> IO ()
+    cleanup (tmpFile, tmpHandle) = do
+      hClose tmpHandle
+      removeFile tmpFile
 
 getTempOrCurrentDirectory :: IO String
 getTempOrCurrentDirectory = getTemporaryDirectory `catchIOError` (\_ -> return ".")
@@ -69,7 +79,8 @@
     catchIOError = E.catch
 
 -- | Run an IO action while preventing and capturing all output to stdout.
--- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory.
+-- This will, as a side effect, create and delete a temp file in the temp directory
+-- or current directory if there is no temp directory.
 capture :: IO a -> IO (String, a)
 capture = hCapture [stdout]
 
@@ -82,29 +93,24 @@
 hCapture_ handles = fmap fst . hCapture handles
 
 -- | Run an IO action while preventing and capturing all output to the given handles.
--- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory.
-hCapture :: [Handle] -> IO a -> IO (String, a)
-hCapture handles action = do
-  tmpDir <- getTempOrCurrentDirectory
-  E.bracket (openTempFile tmpDir "capture")
-                             cleanup
-                             (prepareAndRun . snd)
- where
-  cleanup (tmpFile,tmpHandle) = do
-    hClose tmpHandle
-    removeFile tmpFile
-  prepareAndRun tmpHandle = go handles
-    where
-      go [] = do
-              a <- action
-              mapM_ hFlush handles
-              hSeek tmpHandle AbsoluteSeek 0
-              str <- hGetContents tmpHandle
-              str `deepseq` return (str,a)
-      go hs = goBracket go tmpHandle hs
+-- This will, as a side effect, create and delete a temp file in the temp directory
+-- or current directory if there is no temp directory.
+hCapture :: forall a. [Handle] -> IO a -> IO (String, a)
+hCapture handles action = withTempFile "capture" prepareAndRun
+  where
+    prepareAndRun :: Handle -> IO (String, a)
+    prepareAndRun tmpHandle = go handles
+      where
+        go [] = do
+          a <- action
+          mapM_ hFlush handles
+          hSeek tmpHandle AbsoluteSeek 0
+          str <- hGetContents tmpHandle
+          str `deepseq` return (str, a)
+        go (h:hs) = goBracket go tmpHandle h hs
 
-goBracket :: ([Handle] -> IO a) -> Handle -> [Handle] -> IO a
-goBracket go tmpHandle (h:hs) = do
+goBracket :: ([Handle] -> IO a) -> Handle -> Handle -> [Handle] -> IO a
+goBracket go tmpHandle h hs = do
   buffering <- hGetBuffering h
   let redirect = do
         old <- hDuplicate h
