diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
 # fast-tags - fast and robust tag generator for Haskell #
 
-[![Build Status][badge-travis]](https://travis-ci.org/elaforge/fast-tags)
+[![Build Status](https://github.com/elaforge/fast-tags/workflows/ci/badge.svg)](https://github.com/elaforge/fast-tags/actions?query=workflow%3Aci)
 
 # Supported GHC versions #
 
-Tested with GHC `7.8.4`, `7.10.3`, `8.0.2`, `8.2.2`, `8.4.1`.
+Tested with GHC `7.10`, `8.0`, `8.2`, `8.4`, `8.4`, `8.6`, `8.8`, `8.10`, `9.0`.
 
 # Installation #
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+2.0.2
+
+* fixes for ghc 9.0 and 9.2, thanks to @sergv and @ozkutuk
+
 2.0.1
 
 * Add support to qualified_tags.py for tag preview.
diff --git a/fast-tags.cabal b/fast-tags.cabal
--- a/fast-tags.cabal
+++ b/fast-tags.cabal
@@ -1,5 +1,5 @@
 name: fast-tags
-version: 2.0.1
+version: 2.0.2
 cabal-version: >= 1.10
 build-type: Simple
 synopsis: Fast incremental vi and emacs tags.
@@ -36,7 +36,14 @@
 maintainer: Evan Laforge <qdunkan@gmail.com>
 stability: stable
 tested-with:
-    GHC ==7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
+    GHC == 7.10,
+    GHC == 8.0,
+    GHC == 8.2,
+    GHC == 8.4,
+    GHC == 8.6,
+    GHC == 8.8,
+    GHC == 8.10,
+    GHC == 9.0
 extra-source-files:
     README.md
     changelog.md
diff --git a/src/FastTags/Lexer.x b/src/FastTags/Lexer.x
--- a/src/FastTags/Lexer.x
+++ b/src/FastTags/Lexer.x
@@ -357,7 +357,7 @@
 scanTokens = go
     where
     go = do
-        nextTok <- continueScanning
+        !nextTok <- continueScanning
         case nextTok of
             EOF       -> pure Nothing
             Error err -> pure $ Just err
diff --git a/src/FastTags/LexerM.hs b/src/FastTags/LexerM.hs
--- a/src/FastTags/LexerM.hs
+++ b/src/FastTags/LexerM.hs
@@ -78,6 +78,7 @@
 
 import Control.Applicative as A
 import Control.DeepSeq
+import Control.Exception
 import Control.Monad.ST
 import Control.Monad.State.Strict
 import Control.Monad.Writer.Strict
@@ -105,6 +106,19 @@
 import FastTags.LexerTypes
 import FastTags.Token
 
+#if __GLASGOW_HASKELL__ >= 902
+import GHC.Exts (word8ToWord#, wordToWord8#)
+#else
+{-# INLINE word8ToWord# #-}
+word8ToWord# :: Word# -> Word#
+word8ToWord# x = x
+
+{-# INLINE wordToWord8# #-}
+wordToWord8# :: Word# -> Word#
+wordToWord8# x = x
+#endif
+
+
 data AlexState = AlexState
     { asInput        :: {-# UNPACK #-} !AlexInput
     , asIntStore     :: {-# UNPACK #-} !Word64
@@ -273,19 +287,28 @@
   -> AlexM a
   -> (a, [Token])
 runAlexM filepath trackPrefixesAndOffsets litLoc startCode input action =
-    withAlexInput input $ \input' inputSize ->
+    performIO $
+    withAlexInput input $ \input' inputSize -> do
         let (a, xs) = evalState (runWriterT action)
                     $ mkAlexState litLoc startCode input'
-        in if trackPrefixesAndOffsets
-        then
+        if trackPrefixesAndOffsets
+        then do
             let !ptr  = aiPtr input' `plusPtr` 1 -- Drop first newline
                 !size = inputSize - 1
                 !idx  = positionsIndex ptr size
                 res   =
                     map (\(x, y) -> Pos (mkSrcPos filepath idx ptr x) y) xs
-            in res `deepseq` (a, res)
-        else
-            (a, map (\(x, y) -> Pos (mkSrcPosNoPrefix filepath x) y) xs)
+            pure $! res `deepseq` (a, res)
+        else do
+            -- Contents of 'xs' has been seq'ed so TokenVals in there should
+            -- have been forced and thus should not contain any references to the
+            -- original input bytestring. However, in GHC 9.0 it seems that
+            -- GHC does some transformation which results in some entries within 'xs'
+            -- being not fully evaluated and thus lead to an error since they get
+            -- forced outside of 'withForeignPtr' bounds. The call to 'evaluate' below
+            -- is intended to prevent such transformation from occuring.
+            _ <- evaluate xs
+            pure (a, map (\(x, y) -> Pos (mkSrcPosNoPrefix filepath x) y) xs)
 
 mkSrcPosNoPrefix :: FilePath -> AlexInput -> SrcPos
 mkSrcPosNoPrefix filename input =
@@ -370,7 +393,7 @@
 {-# INLINE takeText #-}
 takeText :: AlexInput -> Int -> T.Text
 takeText AlexInput{aiPtr} len =
-    TE.decodeUtf8 $ utf8BS len aiPtr
+    TE.decodeUtf8 $! utf8BS len aiPtr
 
 countInputSpace :: AlexInput -> Int -> Int
 countInputSpace AlexInput{aiPtr} len =
@@ -382,22 +405,23 @@
         1## -> acc + 1
         _   -> acc
 
+{-# INLINE performIO #-}
+performIO :: IO a -> a
+performIO = BSI.accursedUnutterablePerformIO
 
 {-# INLINE withAlexInput #-}
-withAlexInput :: C8.ByteString -> (AlexInput -> Int -> a) -> a
+withAlexInput :: C8.ByteString -> (AlexInput -> Int -> IO a) -> IO a
 withAlexInput s f =
     case s' of
         BSI.PS ptr offset len ->
-            BSI.accursedUnutterablePerformIO $ withForeignPtr ptr $ \ptr' -> do
+            withForeignPtr ptr $ \ptr' -> do
                 let !input =
                         set aiLineL initLine $
                         AlexInput
                             { aiPtr      = ptr' `plusPtr` offset
                             , aiIntStore = 0
                             }
-                    !res = f input $ len - offset
-                touchForeignPtr ptr
-                pure res
+                f input $! len - offset
     where
     -- Line numbering starts from 0 because we're adding additional newline
     -- at the beginning to simplify processing. Thus, line numbers in the
@@ -424,7 +448,7 @@
     start#      = (goBack# (end# `plusAddr#` -1#)) `plusAddr#` 1#
 
     goBack# :: Addr# -> Addr#
-    goBack# ptr# = case indexWord8OffAddr# ptr# 0# of
+    goBack# ptr# = case word8ToWord# (indexWord8OffAddr# ptr# 0#) of
         0##  -> ptr#
         9##  -> ptr# -- '\n'
         10## -> ptr# -- '\n'
@@ -470,7 +494,7 @@
         _  -> '\0' -- Invalid!
     where
     ch0 :: Int#
-    !ch0 = word2Int# (indexWord8OffAddr# start# 0#)
+    !ch0 = word2Int# (word8ToWord# (indexWord8OffAddr# start# 0#))
 
     base# = findCharStart ptr# `plusAddr#` -1#
 
@@ -483,7 +507,7 @@
         | otherwise
         = p#
         where
-        w# = word2Int# (indexWord8OffAddr# p# 0#)
+        w# = word2Int# (word8ToWord# (indexWord8OffAddr# p# 0#))
 
 {-# INLINE alexGetByte #-}
 alexGetByte :: AlexInput -> Maybe (Word8, AlexInput)
@@ -501,7 +525,7 @@
                         input { aiPtr = cs }
                 c    -> Just (b, input')
                     where
-                    !b     = W8# c
+                    !b     = W8# (wordToWord8# c)
                     !input' =
                         over aiLineLengthL (+ I# n) $
                         input { aiPtr = cs }
@@ -602,7 +626,7 @@
 dropUntilNL# (Ptr start#) = Ptr (go start#)
     where
     go :: Addr# -> Addr#
-    go ptr# = case indexWord8OffAddr# ptr# 0# of
+    go ptr# = case word8ToWord# (indexWord8OffAddr# ptr# 0#) of
         0##  -> ptr#
         10## -> ptr# -- '\n'
         _    -> go (ptr# `plusAddr#` 1#)
@@ -612,13 +636,13 @@
 dropUntilUnescapedNL# (Ptr start#) = go 0 start#
     where
     go :: Int -> Addr# -> (# Int, Ptr Word8 #)
-    go !n ptr# = case indexWord8OffAddr# ptr# 0# of
+    go !n ptr# = case word8ToWord# (indexWord8OffAddr# ptr# 0#) of
         0##  -> (# n, Ptr ptr# #)
         -- '\n'
         10## -> (# n, Ptr ptr# #)
         -- '\\'
         92## ->
-            case indexWord8OffAddr# ptr# 1# of
+            case word8ToWord# (indexWord8OffAddr# ptr# 1#) of
                 0##  -> (# n, Ptr (ptr# `plusAddr#` 1#) #)
                 -- '\n'
                 10## -> go (n + 1) (ptr# `plusAddr#` 2#)
@@ -630,11 +654,11 @@
 dropUntilNLOr# (W8# w#) (Ptr start#) = Ptr (go start#)
     where
     go :: Addr# -> Addr#
-    go ptr# = case indexWord8OffAddr# ptr# 0# of
+    go ptr# = case word8ToWord# (indexWord8OffAddr# ptr# 0#) of
         0##  -> ptr#
         -- '\n'
         10## -> ptr#
-        c# | isTrue# (c# `eqWord#` w#) -> ptr#
+        c# | isTrue# (c# `eqWord#` word8ToWord# w#) -> ptr#
            | otherwise                 -> go (ptr# `plusAddr#` 1#)
 
 {-# INLINE dropUntilNLOrEither# #-}
@@ -642,11 +666,11 @@
 dropUntilNLOrEither# (W8# w1#) (W8# w2#) (Ptr start#) = Ptr (go start#)
     where
     go :: Addr# -> Addr#
-    go ptr# = case indexWord8OffAddr# ptr# 0# of
+    go ptr# = case word8ToWord# (indexWord8OffAddr# ptr# 0#) of
         0##  -> ptr#
         -- '\n'
         10## -> ptr#
-        c# | isTrue# ((c# `eqWord#` w1#) `orI#` (c# `eqWord#` w2#))
+        c# | isTrue# ((c# `eqWord#` word8ToWord# w1#) `orI#` (c# `eqWord#` word8ToWord# w2#))
            -> ptr#
            | otherwise
            -> go (ptr# `plusAddr#` 1#)
@@ -678,7 +702,7 @@
 {-# INLINE utf8BS #-}
 utf8BS :: Int -> Ptr Word8 -> BS.ByteString
 utf8BS (I# nChars#) (Ptr start#) =
-    BSI.PS (BSI.accursedUnutterablePerformIO (newForeignPtr_ (Ptr start#))) 0 (I# (go nChars# 0#))
+    BSI.PS (performIO (newForeignPtr_ (Ptr start#))) 0 (I# (go nChars# 0#))
     where
     go :: Int# -> Int# -> Int#
     go 0# bytes# = bytes#
@@ -690,17 +714,17 @@
 {-# INLINE bytesToUtf8BS #-}
 bytesToUtf8BS :: Int -> Ptr Word8 -> BS.ByteString
 bytesToUtf8BS (I# nbytes#) (Ptr start#) =
-    BSI.PS (BSI.accursedUnutterablePerformIO (newForeignPtr_ (Ptr start#))) 0 (I# nbytes#)
+    BSI.PS (performIO (newForeignPtr_ (Ptr start#))) 0 (I# nbytes#)
 
 {-# INLINE regionToUtf8BS #-}
 regionToUtf8BS :: Ptr Word8 -> Ptr Word8 -> BS.ByteString
 regionToUtf8BS start end =
-    BSI.PS (BSI.accursedUnutterablePerformIO (newForeignPtr_ start)) 0 (minusPtr end start)
+    BSI.PS (performIO (newForeignPtr_ start)) 0 (minusPtr end start)
 
 {-# INLINE utf8DecodeChar# #-}
 utf8DecodeChar# :: Addr# -> (# Char#, Int# #)
 utf8DecodeChar# a# =
-    case indexWord8OffAddr# a# 0# of
+    case word8ToWord# (indexWord8OffAddr# a# 0#) of
         0## -> (# '\0'#, 0# #)
         !x# ->
             let !ch0 = word2Int# x# in
@@ -723,7 +747,7 @@
 {-# INLINE readChar1# #-}
 readChar1# :: Addr# -> Int# -> (# Char#, Int# #)
 readChar1# a# ch0 =
-    let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in
+    let !ch1 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 1#)) in
     if noValidUtf8Cont# ch1 then invalid# 1# else
     (# chr# (((ch0 `andI#` 0x3F#) `uncheckedIShiftL#` 6#) `orI#`
               (ch1 `andI#` 0x7F#)),
@@ -732,9 +756,9 @@
 {-# INLINE readChar2# #-}
 readChar2# :: Addr# -> Int# -> (# Char#, Int# #)
 readChar2# a# ch0 =
-    let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in
+    let !ch1 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 1#)) in
     if noValidUtf8Cont# ch1 then invalid# 1# else
-    let !ch2 = word2Int# (indexWord8OffAddr# a# 2#) in
+    let !ch2 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 2#)) in
     if noValidUtf8Cont# ch2 then invalid# 2# else
     (# chr# (((ch0 `andI#` 0x1F#) `uncheckedIShiftL#` 12#) `orI#`
              ((ch1 `andI#` 0x7F#) `uncheckedIShiftL#` 6#)  `orI#`
@@ -744,11 +768,11 @@
 {-# INLINE readChar3# #-}
 readChar3# :: Addr# -> Int# -> (# Char#, Int# #)
 readChar3# a# ch0 =
-    let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in
+    let !ch1 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 1#)) in
     if noValidUtf8Cont# ch1 then invalid# 1# else
-    let !ch2 = word2Int# (indexWord8OffAddr# a# 2#) in
+    let !ch2 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 2#)) in
     if noValidUtf8Cont# ch2 then invalid# 2# else
-    let !ch3 = word2Int# (indexWord8OffAddr# a# 3#) in
+    let !ch3 = word2Int# (word8ToWord# (indexWord8OffAddr# a# 3#)) in
     if noValidUtf8Cont# ch3 then invalid# 3# else
     (# chr# (((ch0 `andI#` 0x0F#) `uncheckedIShiftL#` 18#) `orI#`
              ((ch1 `andI#` 0x7F#) `uncheckedIShiftL#` 12#) `orI#`
@@ -783,7 +807,7 @@
 {-# INLINE utf8SizeChar# #-}
 utf8SizeChar# :: Addr# -> Int#
 utf8SizeChar# a# =
-    case indexWord8OffAddr# a# 0# of
+    case word8ToWord# (indexWord8OffAddr# a# 0#) of
         0## -> 0#
         !x# ->
             let !ch0 = word2Int# x# in
