diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
 ## Getting started
 
 Let's say we want to compute the cosine of a number using C from
-Haskell. `inline-c` let's you write this function call inline, without
+Haskell. `inline-c` lets you write this function call inline, without
 any need for a binding to the foreign function:
 
 ```
@@ -48,7 +48,7 @@
 A `C.exp` quasiquotation always includes a type annotation for the
 inline C expression. This annotation determines the type of the
 quasiquotation in Haskell. Out of the box, `inline-c` knows how to map
-many common C types to Haskell type. In this case,
+many common C types to Haskell types. In this case,
 
 ```
 [C.exp| double { cos(1) } |] :: IO CDouble
@@ -227,9 +227,9 @@
 
 ## ByteStrings
 
-The `bs-len` and `bs-ptr` ant-quoters in the `C.bsCtx` context work
+The `bs-len` and `bs-ptr` anti-quoters in the `C.bsCtx` context work
 exactly the same as the `vec-len` and `vec-ptr` counterparts, but with
-strict `ByteString`s.  The only difference is that it is no necessary to
+strict `ByteString`s.  The only difference is that it is not necessary to
 specify the type of the pointer from C -- it is always going to be
 `char *`:
 
@@ -267,7 +267,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 import qualified Language.C.Inline as C
 
--- To use the function pointer anti-quoter, we need the 'C.funCtx along with
+-- To use the function pointer anti-quoter, we need the 'C.funCtx' along with
 -- the 'C.baseCtx'.
 C.context (C.baseCtx <> C.funCtx)
 
@@ -304,7 +304,7 @@
 
 Currently `inline-c` does not work in interpreted mode. However, GHCi
 can still be used using the `-fobject-code` flag. For speed, we
-reccomend passing `-fobject-code -O0`, for example
+recommend passing `-fobject-code -O0`, for example
 
 ```
 stack ghci --ghci-options='-fobject-code -O0'
@@ -317,5 +317,6 @@
 ```
 
 [ghc-manual-quasiquotation]:
-https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/template-haskell.html#th-quasiquotation
-[ghc-manual-template-haskell]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/template-haskell.html
+https://downloads.haskell.org/ghc/latest/docs/html/users_guide/glasgow_exts.html#template-haskell-quasi-quotation
+[ghc-manual-template-haskell]:
+https://downloads.haskell.org/ghc/latest/docs/html/users_guide/glasgow_exts.html#template-haskell
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,20 @@
+- 0.9.1.10:
+  * Add -fcompact-unwind for darwin exceptions(#131).
+  * Fix Cpp.Exception error message line numbers(#133).
+  * Skip generating foreign calls under ghcide(HSL), generate stubs instead(#128).
+  * Add ctxRawObjectCompile option to support CUDA(#147).
+- 0.9.1.8: Tighten ansi-wl-pprint upper bound, see issue #144.
+- 0.9.1.7: Allow arbitrary number of C++ templates, see PR #141.
+- 0.9.1.6: Fix mistakenly unsafe call, see issue #137.
+- 0.9.1.5: Support multi-token types in C++ template arguments, see issue #125 and PR #126.
+- 0.9.1.4: Support GHC 8.10, including better C++ flags handling, see PR #121.
+- 0.9.1.3: Work around spurious test failures, see PR #118.
+- 0.9.1.2: Update haddock for `Language.C.Inline.Interruptible.pure`.
+- 0.9.1.1: Use `unsafeDupablePerformIO` rather than `unsafePerformIO`. See issue #115 and PR #117.
+- 0.9.1.0: Add `Language.C.Inline.substitute` and `Language.C.Inline.getHaskellType`.
+- 0.9.0.0: Add support for C++ namespace and template.
+- 0.8.0.1: Compatibility with GHC 8.8
+- 0.8: Add code locations.
 - 0.7.0.1: Add more docs for `funPtr`
 - 0.7.0.0: Add `funPtr` quasi-quoter
 - 0.6.0.6: Support GHC 8.4
diff --git a/examples/gsl-ode.hs b/examples/gsl-ode.hs
--- a/examples/gsl-ode.hs
+++ b/examples/gsl-ode.hs
@@ -3,7 +3,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE MultiWayIf #-}
-import           Data.Coerce (coerce)
+import           Unsafe.Coerce (unsafeCoerce)
 import           Data.Monoid ((<>))
 import qualified Data.Vector.Storable as V
 import qualified Data.Vector.Storable.Mutable as VM
@@ -11,11 +11,11 @@
 import           Foreign.ForeignPtr (newForeignPtr_)
 import           Foreign.Ptr (Ptr)
 import           Foreign.Storable (Storable)
-import qualified Graphics.Rendering.Chart.Backend.Cairo as Chart
-import qualified Graphics.Rendering.Chart.Easy as Chart
 import qualified Language.C.Inline as C
 import qualified Language.C.Inline.Unsafe as CU
 import           System.IO.Unsafe (unsafePerformIO)
+import           Control.Monad (forM_)
+import           System.IO (withFile, hPutStrLn, IOMode(..))
 
 C.context (C.baseCtx <> C.vecCtx <> C.funCtx)
 
@@ -94,7 +94,7 @@
   -> Either String (V.Vector Double)
   -- ^ Solution at end point, or error.
 solveOde fun x0 f0 xend =
-  coerce $ solveOdeC (coerce fun) (coerce x0) (coerce f0) (coerce xend)
+  unsafeCoerce $ solveOdeC (unsafeCoerce fun) (unsafeCoerce x0) (unsafeCoerce f0) (unsafeCoerce xend)
 
 lorenz
   :: Double
@@ -121,9 +121,9 @@
            ]
 
 main :: IO ()
-main = Chart.toFile Chart.def "lorenz.png" $ do
-    Chart.layout_title Chart..= "Lorenz"
-    Chart.plot $ Chart.line "curve" [pts]
+main = withFile "lorenz.csv" WriteMode $ \h ->
+         forM_ pts $ \(x,y) ->
+           hPutStrLn h $ show x ++ ", " ++ show y
   where
     pts = [(f V.! 0, f V.! 2) | (_x, f) <- go 0 (V.fromList [10.0 , 1.0 , 1.0])]
 
diff --git a/inline-c.cabal b/inline-c.cabal
--- a/inline-c.cabal
+++ b/inline-c.cabal
@@ -1,14 +1,14 @@
 name:                inline-c
-version:             0.7.0.1
+version:             0.9.1.10
 synopsis:            Write Haskell source files including C code inline. No FFI required.
 description:         See <https://github.com/fpco/inline-c/blob/master/README.md>.
 license:             MIT
 license-file:        LICENSE
 author:              Francesco Mazzoli, Mathieu Boespflug
-maintainer:          francesco@fpcomplete.com
-copyright:           (c) 2015-2016 FP Complete Corporation, (c) 2017-2018 Francesco Mazzoli
+maintainer:          f@mazzo.li
+copyright:           (c) 2015-2016 FP Complete Corporation, (c) 2017-2019 Francesco Mazzoli
 category:            FFI
-tested-with:         GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.1
+tested-with:         GHC == 9.2.8, GHC == 9.4.7, GHC == 9.6.2
 build-type:          Simple
 cabal-version:       >=1.10
 Extra-Source-Files:  README.md, changelog.md
@@ -33,7 +33,7 @@
   other-modules:       Language.C.Inline.FunPtr
   ghc-options:         -Wall
   build-depends:       base >=4.7 && <5
-                     , ansi-wl-pprint >= 0.6.8
+                     , prettyprinter >=1.7
                      , bytestring
                      , containers
                      , hashable
@@ -57,19 +57,20 @@
                      , Language.C.Types.ParseSpec
   build-depends:       base >=4 && <5
                      , QuickCheck
-                     , ansi-wl-pprint
                      , containers
                      , hashable
                      , hspec >= 2
                      , inline-c
                      , parsers
                      , QuickCheck
+                     , prettyprinter
                      , raw-strings-qq
                      , regex-posix
                      , template-haskell
                      , transformers
                      , unordered-containers
                      , vector
+                     , split
   default-language:    Haskell2010
   ghc-options:         -Wall
   cc-options:          -Wall -Werror
@@ -87,7 +88,5 @@
     build-depends:     base >=4 && <5
                      , inline-c
                      , vector
-                     , Chart >= 1.3
-                     , Chart-cairo
   else
     buildable: False
diff --git a/src/Language/C/Inline.hs b/src/Language/C/Inline.hs
--- a/src/Language/C/Inline.hs
+++ b/src/Language/C/Inline.hs
@@ -31,6 +31,10 @@
   , bsCtx
   , context
 
+    -- * Substitution
+  , substitute
+  , getHaskellType
+
     -- * Inline C
     -- $quoting
   , exp
@@ -38,6 +42,7 @@
   , block
   , include
   , verbatim
+  , emitBlock
 
     -- * 'Ptr' utils
   , withPtr
@@ -237,10 +242,15 @@
 
 -- | Variant of 'exp', for use with expressions known to have no side effects.
 --
--- BEWARE: use this function with caution, only when you know what you are
+-- __BEWARE__: Use this function with caution, only when you know what you are
 -- doing. If an expression does in fact have side-effects, then indiscriminate
 -- use of 'pure' may endanger referential transparency, and in principle even
--- type safety.
+-- type safety. Also note that the function might be called multiple times,
+-- given that 'System.IO.Unsafe.unsafeDupablePerformIO' is used to call the
+-- provided C code.  Please refer to the documentation for
+-- 'System.IO.Unsafe.unsafePerformIO' for more details.
+-- [unsafeDupablePerformIO is used to ensure good performance using the
+-- threaded runtime](https://github.com/fpco/inline-c/issues/115).
 pure :: TH.QuasiQuoter
 pure = genericQuote Pure $ inlineExp TH.Safe
 
diff --git a/src/Language/C/Inline/Context.hs b/src/Language/C/Inline/Context.hs
--- a/src/Language/C/Inline/Context.hs
+++ b/src/Language/C/Inline/Context.hs
@@ -1,14 +1,20 @@
-{-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 -- | A 'Context' is used to define the capabilities of the Template Haskell code
 -- that handles the inline C code. See the documentation of the data type for
@@ -43,7 +49,7 @@
   ) where
 
 import           Control.Applicative ((<|>))
-import           Control.Monad (mzero)
+import           Control.Monad (mzero, forM)
 import           Control.Monad.Trans.Class (lift)
 import           Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
 import qualified Data.ByteString as BS
@@ -64,6 +70,7 @@
 import qualified Text.Parser.Token as Parser
 import qualified Data.HashSet as HashSet
 
+
 #if MIN_VERSION_base(4,9,0)
 import           Data.Semigroup (Semigroup, (<>))
 #else
@@ -153,6 +160,9 @@
     -- when generating C++ code.
   , ctxForeignSrcLang :: Maybe TH.ForeignSrcLang
     -- ^ TH.LangC by default
+  , ctxEnableCpp :: Bool
+    -- ^ Compile source code to raw object.
+  , ctxRawObjectCompile :: Maybe (String -> TH.Q FilePath)
   }
 
 
@@ -163,6 +173,8 @@
     , ctxAntiQuoters = ctxAntiQuoters ctx1 <> ctxAntiQuoters ctx2
     , ctxOutput = ctxOutput ctx1 <|> ctxOutput ctx2
     , ctxForeignSrcLang = ctxForeignSrcLang ctx1 <|> ctxForeignSrcLang ctx2
+    , ctxEnableCpp = ctxEnableCpp ctx1 || ctxEnableCpp ctx2
+    , ctxRawObjectCompile = ctxRawObjectCompile ctx1 <|> ctxRawObjectCompile ctx2
     }
 #endif
 
@@ -172,6 +184,8 @@
     , ctxAntiQuoters = mempty
     , ctxOutput = Nothing
     , ctxForeignSrcLang = Nothing
+    , ctxEnableCpp = False
+    , ctxRawObjectCompile = Nothing
     }
 
 #if !MIN_VERSION_base(4,11,0)
@@ -180,6 +194,8 @@
     , ctxAntiQuoters = ctxAntiQuoters ctx1 <> ctxAntiQuoters ctx2
     , ctxOutput = ctxOutput ctx1 <|> ctxOutput ctx2
     , ctxForeignSrcLang = ctxForeignSrcLang ctx1 <|> ctxForeignSrcLang ctx2
+    , ctxEnableCpp = ctxEnableCpp ctx1 || ctxEnableCpp ctx2
+    , ctxRawObjectCompile = ctxRawObjectCompile ctx1 <|> ctxRawObjectCompile ctx2
     }
 #endif
 
