diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
 # inline-c
 
-[![Build Status](https://travis-ci.org/fpco/inline-c.svg)](https://travis-ci.org/fpco/inline-c)
-
 `inline-c` lets you seamlessly call C libraries and embed
 high-performance inline C code in Haskell modules. Haskell and C can
 be freely intermixed in the same source file, and data passed to and
@@ -14,13 +12,13 @@
 bit of extra performance in those rare cases where C still beats
 Haskell.
 
-Build instructions are reserved for the [last section](#how-to-build).
-You'll need to compile the examples below and try them out.
+GHCi support is currently limited to using `-fobject-code`, see
+the [last section](#ghci) for more info.
 
 ## 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:
 
 ```
@@ -50,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
@@ -229,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 *`:
 
@@ -269,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)
 
@@ -302,53 +300,23 @@
 the target C type and the Haskell identifier are mentioned using C
 declaration syntax.
 
-## How to build
-
-Each module that uses at least one of the `inline-c` functions gets a C
-file associated to it, where the filename of said file will be the same
-as the module but with a C extension.  This C file must be built after
-the Haskell code and linked appropriately.
-
-If you use cabal, you **must** manually declare each associated C file in
-the `c-sources` section of the `.cabal` file and you are good.
+## GHCi
 
-For example we might have
+Currently `inline-c` does not work in interpreted mode. However, GHCi
+can still be used using the `-fobject-code` flag. For speed, we
+recommend passing `-fobject-code -O0`, for example
 
 ```
-executable foo
-  main-is:             Main.hs, Foo.hs, Bar.hs
-  hs-source-dirs:      src
-
-  -- IMPORTANT!
-  -- Here the corresponding C sources must be listed for every module
-  -- that uses C code.  In this example, Main.hs and Bar.hs do, but
-  -- Foo.hs does not.
-  c-sources:           src/Main.c, src/Bar.c
-
-  -- These flags will be passed to the C compiler
-  cc-options:          -Wall -O2
-  -- Libraries to link the code with.
-  extra-libraries:     m
-  ...
+stack ghci --ghci-options='-fobject-code -O0'
 ```
 
-Note that currently `cabal repl` is not supported, because the C code is
-not compiled and linked appropriately.  Type-checking will still be
-performed, so `cabal repl` can still be used to develop.
-
-See `sample-cabal-project` for a working example.
-
-If we were to compile the above manually we could do:
+or
 
 ```
-$ ghc -c Main.hs
-$ cc -c Main.c -o Main_c.o
-$ ghc Foo.hs
-$ ghc Bar.hs
-$ cc -c Bar.c -o Bar_c.o
-$ ghc Main.o Foo.o Bar.o Main_c.o Bar_c.o -lm -o Main
+cabal repl --ghc-options='-fobject-code -O0'
 ```
 
 [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/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,28 @@
+- 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
+- 0.6.0.5: Update readme
+- 0.6.0.4: Remove QuickCheck dependency
+- 0.6.0.3: Remove cryptohash dependencies
+- 0.6.0.2: Update haddock
+- 0.6.0.0: Use `addDependentFile` so separate compilation is not needed.
 - 0.5.6.0: Add `ForeignPtr` anti-quoter
 - 0.5.5.9: Make tests work with QuickCheck < 2.9
 - 0.5.5.8: Add workaround for QuickCheck-2.9 bug. See issue #51
diff --git a/examples/gsl-ode.c b/examples/gsl-ode.c
deleted file mode 100644
--- a/examples/gsl-ode.c
+++ /dev/null
@@ -1,50 +0,0 @@
-
-#include <gsl/gsl_errno.h>
-
-#include <gsl/gsl_matrix.h>
-
-#include <gsl/gsl_odeiv2.h>
-
-int inline_c_Main_0_31a6738e02530b20854a5ca8638293b1032edaf3() {
-return ( GSL_SUCCESS );
-}
-
-
-int inline_c_Main_1_a6e274e32d1c2e90339edd389a8b86d3fe8dae07(int (* funIO_inline_c_0)(double t, const double y[], double dydt[], void * params), int dim_c_inline_c_1, double x0_inline_c_2, double xend_inline_c_3, double * fMut_inline_c_4) {
-
-      gsl_odeiv2_system sys = {
-        funIO_inline_c_0,
-        // The ODE to solve, converted to function pointer using the `fun`
-        // anti-quoter
-        NULL,                   // We don't provide a Jacobian
-        dim_c_inline_c_1,           // The dimension
-        NULL                    // We don't need the parameter pointer
-      };
-      // Create the driver, using some sensible values for the stepping
-      // function and the tolerances
-      gsl_odeiv2_driver *d = gsl_odeiv2_driver_alloc_y_new (
-        &sys, gsl_odeiv2_step_rk8pd, 1e-6, 1e-6, 0.0);
-      // Finally, apply the driver.
-      int status = gsl_odeiv2_driver_apply(
-        d, &x0_inline_c_2, xend_inline_c_3, fMut_inline_c_4);
-      // Free the driver
-      gsl_odeiv2_driver_free(d);
-      return status;
-    
-}
-
-
-int inline_c_Main_2_189238c774f5c8439b92bfd53fe3cdd4e56f6e81() {
-return ( GSL_EMAXITER );
-}
-
-
-int inline_c_Main_3_b4b4adc018e7fe003e77992771fc803668198b63() {
-return ( GSL_ENOPROG );
-}
-
-
-int inline_c_Main_4_31a6738e02530b20854a5ca8638293b1032edaf3() {
-return ( GSL_SUCCESS );
-}
-
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,15 +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)
-
-#if __GLASGOW_HASKELL__ < 710
-import           Data.Functor ((<$>))
-#endif
+import           Control.Monad (forM_)
+import           System.IO (withFile, hPutStrLn, IOMode(..))
 
 C.context (C.baseCtx <> C.vecCtx <> C.funCtx)
 
@@ -98,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
@@ -125,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.5.6.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 FP Complete Corporation
+maintainer:          f@mazzo.li
+copyright:           (c) 2015-2016 FP Complete Corporation, (c) 2017-2019 Francesco Mazzoli
 category:            FFI
-tested-with:         GHC == 7.8.4, GHC == 7.10.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,19 +33,14 @@
   other-modules:       Language.C.Inline.FunPtr
   ghc-options:         -Wall
   build-depends:       base >=4.7 && <5
-                     , QuickCheck
-                     , ansi-wl-pprint
-                     , binary
+                     , prettyprinter >=1.7
                      , bytestring
                      , containers
-                     , cryptohash
-                     , directory
-                     , filepath
                      , hashable
                      , mtl
                      , parsec >= 3
                      , parsers
-                     , template-haskell >= 2.9
+                     , template-haskell >= 2.12.0.0
                      , transformers >= 0.1.3.0
                      , unordered-containers
                      , vector
@@ -56,42 +51,42 @@
   type:                exitcode-stdio-1.0
   hs-source-dirs:      test
   main-is:             tests.hs
-  c-sources:           test/tests.c
   other-modules:       Dummy
                      , Language.C.Inline.ContextSpec
                      , Language.C.Inline.ParseSpec
                      , Language.C.Types.ParseSpec
   build-depends:       base >=4 && <5
-                     , ansi-wl-pprint
+                     , QuickCheck
                      , 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
 
 executable gsl-ode
   hs-source-dirs:      examples
   main-is:             gsl-ode.hs
-  c-sources:           examples/gsl-ode.c
   default-language:    Haskell2010
   extra-libraries:     gsl gslcblas m
   ghc-options:         -Wall
+  cc-options:          -Wall -Werror
 
   if flag(gsl-example)
     buildable: True
     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
@@ -19,7 +19,7 @@
 -- @
 
 module Language.C.Inline
-  ( -- * Build process
+  ( -- * GHCi
     -- $building
 
     -- * Contexts
@@ -31,6 +31,10 @@
   , bsCtx
   , context
 
+    -- * Substitution
+  , substitute
+  , getHaskellType
+
     -- * Inline C
     -- $quoting
   , exp
@@ -38,6 +42,7 @@
   , block
   , include
   , verbatim
+  , emitBlock
 
     -- * 'Ptr' utils
   , withPtr
@@ -45,6 +50,8 @@
   , WithPtrs(..)
 
     -- * 'FunPtr' utils
+  , funPtr
+    -- ** 'FunPtr' conversion
     --
     -- Functions to quickly convert from/to 'FunPtr's. They're provided here
     -- since they can be useful to work with Haskell functions in C, and
@@ -81,41 +88,18 @@
 
 -- $building
 --
--- Each module that uses at least one of the TH functions in this module gets
--- a C file associated to it, where the filename of said file will be the same
--- as the module but with a `.c` extension. This C file must be built after the
--- Haskell code and linked appropriately. If you use cabal, all you have to do
--- is declare each associated C file in the @.cabal@ file.
---
--- For example:
+-- 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
 --
 -- @
--- executable foo
---   main-is:             Main.hs, Foo.hs, Bar.hs
---   hs-source-dirs:      src
---   -- Here the corresponding C sources must be listed for every module
---   -- that uses C code.  In this example, Main.hs and Bar.hs do, but
---   -- Foo.hs does not.
---   c-sources:           src\/Main.c, src\/Bar.c
---   -- These flags will be passed to the C compiler
---   cc-options:          -Wall -O2
---   -- Libraries to link the code with.
---   extra-libraries:     -lm
---   ...
+-- stack ghci --ghci-options='-fobject-code -O0'
 -- @
 --
--- Note that currently @cabal repl@ is not supported, because the C code is not
--- compiled and linked appropriately.
---
--- If we were to compile the above manually, we could:
+-- or
 --
 -- @
--- $ ghc -c Main.hs
--- $ cc -c Main.c -o Main_c.o
--- $ ghc Foo.hs
--- $ ghc Bar.hs
--- $ cc -c Bar.c -o Bar_c.o
--- $ ghc Main.o Foo.o Bar.o Main_c.o Bar_c.o -lm -o Main
+-- cabal repl --ghc-options='-fobject-code -O0'
 -- @
 
 ------------------------------------------------------------------------
@@ -237,7 +221,7 @@
 -- corresponding to the current Haskell file. Every inline C expression will result
 -- in a corresponding C function.
 -- For example, if we define @c_cos@
--- as in the example above in @CCos.hs@, we will get a file @CCos.c@ containing
+-- as in the example above in @CCos.hs@, we will get a file containing
 --
 -- @
 -- #include <math.h>
@@ -250,12 +234,7 @@
 -- Every anti-quotation will correspond to an argument in the C function. If the same
 -- Haskell variable is anti-quoted twice, this will result in two arguments.
 --
--- The C function is then invoked from Haskell with the correct arguments passed in.
---
--- == Known issues
---
--- * https://github.com/fpco/inline-c/issues/21
--- * https://github.com/fpco/inline-c/issues/11
+-- The C function is then automatically compiled and invoked from Haskell with the correct arguments passed in.
 
 -- | C expressions.
 exp :: TH.QuasiQuoter
@@ -263,16 +242,56 @@
 
 -- | 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
 
 -- | C code blocks (i.e. statements).
 block :: TH.QuasiQuoter
-block = genericQuote IO $ inlineItems TH.Safe
+block = genericQuote IO $ inlineItems TH.Safe False Nothing
+
+-- | Easily get a 'FunPtr':
+--
+-- @
+-- let fp :: FunPtr (Ptr CInt -> IO ()) = [C.funPtr| void poke42(int *ptr) { *ptr = 42; } |]
+-- @
+--
+-- Especially useful to generate finalizers that require C code.
+--
+-- Most importantly, this allows you to write `Foreign.ForeignPtr.newForeignPtr` invocations conveniently:
+--
+-- @
+-- do
+--   let c_finalizer_funPtr =
+--         [C.funPtr| void myfree(char * ptr) { free(ptr); } |]
+--   fp <- newForeignPtr c_finalizer_funPtr objPtr
+-- @
+--
+-- Using where possible `Foreign.ForeignPtr.newForeignPtr` is superior to
+-- resorting to its delayed-by-a-thread alternative `Foreign.Concurrent.newForeignPtr`
+-- from "Foreign.Concurrent" which takes an @IO ()@ Haskell finaliser action:
+-- With the non-concurrent `newForeignPtr` you can guarantee that the finaliser
+-- will actually be run
+--
+-- * when a GC is executed under memory pressure, because it can point directly
+--   to a C function that doesn't have to run any Haskell code (which is
+--   problematic when you're out of memory)
+-- * when the program terminates (`Foreign.Concurrent.newForeignPtr`'s finaliser
+--   will likely NOT be called if your main thread exits, making your program
+--   e.g. not Valgrind-clean if your finaliser is @free@ or C++'s @delete@).
+--
+-- `funPtr` makes the normal `newForeignPtr` as convenient as its concurrent
+-- counterpart.
+funPtr :: TH.QuasiQuoter
+funPtr = funPtrQuote TH.Unsafe -- doesn't make much sense for this to be "safe", but it'd be good to verify what this means
 
 -- | Emits a CPP include directive for C code associated with the current
 -- module. To avoid having to escape quotes, the function itself adds them when
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
@@ -51,7 +57,6 @@
 import           Data.Coerce
 import           Data.Int (Int8, Int16, Int32, Int64)
 import qualified Data.Map as Map
-import           Data.Monoid ((<>))
 import           Data.Typeable (Typeable)
 import qualified Data.Vector.Storable as V
 import qualified Data.Vector.Storable.Mutable as VM
@@ -61,9 +66,17 @@
 import           Foreign.Ptr (Ptr, FunPtr, freeHaskellFunPtr)
 import           Foreign.Storable (Storable)
 import qualified Language.Haskell.TH as TH
+import qualified Language.Haskell.TH.Syntax as TH
 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
+import           Data.Monoid ((<>))
+#endif
+
 #if __GLASGOW_HASKELL__ < 710
 import           Data.Monoid (Monoid(..))
 import           Data.Traversable (traverse)
@@ -141,29 +154,50 @@
     -- ^ Needed to convert C types to Haskell types.
   , ctxAntiQuoters :: AntiQuoters
     -- ^ Needed to parse and process antiquotations.
-  , ctxFileExtension :: Maybe String
-    -- ^ Will determine the extension of the file containing the inline
-    -- C snippets.
   , ctxOutput :: Maybe (String -> String)
     -- ^ This function is used to post-process the functions generated
     -- from the C snippets.  Currently just used to specify C linkage
     -- 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)
   }
 
+
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup Context where
+  ctx2 <> ctx1 = Context
+    { ctxTypesTable = ctxTypesTable ctx1 <> ctxTypesTable ctx2
+    , 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
+
 instance Monoid Context where
   mempty = Context
     { ctxTypesTable = mempty
     , ctxAntiQuoters = mempty
-    , ctxFileExtension = Nothing
     , ctxOutput = Nothing
+    , ctxForeignSrcLang = Nothing
+    , ctxEnableCpp = False
+    , ctxRawObjectCompile = Nothing
     }
 
+#if !MIN_VERSION_base(4,11,0)
   mappend ctx2 ctx1 = Context
     { ctxTypesTable = ctxTypesTable ctx1 <> ctxTypesTable ctx2
     , ctxAntiQuoters = ctxAntiQuoters ctx1 <> ctxAntiQuoters ctx2
-    , ctxFileExtension = ctxFileExtension ctx1 <|> ctxFileExtension ctx2
     , ctxOutput = ctxOutput ctx1 <|> ctxOutput ctx2
+    , ctxForeignSrcLang = ctxForeignSrcLang ctx1 <|> ctxForeignSrcLang ctx2
+    , ctxEnableCpp = ctxEnableCpp ctx1 || ctxEnableCpp ctx2
+    , ctxRawObjectCompile = ctxRawObjectCompile ctx1 <|> ctxRawObjectCompile ctx2
     }
+#endif
 
 -- | Context useful to work with vanilla C. Used by default.
 --
@@ -183,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 |])
@@ -245,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
@@ -294,7 +350,7 @@
     Just hsType -> return hsType
 
 -- | This 'Context' adds support for 'ForeignPtr' arguments. It adds a unique
--- marshaller called @fptr-ptr@. For example, @$fptr-ptr:$(int *x)@ extracts the
+-- marshaller called @fptr-ptr@. For example, @$fptr-ptr:(int *x)@ extracts the
 -- bare C pointer out of foreign pointer @x@.
 fptrCtx :: Context
 fptrCtx = mempty
@@ -312,7 +368,8 @@
   }
 
 -- | This 'Context' includes a 'AntiQuoter' that removes the need for
--- explicitely creating 'FunPtr's, named @"fun"@.
+-- explicitely creating 'FunPtr's, named @"fun"@ along with one which
+-- allocates new memory which must be manually freed named @"fun-alloc"@.
 --
 -- For example, we can capture function @f@ of type @CInt -> CInt -> IO
 -- CInt@ in C code using @$fun:(int (*f)(int, int))@.
@@ -331,9 +388,15 @@
 -- allocate it and free it manually using 'freeHaskellFunPtr'.
 -- We provide utilities to easily
 -- allocate them (see 'Language.C.Inline.mkFunPtr').
+--
+-- IMPORTANT: When using the @fun-alloc@ anti quoter, one must free the allocated
+-- function pointer. The GHC runtime provides a function to do this,
+-- 'hs_free_fun_ptr' available in the 'HsFFI.h' header.
+
 funCtx :: Context
 funCtx = mempty
-  { ctxAntiQuoters = Map.fromList [("fun", SomeAntiQuoter funPtrAntiQuoter)]
+  { ctxAntiQuoters = Map.fromList [("fun", SomeAntiQuoter funPtrAntiQuoter)
+                                  ,("fun-alloc", SomeAntiQuoter funAllocPtrAntiQuoter)]
   }
 
 funPtrAntiQuoter :: AntiQuoter HaskellIdentifier
@@ -354,6 +417,22 @@
         _ -> fail "The `fun' marshaller captures function pointers only"
   }
 
+funAllocPtrAntiQuoter :: AntiQuoter HaskellIdentifier
+funAllocPtrAntiQuoter = AntiQuoter
+  { aqParser = cDeclAqParser
+  , aqMarshaller = \purity cTypes cTy cId -> do
+      hsTy <- convertType_ "funCtx" purity cTypes cTy
+      hsExp <- getHsVariable "funCtx" cId
+      case hsTy of
+        TH.AppT (TH.ConT n) hsTy' | n == ''FunPtr -> do
+          hsExp' <- [| \cont -> do
+              funPtr <- $(mkFunPtr (return hsTy')) $(return hsExp)
+              cont funPtr
+            |]
+          return (hsTy, hsExp')
+        _ -> fail "The `fun-alloc' marshaller captures function pointers only"
+  }
+
 -- | This 'Context' includes two 'AntiQuoter's that allow to easily use
 -- Haskell vectors in C.
 --
@@ -410,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
@@ -429,11 +509,15 @@
 -- 'BS.ByteString'.  @vec-ptr@ becomes @bs-ptr@, and @vec-len@ becomes
 -- @bs-len@.  You don't need to specify the type of the pointer in
 -- @bs-ptr@, it will always be @char*@.
+--
+-- Moreover, @bs-cstr@ works as @bs-ptr@ but it provides a null-terminated
+-- copy of the given 'BS.ByteString'.
 bsCtx :: Context
 bsCtx = mempty
   { ctxAntiQuoters = Map.fromList
       [ ("bs-ptr", SomeAntiQuoter bsPtrAntiQuoter)
       , ("bs-len", SomeAntiQuoter bsLenAntiQuoter)
+      , ("bs-cstr", SomeAntiQuoter bsCStrAntiQuoter)
       ]
   }
 
@@ -441,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
@@ -458,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
@@ -472,6 +558,25 @@
           fail "impossible: got type different from `long' (bsCtx)"
   }
 
+bsCStrAntiQuoter :: AntiQuoter HaskellIdentifier
+bsCStrAntiQuoter = AntiQuoter
+  { aqParser = do
+      hId <- C.parseIdentifier
+      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
+        C.Ptr _ (C.TypeSpecifier _ (C.Char Nothing)) -> do
+          hsTy <- [t| Ptr CChar |]
+          hsExp <- getHsVariable "bsCtx" cId
+          hsExp' <- [| \cont -> BS.useAsCString $(return hsExp) $ \ptr -> cont ptr  |]
+          return (hsTy, hsExp')
+        _ ->
+          fail "impossible: got type different from `char *' (bsCtx)"
+  }
+
+
 -- Utils
 ------------------------------------------------------------------------
 
@@ -480,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)
 
@@ -491,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
@@ -11,6 +11,9 @@
   , haskellCParserContext
   , parseHaskellIdentifier
   , mangleHaskellIdentifier
+
+    -- * for testing
+  , haskellReservedWords
   ) where
 
 import           Control.Applicative ((<|>))
@@ -23,12 +26,11 @@
 import           Data.String (IsString(..))
 import           Data.Typeable (Typeable)
 import           Numeric (showHex)
-import qualified Test.QuickCheck as QC
 import           Text.Parser.Char (upper, lower, digit, char)
 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
 
@@ -42,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
@@ -119,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
@@ -145,26 +148,3 @@
   when (HashSet.member name (_styleReserved s)) $ unexpected $ "reserved " ++ _styleName s ++ " " ++ show name
   return name
 
--- Arbitrary instance
-------------------------------------------------------------------------
-
-instance QC.Arbitrary HaskellIdentifier where
-  arbitrary = do
-    modIds <- QC.listOf arbitraryModId
-    id_ <- QC.oneof [arbitraryConId, arbitraryVarId]
-    if null modIds && HashSet.member id_ haskellReservedWords
-      then QC.arbitrary
-      else return $ HaskellIdentifier $ intercalate "." $ modIds ++ [id_]
-    where
-      arbitraryModId = arbitraryConId
-
-      arbitraryConId =
-        ((:) <$> QC.elements large <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))
-
-      arbitraryVarId =
-        ((:) <$> QC.elements small <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))
-
-      -- We currently do not generate unicode identifiers.
-      large = ['A'..'Z']
-      small = ['a'..'z'] ++ ['_']
-      digit' = ['0'..'9']
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 #-}
@@ -10,12 +11,18 @@
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE MonoLocalBinds #-}
 
 module Language.C.Inline.Internal
     ( -- * Context handling
       setContext
     , getContext
 
+      -- * Substitution
+    , Substitutions(..)
+    , substitute
+    , getHaskellType
+
       -- * Emitting and invoking C code
       --
       -- | The functions in this section let us access more the C file
@@ -25,6 +32,7 @@
 
       -- ** Emitting C code
     , emitVerbatim
+    , emitBlock
 
       -- ** Inlining C code
       -- $embedding
@@ -44,39 +52,46 @@
     , ParseTypedC(..)
     , parseTypedC
     , runParserInQ
+    , splitTypedC
 
+      -- * Line directives
+    , lineDirective
+    , here
+    , shiftLines
+
       -- * Utility functions for writing quasiquoters
     , genericQuote
+    , funPtrQuote
     ) where
 
 import           Control.Applicative
