diff --git a/inline-c-cpp.cabal b/inline-c-cpp.cabal
--- a/inline-c-cpp.cabal
+++ b/inline-c-cpp.cabal
@@ -1,5 +1,5 @@
 name:                inline-c-cpp
-version:             0.2.0.2
+version:             0.2.1.0
 synopsis:            Lets you embed C++ code into Haskell.
 description:         Utilities to inline C++ code into Haskell using inline-c.  See
                      tests for example on how to build.
@@ -19,10 +19,12 @@
 
 library
   exposed-modules:     Language.C.Inline.Cpp
+                       Language.C.Inline.Cpp.Exceptions
   ghc-options:         -Wall
   build-depends:       base >=4.7 && <5
                      , inline-c >= 0.6.0.0
                      , template-haskell
+                     , safe-exceptions
   hs-source-dirs:      src
   default-language:    Haskell2010
 
@@ -31,6 +33,9 @@
   hs-source-dirs:      test
   main-is:             tests.hs
   build-depends:       base >=4 && <5
+                     , inline-c
                      , inline-c-cpp
+                     , safe-exceptions
+                     , hspec
   default-language:    Haskell2010
   extra-libraries:     stdc++
diff --git a/src/Language/C/Inline/Cpp/Exceptions.hs b/src/Language/C/Inline/Cpp/Exceptions.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/C/Inline/Cpp/Exceptions.hs
@@ -0,0 +1,88 @@
+-- | A module that contains exception-safe equivalents of @inline-c@ QuasiQuoters.
+
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE PatternSynonyms #-}
+
+module Language.C.Inline.Cpp.Exceptions
+  ( CppException(..)
+  , catchBlock
+  ) where
+
+import           Control.Exception.Safe
+import qualified Language.C.Inline as C
+import           Language.Haskell.TH
+import           Language.Haskell.TH.Quote
+import           Foreign
+import           Foreign.C
+
+-- | An exception thrown in C++ code.
+data CppException
+  = CppStdException String
+  | CppOtherException
+  deriving (Eq, Ord, Show)
+
+instance Exception CppException
+
+-- NOTE: Other C++ exception types (std::runtime_error etc) could be distinguished like this in the future.
+pattern ExTypeNoException :: CInt
+pattern ExTypeNoException = 0
+
+pattern ExTypeStdException :: CInt
+pattern ExTypeStdException = 1
+
+pattern ExTypeOtherException :: CInt
+pattern ExTypeOtherException = 2
+
+handleForeign :: (Ptr CInt -> Ptr CString -> IO ()) -> IO ()
+handleForeign cont =
+  alloca $ \exTypePtr ->
+  alloca $ \msgPtrPtr -> do
+    poke exTypePtr ExTypeNoException
+    cont exTypePtr msgPtrPtr `finally` do
+      exType <- peek exTypePtr
+      case exType of
+        ExTypeNoException -> return ()
+        ExTypeStdException -> do
+          msgPtr <- peek msgPtrPtr
+          errMsg <- peekCString msgPtr
+          free msgPtr
+          throwM $ CppStdException errMsg
+        ExTypeOtherException ->
+          throwM CppOtherException
+        _ -> error "Unexpected C++ exception type."
+
+-- | Similar to `C.block`, but C++ exceptions will be caught and rethrown as `ForeignException`s.
+-- Unlike `C.block`, the return type can only be @void@ (and doesn't need to be specified), but you can use `C.withPtr_` to extract a result yourself.
+--
+-- Using this will automatically include @exception@, @cstring@ and @cstdlib@.
+catchBlock :: QuasiQuoter
+catchBlock = QuasiQuoter
+  { quoteExp = \blockStr -> do
+      _ <- C.include "<exception>"
+      _ <- C.include "<cstring>"
+      _ <- C.include "<cstdlib>"
+      typePtrVarName <- newName "exTypePtr"
+      msgPtrVarName <- newName "msgPtr"
+      let inlineCStr = unlines
+            [ "void {"
+            , "  int* __inline_c_cpp_exception_type__ = $(int* " ++ nameBase typePtrVarName ++ ");"
+            , "  char** __inline_c_cpp_error_message__ = $(char** " ++ nameBase msgPtrVarName ++ ");"
+            , "  try {"
+            , blockStr
+            , "  } catch (std::exception &e) {"
+            , "    *__inline_c_cpp_exception_type__ = " ++ show ExTypeStdException ++ ";"
+            , "    size_t whatLen = std::strlen(e.what()) + 1;"
+            , "    *__inline_c_cpp_error_message__ = static_cast<char*>(std::malloc(whatLen));"
+            , "    std::memcpy(*__inline_c_cpp_error_message__, e.what(), whatLen);"
+            , "  } catch (...) {"
+            , "    *__inline_c_cpp_exception_type__ = " ++ show ExTypeOtherException ++ ";"
+            , "  }"
+            , "}"
+            ]
+      [e| handleForeign $ \ $(varP typePtrVarName) $(varP msgPtrVarName) -> $(quoteExp C.block inlineCStr) |]
+
+  , quotePat = unsupported
+  , quoteType = unsupported
+  , quoteDec = unsupported
+  } where
+      unsupported _ = fail "Unsupported quasiquotation."
diff --git a/test/tests.hs b/test/tests.hs
--- a/test/tests.hs
+++ b/test/tests.hs
@@ -1,15 +1,45 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+import           Control.Exception.Safe
+import           Control.Monad
 import qualified Language.C.Inline.Cpp as C
+import qualified Language.C.Inline.Cpp.Exceptions as C
+import qualified Test.Hspec as Hspec
 
 C.context C.cppCtx
 
 C.include "<iostream>"
+C.include "<stdexcept>"
 
 main :: IO ()
-main = do
-  let x = 3
-  [C.block| void {
-      std::cout << "Hello, world!" << $(int x) << std::endl;
-    } |]
+main = Hspec.hspec $ do
+  Hspec.describe "Basic C++" $ do
+    Hspec.it "Hello World" $ do
+      let x = 3
+      [C.block| void {
+          std::cout << "Hello, world!" << $(int x) << std::endl;
+        } |]
+
+  Hspec.describe "Exception handling" $ do
+    Hspec.it "std::exceptions are caught" $ do
+      result <- try [C.catchBlock|
+        throw std::runtime_error("C++ error message");
+        |]
+
+      result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")
+
+    Hspec.it "non-exceptions are caught" $ do
+      result <- try [C.catchBlock|
+        throw 0xDEADBEEF;
+        |]
+
+      result `Hspec.shouldBe` Left C.CppOtherException
+
+    Hspec.it "code without exceptions works normally" $ do
+      result :: Either C.CppException C.CInt <- try $ C.withPtr_ $ \resPtr -> [C.catchBlock|
+          *$(int* resPtr) = 0xDEADBEEF;
+        |]
+
+      result `Hspec.shouldBe` Right 0xDEADBEEF
