Skip to content

Commit 855bff9

Browse files
authored
Merge pull request #611 from dtolnay/lifetime
Emit lifetimes on extern type into Rust macro output
2 parents 0c8cb95 + 8c80de7 commit 855bff9

File tree

6 files changed

+64
-24
lines changed

6 files changed

+64
-24
lines changed

gen/src/nested.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
5252
mod tests {
5353
use super::NamespaceEntries;
5454
use crate::syntax::namespace::Namespace;
55-
use crate::syntax::{Api, Doc, ExternType, Lang, Pair};
55+
use crate::syntax::{Api, Doc, ExternType, Lang, Lifetimes, Pair};
5656
use proc_macro2::{Ident, Span};
5757
use std::iter::FromIterator;
58+
use syn::punctuated::Punctuated;
5859
use syn::Token;
5960

6061
#[test]
@@ -136,7 +137,11 @@ mod tests {
136137
cxx: ident.clone(),
137138
rust: ident,
138139
},
139-
lifetimes: Vec::new(),
140+
generics: Lifetimes {
141+
lt_token: None,
142+
lifetimes: Punctuated::new(),
143+
gt_token: None,
144+
},
140145
colon_token: None,
141146
bounds: Vec::new(),
142147
semi_token: Token![;](Span::call_site()),

macro/src/expand.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,23 @@ fn expand_enum(enm: &Enum) -> TokenStream {
313313
fn expand_cxx_type(ety: &ExternType) -> TokenStream {
314314
let ident = &ety.name.rust;
315315
let doc = &ety.doc;
316+
let generics = &ety.generics;
316317
let type_id = type_id(&ety.name);
317318

319+
let lifetime_fields = ety.generics.lifetimes.iter().map(|lifetime| {
320+
let field = format_ident!("_lifetime_{}", lifetime.ident);
321+
quote!(#field: ::std::marker::PhantomData<&#lifetime ()>)
322+
});
323+
318324
quote! {
319325
#doc
320326
#[repr(C)]
321-
pub struct #ident {
327+
pub struct #ident #generics {
322328
_private: ::cxx::private::Opaque,
329+
#(#lifetime_fields,)*
323330
}
324331

325-
unsafe impl ::cxx::ExternType for #ident {
332+
unsafe impl #generics ::cxx::ExternType for #ident #generics {
326333
type Id = #type_id;
327334
type Kind = ::cxx::kind::Opaque;
328335
}
@@ -959,10 +966,11 @@ fn expand_rust_function_shim_super(
959966
fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
960967
let doc = &alias.doc;
961968
let ident = &alias.name.rust;
969+
let generics = &alias.generics;
962970
let ty = &alias.ty;
963971
quote! {
964972
#doc
965-
pub type #ident = #ty;
973+
pub type #ident #generics = #ty;
966974
}
967975
}
968976

syntax/check.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ fn check_api_type(cx: &mut Check, ety: &ExternType) {
337337
cx.error(derive, msg);
338338
}
339339

340-
if let Some(lifetime) = ety.lifetimes.first() {
340+
if let Some(lifetime) = ety.generics.lifetimes.first() {
341341
cx.error(lifetime, "extern type with lifetimes is not supported yet");
342342
}
343343

@@ -445,7 +445,7 @@ fn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) {
445445
cx.error(derive, msg);
446446
}
447447

448-
if let Some(lifetime) = alias.lifetimes.first() {
448+
if let Some(lifetime) = alias.generics.lifetimes.first() {
449449
cx.error(lifetime, "extern type with lifetimes is not supported yet");
450450
}
451451
}

syntax/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub struct ExternType {
7474
pub derives: Vec<Derive>,
7575
pub type_token: Token![type],
7676
pub name: Pair,
77-
pub lifetimes: Vec<Lifetime>,
77+
pub generics: Lifetimes,
7878
pub colon_token: Option<Token![:]>,
7979
pub bounds: Vec<Derive>,
8080
pub semi_token: Token![;],
@@ -116,7 +116,7 @@ pub struct TypeAlias {
116116
pub derives: Vec<Derive>,
117117
pub type_token: Token![type],
118118
pub name: Pair,
119-
pub lifetimes: Vec<Lifetime>,
119+
pub generics: Lifetimes,
120120
pub eq_token: Token![=],
121121
pub ty: RustType,
122122
pub semi_token: Token![;],
@@ -130,6 +130,12 @@ pub struct Impl {
130130
pub negative_token: Option<Token![!]>,
131131
}
132132

133+
pub struct Lifetimes {
134+
pub lt_token: Option<Token![<]>,
135+
pub lifetimes: Punctuated<Lifetime, Token![,]>,
136+
pub gt_token: Option<Token![>]>,
137+
}
138+
133139
pub struct Signature {
134140
pub unsafety: Option<Token![unsafe]>,
135141
pub fn_token: Token![fn],

syntax/parse.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ use crate::syntax::report::Errors;
44
use crate::syntax::Atom::*;
55
use crate::syntax::{
66
attrs, error, Api, Array, Derive, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind,
7-
Lang, Namespace, Pair, Receiver, Ref, RustName, Signature, SliceRef, Struct, Ty1, Type,
8-
TypeAlias, Var, Variant,
7+
Lang, Lifetimes, Namespace, Pair, Receiver, Ref, RustName, Signature, SliceRef, Struct, Ty1,
8+
Type, TypeAlias, Var, Variant,
99
};
1010
use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
1111
use quote::{format_ident, quote, quote_spanned};
1212
use syn::parse::{ParseStream, Parser};
1313
use syn::punctuated::Punctuated;
1414
use syn::{
1515
Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
16-
GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lifetime, Lit,
17-
LitStr, Pat, PathArguments, Result, ReturnType, Token, TraitBound, TraitBoundModifier,
16+
GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
17+
Pat, PathArguments, Result, ReturnType, Token, TraitBound, TraitBoundModifier,
1818
Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypeReference,
1919
Variant as RustVariant,
2020
};
@@ -385,7 +385,11 @@ fn parse_extern_type(
385385

386386
let type_token = foreign_type.type_token;
387387
let name = pair(namespace, &foreign_type.ident, cxx_name, rust_name);
388-
let lifetimes = Vec::new();
388+
let generics = Lifetimes {
389+
lt_token: None,
390+
lifetimes: Punctuated::new(),
391+
gt_token: None,
392+
};
389393
let colon_token = None;
390394
let bounds = Vec::new();
391395
let semi_token = foreign_type.semi_token;
@@ -399,7 +403,7 @@ fn parse_extern_type(
399403
derives,
400404
type_token,
401405
name,
402-
lifetimes,
406+
generics,
403407
colon_token,
404408
bounds,
405409
semi_token,
@@ -581,17 +585,21 @@ fn parse_extern_verbatim(
581585
};
582586
let ident: Ident = input.parse()?;
583587
let generics: Generics = input.parse()?;
584-
let mut lifetimes = Vec::new();
588+
let mut lifetimes = Punctuated::new();
585589
let mut has_unsupported_generic_param = false;
586-
for param in generics.params {
590+
for pair in generics.params.into_pairs() {
591+
let (param, punct) = pair.into_tuple();
587592
match param {
588593
GenericParam::Lifetime(param) => {
589594
if !param.bounds.is_empty() && !has_unsupported_generic_param {
590595
let msg = "lifetime parameter with bounds is not supported yet";
591596
cx.error(&param, msg);
592597
has_unsupported_generic_param = true;
593598
}
594-
lifetimes.push(param.lifetime);
599+
lifetimes.push_value(param.lifetime);
600+
if let Some(punct) = punct {
601+
lifetimes.push_punct(punct);
602+
}
595603
}
596604
GenericParam::Type(param) => {
597605
if !has_unsupported_generic_param {
@@ -609,6 +617,11 @@ fn parse_extern_verbatim(
609617
}
610618
}
611619
}
620+
let lifetimes = Lifetimes {
621+
lt_token: generics.lt_token,
622+
lifetimes,
623+
gt_token: generics.gt_token,
624+
};
612625
let lookahead = input.lookahead1();
613626
if lookahead.peek(Token![=]) {
614627
// type Alias = crate::path::to::Type;
@@ -632,7 +645,7 @@ fn parse_type_alias(
632645
attrs: Vec<Attribute>,
633646
type_token: Token![type],
634647
ident: Ident,
635-
lifetimes: Vec<Lifetime>,
648+
generics: Lifetimes,
636649
input: ParseStream,
637650
lang: Lang,
638651
namespace: &Namespace,
@@ -672,7 +685,7 @@ fn parse_type_alias(
672685
derives,
673686
type_token,
674687
name,
675-
lifetimes,
688+
generics,
676689
eq_token,
677690
ty,
678691
semi_token,
@@ -684,7 +697,7 @@ fn parse_extern_type_bounded(
684697
attrs: Vec<Attribute>,
685698
type_token: Token![type],
686699
ident: Ident,
687-
lifetimes: Vec<Lifetime>,
700+
generics: Lifetimes,
688701
input: ParseStream,
689702
lang: Lang,
690703
trusted: bool,
@@ -752,7 +765,7 @@ fn parse_extern_type_bounded(
752765
derives,
753766
type_token,
754767
name,
755-
lifetimes,
768+
generics,
756769
colon_token,
757770
bounds,
758771
semi_token,

syntax/tokens.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::syntax::atom::Atom::*;
22
use crate::syntax::{
3-
Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, RustName, Signature,
4-
SliceRef, Struct, Ty1, Type, TypeAlias, Var,
3+
Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Lifetimes, Receiver, Ref, RustName,
4+
Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
55
};
66
use proc_macro2::{Ident, Span, TokenStream};
77
use quote::{quote_spanned, ToTokens};
@@ -157,6 +157,14 @@ impl ToTokens for Impl {
157157
}
158158
}
159159

160+
impl ToTokens for Lifetimes {
161+
fn to_tokens(&self, tokens: &mut TokenStream) {
162+
self.lt_token.to_tokens(tokens);
163+
self.lifetimes.to_tokens(tokens);
164+
self.gt_token.to_tokens(tokens);
165+
}
166+
}
167+
160168
impl ToTokens for Signature {
161169
fn to_tokens(&self, tokens: &mut TokenStream) {
162170
self.fn_token.to_tokens(tokens);

0 commit comments

Comments
 (0)