-import           Control.Exception (catch, throwIO)
-import           Control.Monad (forM, void, msum, unless)
+import           Control.Monad (forM, void, msum)
 import           Control.Monad.State (evalStateT, StateT, get, put)
 import           Control.Monad.Trans.Class (lift)
-import qualified Crypto.Hash as CryptoHash
-import qualified Data.Binary as Binary
 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.Directory (removeFile)
-import           System.FilePath (addExtension, dropExtension)
-import           System.IO.Error (isDoesNotExistError)
-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           System.Environment (getProgName)
+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))
@@ -93,6 +108,7 @@
 data ModuleState = ModuleState
   { msContext :: Context
   , msGeneratedNames :: Int
+  , msFileChunks :: [String]
   } deriving (Typeable)
 
 getModuleState :: TH.Q (Maybe ModuleState)
@@ -143,18 +159,31 @@
   -- 'baseCtx' will be used.
   -> TH.Q Context
 initialiseModuleState mbContext = do
-  mbcFile <- cSourceLoc context
   mbModuleState <- getModuleState
   case mbModuleState of
     Just moduleState -> return (msContext moduleState)
     Nothing -> do
-      -- If the file exists and this is the first time we write
-      -- something from this module (in other words, if we are
-      -- recompiling the module), kill the file first.
-      TH.runIO $ forM_ mbcFile $ \cFile -> removeIfExists cFile
+      -- Add hook to add the file
+      TH.addModFinalizer $ do
+        mbMs <- getModuleState
+        ms <- case mbMs of
+          Nothing -> fail "inline-c: ModuleState not present (initialiseModuleState)"
+          Just ms -> return ms
+        let lang = fromMaybe TH.LangC (ctxForeignSrcLang context)
+            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
+            , msFileChunks = mempty
             }
       putModuleState moduleState
       return context
