diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index a7757ec4..918d47bf 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -1,6 +1,6 @@ use internals::symbol::*; use internals::{ungroup, Ctxt}; -use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree}; use quote::ToTokens; use std::borrow::Cow; use std::collections::BTreeSet; @@ -1901,17 +1901,40 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { syn::Type::Group(ty) => { collect_lifetimes(&ty.elem, out); } + syn::Type::Macro(ty) => { + collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); + } syn::Type::BareFn(_) | syn::Type::Never(_) | syn::Type::TraitObject(_) | syn::Type::ImplTrait(_) | syn::Type::Infer(_) - | syn::Type::Macro(_) | syn::Type::Verbatim(_) | _ => {} } } +fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet) { + let mut iter = tokens.into_iter(); + while let Some(tt) = iter.next() { + match &tt { + TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + if let Some(TokenTree::Ident(ident)) = iter.next() { + out.insert(syn::Lifetime { + apostrophe: op.span(), + ident, + }); + } + } + TokenTree::Group(group) => { + let tokens = group.stream(); + collect_lifetimes_from_tokens(tokens, out); + } + _ => {} + } + } +} + fn parse_lit_str(s: &syn::LitStr) -> parse::Result where T: Parse, diff --git a/test_suite/tests/test_gen.rs b/test_suite/tests/test_gen.rs index d8def742..73f7fa50 100644 --- a/test_suite/tests/test_gen.rs +++ b/test_suite/tests/test_gen.rs @@ -723,6 +723,18 @@ fn test_gen() { } deriving!(&'a str); + + macro_rules! mac { + ($($tt:tt)*) => { + $($tt)* + }; + } + + #[derive(Deserialize)] + struct BorrowLifetimeInsideMacro<'a> { + #[serde(borrow = "'a")] + f: mac!(Cow<'a, str>), + } } //////////////////////////////////////////////////////////////////////////