Allow lifetime in extern fn signature
diff --git a/syntax/check.rs b/syntax/check.rs
index 7e368f4..9aaf738 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -147,10 +147,6 @@
 }
 
 fn check_type_ref(cx: &mut Check, ty: &Ref) {
-    if ty.lifetime.is_some() {
-        cx.error(ty, "references with explicit lifetimes are not supported");
-    }
-
     if ty.mutability.is_some() && !ty.pinned {
         if let Some(requires_pin) = match &ty.inner {
             Type::Ident(ident) if ident.rust == CxxString || is_opaque_cxx(cx, &ident.rust) => {
@@ -249,6 +245,25 @@
 }
 
 fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
+    match efn.lang {
+        Lang::Cxx => {
+            if !efn.generics.params.is_empty() && !efn.trusted {
+                let ref span = span_for_generics_error(efn);
+                cx.error(span, "extern C++ function with lifetimes must be declared in `unsafe extern \"C++\"` block");
+            }
+        }
+        Lang::Rust => {
+            if !efn.generics.params.is_empty() && efn.unsafety.is_none() {
+                let ref span = span_for_generics_error(efn);
+                let message = format!(
+                    "must be `unsafe fn {}` in order to expose explicit lifetimes to C++",
+                    efn.name.rust,
+                );
+                cx.error(span, message);
+            }
+        }
+    }
+
     if let Some(receiver) = &efn.receiver {
         let ref span = span_for_receiver_error(receiver);
 
@@ -281,10 +296,6 @@
                 ),
             );
         }
-
-        if receiver.lifetime.is_some() {
-            cx.error(span, "references with explicit lifetimes are not supported");
-        }
     }
 
     for arg in &efn.args {
@@ -436,6 +447,13 @@
     }
 }
 
+fn span_for_generics_error(efn: &ExternFn) -> TokenStream {
+    let unsafety = efn.unsafety;
+    let fn_token = efn.fn_token;
+    let generics = &efn.generics;
+    quote!(#unsafety #fn_token #generics)
+}
+
 fn describe(cx: &mut Check, ty: &Type) -> String {
     match ty {
         Type::Ident(ident) => {
diff --git a/syntax/impls.rs b/syntax/impls.rs
index 58d8fd3..318cfae 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -187,6 +187,7 @@
         let Signature {
             unsafety,
             fn_token: _,
+            generics: _,
             receiver,
             args,
             ret,
@@ -197,6 +198,7 @@
         let Signature {
             unsafety: unsafety2,
             fn_token: _,
+            generics: _,
             receiver: receiver2,
             args: args2,
             ret: ret2,
@@ -218,6 +220,7 @@
         let Signature {
             unsafety,
             fn_token: _,
+            generics: _,
             receiver,
             args,
             ret,
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 853db90..9d0f829 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -30,7 +30,7 @@
 use proc_macro2::{Ident, Span};
 use syn::punctuated::Punctuated;
 use syn::token::{Brace, Bracket, Paren};
-use syn::{Expr, Lifetime, Token, Type as RustType};
+use syn::{Expr, Generics, Lifetime, Token, Type as RustType};
 
 pub use self::atom::Atom;
 pub use self::derive::Derive;
@@ -119,6 +119,7 @@
 pub struct Signature {
     pub unsafety: Option<Token![unsafe]>,
     pub fn_token: Token![fn],
+    pub generics: Generics,
     pub receiver: Option<Receiver>,
     pub args: Punctuated<Var, Token![,]>,
     pub ret: Option<Type>,
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 6010492..fcc44d2 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -13,8 +13,9 @@
 use syn::punctuated::Punctuated;
 use syn::{
     Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
-    GenericArgument, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat, PathArguments, Result,
-    ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
+    GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat,
+    PathArguments, Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath,
+    TypeReference, TypeSlice,
 };
 
 pub mod kw {
@@ -351,7 +352,12 @@
     namespace: &Namespace,
 ) -> Result<Api> {
     let generics = &foreign_fn.sig.generics;
-    if !generics.params.is_empty() || generics.where_clause.is_some() {
+    if generics.where_clause.is_some()
+        || generics.params.iter().any(|param| match param {
+            GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
+            GenericParam::Type(_) | GenericParam::Const(_) => true,
+        })
+    {
         return Err(Error::new_spanned(
             foreign_fn,
             "extern function with generic parameters is not supported yet",
@@ -447,6 +453,7 @@
         cxx_name.unwrap_or(foreign_fn.sig.ident.clone()),
         rust_name.unwrap_or(foreign_fn.sig.ident.clone()),
     );
+    let generics = generics.clone();
     let paren_token = foreign_fn.sig.paren_token;
     let semi_token = foreign_fn.semi_token;
     let api_function = match lang {
@@ -461,6 +468,7 @@
         sig: Signature {
             unsafety,
             fn_token,
+            generics,
             receiver,
             args,
             ret,
@@ -759,6 +767,7 @@
     Ok(Type::Fn(Box::new(Signature {
         unsafety: ty.unsafety,
         fn_token: ty.fn_token,
+        generics: Generics::default(),
         receiver: None,
         args,
         ret,