@@ -170,7 +199,7 @@
 modifyModuleState f = do
   mbModuleState <- getModuleState
   case mbModuleState of
-    Nothing -> fail "inline-c: ModuleState not present"
+    Nothing -> fail "inline-c: ModuleState not present (modifyModuleState)"
     Just ms -> do
       let (ms', x) = f ms
       putModuleState ms'
@@ -202,38 +231,25 @@
 ------------------------------------------------------------------------
 -- Emitting
 
--- | Return the path in which to emit C code. Or 'Nothing' if emitting should be
--- inhibited, say because we're only type checking the module, not emitting code
--- (e.g. with @-fno-code@ or in @haddock@)
-cSourceLoc :: Context -> TH.Q (Maybe FilePath)
-cSourceLoc ctx = do
-    prog <- TH.runIO getProgName
-    -- Hard-code a common case for not generating code.  haddock just
-    -- type-checks, so we do not need to generate the C file again.
-    -- See issue #24.
-    let emitCode = prog /= "haddock"
-    if not emitCode
-      then return Nothing
-      else do
-        thisFile <- TH.loc_filename <$> TH.location
-        let ext = fromMaybe "c" $ ctxFileExtension ctx
-        return $ Just $ dropExtension thisFile `addExtension` ext
-
-removeIfExists :: FilePath -> IO ()
-removeIfExists fileName = removeFile fileName `catch` handleExists
-  where
-    handleExists e = unless (isDoesNotExistError e) $ throwIO e
-
 -- | Simply appends some string to the module's C file.  Use with care.
 emitVerbatim :: String -> TH.DecsQ
 emitVerbatim s = do
-  ctx <- getContext
-  mbCFile <- cSourceLoc ctx
-  case mbCFile of
-    Nothing -> return ()
-    Just cFile -> TH.runIO $ appendFile cFile $ "\n" ++ s ++ "\n"
+  -- Make sure that the 'ModuleState' is initialized
+  void (initialiseModuleState Nothing)
+  let chunk = "\n" ++ s ++ "\n"
+  modifyModuleState $ \ms ->
+    (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
 
@@ -256,12 +272,17 @@
 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
     -- ^ Name of the function to call in the code below.
   , codeDefs :: String
     -- ^ The C code.
+  , codeFunPtr :: Bool
+    -- ^ If 'True', the type will be wrapped in 'FunPtr', and
+    -- the call will be static (e.g. prefixed by &).
   }
 
 -- TODO use the #line CPP macro to have the functions in the C file
@@ -280,63 +301,85 @@
 --
 -- @
 -- 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 <- 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
-  :: String
-  -- ^ Some string identifying the body of the symbol the name will
-  -- refer too -- e.g. the function arguments + body.  This is used to
-  -- generate persistent names: we do not want completely random names
-  -- since this causes issues when cabal builds things repeatedly, for
-  -- example when building with profiling.
-  -> TH.Q String
-uniqueCName x = do
+uniqueCName :: Maybe String -> TH.Q String
+uniqueCName mbPostfix = do
   -- The name looks like this:
-  -- inline_c_MODULE_INDEX_HASH
+  -- inline_c_MODULE_INDEX_POSTFIX
   --
   -- Where:
   --  * MODULE is the module name but with _s instead of .s;
   --  * INDEX is a counter that keeps track of how many names we're generating
-  --    for each module;
-  --  * HASH is the SHA1 hash of the contents.
+  --    for each module.
+  --  * POSTFIX is an optional postfix to ease debuggability
+  --
+  -- we previously also generated a hash from the contents of the
+  -- C code because of problems when cabal recompiled but now this
+  -- is not needed anymore since we use 'addDependentFile' to compile
+  -- the C code.
   c' <- bumpGeneratedNames
-  let unique :: CryptoHash.Digest CryptoHash.SHA1 = CryptoHash.hashlazy $ Binary.encode x
   module_ <- TH.loc_module <$> TH.location
   let replaceDot '.' = '_'
       replaceDot c = c
-  return $ "inline_c_" ++ map replaceDot module_ ++ "_" ++ show c' ++ "_" ++ show unique
+  let postfix = case mbPostfix of
+        Nothing -> ""
+        Just s -> "_" ++ s ++ "_"
+  return $ "inline_c_" ++ map replaceDot module_ ++ "_" ++ show c' ++ postfix
 
 -- | Same as 'inlineCItems', but with a single expression.
 --
 -- @
 -- 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
@@ -346,8 +389,8 @@
   -> String
   -- ^ The C expression
   -> TH.ExpQ
-inlineExp callSafety type_ cRetType cParams cExp =
-  inlineItems callSafety 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 ++ ";"
@@ -359,8 +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)]
@@ -369,6 +417,12 @@
 inlineItems
   :: TH.Safety
   -- ^ Safety of the foreign call
