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,