Implement fallible C++ functions
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 88fc812..e11b2d3 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -134,7 +134,11 @@
             quote!(#ident: #ty)
         }
     });
-    let ret = expand_extern_return_type(&efn.ret, types);
+    let ret = if efn.throws {
+        quote!(-> ::cxx::private::Result)
+    } else {
+        expand_extern_return_type(&efn.ret, types)
+    };
     let mut outparam = None;
     if indirect_return(efn, types) {
         let ret = expand_extern_type(efn.ret.as_ref().unwrap());
@@ -153,7 +157,15 @@
     let doc = &efn.doc;
     let decl = expand_cxx_function_decl(namespace, efn, types);
     let args = &efn.args;
-    let ret = expand_return_type(&efn.ret);
+    let ret = if efn.throws {
+        let ok = match &efn.ret {
+            Some(ret) => quote!(#ret),
+            None => quote!(()),
+        };
+        quote!(-> ::std::result::Result<#ok, ::cxx::Exception>)
+    } else {
+        expand_return_type(&efn.ret)
+    };
     let indirect_return = indirect_return(efn, types);
     let vars = efn.args.iter().map(|arg| {
         let var = &arg.ident;
@@ -192,10 +204,21 @@
         let ret = expand_extern_type(efn.ret.as_ref().unwrap());
         setup.extend(quote! {
             let mut __return = ::std::mem::MaybeUninit::<#ret>::uninit();
-            #local_name(#(#vars,)* __return.as_mut_ptr());
         });
+        if efn.throws {
+            setup.extend(quote! {
+                #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
+            });
+            quote!(::std::result::Result::Ok(__return.assume_init()))
+        } else {
+            setup.extend(quote! {
+                #local_name(#(#vars,)* __return.as_mut_ptr());
+            });
+            quote!(__return.assume_init())
+        }
+    } else if efn.throws {
         quote! {
-            __return.assume_init()
+            #local_name(#(#vars),*).exception()
         }
     } else {
         quote! {