+  -> Bool
+  -- ^ 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
@@ -378,36 +432,40 @@
   -> String
   -- ^ The C items
   -> TH.ExpQ
-inlineItems callSafety 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)
-  funName <- uniqueCName $ show proto ++ cItems
-  cFunName <- case C.cIdentifierFromString funName of
+  ctx <- getContext
+  funName <- uniqueCName mbPostfix
+  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
+    , codeFunPtr = funPtr
     }
 
 ------------------------------------------------------------------------
 -- Parsing
 
 runParserInQ
-  :: String -> C.TypeNames -> (forall m. C.CParser HaskellIdentifier m => m a) -> TH.Q a
-runParserInQ s typeNames' p = do
+  :: (Hashable ident)
+  => String
+  -> C.CParserContext ident
+  -> (forall m. C.CParser ident m => m a) -> TH.Q a
+runParserInQ s ctx p = do
   loc <- TH.location
   let (line, col) = TH.loc_start loc
   let parsecLoc = Parsec.newPos (TH.loc_filename loc) line col
   let p' = lift (Parsec.setPosition parsecLoc) *> p <* lift Parser.eof
-  case C.runCParser (haskellCParserContext typeNames') (TH.loc_filename loc) s p' of
+  case C.runCParser ctx (TH.loc_filename loc) s p' of
     Left err -> do
       -- TODO consider prefixing with "error while parsing C" or similar
       fail $ show err
@@ -441,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
@@ -449,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
@@ -511,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
 
@@ -541,26 +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 (typeNamesFromTypesTable (ctxTypesTable ctx)) $ parseTypedC $ ctxAntiQuoters ctx
-    hsType <- cToHs ctx cType
+      runParserInQ s
+        (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,11 +712,155 @@
         go (paramType : params) = do
           [t| $(return paramType) -> $(go params) |]
 
+
+-- 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
+  , funPtrParameters :: [(C.CIdentifier, C.Type C.CIdentifier)]
+  , funPtrBody :: String
+  , funPtrName :: Maybe String
+  } deriving (Eq, Show)
+
+funPtrQuote :: TH.Safety -> TH.QuasiQuoter
+funPtrQuote callSafety = quoteCode $ \rawCode -> do
+  loc <- TH.location
+  ctx <- getContext
+  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 loc hsFunType funPtrReturnType funPtrParameters funPtrBody
+  where
+    convertCFunSig :: TH.Type -> [TH.Type] -> TH.TypeQ
+    convertCFunSig retType params0 = do
+      go params0
+      where
+        go [] =
+          [t| IO $(return retType) |]
+        go (paramType : params) = do
+          [t| $(return paramType) -> $(go params) |]
+
+    parse :: C.CParser C.CIdentifier m => m FunPtrDecl
+    parse = do
+      -- skip spaces
+      Parser.spaces
+      -- parse a proto
+      C.ParameterDeclaration mbName protoTyp <- C.parseParameterDeclaration
+      case protoTyp of
+        C.Proto retType paramList -> do
+          args <- forM paramList $ \decl -> case C.parameterDeclarationId decl of
+            Nothing -> fail $ pretty80 $
+              "Un-named captured variable in decl" <+> PP.pretty decl
+            Just declId -> return (declId, C.parameterDeclarationType decl)
+          -- get the rest of the body
+          void (Parser.symbolic '{')
+          body <- parseBody
+          return FunPtrDecl
+            { funPtrReturnType = retType
+            , funPtrParameters = args
+            , funPtrBody = body
+            , funPtrName = fmap C.unCIdentifier mbName
+            }
+        _ -> fail $ "Expecting function declaration"
+
+    parseBody :: C.CParser C.CIdentifier m => m String
+    parseBody = do
+      s <- Parser.manyTill Parser.anyChar $
+           Parser.lookAhead (Parser.char '}')
+      s' <- msum
+        [ do Parser.try $ do -- Try because we might fail to parse the 'eof'
+                -- 'symbolic' because we want to consume whitespace
+               void $ Parser.symbolic '}'
+               Parser.eof
+             return ""
+        , do void $ Parser.char '}'
+             s' <- parseBody
+             return ("}" ++ s')
+        ]
+      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.Interruptible
+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,13 +37,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.Unsafe
 
 -- | C code blocks (i.e. statements).
 block :: TH.QuasiQuoter
-block = genericQuote IO $ inlineItems TH.Unsafe
+block = genericQuote IO $ inlineItems TH.Unsafe False Nothing
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,15 +62,23 @@
   ) 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.Monoid ((<>))
+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, (<>))
+#else
+import           Data.Monoid ((<>))
+#endif
+
 #if __GLASGOW_HASKELL__ < 710
 import           Data.Foldable (Foldable)
 import           Data.Functor ((<$>))