@@ -201,6 +217,7 @@
   -- along with its documentation's section headers.
   --
   -- Integral types
+  , (C.Bool, [t| CBool |])
   , (C.Char Nothing, [t| CChar |])
   , (C.Char (Just C.Signed), [t| CSChar |])
   , (C.Char (Just C.Unsigned), [t| CUChar |])
@@ -263,7 +280,28 @@
     goDecl = go . C.parameterDeclarationType
 
     go :: C.Type C.CIdentifier -> MaybeT TH.Q TH.Type
-    go cTy = case cTy of
+    go cTy = do
+     case cTy of
+      C.TypeSpecifier _specs (C.Template ident' cTys) -> do
+--        let symbol = TH.LitT (TH.StrTyLit (C.unCIdentifier ident'))
+        symbol <- case Map.lookup (C.TypeName ident') cTypes of
+          Nothing -> mzero
+          Just ty -> return ty
+        hsTy <- forM cTys $ \cTys'  -> go (C.TypeSpecifier undefined cTys')
+        case hsTy of
+          [] -> fail $ "Can not find template parameters."
+          (a:[]) ->
+            lift $ TH.AppT <$> symbol <*> return a
+          other ->
+            let tuple = foldl (\tuple arg -> TH.AppT tuple arg) (TH.PromotedTupleT (length other)) other
+            in lift $ TH.AppT <$> symbol <*> return tuple
+      C.TypeSpecifier _specs (C.TemplateConst num) -> do
+        let n = (TH.LitT (TH.NumTyLit (read num)))
+        lift [t| $(return n) |]
+      C.TypeSpecifier _specs (C.TemplatePointer cSpec) -> do
+        case Map.lookup cSpec cTypes of
+          Nothing -> mzero
+          Just ty -> lift [t| Ptr $(ty) |]
       C.TypeSpecifier _specs cSpec ->
         case Map.lookup cSpec cTypes of
           Nothing -> mzero
@@ -451,7 +489,8 @@
 vecLenAntiQuoter = AntiQuoter
   { aqParser = do
       hId <- C.parseIdentifier
-      let cId = mangleHaskellIdentifier hId
+      useCpp <- C.parseEnableCpp
+      let cId = mangleHaskellIdentifier useCpp hId
       return (cId, C.TypeSpecifier mempty (C.Long C.Signed), hId)
   , aqMarshaller = \_purity _cTypes cTy cId -> do
       case cTy of
@@ -486,7 +525,8 @@
 bsPtrAntiQuoter = AntiQuoter
   { aqParser = do
       hId <- C.parseIdentifier
-      let cId = mangleHaskellIdentifier hId
+      useCpp <- C.parseEnableCpp
+      let cId = mangleHaskellIdentifier useCpp hId
       return (cId, C.Ptr [] (C.TypeSpecifier mempty (C.Char Nothing)), hId)
   , aqMarshaller = \_purity _cTypes cTy cId -> do
       case cTy of
@@ -503,7 +543,8 @@
 bsLenAntiQuoter = AntiQuoter
   { aqParser = do
       hId <- C.parseIdentifier
-      let cId = mangleHaskellIdentifier hId
+      useCpp <- C.parseEnableCpp
+      let cId = mangleHaskellIdentifier useCpp hId
       return (cId, C.TypeSpecifier mempty (C.Long C.Signed), hId)
   , aqMarshaller = \_purity _cTypes cTy cId -> do
       case cTy of
@@ -521,7 +562,8 @@
 bsCStrAntiQuoter = AntiQuoter
   { aqParser = do
       hId <- C.parseIdentifier
-      let cId = mangleHaskellIdentifier hId
+      useCpp <- C.parseEnableCpp
+      let cId = mangleHaskellIdentifier useCpp hId
       return (cId, C.Ptr [] (C.TypeSpecifier mempty (C.Char Nothing)), hId)
   , aqMarshaller = \_purity _cTypes cTy cId -> do
       case cTy of
@@ -543,10 +585,11 @@
   => m (C.CIdentifier, C.Type C.CIdentifier, HaskellIdentifier)
 cDeclAqParser = do
   cTy <- Parser.parens C.parseParameterDeclaration
+  useCpp <- C.parseEnableCpp
   case C.parameterDeclarationId cTy of
     Nothing -> fail "Every captured function must be named (funCtx)"
     Just hId -> do
-     let cId = mangleHaskellIdentifier hId
+     let cId = mangleHaskellIdentifier useCpp hId
      cTy' <- deHaskellifyCType $ C.parameterDeclarationType cTy
      return (cId, cTy', hId)
 
@@ -554,7 +597,8 @@
   :: C.CParser HaskellIdentifier m
   => C.Type HaskellIdentifier -> m (C.Type C.CIdentifier)
 deHaskellifyCType = traverse $ \hId -> do
-  case C.cIdentifierFromString (unHaskellIdentifier hId) of
+  useCpp <- C.parseEnableCpp
+  case C.cIdentifierFromString useCpp (unHaskellIdentifier hId) of
     Left err -> fail $ "Illegal Haskell identifier " ++ unHaskellIdentifier hId ++
                        " in C type:\n" ++ err
     Right x -> return x
diff --git a/src/Language/C/Inline/FunPtr.hs b/src/Language/C/Inline/FunPtr.hs
--- a/src/Language/C/Inline/FunPtr.hs
+++ b/src/Language/C/Inline/FunPtr.hs
@@ -9,7 +9,9 @@
   , uniqueFfiImportName
   ) where
 
+import           Data.Maybe (isJust)
 import           Foreign.Ptr (FunPtr)
+import           System.Environment (lookupEnv)
 import qualified Language.Haskell.TH as TH
 import qualified Language.Haskell.TH.Syntax as TH
 
@@ -27,9 +29,15 @@
 mkFunPtr :: TH.TypeQ -> TH.ExpQ
 mkFunPtr hsTy = do
   ffiImportName <- uniqueFfiImportName
-  dec <- TH.forImpD TH.CCall TH.Safe "wrapper" ffiImportName [t| $(hsTy) -> IO (FunPtr $(hsTy)) |]
-  TH.addTopDecls [dec]
-  TH.varE ffiImportName
+  -- See note [ghcide-support]
+  usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
+  if usingGhcide
+    then do
+      [e|error "inline-c: A 'usingGhcide' mkFunPtr stub was evaluated -- this should not happen" :: $(hsTy) -> IO (FunPtr $(hsTy)) |]
+    else do -- Actual foreign function call generation.
+      dec <- TH.forImpD TH.CCall TH.Safe "wrapper" ffiImportName [t| $(hsTy) -> IO (FunPtr $(hsTy)) |]
+      TH.addTopDecls [dec]
+      TH.varE ffiImportName
 
 -- | @$('mkFunPtrFromName' 'foo)@, if @foo :: 'CDouble' -> 'IO'
 -- 'CDouble'@, splices in an expression of type @'IO' ('FunPtr'
@@ -56,9 +64,15 @@
 peekFunPtr :: TH.TypeQ -> TH.ExpQ
 peekFunPtr hsTy = do
   ffiImportName <- uniqueFfiImportName
-  dec <- TH.forImpD TH.CCall TH.Safe "dynamic" ffiImportName [t| FunPtr $(hsTy) -> $(hsTy) |]
-  TH.addTopDecls [dec]
-  TH.varE ffiImportName
+  usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
+  -- See note [ghcide-support]
+  if usingGhcide
+    then do
+      [e|error "inline-c: A 'usingGhcide' peekFunPtr stub was evaluated -- this should not happen" :: FunPtr $(hsTy) -> $(hsTy) |]
+    else do -- Actual foreign function call generation.
+      dec <- TH.forImpD TH.CCall TH.Safe "dynamic" ffiImportName [t| FunPtr $(hsTy) -> $(hsTy) |]
+      TH.addTopDecls [dec]
+      TH.varE ffiImportName
 
 -- TODO absurdly, I need to 'newName' twice for things to work.  I found
 -- this hack in language-c-inline.  Why is this?
diff --git a/src/Language/C/Inline/HaskellIdentifier.hs b/src/Language/C/Inline/HaskellIdentifier.hs
--- a/src/Language/C/Inline/HaskellIdentifier.hs
+++ b/src/Language/C/Inline/HaskellIdentifier.hs
@@ -30,7 +30,7 @@
 import           Text.Parser.Combinators (many, eof, try, unexpected, (<?>))
 import           Text.Parser.Token (IdentifierStyle(..), highlight, TokenParsing)
 import qualified Text.Parser.Token.Highlight as Highlight
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import qualified Prettyprinter as PP
 
 import qualified Language.C.Types.Parse as C
 
@@ -44,27 +44,28 @@
 
 instance IsString HaskellIdentifier where
   fromString s =
-    case haskellIdentifierFromString s of
+    case haskellIdentifierFromString True s of
       Left err -> error $ "HaskellIdentifier fromString: invalid string " ++ s ++ ":\n" ++ err
       Right x -> x
 
 instance PP.Pretty HaskellIdentifier where
-  pretty = PP.text . unHaskellIdentifier
+  pretty = fromString . unHaskellIdentifier
 
-haskellIdentifierFromString :: String -> Either String HaskellIdentifier
-haskellIdentifierFromString s =
+haskellIdentifierFromString :: Bool -> String -> Either String HaskellIdentifier
+haskellIdentifierFromString useCpp s =
   case C.runCParser cpc "haskellIdentifierFromString" s (parseHaskellIdentifier <* eof) of
     Left err -> Left $ show err
     Right x -> Right x
   where
-    cpc = haskellCParserContext HashSet.empty
+    cpc = haskellCParserContext useCpp HashSet.empty
 
-haskellCParserContext :: C.TypeNames -> C.CParserContext HaskellIdentifier
-haskellCParserContext typeNames = C.CParserContext
+haskellCParserContext :: Bool -> C.TypeNames -> C.CParserContext HaskellIdentifier
+haskellCParserContext useCpp typeNames = C.CParserContext
   { C.cpcTypeNames = typeNames
   , C.cpcParseIdent = parseHaskellIdentifier
   , C.cpcIdentName = "Haskell identifier"
   , C.cpcIdentToString = unHaskellIdentifier
+  , C.cpcEnableCpp = useCpp
   }
 
 -- | See
@@ -121,15 +122,15 @@
 
 -- | Mangles an 'HaskellIdentifier' to produce a valid 'C.CIdentifier'
 -- which still sort of resembles the 'HaskellIdentifier'.
-mangleHaskellIdentifier :: HaskellIdentifier -> C.CIdentifier
-mangleHaskellIdentifier (HaskellIdentifier hs) =
+mangleHaskellIdentifier :: Bool -> HaskellIdentifier -> C.CIdentifier
+mangleHaskellIdentifier useCpp (HaskellIdentifier hs) =
   -- The leading underscore if we have no valid chars is because then
   -- we'd have an identifier starting with numbers.
   let cs = (if null valid then "_" else "") ++
            valid ++
            (if null mangled || null valid then "" else "_") ++
            mangled
-  in case C.cIdentifierFromString cs of
+  in case C.cIdentifierFromString useCpp cs of
     Left err -> error $ "mangleHaskellIdentifier: produced bad C identifier\n" ++ err
     Right x -> x
   where
diff --git a/src/Language/C/Inline/Internal.hs b/src/Language/C/Inline/Internal.hs
--- a/src/Language/C/Inline/Internal.hs
+++ b/src/Language/C/Inline/Internal.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -17,6 +18,11 @@
       setContext
     , getContext
 
+      -- * Substitution
+    , Substitutions(..)
+    , substitute
+    , getHaskellType
+
       -- * Emitting and invoking C code
       --
       -- | The functions in this section let us access more the C file
@@ -26,6 +32,7 @@
 
       -- ** Emitting C code
     , emitVerbatim
+    , emitBlock
 
       -- ** Inlining C code
       -- $embedding
@@ -47,6 +54,11 @@
     , runParserInQ
     , splitTypedC
 
+      -- * Line directives
+    , lineDirective
+    , here
+    , shiftLines
+
       -- * Utility functions for writing quasiquoters
     , genericQuote
     , funPtrQuote
@@ -58,25 +70,28 @@
 import           Control.Monad.Trans.Class (lift)
 import           Data.Foldable (forM_)
 import qualified Data.Map as Map
-import           Data.Maybe (fromMaybe)
+import           Data.Maybe (fromMaybe, isJust)
 import           Data.Traversable (for)
 import           Data.Typeable (Typeable, cast)
 import qualified Language.Haskell.TH as TH
 import qualified Language.Haskell.TH.Quote as TH
 import qualified Language.Haskell.TH.Syntax as TH
-import           System.IO.Unsafe (unsafePerformIO)
+import           System.Environment (lookupEnv)
+import           System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO)
 import qualified Text.Parsec as Parsec
 import qualified Text.Parsec.Pos as Parsec
 import qualified Text.Parser.Char as Parser
 import qualified Text.Parser.Combinators as Parser
 import qualified Text.Parser.LookAhead as Parser
 import qualified Text.Parser.Token as Parser
-import           Text.PrettyPrint.ANSI.Leijen ((<+>))
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import           Prettyprinter ((<+>))
+import qualified Prettyprinter as PP
+import qualified Prettyprinter.Render.String as PP
 import qualified Data.List as L
 import qualified Data.Char as C
 import           Data.Hashable (Hashable)
 import           Foreign.Ptr (FunPtr)
+import qualified Data.Map as M
 
 -- We cannot use getQ/putQ before 7.10.3 because of <https://ghc.haskell.org/trac/ghc/ticket/10596>
 #define USE_GETQ (__GLASGOW_HASKELL__ > 710 || (__GLASGOW_HASKELL__ == 710 && __GLASGOW_HASKELL_PATCHLEVEL1__ >= 3))
@@ -155,7 +170,16 @@
           Nothing -> fail "inline-c: ModuleState not present (initialiseModuleState)"
           Just ms -> return ms
         let lang = fromMaybe TH.LangC (ctxForeignSrcLang context)
-        TH.addForeignFile lang (concat (reverse (msFileChunks ms)))
+            addForeignSource =
+#if MIN_VERSION_base(4,12,0)
+              TH.addForeignSource
+#else
+              TH.addForeignFile
+#endif
+            src = (concat (reverse (msFileChunks ms)))
+        case (lang, ctxRawObjectCompile context) of
+          (TH.RawObject, Just compile) -> compile src >>= TH.addForeignFilePath lang
+          (_, _)  -> addForeignSource lang src
       let moduleState = ModuleState
             { msContext = context
             , msGeneratedNames = 0
@@ -217,6 +241,15 @@
     (ms{msFileChunks = chunk : msFileChunks ms}, ())
   return []
 
+-- | Simply appends some string of block to the module's C file.  Use with care.
+emitBlock :: TH.QuasiQuoter
+emitBlock = TH.QuasiQuoter
+  { TH.quoteExp = const $ fail "inline-c: quoteExp not implemented (quoteCode)"
+  , TH.quotePat = const $ fail "inline-c: quotePat not implemented (quoteCode)"
+  , TH.quoteType = const $ fail "inline-c: quoteType not implemented (quoteCode)"
+  , TH.quoteDec = emitVerbatim
+  }
+
 ------------------------------------------------------------------------
 -- Inlining
 
@@ -239,6 +272,8 @@
 data Code = Code
   { codeCallSafety :: TH.Safety
     -- ^ Safety of the foreign call.
+  , codeLoc :: Maybe TH.Loc
+    -- ^ The haskell source location used for the #line directive
   , codeType :: TH.TypeQ
     -- ^ Type of the foreign call.
   , codeFunName :: String
@@ -266,27 +301,41 @@
 --
 -- @
 -- c_add :: Int -> Int -> Int
--- c_add = $(inlineCode $ Code
---   TH.Unsafe                   -- Call safety
---   [t| Int -> Int -> Int |]    -- Call type
---   "francescos_add"            -- Call name
---   -- C Code
---   \"int francescos_add(int x, int y) { int z = x + y; return z; }\")
+-- c_add = $(do
+--   here <- TH.location
+--   inlineCode $ Code
+--     TH.Unsafe                   -- Call safety
+--     (Just here)
+--     [t| Int -> Int -> Int |]    -- Call type
+--     "francescos_add"            -- Call name
+--     -- C Code
+--     \"int francescos_add(int x, int y) { int z = x + y; return z; }\")
 -- @
 inlineCode :: Code -> TH.ExpQ
 inlineCode Code{..} = do
   -- Write out definitions
   ctx <- getContext
   let out = fromMaybe id $ ctxOutput ctx
-  void $ emitVerbatim $ out codeDefs
+  let directive = maybe "" lineDirective codeLoc
+  void $ emitVerbatim $ out $ directive ++ codeDefs
   -- Create and add the FFI declaration.
   ffiImportName <- uniqueFfiImportName
-  dec <- if codeFunPtr
-    then
-      TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
-    else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
-  TH.addTopDecls [dec]
-  TH.varE ffiImportName
+  -- Note [ghcide-support]
+  -- haskell-language-server / ghcide cannot handle code that use
+  -- `addForeignFile`/`addForeignSource` as we do here; it will result
+  -- in linker errors during TH evaluations, see:
+  -- <https://github.com/haskell/haskell-language-server/issues/365#issuecomment-976294466>
+  -- Thus for GHCIDE, simply generate a call to `error` instead of a call to a foreign import.
+  usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
+  if usingGhcide
+    then do
+      [e|error "inline-c: A 'usingGhcide' inlineCode stub was evaluated -- this should not happen" :: $(if codeFunPtr then [t| FunPtr $(codeType) |] else codeType) |]
+    else do -- Actual foreign function call generation.
+      dec <- if codeFunPtr
+        then TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
+        else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
+      TH.addTopDecls [dec]
+      TH.varE ffiImportName
 
 uniqueCName :: Maybe String -> TH.Q String
 uniqueCName mbPostfix = do
@@ -316,16 +365,21 @@
 --
 -- @
 -- c_cos :: Double -> Double
--- c_cos = $(inlineExp
---   TH.Unsafe
---   [t| Double -> Double |]
---   (quickCParser_ \"double\" parseType)
---   [("x", quickCParser_ \"double\" parseType)]
---   "cos(x)")
+-- c_cos = $(do
+--   here <- TH.location
+--   inlineExp
+--     TH.Unsafe
+--     here
+--     [t| Double -> Double |]
+--     (quickCParser_ \"double\" parseType)
+--     [("x", quickCParser_ \"double\" parseType)]
+--     "cos(x)")
 -- @
 inlineExp
   :: TH.Safety
   -- ^ Safety of the foreign call
+  -> TH.Loc
+  -- ^ The location to report
   -> TH.TypeQ
   -- ^ Type of the foreign call
   -> C.Type C.CIdentifier
@@ -335,8 +389,8 @@
   -> String
   -- ^ The C expression
   -> TH.ExpQ
-inlineExp callSafety type_ cRetType cParams cExp =
-  inlineItems callSafety False Nothing type_ cRetType cParams cItems
+inlineExp callSafety loc type_ cRetType cParams cExp =
+  inlineItems callSafety False Nothing loc type_ cRetType cParams cItems
   where
     cItems = case cRetType of
       C.TypeSpecifier _quals C.Void -> cExp ++ ";"
@@ -348,9 +402,13 @@
 --
 -- @
 -- c_cos :: Double -> Double
--- c_cos = $(inlineItems
+-- c_cos = $(do
+--  here <- TH.location
+--  inlineItems
 --   TH.Unsafe
 --   False
+--   Nothing
+--   here
 --   [t| Double -> Double |]
 --   (quickCParser_ \"double\" parseType)
 --   [("x", quickCParser_ \"double\" parseType)]
@@ -363,6 +421,8 @@
   -- ^ Whether to return as a FunPtr or not
   -> Maybe String
   -- ^ Optional postfix for the generated name
+  -> TH.Loc
+  -- ^ The location to report
   -> TH.TypeQ
   -- ^ Type of the foreign call
   -> C.Type C.CIdentifier
@@ -372,20 +432,20 @@
   -> String
   -- ^ The C items
   -> TH.ExpQ
-inlineItems callSafety funPtr mbPostfix type_ cRetType cParams cItems = do
+inlineItems callSafety funPtr mbPostfix loc type_ cRetType cParams cItems = do
   let mkParam (id', paramTy) = C.ParameterDeclaration (Just id') paramTy
   let proto = C.Proto cRetType (map mkParam cParams)
+  ctx <- getContext
   funName <- uniqueCName mbPostfix
-  cFunName <- case C.cIdentifierFromString funName of
+  cFunName <- case C.cIdentifierFromString (ctxEnableCpp ctx) funName of
     Left err -> fail $ "inlineItems: impossible, generated bad C identifier " ++
                        "funName:\n" ++ err
     Right x -> return x
   let decl = C.ParameterDeclaration (Just cFunName) proto
-  let defs =
-        prettyOneLine decl ++ " {\n" ++
-        cItems ++ "\n}\n"
+  let defs = prettyOneLine (PP.pretty decl) ++ " { " ++ cItems ++ " }\n"
   inlineCode $ Code
     { codeCallSafety = callSafety
+    , codeLoc = Just loc
     , codeType = type_
     , codeFunName = funName
     , codeDefs = defs
@@ -439,6 +499,44 @@
   , ptcBody :: String
   }
 
+newtype Substitutions = Substitutions { unSubstitutions :: M.Map String (String -> String) }
+
+applySubstitutions :: String -> TH.Q String
+applySubstitutions str = do
+  subs <- maybe mempty unSubstitutions <$> TH.getQ
+  let substitution = msum $ flip map (M.toList subs) $ \( subName, subFunc ) ->
+        Parsec.try $ do
+          _ <- Parsec.string ('@' : subName ++ "(")
+          subArg <- Parsec.manyTill Parsec.anyChar (Parsec.char ')')
+          return (subFunc subArg)
+  let someChar = (:[]) <$> Parsec.anyChar
+  case Parsec.parse (many (substitution <|> someChar)) "" str of
+    Left _ -> fail "Substitution failed (should be impossible)"
+    Right chunks -> return (concat chunks)
+
+-- | Define macros that can be used in the nested Template Haskell expression.
+-- Macros can be used as @\@MACRO_NAME(input)@ in inline-c quotes, and will transform their input with the given function.
+-- They can be useful for passing in types when defining Haskell instances for C++ template types.
+substitute :: [ ( String, String -> String ) ] -> TH.Q a -> TH.Q a
+substitute subsList cont = do
+  oldSubs <- maybe mempty unSubstitutions <$> TH.getQ
+  let subs = M.fromList subsList
+  let conflicting = M.intersection subs oldSubs
+  newSubs <-
+    if M.null conflicting
+      then return (Substitutions (M.union oldSubs subs))
+      else fail ("Conflicting substitutions `" ++ show (M.keys conflicting) ++ "`")
+  TH.putQ newSubs *> cont <* TH.putQ (Substitutions oldSubs)
+
+-- | Given a C type name, return the Haskell type in Template Haskell. The first parameter controls whether function pointers
+-- should be mapped as pure or IO functions.
+getHaskellType :: Bool -> String -> TH.TypeQ
+getHaskellType pureFunctions cTypeStr = do
+  ctx <- getContext
+  let cParseCtx = C.cCParserContext (ctxEnableCpp ctx) (typeNamesFromTypesTable (ctxTypesTable ctx))
+  cType <- runParserInQ cTypeStr cParseCtx C.parseType
+  cToHs ctx (if pureFunctions then Pure else IO) cType
+
 -- To parse C declarations, we're faced with a bit of a problem: we want
 -- to parse the anti-quotations so that Haskell identifiers are
 -- accepted, but we want them to appear only as the root of
@@ -447,9 +545,9 @@
 -- the root.
 parseTypedC
   :: forall m. C.CParser HaskellIdentifier m
-  => AntiQuoters -> m ParseTypedC
+  => Bool -> AntiQuoters -> m ParseTypedC
   -- ^ Returns the return type, the captured variables, and the body.
-parseTypedC antiQs = do
+parseTypedC useCpp antiQs = do
   -- Parse return type (consume spaces first)
   Parser.spaces
   cRetType <- purgeHaskellIdentifiers =<< C.parseType
@@ -509,27 +607,31 @@
         Nothing -> fail $ pretty80 $
           "Un-named captured variable in decl" <+> PP.pretty decl
         Just hId -> return hId
-      id' <- freshId $ mangleHaskellIdentifier hId
+      id' <- freshId $ mangleHaskellIdentifier useCpp hId
       void $ Parser.char ')'
       return ([(id', declType, Plain hId)], C.unCIdentifier id')
 
     freshId s = do
       c <- get
       put $ c + 1
-      case C.cIdentifierFromString (C.unCIdentifier s ++ "_inline_c_" ++ show c) of
+      case C.cIdentifierFromString useCpp (C.unCIdentifier s ++ "_inline_c_" ++ show c) of
         Left _err -> error "freshId: The impossible happened"
         Right x -> return x
 
     -- The @m@ is polymorphic because we use this both for the plain
     -- parser and the StateT parser we use above.  We only need 'fail'.
     purgeHaskellIdentifiers
+#if MIN_VERSION_base(4,13,0)
+      :: forall n. MonadFail n
+#else
       :: forall n. (Applicative n, Monad n)
+#endif
       => C.Type HaskellIdentifier -> n (C.Type C.CIdentifier)
     purgeHaskellIdentifiers cTy = for cTy $ \hsIdent -> do
       let hsIdentS = unHaskellIdentifier hsIdent
-      case C.cIdentifierFromString hsIdentS of
+      case C.cIdentifierFromString useCpp hsIdentS of
         Left err -> fail $ "Haskell identifier " ++ hsIdentS ++ " in illegal position" ++
-                           "in C type\n" ++ pretty80 cTy ++ "\n" ++
+                           "in C type\n" ++ pretty80 (PP.pretty cTy) ++ "\n" ++
                            "A C identifier was expected, but:\n" ++ err
         Right cIdent -> return cIdent
 
@@ -539,28 +641,37 @@
   -> TH.QuasiQuoter
 quoteCode p = TH.QuasiQuoter
   { TH.quoteExp = p
-  , TH.quotePat = fail "inline-c: quotePat not implemented (quoteCode)"
-  , TH.quoteType = fail "inline-c: quoteType not implemented (quoteCode)"
-  , TH.quoteDec = fail "inline-c: quoteDec not implemented (quoteCode)"
+  , TH.quotePat = const $ fail "inline-c: quotePat not implemented (quoteCode)"
+  , TH.quoteType = const $ fail "inline-c: quoteType not implemented (quoteCode)"
+  , TH.quoteDec = const $ fail "inline-c: quoteDec not implemented (quoteCode)"
   }
 
+cToHs :: Context -> Purity -> C.Type C.CIdentifier -> TH.TypeQ
+cToHs ctx purity cTy = do
+  mbHsTy <- convertType purity (ctxTypesTable ctx) cTy
+  case mbHsTy of
+    Nothing -> fail $ "Could not resolve Haskell type for C type " ++ pretty80 (PP.pretty cTy)
+    Just hsTy -> return hsTy
+
 genericQuote
   :: Purity
-  -> (TH.TypeQ -> C.Type C.CIdentifier -> [(C.CIdentifier, C.Type C.CIdentifier)] -> String -> TH.ExpQ)
+  -> (TH.Loc -> TH.TypeQ -> C.Type C.CIdentifier -> [(C.CIdentifier, C.Type C.CIdentifier)] -> String -> TH.ExpQ)
   -- ^ Function building an Haskell expression, see 'inlineExp' for
   -- guidance on the other args.
   -> TH.QuasiQuoter
-genericQuote purity build = quoteCode $ \s -> do
+genericQuote purity build = quoteCode $ \rawStr -> do
     ctx <- getContext
+    here <- TH.location
+    s <- applySubstitutions rawStr
     ParseTypedC cType cParams cExp <-
       runParserInQ s
-        (haskellCParserContext (typeNamesFromTypesTable (ctxTypesTable ctx)))
-        (parseTypedC (ctxAntiQuoters ctx))
-    hsType <- cToHs ctx cType
+        (haskellCParserContext (ctxEnableCpp ctx) (typeNamesFromTypesTable (ctxTypesTable ctx)))
+        (parseTypedC (ctxEnableCpp ctx) (ctxAntiQuoters ctx))
+    hsType <- cToHs ctx purity cType
     hsParams <- forM cParams $ \(_cId, cTy, parTy) -> do
       case parTy of
         Plain s' -> do
-          hsTy <- cToHs ctx cTy
+          hsTy <- cToHs ctx purity cTy
           let hsName = TH.mkName (unHaskellIdentifier s')
           hsExp <- [| \cont -> cont ($(TH.varE hsName) :: $(return hsTy)) |]
           return (hsTy, hsExp)
@@ -577,19 +688,13 @@
                 aqMarshaller antiQ purity (ctxTypesTable ctx) cTy x
     let hsFunType = convertCFunSig hsType $ map fst hsParams
     let cParams' = [(cId, cTy) | (cId, cTy, _) <- cParams]
-    ioCall <- buildFunCall ctx (build hsFunType cType cParams' cExp) (map snd hsParams) []
+    ioCall <- buildFunCall ctx (build here hsFunType cType cParams' cExp) (map snd hsParams) []
     -- If the user requested a pure function, make it so.
     case purity of
-      Pure -> [| unsafePerformIO $(return ioCall) |]
+      -- Using unsafeDupablePerformIO to increase performance of pure calls, see <https://github.com/fpco/inline-c/issues/115>
+      Pure -> [| unsafeDupablePerformIO $(return ioCall) |]
       IO -> return ioCall
   where
-    cToHs :: Context -> C.Type C.CIdentifier -> TH.TypeQ
-    cToHs ctx cTy = do
-      mbHsTy <- convertType purity (ctxTypesTable ctx) cTy
-      case mbHsTy of
-        Nothing -> fail $ "Could not resolve Haskell type for C type " ++ pretty80 cTy
-        Just hsTy -> return hsTy
-
     buildFunCall :: Context -> TH.ExpQ -> [TH.Exp] -> [TH.Name] -> TH.ExpQ
     buildFunCall _ctx f [] args =
       foldl (\f' arg -> [| $f' $(TH.varE arg) |]) f args
@@ -607,14 +712,37 @@
         go (paramType : params) = do
           [t| $(return paramType) -> $(go params) |]
 
-splitTypedC :: String -> (String, String)
-  -- ^ Returns the type and the body separately
-splitTypedC s = (trim ty, case body of
-                            [] -> []
-                            r  -> r)
+
+-- NOTE: splitTypedC wouldn't be necessary if inline-c-cpp could reuse C.block
+-- internals with a clean interface.
+-- This would be a significant refactoring but presumably it would lead to an
+-- api that could let users write their own quasiquoters a bit more conveniently.
+
+-- | Returns the type and the body separately.
+splitTypedC :: String -> (String, String, Int)
+splitTypedC s = (trim ty, bodyIndent <> body, bodyLineShift)
   where (ty, body) = span (/= '{') s
         trim x = L.dropWhileEnd C.isSpace (dropWhile C.isSpace x)
 
+        -- We may need to correct the line number of the body
+        bodyLineShift = length (filter (== '\n') ty)
+
+        -- Indentation is relevant for error messages when the syntax is:
+        -- [C.foo| type
+        --   { foo(); }
+        -- |]
+        bodyIndent =
+          let precedingSpaceReversed =
+                takeWhile (\c -> C.isSpace c) $
+                reverse $
+                ty
+              (precedingSpacesTabsReversed, precedingLine) =
+                span (`notElem` ("\n\r" :: [Char])) precedingSpaceReversed
+          in case precedingLine of
+            ('\n':_) -> reverse precedingSpacesTabsReversed
+            ('\r':_) -> reverse precedingSpacesTabsReversed
+            _ -> "" -- it wasn't indentation after all; just spaces after the type
+
 -- | Data to parse for the 'funPtr' quasi-quoter.
 data FunPtrDecl = FunPtrDecl
   { funPtrReturnType :: C.Type C.CIdentifier
@@ -624,21 +752,16 @@
   } deriving (Eq, Show)
 
 funPtrQuote :: TH.Safety -> TH.QuasiQuoter
-funPtrQuote callSafety = quoteCode $ \code -> do
+funPtrQuote callSafety = quoteCode $ \rawCode -> do
+  loc <- TH.location
   ctx <- getContext
-  FunPtrDecl{..} <- runParserInQ code (C.cCParserContext (typeNamesFromTypesTable (ctxTypesTable ctx))) parse
-  hsRetType <- cToHs ctx funPtrReturnType
-  hsParams <- forM funPtrParameters (\(_ident, typ_) -> cToHs ctx typ_)
+  code <- applySubstitutions rawCode
+  FunPtrDecl{..} <- runParserInQ code (C.cCParserContext (ctxEnableCpp ctx) (typeNamesFromTypesTable (ctxTypesTable ctx))) parse
+  hsRetType <- cToHs ctx IO funPtrReturnType
+  hsParams <- forM funPtrParameters (\(_ident, typ_) -> cToHs ctx IO typ_)
   let hsFunType = convertCFunSig hsRetType hsParams
-  inlineItems callSafety True funPtrName hsFunType funPtrReturnType funPtrParameters funPtrBody
+  inlineItems callSafety True funPtrName loc hsFunType funPtrReturnType funPtrParameters funPtrBody
   where
-    cToHs :: Context -> C.Type C.CIdentifier -> TH.TypeQ
-    cToHs ctx cTy = do
-      mbHsTy <- convertType IO (ctxTypesTable ctx) cTy
-      case mbHsTy of
-        Nothing -> fail $ "Could not resolve Haskell type for C type " ++ pretty80 cTy
-        Just hsTy -> return hsTy
-
     convertCFunSig :: TH.Type -> [TH.Type] -> TH.TypeQ
     convertCFunSig retType params0 = do
       go params0
@@ -688,10 +811,56 @@
       return (s ++ s')
 
 ------------------------------------------------------------------------
+-- Line directives
+
+-- | Tell the C compiler where the next line came from.
+--
+-- Example:
+--
+-- @@@
+-- there <- location
+-- f (unlines
+--   [ lineDirective $(here)
+--   , "generated_code_user_did_not_write()"
+--   , lineDirective there
+--   ] ++ userCode
+-- ])
+-- @@@
+--
+-- Use @lineDirective $(C.here)@ when generating code, so that any errors or
+-- warnings report the location of the generating haskell module, rather than
+-- tangentially related user code that doesn't contain the actual problem.
+lineDirective :: TH.Loc -> String
+lineDirective l = "#line " ++ show (fst $ TH.loc_start l) ++ " " ++ show (TH.loc_filename l ) ++ "\n"
+
+-- | Get the location of the code you're looking at, for use with
+-- 'lineDirective'; place before generated code that user did not write.
+here :: TH.ExpQ
+here = [| $(TH.location >>= \(TH.Loc a b c (d1, d2) (e1, e2)) ->
+    [|Loc
+      $(TH.lift a)
+      $(TH.lift b)
+      $(TH.lift c)
+      ($(TH.lift d1), $(TH.lift d2))
+      ($(TH.lift e1), $(TH.lift e2))
+    |])
+  |]
+
+shiftLines :: Int -> TH.Loc -> TH.Loc
+shiftLines n l = l
+  { TH.loc_start =
+      let (startLn, startCol) = TH.loc_start l
+      in (startLn + n, startCol)
+  , TH.loc_end =
+      let (endLn, endCol) = TH.loc_end l
+      in (endLn + n, endCol)
+  }
+
+------------------------------------------------------------------------
 -- Utils
 
-pretty80 :: PP.Pretty a => a -> String
-pretty80 x = PP.displayS (PP.renderPretty 0.8 80 (PP.pretty x)) ""
+pretty80 :: PP.Doc ann -> String
+pretty80 x = PP.renderString $ PP.layoutSmart (PP.LayoutOptions { PP.layoutPageWidth = PP.AvailablePerLine 80 0.8 }) x
 
-prettyOneLine :: PP.Pretty a => a -> String
-prettyOneLine x = PP.displayS (PP.renderCompact (PP.pretty x)) ""
+prettyOneLine :: PP.Doc ann -> String
+prettyOneLine x = PP.renderString $ PP.layoutCompact x
diff --git a/src/Language/C/Inline/Interruptible.hs b/src/Language/C/Inline/Interruptible.hs
--- a/src/Language/C/Inline/Interruptible.hs
+++ b/src/Language/C/Inline/Interruptible.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE CPP #-}
 
 -- | @interruptible@ variants of the "Language.C.Inline" quasi-quoters, to call
--- interruptible C code. See <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ffi.html#ffi-interruptible>
+-- interruptible C code. See <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ffi-chap.html#interruptible-foreign-calls>
 -- for more information.
 --
 -- This module is intended to be imported qualified:
@@ -34,13 +34,19 @@
 
 -- | Variant of 'exp', for use with expressions known to have no side effects.
 --
--- BEWARE: use this function with caution, only when you know what you are
+-- __BEWARE__: Use this function with caution, only when you know what you are
 -- doing. If an expression does in fact have side-effects, then indiscriminate
 -- use of 'pure' may endanger referential transparency, and in principle even
--- type safety.
+-- type safety. Also note that the function may run more than once and that it
+-- may run in parallel with itself, given that
+-- 'System.IO.Unsafe.unsafeDupablePerformIO' is used to call the provided C
+-- code [to ensure good performance using the threaded
+-- runtime](https://github.com/fpco/inline-c/issues/115).  Please refer to the
+-- documentation for 'System.IO.Unsafe.unsafeDupablePerformIO' for more
+-- details.
 pure :: TH.QuasiQuoter
 pure = genericQuote Pure $ inlineExp TH.Interruptible
 
 -- | C code blocks (i.e. statements).
 block :: TH.QuasiQuoter
-block = genericQuote IO $ inlineItems TH.Unsafe False Nothing
+block = genericQuote IO $ inlineItems TH.Interruptible False Nothing
diff --git a/src/Language/C/Inline/Unsafe.hs b/src/Language/C/Inline/Unsafe.hs
--- a/src/Language/C/Inline/Unsafe.hs
+++ b/src/Language/C/Inline/Unsafe.hs
@@ -37,10 +37,16 @@
 
 -- | Variant of 'exp', for use with expressions known to have no side effects.
 --
--- BEWARE: use this function with caution, only when you know what you are
+-- __BEWARE__: Use this function with caution, only when you know what you are
 -- doing. If an expression does in fact have side-effects, then indiscriminate
 -- use of 'pure' may endanger referential transparency, and in principle even
--- type safety.
+-- type safety. Also note that the function may run more than once and that it
+-- may run in parallel with itself, given that
+-- 'System.IO.Unsafe.unsafeDupablePerformIO' is used to call the provided C
+-- code [to ensure good performance using the threaded
+-- runtime](https://github.com/fpco/inline-c/issues/115).  Please refer to the
+-- documentation for 'System.IO.Unsafe.unsafeDupablePerformIO' for more
+-- details.
 pure :: TH.QuasiQuoter
 pure = genericQuote Pure $ inlineExp TH.Unsafe
 
diff --git a/src/Language/C/Types.hs b/src/Language/C/Types.hs
--- a/src/Language/C/Types.hs
+++ b/src/Language/C/Types.hs
@@ -48,6 +48,7 @@
   , parseParameterDeclaration
   , parseParameterList
   , parseIdentifier
+  , parseEnableCpp
   , parseType
 
     -- * Convert to and from high-level views
@@ -61,13 +62,16 @@
   ) where
 
 import           Control.Arrow (second)
-import           Control.Monad (when, unless, forM_)
+import           Control.Monad (when, unless, forM_, forM)
 import           Control.Monad.State (execState, modify)
-import           Data.List (partition)
+import           Control.Monad.Reader (ask)
+import           Data.List (partition, intersperse)
 import           Data.Maybe (fromMaybe)
+import           Data.String (fromString)
 import           Data.Typeable (Typeable)
-import           Text.PrettyPrint.ANSI.Leijen ((</>), (<+>))
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import           Prettyprinter ((<+>))
+import qualified Prettyprinter as PP
+import qualified Prettyprinter.Render.String as PP
 
 #if MIN_VERSION_base(4,9,0)
 import           Data.Semigroup (Semigroup, (<>))
@@ -89,6 +93,7 @@
 
 data TypeSpecifier
   = Void
+  | Bool
   | Char (Maybe Sign)
   | Short Sign
   | Int Sign
@@ -100,6 +105,9 @@
   | TypeName P.CIdentifier
   | Struct P.CIdentifier
   | Enum P.CIdentifier
+  | Template P.CIdentifier [TypeSpecifier]
+  | TemplateConst String
+  | TemplatePointer TypeSpecifier
   deriving (Typeable, Show, Eq, Ord)
 
 data Specifiers = Specifiers
@@ -173,74 +181,93 @@
           P.TypeSpecifier x -> modify $ \(a, b, c, d) -> (a, x:b, c, d)
           P.TypeQualifier x -> modify $ \(a, b, c, d) -> (a, b, x:c, d)
           P.FunctionSpecifier x -> modify $ \(a, b, c, d) -> (a, b, c, x:d)
-  -- Split data type and specifiers
-  let (dataTypes, specs) =
-        partition (\x -> not (x `elem` [P.SIGNED, P.UNSIGNED, P.LONG, P.SHORT])) pTySpecs
-  let illegalSpecifiers s = failConversion $ IllegalSpecifiers s specs
-  -- Find out sign, if present
-  mbSign0 <- case filter (== P.SIGNED) specs of
-    []  -> return Nothing
-    [_] -> return $ Just Signed
-    _:_ -> illegalSpecifiers "conflicting/duplicate sign information"
-  mbSign <- case (mbSign0, filter (== P.UNSIGNED) specs) of
-    (Nothing, []) -> return Nothing
-    (Nothing, [_]) -> return $ Just Unsigned
-    (Just b, []) -> return $ Just b
-    _ -> illegalSpecifiers "conflicting/duplicate sign information"
-  let sign = fromMaybe Signed mbSign
-  -- Find out length
-  let longs = length $ filter (== P.LONG) specs
-  let shorts = length $ filter (== P.SHORT) specs
-  when (longs > 0 && shorts > 0) $ illegalSpecifiers "both long and short"
-  -- Find out data type
-  dataType <- case dataTypes of
-    [x] -> return x
-    [] | longs > 0 || shorts > 0 -> return P.INT
-    [] -> failConversion $ NoDataTypes declSpecs
-    _:_ -> failConversion $ MultipleDataTypes declSpecs
-  -- Check if things are compatible with one another
-  let checkNoSpecs =
-        unless (null specs) $ illegalSpecifiers "expecting no specifiers"
-  let checkNoLength =
-        when (longs > 0 || shorts > 0) $ illegalSpecifiers "unexpected long/short"
-  tySpec <- case dataType of
-    P.TypeName s -> do
-      checkNoSpecs
-      return $ TypeName s
-    P.Struct s -> do
-      checkNoSpecs
-      return $ Struct s
-    P.Enum s -> do
-      checkNoSpecs
-      return $ Enum s
-    P.VOID -> do
-      checkNoSpecs
-      return Void
-    P.CHAR -> do
-      checkNoLength
-      return $ Char mbSign
-    P.INT | longs == 0 && shorts == 0 -> do
-      return $ Int sign
-    P.INT | longs == 1 -> do
-      return $ Long sign
-    P.INT | longs == 2 -> do
-      return $ LLong sign
-    P.INT | shorts == 1 -> do
-      return $ Short sign
-    P.INT -> do
-      illegalSpecifiers "too many long/short"
-    P.FLOAT -> do
-      checkNoLength
-      return Float
-    P.DOUBLE -> do
-      if longs == 1
-        then return LDouble
-        else do
-          checkNoLength
-          return Double
-    _ -> do
-      error $ "untangleDeclarationSpecifiers impossible: " ++ show dataType
+  tySpec <- type2type pTySpecs
   return (Specifiers pStorage pTyQuals pFunSpecs, tySpec)
+  where
+    type2type pTySpecs = do
+      -- Split data type and specifiers
+      let (dataTypes, specs) =
+            partition (\x -> not (x `elem` [P.SIGNED, P.UNSIGNED, P.LONG, P.SHORT])) pTySpecs
+      let illegalSpecifiers s = failConversion $ IllegalSpecifiers s specs
+      -- Find out sign, if present
+      mbSign0 <- case filter (== P.SIGNED) specs of
+        []  -> return Nothing
+        [_] -> return $ Just Signed
+        _:_ -> illegalSpecifiers "conflicting/duplicate sign information"
+      mbSign <- case (mbSign0, filter (== P.UNSIGNED) specs) of
+        (Nothing, []) -> return Nothing
+        (Nothing, [_]) -> return $ Just Unsigned
+        (Just b, []) -> return $ Just b
+        _ -> illegalSpecifiers "conflicting/duplicate sign information"
+      let sign = fromMaybe Signed mbSign
+      -- Find out length
+      let longs = length $ filter (== P.LONG) specs
+      let shorts = length $ filter (== P.SHORT) specs
+      when (longs > 0 && shorts > 0) $ illegalSpecifiers "both long and short"
+      -- Find out data type
+      dataType <- case dataTypes of
+        [x] -> return x
+        [] | mbSign0 == Just Signed -> return P.INT -- "The Case of 'signed' not including 'signed int'"
+        [] | mbSign == Just Unsigned -> return P.INT -- "The Case of 'unsigned' not including 'unsigned int'"
+        [] | longs > 0 || shorts > 0 -> return P.INT
+        [] -> failConversion $ NoDataTypes declSpecs
+        _:_ -> failConversion $ MultipleDataTypes declSpecs
+      -- Check if things are compatible with one another
+      let checkNoSpecs =
+            unless (null specs) $ illegalSpecifiers "expecting no specifiers"
+      let checkNoLength =
+            when (longs > 0 || shorts > 0) $ illegalSpecifiers "unexpected long/short"
+      case dataType of
+        P.Template s args -> do
+          checkNoSpecs
+          args' <- forM args type2type
+          return $ Template s args'
+        P.TemplateConst s -> do
+          checkNoSpecs
+          return $ TemplateConst s
+        P.TemplatePointer s -> do
+          checkNoSpecs
+          s' <- type2type [s]
+          return $ TemplatePointer s'
+        P.TypeName s -> do
+          checkNoSpecs
+          return $ TypeName s
+        P.Struct s -> do
+          checkNoSpecs
+          return $ Struct s
+        P.Enum s -> do
+          checkNoSpecs
+          return $ Enum s
+        P.VOID -> do
+          checkNoSpecs
+          return Void
+        P.BOOL -> do
+          checkNoLength
+          return $ Bool
+        P.CHAR -> do
+          checkNoLength
+          return $ Char mbSign
+        P.INT | longs == 0 && shorts == 0 -> do
+          return $ Int sign
+        P.INT | longs == 1 -> do
+          return $ Long sign
+        P.INT | longs == 2 -> do
+          return $ LLong sign
+        P.INT | shorts == 1 -> do
+          return $ Short sign
+        P.INT -> do
+          illegalSpecifiers "too many long/short"
+        P.FLOAT -> do
+          checkNoLength
+          return Float
+        P.DOUBLE -> do
+          if longs == 1
+            then return LDouble
+            else do
+              checkNoLength
+              return Double
+        _ -> do
+          error $ "untangleDeclarationSpecifiers impossible: " ++ show dataType
 
 untangleDeclarator
   :: forall i. Type i -> P.Declarator i -> Either UntangleErr (i, Type i)
@@ -368,8 +395,9 @@
 
 tangleTypeSpecifier :: Specifiers -> TypeSpecifier -> [P.DeclarationSpecifier]
 tangleTypeSpecifier (Specifiers storages tyQuals funSpecs) tySpec =
-  let pTySpecs = case tySpec of
+  let pTySpecs ty = case ty of
         Void -> [P.VOID]
+        Bool -> [P.BOOL]
         Char Nothing -> [P.CHAR]
         Char (Just Signed) -> [P.SIGNED, P.CHAR]
         Char (Just Unsigned) -> [P.UNSIGNED, P.CHAR]
@@ -387,22 +415,25 @@
         TypeName s -> [P.TypeName s]
         Struct s -> [P.Struct s]
         Enum s -> [P.Enum s]
+        Template s types -> [P.Template s (map pTySpecs types)]
+        TemplateConst s -> [P.TemplateConst s]
+        TemplatePointer type' -> [P.TemplatePointer (head (pTySpecs type'))]
   in map P.StorageClassSpecifier storages ++
      map P.TypeQualifier tyQuals ++
      map P.FunctionSpecifier funSpecs ++
-     map P.TypeSpecifier pTySpecs
+     map P.TypeSpecifier (pTySpecs tySpec)
 
 ------------------------------------------------------------------------
 -- To english
 
-describeParameterDeclaration :: PP.Pretty i => ParameterDeclaration i -> PP.Doc
+describeParameterDeclaration :: PP.Pretty i => ParameterDeclaration i -> PP.Doc ann
 describeParameterDeclaration (ParameterDeclaration mbId ty) =
   let idDoc = case mbId of
         Nothing -> ""
         Just id' -> PP.pretty id' <+> "is a "
   in idDoc <> describeType ty
 
-describeType :: PP.Pretty i => Type i -> PP.Doc
+describeType :: PP.Pretty i => Type i -> PP.Doc ann
 describeType ty0 = case ty0 of
   TypeSpecifier specs tySpec -> engSpecs specs <> PP.pretty tySpec
   Ptr quals ty -> engQuals quals <> "ptr to" <+> describeType ty
@@ -420,7 +451,7 @@
 
     engArrTy arrTy = case arrTy of
       P.VariablySized -> "variably sized array "
-      P.SizedByInteger n -> "array of size" <+> PP.text (show n) <> " "
+      P.SizedByInteger n -> "array of size" <+> fromString (show n) <> " "
       P.SizedByIdentifier s -> "array of size" <+> PP.pretty s <> " "
       P.Unsized -> "array "
 
@@ -441,7 +472,7 @@
 untangleParameterDeclaration' pDecl =
   case untangleParameterDeclaration pDecl of
     Left err -> fail $ pretty80 $
-      "Error while parsing declaration:" </> PP.pretty err </> PP.pretty pDecl
+      PP.vsep ["Error while parsing declaration:", PP.pretty err, PP.pretty pDecl]
     Right x -> return x
 
 parseParameterDeclaration
@@ -458,6 +489,11 @@
 parseIdentifier :: P.CParser i m => m i
 parseIdentifier = P.identifier_no_lex
 
+parseEnableCpp :: P.CParser i m => m Bool
+parseEnableCpp = do
+  ctx <- ask
+  return (P.cpcEnableCpp ctx)
+
 parseType :: (P.CParser i m, PP.Pretty i) => m (Type i)
 parseType = parameterDeclarationType <$> parseParameterDeclaration
 
@@ -467,6 +503,7 @@
 instance PP.Pretty TypeSpecifier where
   pretty tySpec = case tySpec of
     Void -> "void"
+    Bool -> "bool"
     Char Nothing -> "char"
     Char (Just Signed) -> "signed char"
     Char (Just Unsigned) -> "unsigned char"
@@ -484,15 +521,18 @@
     TypeName s -> PP.pretty s
     Struct s -> "struct" <+> PP.pretty s
     Enum s -> "enum" <+> PP.pretty s
+    Template s args -> PP.pretty s <+> "<"  <+>  mconcat (intersperse "," (map PP.pretty args))  <+> ">"
+    TemplateConst s -> PP.pretty s
+    TemplatePointer s -> PP.pretty s <+> "*"
 
 instance PP.Pretty UntangleErr where
   pretty err = case err of
     MultipleDataTypes specs ->
-      "Multiple data types in" </> PP.prettyList specs
+      PP.vsep ["Multiple data types in", PP.prettyList specs]
     IllegalSpecifiers s specs ->
-      "Illegal specifiers, " <+> PP.text s <+> ", in" </> PP.prettyList specs
+      PP.vsep ["Illegal specifiers," <+> fromString s <> ", in", PP.prettyList specs]
     NoDataTypes specs ->
-      "No data types in " </> PP.prettyList specs
+      PP.vsep ["No data types in", PP.prettyList specs]
 
 instance PP.Pretty i => PP.Pretty (ParameterDeclaration i) where
   pretty = PP.pretty . tangleParameterDeclaration
@@ -504,5 +544,5 @@
 ------------------------------------------------------------------------
 -- Utils
 
-pretty80 :: PP.Doc -> String
-pretty80 x = PP.displayS (PP.renderPretty 0.8 80 x) ""
+pretty80 :: PP.Doc ann -> String
+pretty80 x = PP.renderString $ PP.layoutSmart (PP.LayoutOptions { PP.layoutPageWidth = PP.AvailablePerLine 80 0.8 }) x
diff --git a/src/Language/C/Types/Parse.hs b/src/Language/C/Types/Parse.hs
--- a/src/Language/C/Types/Parse.hs
+++ b/src/Language/C/Types/Parse.hs
@@ -89,6 +89,7 @@
 import           Control.Applicative
 import           Control.Monad (msum, void, MonadPlus, unless, when)
 import           Control.Monad.Reader (MonadReader, runReaderT, ReaderT, asks, ask)
+import           Data.List (intersperse)
 import           Data.Functor.Identity (Identity)
 import qualified Data.HashSet as HashSet
 import           Data.Hashable (Hashable)
@@ -101,8 +102,8 @@
 import           Text.Parser.LookAhead
 import           Text.Parser.Token
 import qualified Text.Parser.Token.Highlight as Highlight
-import           Text.PrettyPrint.ANSI.Leijen (Pretty(..), (<+>), Doc, hsep)
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import           Prettyprinter (Pretty(..), (<+>), Doc, hsep)
+import qualified Prettyprinter as PP
 
 #if __GLASGOW_HASKELL__ < 710
 import           Data.Foldable (Foldable)
@@ -122,36 +123,38 @@
   , cpcParseIdent :: forall m. CParser i m => m i
     -- ^ Parses an identifier, *without consuming whitespace afterwards*.
   , cpcIdentToString :: i -> String
+  , cpcEnableCpp :: Bool
   }
 
 -- | A type for C identifiers.
 newtype CIdentifier = CIdentifier {unCIdentifier :: String}
   deriving (Typeable, Eq, Ord, Show, Hashable)
 
-cIdentifierFromString :: String -> Either String CIdentifier
-cIdentifierFromString s =
+cIdentifierFromString :: Bool -> String -> Either String CIdentifier
+cIdentifierFromString useCpp s =
   -- Note: it's important not to use 'cidentifier_raw' here, otherwise
   -- we go in a loop:
   --
   -- @
   -- cIdentifierFromString => fromString => cIdentifierFromString => ...
   -- @
-  case Parsec.parse (identNoLex cIdentStyle <* eof) "cIdentifierFromString" s of
+  case Parsec.parse (identNoLex useCpp cIdentStyle <* eof) "cIdentifierFromString" s of
     Left err -> Left $ show err
     Right x -> Right $ CIdentifier x
 
 instance IsString CIdentifier where
   fromString s =
-    case cIdentifierFromString s of
+    case cIdentifierFromString True s of
       Left err -> error $ "CIdentifier fromString: invalid string " ++ show s ++ "\n" ++ err
       Right x -> x
 
-cCParserContext :: TypeNames -> CParserContext CIdentifier
-cCParserContext typeNames = CParserContext
+cCParserContext :: Bool -> TypeNames -> CParserContext CIdentifier
+cCParserContext useCpp typeNames = CParserContext
   { cpcTypeNames = typeNames
   , cpcParseIdent = cidentifier_no_lex
   , cpcIdentToString = unCIdentifier
   , cpcIdentName = "C identifier"
+  , cpcEnableCpp = useCpp
   }
 
 ------------------------------------------------------------------------
@@ -175,6 +178,9 @@
   , TokenParsing m
   , LookAheadParsing m
   , MonadReader (CParserContext i) m
+#if (MIN_VERSION_base(4,13,0))
+  , MonadFail m
+#endif
   , Hashable i
   )
 
@@ -209,13 +215,14 @@
 -- | Like 'quickCParser', but uses @'cCParserContext' ('const' 'False')@ as
 -- 'CParserContext'.
 quickCParser_
-  :: String
+  :: Bool
+  -> String
   -- ^ String to parse.
   -> (ReaderT (CParserContext CIdentifier) (Parsec.Parsec String ()) a)
   -- ^ Parser.  Anything with type @forall m. CParser i m => m a@ is a
   -- valid argument.
   -> a
-quickCParser_ = quickCParser (cCParserContext HashSet.empty)
+quickCParser_ useCpp = quickCParser (cCParserContext useCpp HashSet.empty)
 
 cReservedWords :: HashSet.HashSet String
 cReservedWords = HashSet.fromList
@@ -279,6 +286,7 @@
 
 data TypeSpecifier
   = VOID
+  | BOOL
   | CHAR
   | SHORT
   | INT
@@ -290,11 +298,15 @@
   | Struct CIdentifier
   | Enum CIdentifier
   | TypeName CIdentifier
+  | Template CIdentifier [[TypeSpecifier]]
+  | TemplateConst String
+  | TemplatePointer TypeSpecifier
   deriving (Typeable, Eq, Show)
 
 type_specifier :: CParser i m => m TypeSpecifier
 type_specifier = msum
   [ VOID <$ reserve cIdentStyle "void"
+  , BOOL <$ reserve cIdentStyle "bool"
   , CHAR <$ reserve cIdentStyle "char"
   , SHORT <$ reserve cIdentStyle "short"
   , INT <$ reserve cIdentStyle "int"
@@ -305,15 +317,16 @@
   , UNSIGNED <$ reserve cIdentStyle "unsigned"
   , Struct <$> (reserve cIdentStyle "struct" >> cidentifier)
   , Enum <$> (reserve cIdentStyle "enum" >> cidentifier)
+  , template_parser
   , TypeName <$> type_name
   ]
 
 identifier :: CParser i m => m i
 identifier = token identifier_no_lex
 
-isTypeName :: TypeNames -> String -> Bool
-isTypeName typeNames id_ =
-  case cIdentifierFromString id_ of
+isTypeName :: Bool -> TypeNames -> String -> Bool
+isTypeName useCpp typeNames id_ =
+  case cIdentifierFromString useCpp id_ of
     -- If it's not a valid C identifier, then it's definitely not a C type name.
     Left _err -> False
     Right s -> HashSet.member s typeNames
@@ -322,20 +335,21 @@
 identifier_no_lex = try $ do
   ctx <- ask
   id_ <- cpcParseIdent ctx <?> cpcIdentName ctx
-  when (isTypeName (cpcTypeNames ctx) (cpcIdentToString ctx id_)) $
+  when (isTypeName (cpcEnableCpp ctx) (cpcTypeNames ctx) (cpcIdentToString ctx id_)) $
     unexpected $ "type name " ++ cpcIdentToString ctx id_
   return id_
 
 -- | Same as 'cidentifier_no_lex', but does not check that the
 -- identifier is not a type name.
-cidentifier_raw :: (TokenParsing m, Monad m) => m CIdentifier
-cidentifier_raw = identNoLex cIdentStyle
+cidentifier_raw :: (TokenParsing m, Monad m) => Bool -> m CIdentifier
+cidentifier_raw useCpp = identNoLex useCpp cIdentStyle
 
 -- | This parser parses a 'CIdentifier' and nothing else -- it does not consume
 -- trailing spaces and the like.
 cidentifier_no_lex :: CParser i m => m CIdentifier
 cidentifier_no_lex = try $ do
-  s <- cidentifier_raw
+  ctx <- ask
+  s <- cidentifier_raw (cpcEnableCpp ctx)
   typeNames <- asks cpcTypeNames
   when (HashSet.member s typeNames) $
     unexpected $ "type name " ++ unCIdentifier s
@@ -346,12 +360,38 @@
 
 type_name :: CParser i m => m CIdentifier
 type_name = try $ do
-  s <- ident cIdentStyle <?> "type name"
+  ctx <- ask
+  s <- ident' (cpcEnableCpp ctx) cIdentStyle <?> "type name"
   typeNames <- asks cpcTypeNames
   unless (HashSet.member s typeNames) $
     unexpected $ "identifier  " ++ unCIdentifier s
   return s
 
+templateParser :: (Monad m, CharParsing m, CParser i m) => IdentifierStyle m -> m TypeSpecifier
+templateParser s = parse'
+  where
+    parse' = do
+      id' <- cidentParserWithNamespace
+      _ <- string "<"
+      args <- templateArgParser
+      _ <- string ">"
+      return $ Template (CIdentifier id') args
+    cidentParser = ((:) <$> _styleStart s <*> many (_styleLetter s) <?> _styleName s)
+    cidentParserWithNamespace =
+      try (concat <$> sequence [cidentParser, (string "::"), cidentParserWithNamespace]) <|>
+      cidentParser
+    templateArgType = try ((TemplatePointer <$> (type_specifier)) <* (string "*")) <|> try type_specifier <|> (TemplateConst <$> (some $ oneOf ['0'..'9']))
+    templateArgParser' = do
+      t <- some (token templateArgType)
+      _ <- string ","
+      tt <- templateArgParser
+      return $ t:tt
+    templateArgParser =
+      try (templateArgParser') <|> ((:) <$> some (token templateArgType) <*> return [])
+
+template_parser :: CParser i m => m TypeSpecifier
+template_parser = try $ templateParser cIdentStyle <?> "template name"
+
 data TypeQualifier
   = CONST
   | RESTRICT
@@ -491,7 +531,7 @@
 -- Pretty printing
 
 instance Pretty CIdentifier where
-  pretty = PP.text . unCIdentifier
+  pretty = fromString . unCIdentifier
 
 instance Pretty DeclarationSpecifier where
   pretty dspec = case dspec of
@@ -511,6 +551,7 @@
 instance Pretty TypeSpecifier where
   pretty tySpec = case tySpec of
    VOID -> "void"
+   BOOL -> "bool"
    CHAR -> "char"
    SHORT -> "short"
    INT -> "int"
@@ -522,6 +563,13 @@
    Struct x -> "struct" <+> pretty x
    Enum x -> "enum" <+> pretty x
    TypeName x -> pretty x
+   Template x args ->
+     -- This code generates a c++ code of "template-identifier<template-argument1,template-argument2,..>" like "std::vector<int>".
+     -- concat_with_space is used to concat multiple terms like "unsigned int".
+     let concat_with_space = mconcat . (intersperse " ") . (map pretty)
+     in pretty x <+> "<" <+> mconcat (intersperse "," (map concat_with_space args))  <+> ">"
+   TemplateConst x -> pretty x
+   TemplatePointer x -> pretty x <+> "*"
 
 instance Pretty TypeQualifier where
   pretty tyQual = case tyQual of
@@ -538,7 +586,7 @@
     [] -> pretty ddecltor
     _:_ -> prettyPointers ptrs <+> pretty ddecltor
 
-prettyPointers :: [Pointer] -> Doc
+prettyPointers :: [Pointer] -> Doc ann
 prettyPointers [] = ""
 prettyPointers (x : xs) = pretty x <> prettyPointers xs
 
@@ -556,7 +604,7 @@
     Array x -> "[" <> pretty x <> "]"
     Proto x -> "(" <> prettyParams x <> ")"
 
-prettyParams :: (Pretty a) => [a] -> Doc
+prettyParams :: (Pretty a) => [a] -> Doc ann
 prettyParams xs = case xs of
   [] -> ""
   [x] -> pretty x
@@ -743,9 +791,26 @@
 -- Utils
 ------------------------------------------------------------------------
 
-identNoLex :: (TokenParsing m, Monad m, IsString s) => IdentifierStyle m -> m s
-identNoLex s = fmap fromString $ try $ do
-  name <- highlight (_styleHighlight s)
-          ((:) <$> _styleStart s <*> many (_styleLetter s) <?> _styleName s)
+cppIdentParser :: (Monad m, CharParsing m) => Bool -> IdentifierStyle m -> m [Char]
+cppIdentParser useCpp s = cidentParserWithNamespace
+  where
+    cidentParser = ((:) <$> _styleStart s <*> many (_styleLetter s) <?> _styleName s)
+    cidentParserWithNamespace =
+      if useCpp
+      then
+        try (concat <$> sequence [cidentParser, (string "::"), cidentParserWithNamespace]) <|>
+        cidentParser
+      else
+        cidentParser
+
+identNoLex :: (TokenParsing m, Monad m, IsString s) => Bool -> IdentifierStyle m -> m s
+identNoLex useCpp s = fmap fromString $ try $ do
+  name <- highlight (_styleHighlight s) (cppIdentParser useCpp s)
+  when (HashSet.member name (_styleReserved s)) $ unexpected $ "reserved " ++ _styleName s ++ " " ++ show name
+  return name
+
+ident' :: (TokenParsing m, Monad m, IsString s) => Bool -> IdentifierStyle m -> m s
+ident' useCpp s = fmap fromString $ token $ try $ do
+  name <- highlight (_styleHighlight s) (cppIdentParser useCpp s)
   when (HashSet.member name (_styleReserved s)) $ unexpected $ "reserved " ++ _styleName s ++ " " ++ show name
   return name
diff --git a/test/Language/C/Inline/ContextSpec.hs b/test/Language/C/Inline/ContextSpec.hs
--- a/test/Language/C/Inline/ContextSpec.hs
+++ b/test/Language/C/Inline/ContextSpec.hs
@@ -6,10 +6,12 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE DataKinds #-}
 module Language.C.Inline.ContextSpec (spec) where
 
 import           Control.Monad.Trans.Class (lift)
 import           Data.Word
+import qualified Data.Map as Map
 import qualified Test.Hspec as Hspec
 import           Text.Parser.Char
 import           Text.Parser.Combinators
@@ -22,16 +24,27 @@
 #endif
 
 import qualified Language.C.Types as C
+import qualified Language.C.Types.Parse as P
 import           Language.C.Inline.Context
+import GHC.Exts( IsString(..) )
 
+data Vec a
+data Ary a
+
 spec :: Hspec.SpecWith ()
 spec = do
   Hspec.it "converts simple type correctly (1)" $ do
     shouldBeType (cty "int") [t| CInt |]
   Hspec.it "converts simple type correctly (2)" $ do
     shouldBeType (cty "char") [t| CChar |]
+  Hspec.it "converts bool" $ do
+    shouldBeType (cty "bool") [t| CBool |]
   Hspec.it "converts void" $ do
     shouldBeType (cty "void") [t| () |]
+  Hspec.it "converts signed" $ do
+    shouldBeType (cty "signed") [t| CInt |]
+  Hspec.it "converts unsigned" $ do
+    shouldBeType (cty "unsigned") [t| CUInt |]
   Hspec.it "converts standard library types (1)" $ do
     shouldBeType (cty "FILE") [t| CFile |]
   Hspec.it "converts standard library types (2)" $ do
@@ -77,6 +90,16 @@
     shouldBeType
       (cty "char *(*(**foo [])(int x))[]")
       [t| CArray (Ptr (FunPtr (CInt -> IO (Ptr (CArray (Ptr CChar)))))) |]
+  Hspec.it "converts vector" $ do
+    shouldBeType (cty "vector<int>") [t| Vec CInt |]
+  Hspec.it "converts std::vector" $ do
+    shouldBeType (cty "std::vector<int>") [t| Vec CInt |]
+  Hspec.it "converts std::vector*" $ do
+    shouldBeType (cty "std::vector<int>*") [t| Ptr (Vec CInt) |]
+  Hspec.it "converts array" $ do
+    shouldBeType (cty "array<int,10>") [t| Ary '(CInt,10) |]
+  Hspec.it "converts array*" $ do
+    shouldBeType (cty "array<int,10>*") [t| Ptr (Ary '(CInt,10)) |]
   where
     goodConvert cTy = do
       mbHsTy <- TH.runQ $ convertType IO baseTypes cTy
@@ -90,10 +113,14 @@
       x `Hspec.shouldBe` y
 
     assertParse p s =
-      case C.runCParser (C.cCParserContext (typeNamesFromTypesTable baseTypes)) "spec" s (lift spaces *> p <* lift eof) of
+      case C.runCParser (C.cCParserContext True (typeNamesFromTypesTable baseTypes)) "spec" s (lift spaces *> p <* lift eof) of
         Left err -> error $ "Parse error (assertParse): " ++ show err
         Right x -> x
 
     cty s = C.parameterDeclarationType $ assertParse C.parseParameterDeclaration s
 
-    baseTypes = ctxTypesTable baseCtx
+    baseTypes = ctxTypesTable baseCtx `mappend` Map.fromList [
+                 (C.TypeName (fromString "vector" :: P.CIdentifier), [t|Vec|]),
+                 (C.TypeName (fromString "std::vector" :: P.CIdentifier), [t|Vec|]),
+                 (C.TypeName (fromString "array" :: P.CIdentifier), [t|Ary|])
+                 ]
diff --git a/test/Language/C/Inline/ParseSpec.hs b/test/Language/C/Inline/ParseSpec.hs
--- a/test/Language/C/Inline/ParseSpec.hs
+++ b/test/Language/C/Inline/ParseSpec.hs
@@ -41,6 +41,8 @@
       cExp `shouldMatchBody` " (int) ceil(x[a-z0-9_]+ \\+ ((double) y[a-z0-9_]+)) "
     Hspec.it "accepts anti quotes" $ do
       void $ goodParse [r| int { $(int x) } |]
+    Hspec.it "accepts anti quotes with pointer" $ do
+      void $ goodParse [r| int* { $(int* x) } |]
     Hspec.it "rejects if bad braces (1)" $ do
       badParse [r| int x |]
     Hspec.it "rejects if bad braces (2)" $ do
@@ -85,7 +87,7 @@
       -> IO (C.Type C.CIdentifier, [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String)
     strictParse s = do
       let ParseTypedC retType pars body =
-            assertParse haskellCParserContext (parseTypedC (ctxAntiQuoters ctx)) s
+            assertParse (haskellCParserContext True) (parseTypedC True (ctxAntiQuoters ctx)) s
       void $ evaluate $ length $ show (retType, pars, body)
       return (retType, pars, body)
 
@@ -94,7 +96,7 @@
 
     cty :: String -> C.Type C.CIdentifier
     cty s = C.parameterDeclarationType $
-      assertParse C.cCParserContext C.parseParameterDeclaration s
+      assertParse (C.cCParserContext True) C.parseParameterDeclaration s
 
     shouldMatchParameters
       :: [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)]
diff --git a/test/Language/C/Types/ParseSpec.hs b/test/Language/C/Types/ParseSpec.hs
--- a/test/Language/C/Types/ParseSpec.hs
+++ b/test/Language/C/Types/ParseSpec.hs
@@ -11,15 +11,18 @@
 import           Control.Monad.Trans.Class (lift)
 import           Data.Hashable (Hashable)
 import qualified Test.Hspec as Hspec
+import qualified Test.Hspec.QuickCheck
 import qualified Test.QuickCheck as QC
 import           Text.Parser.Char
 import           Text.Parser.Combinators
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import qualified Prettyprinter as PP
+import qualified Prettyprinter.Render.String as PP
 import           Data.Typeable (Typeable)
 import qualified Data.HashSet as HashSet
 import           Data.List (intercalate)
 import           Data.String (fromString)
 import           Data.Maybe (mapMaybe)
+import           Data.List.Split (splitOn)
 
 import           Language.C.Types.Parse
 import qualified Language.C.Types as Types
@@ -28,7 +31,10 @@
 import Prelude -- Fix for 7.10 unused warnings.
 
 spec :: Hspec.SpecWith ()
-spec = do
+-- modifyMaxDiscardRatio:
+--    'isGoodType' and 'isGoodHaskellIdentifierType' usually make it within the
+--    discard ratio of 10, but we increase the ratio to avoid spurious build failures
+spec = Test.Hspec.QuickCheck.modifyMaxDiscardRatio (const 20) $ do
   Hspec.it "parses everything which is pretty-printable (C)" $ do
 #if MIN_VERSION_QuickCheck(2,9,0)
     QC.property $ QC.again $ do -- Work around <https://github.com/nick8325/quickcheck/issues/113>
@@ -38,7 +44,7 @@
       ParameterDeclarationWithTypeNames typeNames ty <-
         arbitraryParameterDeclarationWithTypeNames unCIdentifier
       return $ isGoodType ty QC.==>
-        let ty' = assertParse (cCParserContext typeNames) parameter_declaration (prettyOneLine ty)
+        let ty' = assertParse (cCParserContext True typeNames) parameter_declaration (prettyOneLine (PP.pretty ty))
         in Types.untangleParameterDeclaration ty == Types.untangleParameterDeclaration ty'
   Hspec.it "parses everything which is pretty-printable (Haskell)" $ do
 #if MIN_VERSION_QuickCheck(2,9,0)
@@ -48,8 +54,8 @@
 #endif
       ParameterDeclarationWithTypeNames typeNames ty <-
         arbitraryParameterDeclarationWithTypeNames unHaskellIdentifier
-      return $ isGoodType ty QC.==>
-        let ty' = assertParse (haskellCParserContext typeNames) parameter_declaration (prettyOneLine ty)
+      return $ isGoodHaskellIdentifierType typeNames ty QC.==>
+        let ty' = assertParse (haskellCParserContext True typeNames) parameter_declaration (prettyOneLine (PP.pretty ty))
         in Types.untangleParameterDeclaration ty == Types.untangleParameterDeclaration ty'
 
 ------------------------------------------------------------------------
@@ -60,17 +66,32 @@
   => CParserContext i -> (forall m. CParser i m => m a) -> String -> a
 assertParse ctx p s =
   case runCParser ctx "spec" s (lift spaces *> p <* lift eof) of
-    Left err -> error $ "Parse error (assertParse): " ++ show err
+    Left err -> error $ "Parse error (assertParse): " ++ show err ++ " parsed string " ++ show s ++ " with type names " ++ show (cpcTypeNames ctx)
     Right x -> x
 
-prettyOneLine :: PP.Pretty a => a -> String
-prettyOneLine x = PP.displayS (PP.renderCompact (PP.pretty x)) ""
+prettyOneLine :: PP.Doc ann -> String
+prettyOneLine x = PP.renderString $ PP.layoutCompact x
 
 isGoodType :: ParameterDeclaration i -> Bool
-isGoodType ty = case Types.untangleParameterDeclaration ty of
-  Left _ -> False
-  Right _ -> True
+isGoodType ty =
+  case Types.untangleParameterDeclaration ty of
+    Left{} -> False
+    Right{} -> True
 
+isGoodHaskellIdentifierType :: TypeNames -> ParameterDeclaration HaskellIdentifier -> Bool
+isGoodHaskellIdentifierType typeNames ty0 =
+  case Types.untangleParameterDeclaration ty0 of
+    Left{} -> False
+    Right ty ->
+      case Types.parameterDeclarationId ty of
+        Nothing -> True
+        Just i -> let
+          -- see <https://github.com/fpco/inline-c/pull/97#issuecomment-538648101>
+          leadingSegment : _ = splitOn "." (unHaskellIdentifier i)
+          in case cIdentifierFromString True leadingSegment of
+           Left{} -> True
+           Right seg -> not (seg `HashSet.member` typeNames)
+
 ------------------------------------------------------------------------
 -- Arbitrary
 
@@ -179,7 +200,7 @@
   :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen i
 arbitraryIdentifierFrom ctx = do
   id' <- QC.arbitrary
-  if isTypeName (acTypeNames ctx) (acIdentToString ctx id')
+  if isTypeName True (acTypeNames ctx) (acIdentToString ctx id')
     then arbitraryIdentifierFrom ctx
     else return id'
 
diff --git a/test/tests.hs b/test/tests.hs
--- a/test/tests.hs
+++ b/test/tests.hs
@@ -50,6 +50,7 @@
     Hspec.it "inlineCode" $ do
       let c_add = $(C.inlineCode $ C.Code
             TH.Unsafe                   -- Call safety
+            Nothing
             [t| Int -> Int -> Int |]    -- Call type
             "francescos_add"            -- Call name
             -- C Code
@@ -57,22 +58,28 @@
             False) -- not a function pointer
       c_add 3 4 `Hspec.shouldBe` 7
     Hspec.it "inlineItems" $ do
-      let c_add3 = $(C.inlineItems
-            TH.Unsafe
-            False                       -- not a function pointer
-            Nothing                     -- no postfix
-            [t| CInt -> CInt |]
-            (C.quickCParser_ "int" C.parseType)
-            [("x", C.quickCParser_ "int" C.parseType)]
-            [r| return x + 3; |])
+      let c_add3 = $(do
+            here <- TH.location
+            C.inlineItems
+              TH.Unsafe
+              False                       -- not a function pointer
+              Nothing                     -- no postfix
+              here
+              [t| CInt -> CInt |]
+              (C.quickCParser_ True "int" C.parseType)
+              [("x", C.quickCParser_ True "int" C.parseType)]
+              [r| return x + 3; |])
       c_add3 1 `Hspec.shouldBe` 1 + 3
     Hspec.it "inlineExp" $ do
-      let x = $(C.inlineExp
-            TH.Safe
-            [t| CInt |]
-            (C.quickCParser_ "int" C.parseType)
-            []
-            [r| 1 + 4 |])
+      let x = $(do
+            here <- TH.location
+            C.inlineExp
+              TH.Safe
+              here
+              [t| CInt |]
+              (C.quickCParser_ True "int" C.parseType)
+              []
+              [r| 1 + 4 |])
       x `Hspec.shouldBe` 1 + 4
     Hspec.it "inlineCode" $ do
       francescos_mul 3 4 `Hspec.shouldBe` 12
@@ -216,3 +223,7 @@
         [C.exp| void { $(void (*fp)(int *))($(int *x_ptr)) } |]
         x <- peek x_ptr
         x `Hspec.shouldBe` 42
+    Hspec.it "cpp namespace identifiers" $ do
+      C.cIdentifierFromString True "Test::Test"  `Hspec.shouldBe`  Right "Test::Test"
+    Hspec.it "cpp template identifiers" $ do
+      C.cIdentifierFromString True "std::vector"  `Hspec.shouldBe`  Right "std::vector"