@@ -84,6 +93,7 @@
 
 data TypeSpecifier
   = Void
+  | Bool
   | Char (Maybe Sign)
   | Short Sign
   | Int Sign
@@ -95,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
@@ -103,11 +116,19 @@
   , functionSpecifiers :: [P.FunctionSpecifier]
   } deriving (Typeable, Show, Eq)
 
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup Specifiers where
+  Specifiers x1 y1 z1 <> Specifiers x2 y2 z2 =
+    Specifiers (x1 ++ x2) (y1 ++ y2) (z1 ++ z2)
+#endif
+
 instance Monoid Specifiers where
   mempty = Specifiers [] [] []
 
+#if !MIN_VERSION_base(4,11,0)
   mappend (Specifiers x1 y1 z1) (Specifiers x2 y2 z2) =
     Specifiers (x1 ++ x2) (y1 ++ y2) (z1 ++ z2)
+#endif
 
 data Type i
   = TypeSpecifier Specifiers TypeSpecifier
@@ -160,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)
@@ -355,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]
@@ -374,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
@@ -407,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 "
 
@@ -428,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
@@ -445,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
 
@@ -454,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"
@@ -471,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
@@ -491,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
@@ -83,29 +83,27 @@
   , cIdentStart
   , cIdentLetter
   , cReservedWords
-  , ParameterDeclarationWithTypeNames(..)
-  , arbitraryParameterDeclarationWithTypeNames
+  , isTypeName
   ) where
 
 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)
-import           Data.Maybe (mapMaybe)
 import           Data.Monoid ((<>))
 import           Data.String (IsString(..))
 import           Data.Typeable (Typeable)
-import qualified Test.QuickCheck as QC
 import qualified Text.Parsec as Parsec
 import           Text.Parser.Char
 import           Text.Parser.Combinators
 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)
@@ -125,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
   }
 
 ------------------------------------------------------------------------
@@ -178,6 +178,9 @@
   , TokenParsing m
   , LookAheadParsing m
   , MonadReader (CParserContext i) m
+#if (MIN_VERSION_base(4,13,0))
+  , MonadFail m
+#endif
   , Hashable i
   )
 
@@ -212,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
@@ -282,6 +286,7 @@
 
 data TypeSpecifier
   = VOID
+  | BOOL
   | CHAR
   | SHORT
   | INT
@@ -293,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"
@@ -308,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
@@ -325,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
@@ -349,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
@@ -494,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
@@ -514,6 +551,7 @@
 instance Pretty TypeSpecifier where
   pretty tySpec = case tySpec of
    VOID -> "void"
+   BOOL -> "bool"
    CHAR -> "char"
    SHORT -> "short"
    INT -> "int"
@@ -525,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
@@ -541,7 +586,7 @@
     [] -> pretty ddecltor
     _:_ -> prettyPointers ptrs <+> pretty ddecltor
 
-prettyPointers :: [Pointer] -> Doc
+prettyPointers :: [Pointer] -> Doc ann
 prettyPointers [] = ""
 prettyPointers (x : xs) = pretty x <> prettyPointers xs
 
@@ -559,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
@@ -594,178 +639,6 @@
     ArrayOrProtoThere ddecltor' aop -> pretty ddecltor' <> pretty aop
 
 ------------------------------------------------------------------------
--- Arbitrary
-
-data OneOfSized a
-  = Anyhow a
-  | IfPositive a
-  deriving (Typeable, Eq, Show)
-
--- | Precondition: there is at least one 'Anyhow' in the list.
-oneOfSized :: [OneOfSized (QC.Gen a)] -> QC.Gen a
-oneOfSized xs = QC.sized $ \n -> do
-  let f (Anyhow a) = Just a
-      f (IfPositive x) | n > 0 = Just x
-      f (IfPositive _) = Nothing
-  QC.oneof $ mapMaybe f xs
-
-halveSize :: QC.Gen a -> QC.Gen a
-halveSize m = QC.sized $ \n -> QC.resize (n `div` 2) m
-
-instance QC.Arbitrary CIdentifier where
-  arbitrary = do
-    s <- ((:) <$> QC.elements cIdentStart <*> QC.listOf (QC.elements cIdentLetter))
-    if HashSet.member s cReservedWords
-      then QC.arbitrary
-      else return $ CIdentifier s
-
--- | Type used to generate an 'QC.Arbitrary' 'ParameterDeclaration' with
--- arbitrary allowed type names.
-data ParameterDeclarationWithTypeNames i = ParameterDeclarationWithTypeNames
-  { pdwtnTypeNames :: HashSet.HashSet CIdentifier
-  , pdwtnParameterDeclaration :: (ParameterDeclaration i)
-  } deriving (Typeable, Eq, Show)
-
-data (QC.Arbitrary i) => ArbitraryContext i = ArbitraryContext
-  { acTypeNames :: TypeNames
-  , acIdentToString :: i -> String
-  }
-
-arbitraryParameterDeclarationWithTypeNames
-  :: (QC.Arbitrary i, Hashable i)
-  => (i -> String)
-  -> QC.Gen (ParameterDeclarationWithTypeNames i)
-arbitraryParameterDeclarationWithTypeNames identToString = do
-    names <- HashSet.fromList <$> QC.listOf QC.arbitrary
-    let ctx = ArbitraryContext names identToString
-    decl <- arbitraryParameterDeclarationFrom ctx
-    return $ ParameterDeclarationWithTypeNames names decl
-
-arbitraryDeclarationSpecifierFrom
-  :: (QC.Arbitrary i, Hashable i) => ArbitraryContext i -> QC.Gen DeclarationSpecifier
-arbitraryDeclarationSpecifierFrom typeNames = QC.oneof $
-  [ StorageClassSpecifier <$> QC.arbitrary
-  , TypeQualifier <$> QC.arbitrary
-  , FunctionSpecifier <$> QC.arbitrary
-  , TypeSpecifier <$> arbitraryTypeSpecifierFrom typeNames
-  ]
-
-instance QC.Arbitrary StorageClassSpecifier where
-  arbitrary = QC.oneof
-    [ return TYPEDEF
-    , return EXTERN
-    , return STATIC
-    , return AUTO
-    , return REGISTER
-    ]
-
-arbitraryTypeSpecifierFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen TypeSpecifier
-arbitraryTypeSpecifierFrom ctx = QC.oneof $
-  [ return VOID
-  , return CHAR
-  , return SHORT
-  , return INT
-  , return LONG
-  , return FLOAT
-  , return DOUBLE
-  , return SIGNED
-  , return UNSIGNED
-  , Struct <$> arbitraryCIdentifierFrom ctx
-  , Enum <$> arbitraryCIdentifierFrom ctx
-  ] ++ if HashSet.null (acTypeNames ctx) then []
-       else [TypeName <$> QC.elements (HashSet.toList (acTypeNames ctx))]
-
-instance QC.Arbitrary TypeQualifier where
-  arbitrary = QC.oneof
-    [ return CONST
-    , return RESTRICT
-    , return VOLATILE
-    ]
-
-instance QC.Arbitrary FunctionSpecifier where
-  arbitrary = QC.oneof
-    [ return INLINE
-    ]
-
-arbitraryDeclaratorFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (Declarator i)
-arbitraryDeclaratorFrom typeNames = halveSize $
-  Declarator <$> QC.arbitrary <*> arbitraryDirectDeclaratorFrom typeNames
-
-arbitraryCIdentifierFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen CIdentifier
-arbitraryCIdentifierFrom ctx =
-  arbitraryIdentifierFrom ctx{acIdentToString = unCIdentifier}
-
-arbitraryIdentifierFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen i
-arbitraryIdentifierFrom ctx = do
-  id' <- QC.arbitrary
-  if isTypeName (acTypeNames ctx) (acIdentToString ctx id')
-    then arbitraryIdentifierFrom ctx
-    else return id'
-
-arbitraryDirectDeclaratorFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectDeclarator i)
-arbitraryDirectDeclaratorFrom typeNames = halveSize $ oneOfSized $
-  [ Anyhow $ DeclaratorRoot <$> arbitraryIdentifierFrom typeNames
-  , IfPositive $ DeclaratorParens <$> arbitraryDeclaratorFrom typeNames
-  , IfPositive $ ArrayOrProto
-      <$> arbitraryDirectDeclaratorFrom typeNames
-      <*> arbitraryArrayOrProtoFrom typeNames
-  ]
-
-arbitraryArrayOrProtoFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayOrProto i)
-arbitraryArrayOrProtoFrom typeNames = halveSize $ oneOfSized $
-  [ Anyhow $ Array <$> arbitraryArrayTypeFrom typeNames
-  , IfPositive $ Proto <$> QC.listOf (arbitraryParameterDeclarationFrom typeNames)
-  ]
-
-arbitraryArrayTypeFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayType i)
-arbitraryArrayTypeFrom typeNames = QC.oneof
-  [ return VariablySized
-  , SizedByInteger . QC.getNonNegative <$> QC.arbitrary
-  , SizedByIdentifier <$> arbitraryIdentifierFrom typeNames
-  , return Unsized
-  ]
-
-instance QC.Arbitrary Pointer where
-  arbitrary = Pointer <$> QC.arbitrary
-
-arbitraryParameterDeclarationFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ParameterDeclaration i)
-arbitraryParameterDeclarationFrom typeNames = halveSize $
-  ParameterDeclaration
-    <$> QC.listOf1 (arbitraryDeclarationSpecifierFrom typeNames)
-    <*> QC.oneof
-          [ IsDeclarator <$> arbitraryDeclaratorFrom typeNames
-          , IsAbstractDeclarator <$> arbitraryAbstractDeclaratorFrom typeNames
-          ]
-
-arbitraryAbstractDeclaratorFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (AbstractDeclarator i)
-arbitraryAbstractDeclaratorFrom typeNames = halveSize $ do
-  ptrs <- QC.arbitrary
-  decl <- if null ptrs
-    then Just <$> arbitraryDirectAbstractDeclaratorFrom typeNames
-    else oneOfSized
-      [ Anyhow $ return Nothing
-      , IfPositive $ Just <$> arbitraryDirectAbstractDeclaratorFrom typeNames
-      ]
-  return $ AbstractDeclarator ptrs decl
-
-arbitraryDirectAbstractDeclaratorFrom
-  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectAbstractDeclarator i)
-arbitraryDirectAbstractDeclaratorFrom typeNames = halveSize $ oneOfSized $
-  [ Anyhow $ ArrayOrProtoHere <$> arbitraryArrayOrProtoFrom typeNames
-  , IfPositive $ AbstractDeclaratorParens <$> arbitraryAbstractDeclaratorFrom typeNames
-  , IfPositive $ ArrayOrProtoThere
-      <$> arbitraryDirectAbstractDeclaratorFrom typeNames
-      <*> arbitraryArrayOrProtoFrom typeNames
-  ]
-
-------------------------------------------------------------------------
 -- Utils
 
 many1 :: CParser i m => m a -> m [a]
@@ -918,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
@@ -4,17 +4,25 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE CPP #-}
-
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 module Language.C.Types.ParseSpec (spec) where
 
 import           Control.Applicative
 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
@@ -23,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>
@@ -33,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)
@@ -43,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'
 
 ------------------------------------------------------------------------
@@ -55,13 +66,221 @@
   => 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
+
+data OneOfSized a
+  = Anyhow a
+  | IfPositive a
+  deriving (Typeable, Eq, Show)
+
+-- | Precondition: there is at least one 'Anyhow' in the list.
+oneOfSized :: [OneOfSized (QC.Gen a)] -> QC.Gen a
+oneOfSized xs = QC.sized $ \n -> do
+  let f (Anyhow a) = Just a
+      f (IfPositive x) | n > 0 = Just x
+      f (IfPositive _) = Nothing
+  QC.oneof $ mapMaybe f xs
+
+halveSize :: QC.Gen a -> QC.Gen a
+halveSize m = QC.sized $ \n -> QC.resize (n `div` 2) m
+
+instance QC.Arbitrary CIdentifier where
+  arbitrary = do
+    s <- ((:) <$> QC.elements cIdentStart <*> QC.listOf (QC.elements cIdentLetter))
+    if HashSet.member s cReservedWords
+      then QC.arbitrary
+      else return $ fromString s
+
+-- | Type used to generate an 'QC.Arbitrary' 'ParameterDeclaration' with
+-- arbitrary allowed type names.
+data ParameterDeclarationWithTypeNames i = ParameterDeclarationWithTypeNames
+  { _pdwtnTypeNames :: HashSet.HashSet CIdentifier
+  , _pdwtnParameterDeclaration :: (ParameterDeclaration i)
+  } deriving (Typeable, Eq, Show)
+
+data ArbitraryContext i = ArbitraryContext
+  { acTypeNames :: TypeNames
+  , acIdentToString :: i -> String
+  }
+
+arbitraryParameterDeclarationWithTypeNames
+  :: (QC.Arbitrary i, Hashable i)
+  => (i -> String)
+  -> QC.Gen (ParameterDeclarationWithTypeNames i)
+arbitraryParameterDeclarationWithTypeNames identToString = do
+    names <- HashSet.fromList <$> QC.listOf QC.arbitrary
+    let ctx = ArbitraryContext names identToString
+    decl <- arbitraryParameterDeclarationFrom ctx
+    return $ ParameterDeclarationWithTypeNames names decl
+
+arbitraryDeclarationSpecifierFrom
+  :: (QC.Arbitrary i, Hashable i) => ArbitraryContext i -> QC.Gen DeclarationSpecifier
+arbitraryDeclarationSpecifierFrom typeNames = QC.oneof $
+  [ StorageClassSpecifier <$> QC.arbitrary
+  , TypeQualifier <$> QC.arbitrary
+  , FunctionSpecifier <$> QC.arbitrary
+  , TypeSpecifier <$> arbitraryTypeSpecifierFrom typeNames
+  ]
+
+instance QC.Arbitrary StorageClassSpecifier where
+  arbitrary = QC.oneof
+    [ return TYPEDEF
+    , return EXTERN
+    , return STATIC
+    , return AUTO
+    , return REGISTER
+    ]
+
+arbitraryTypeSpecifierFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen TypeSpecifier
+arbitraryTypeSpecifierFrom ctx = QC.oneof $
+  [ return VOID
+  , return CHAR
+  , return SHORT
+  , return INT
+  , return LONG
+  , return FLOAT
+  , return DOUBLE
+  , return SIGNED
+  , return UNSIGNED
+  , Struct <$> arbitraryCIdentifierFrom ctx
+  , Enum <$> arbitraryCIdentifierFrom ctx
+  ] ++ if HashSet.null (acTypeNames ctx) then []
+       else [TypeName <$> QC.elements (HashSet.toList (acTypeNames ctx))]
+
+instance QC.Arbitrary TypeQualifier where
+  arbitrary = QC.oneof
+    [ return CONST
+    , return RESTRICT
+    , return VOLATILE
+    ]
+
+instance QC.Arbitrary FunctionSpecifier where
+  arbitrary = QC.oneof
+    [ return INLINE
+    ]
+
+arbitraryDeclaratorFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (Declarator i)
+arbitraryDeclaratorFrom typeNames = halveSize $
+  Declarator <$> QC.arbitrary <*> arbitraryDirectDeclaratorFrom typeNames
+
+arbitraryCIdentifierFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen CIdentifier
+arbitraryCIdentifierFrom ctx =
+  arbitraryIdentifierFrom ctx{acIdentToString = unCIdentifier}
+
+arbitraryIdentifierFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen i
+arbitraryIdentifierFrom ctx = do
+  id' <- QC.arbitrary
+  if isTypeName True (acTypeNames ctx) (acIdentToString ctx id')
+    then arbitraryIdentifierFrom ctx
+    else return id'
+
+arbitraryDirectDeclaratorFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectDeclarator i)
+arbitraryDirectDeclaratorFrom typeNames = halveSize $ oneOfSized $
+  [ Anyhow $ DeclaratorRoot <$> arbitraryIdentifierFrom typeNames
+  , IfPositive $ DeclaratorParens <$> arbitraryDeclaratorFrom typeNames
+  , IfPositive $ ArrayOrProto
+      <$> arbitraryDirectDeclaratorFrom typeNames
+      <*> arbitraryArrayOrProtoFrom typeNames
+  ]
+
+arbitraryArrayOrProtoFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayOrProto i)
+arbitraryArrayOrProtoFrom typeNames = halveSize $ oneOfSized $
+  [ Anyhow $ Array <$> arbitraryArrayTypeFrom typeNames
+  , IfPositive $ Proto <$> QC.listOf (arbitraryParameterDeclarationFrom typeNames)
+  ]
+
+arbitraryArrayTypeFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayType i)
+arbitraryArrayTypeFrom typeNames = QC.oneof
+  [ return VariablySized
+  , SizedByInteger . QC.getNonNegative <$> QC.arbitrary
+  , SizedByIdentifier <$> arbitraryIdentifierFrom typeNames
+  , return Unsized
+  ]
+
+instance QC.Arbitrary Pointer where
+  arbitrary = Pointer <$> QC.arbitrary
+
+arbitraryParameterDeclarationFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ParameterDeclaration i)
+arbitraryParameterDeclarationFrom typeNames = halveSize $
+  ParameterDeclaration
+    <$> QC.listOf1 (arbitraryDeclarationSpecifierFrom typeNames)
+    <*> QC.oneof
+          [ IsDeclarator <$> arbitraryDeclaratorFrom typeNames
+          , IsAbstractDeclarator <$> arbitraryAbstractDeclaratorFrom typeNames
+          ]
+
+arbitraryAbstractDeclaratorFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (AbstractDeclarator i)
+arbitraryAbstractDeclaratorFrom typeNames = halveSize $ do
+  ptrs <- QC.arbitrary
+  decl <- if null ptrs
+    then Just <$> arbitraryDirectAbstractDeclaratorFrom typeNames
+    else oneOfSized
+      [ Anyhow $ return Nothing
+      , IfPositive $ Just <$> arbitraryDirectAbstractDeclaratorFrom typeNames
+      ]
+  return $ AbstractDeclarator ptrs decl
+
+arbitraryDirectAbstractDeclaratorFrom
+  :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectAbstractDeclarator i)
+arbitraryDirectAbstractDeclaratorFrom typeNames = halveSize $ oneOfSized $
+  [ Anyhow $ ArrayOrProtoHere <$> arbitraryArrayOrProtoFrom typeNames
+  , IfPositive $ AbstractDeclaratorParens <$> arbitraryAbstractDeclaratorFrom typeNames
+  , IfPositive $ ArrayOrProtoThere
+      <$> arbitraryDirectAbstractDeclaratorFrom typeNames
+      <*> arbitraryArrayOrProtoFrom typeNames
+  ]
+
+instance QC.Arbitrary HaskellIdentifier where
+  arbitrary = do
+    modIds <- QC.listOf arbitraryModId
+    id_ <- QC.oneof [arbitraryConId, arbitraryVarId]
+    if HashSet.member id_ haskellReservedWords
+      then QC.arbitrary
+      else return $ fromString $ intercalate "." $ modIds ++ [id_]
+    where
+      arbitraryModId = arbitraryConId
+
+      arbitraryConId =
+        ((:) <$> QC.elements large <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))
+
+      arbitraryVarId =
+        ((:) <$> QC.elements small <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))
+
+      -- We currently do not generate unicode identifiers.
+      large = ['A'..'Z']
+      small = ['a'..'z'] ++ ['_']
+      digit' = ['0'..'9']
diff --git a/test/tests.c b/test/tests.c
deleted file mode 100644
--- a/test/tests.c
+++ /dev/null
@@ -1,152 +0,0 @@
-
-#include <math.h>
-
-#include <stddef.h>
-
-#include <stdint.h>
-
-#include <stdio.h>
-
-
-int francescos_mul(int x, int y) {
-  return x * y;
-}
-
-
- int francescos_add(int x, int y) { int z = x + y; return z; } 
-
-int inline_c_Main_0_23225c6b2d15328585f210dc2f989269e95d08ee(int x) {
- return x + 3; 
-}
-
-
-int inline_c_Main_1_7ac34f446e8519c3b967b9fafdc79c95552f35e4() {
-return ( 1 + 4 );
-}
-
-
-int inline_c_Main_2_5fdbbe6da0475522165cd251c48497d38f4710fb(int x_inline_c_0, int y_inline_c_1) {
-return ( x_inline_c_0 + y_inline_c_1 + 5 );
-}
-
-
-int inline_c_Main_3_856f16273cbef2af269b645953d316cb9426784c(int x_inline_c_0, int y_inline_c_1) {
-return ( x_inline_c_0 + 10 + y_inline_c_1 );
-}
-
-
-int inline_c_Main_4_f58397f6204cd35d25406cea930cdd76127e7a8d(int x_inline_c_0, int y_inline_c_1) {
-return ( 7 + x_inline_c_0 + y_inline_c_1 );
-}
-
-
-int inline_c_Main_5_f58397f6204cd35d25406cea930cdd76127e7a8d(int x_inline_c_0, int y_inline_c_1) {
-return ( 7 + x_inline_c_0 + y_inline_c_1 );
-}
-
-
-void inline_c_Main_6_bbad659b194c6226bc20ec8262bc1c599dddeb28() {
- printf("Hello\n") ;
-}
-
-
-ptrdiff_t inline_c_Main_7_4475cd73db749194709e394483ff3e5205688ff8(ptrdiff_t x_inline_c_0) {
- char a[2]; return &a[1] - &a[0] + x_inline_c_0; 
-}
-
-
-size_t inline_c_Main_8_9782c357435fb488c3166bf10e839da13328001e() {
-return ( sizeof (char) );
-}
-
-
-uintmax_t inline_c_Main_9_c0df91f70bbf1f85671339d1bdc524414e112cc2() {
-return ( UINTMAX_MAX );
-}
-
-
-int16_t inline_c_Main_10_9e29ba00e56a81c765067e09a3136fa5232d49a0(int16_t x_inline_c_0) {
-return ( 1 + x_inline_c_0 );
-}
-
-
-uint32_t inline_c_Main_11_08a42fa8f755a36db897898b73bb7aab5b1b58e1(uint32_t y_inline_c_0) {
-return ( y_inline_c_0 * 7 );
-}
-
-
-int inline_c_Main_12_4ffe4d055df0966eedc85f08247aa8880402694a(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {
-return ( ackermannPtr_inline_c_0(x_inline_c_1, y_inline_c_2) );
-}
-
-
-int (* inline_c_Main_13_7e6957a671db751a0a5b5e9721b3c45002fab68f())(int , int ) {
-return ( &francescos_add );
-}
-
-
-int inline_c_Main_14_55555bbb777d25d03fef0a6d6ce9193474a74a35(int (* ackermann__inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {
-return ( ackermann__inline_c_0(x_inline_c_1, y_inline_c_2) );
-}
-
-
-int inline_c_Main_15_4ffe4d055df0966eedc85f08247aa8880402694a(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {
-return ( ackermannPtr_inline_c_0(x_inline_c_1, y_inline_c_2) );
-}
-
-
-int inline_c_Main_16_b7d965842e65c49fcc08b03f70454988290e61e4(int (* ackermann_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {
-return ( ackermann_inline_c_0(x_inline_c_1, y_inline_c_2) );
-}
-
-
-double inline_c_Main_17_5dce1654ef6186acdb189a6ce36f0a66660eb346(double (* fun_inline_c_0)(double )) {
-return ( fun_inline_c_0(3.0) );
-}
-
-
-int inline_c_Main_18_8d0f093895f51773152915c33b75c7aafd8f4f45(int n_inline_c_0, int * ptr_inline_c_1) {
-
-        int i;
-        int x = 0;
-        for (i = 0; i < n_inline_c_0; i++) {
-          x += ptr_inline_c_1[i];
-        }
-        return x;
-      
-}
-
-
-int inline_c_Main_19_62ce8aade5e693f134c6a5c9add3523edab1a63e(long vec_inline_c_0, int * vec_inline_c_1) {
-
-        int i;
-        int x = 0;
-        for (i = 0; i < vec_inline_c_0; i++) {
-          x += vec_inline_c_1[i];
-        }
-        return x;
-      
-}
-
-
-int inline_c_Main_20_75f1401fb8545756b6d329a5352a252bf52db946(long bs_inline_c_0, char * bs_inline_c_1) {
-
-          int i, bits = 0;
-          for (i = 0; i < bs_inline_c_0; i++) {
-            char ch = bs_inline_c_1[i];
-            bits += (ch * 01001001001ULL & 042104210421ULL) % 017;
-          }
-          return bits;
-        
-}
-
-
-int inline_c_Main_21_6fa3d382d3ab7f6d57eec7fbfe64e87fbc2a0ca9(int x_27_inline_c_0) {
-return ( x_27_inline_c_0 );
-}
-
-
-int inline_c_Main_22_a3bae806835fddf243d045e57f2ba979bc7961cc(int foobar_inline_c_0) {
-return ( foobar_inline_c_0 );
-}
-
diff --git a/test/tests.hs b/test/tests.hs
--- a/test/tests.hs
+++ b/test/tests.hs
@@ -12,6 +12,8 @@
 import           Prelude
 import qualified Test.Hspec as Hspec
 import           Text.RawString.QQ (r)
+import           Foreign.Marshal.Alloc (alloca)
+import           Foreign.Storable (peek, poke)
 
 import qualified Language.C.Inline as C
 import qualified Language.C.Inline.Unsafe as CU
@@ -48,26 +50,36 @@
     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
-            [r| int francescos_add(int x, int y) { int z = x + y; return z; } |])
+            [r| int francescos_add(int x, int y) { int z = x + y; return z; } |]
+            False) -- not a function pointer
       c_add 3 4 `Hspec.shouldBe` 7
     Hspec.it "inlineItems" $ do
-      let c_add3 = $(C.inlineItems
-            TH.Unsafe
-            [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
@@ -204,3 +216,14 @@
       let ä = 3
       void $ [C.exp| int { $(int ä) } |]
       void $ [C.exp| int { $(int Prelude.maxBound) } |]
+    Hspec.it "Function pointers" $ do
+      alloca $ \x_ptr -> do
+        poke x_ptr 7
+        let fp = [C.funPtr| void poke42(int *ptr) { *ptr = 42; } |]
+        [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"
