From f7d06cae4c51802692f55eacad43b78cb69db22e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 May 2020 17:58:10 -0700 Subject: [PATCH 1/2] Add failing test involving macro_rules metavariable --- test_suite/tests/test_gen.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test_suite/tests/test_gen.rs b/test_suite/tests/test_gen.rs index 288ba594..dc382b80 100644 --- a/test_suite/tests/test_gen.rs +++ b/test_suite/tests/test_gen.rs @@ -708,6 +708,17 @@ fn test_gen() { x: u8, y: u16, } + + macro_rules! deriving { + ($field:ty) => { + #[derive(Deserialize)] + struct MacroRules<'a> { + field: $field, + } + }; + } + + deriving!(&'a str); } ////////////////////////////////////////////////////////////////////////// From c45a809d5c318a09eb353b09ac767b0a9c6b47c2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 May 2020 17:58:34 -0700 Subject: [PATCH 2/2] Look inside of None-delimited groups when examining types --- serde_derive/src/bound.rs | 4 ++-- serde_derive/src/de.rs | 4 ++-- serde_derive/src/internals/attr.rs | 12 ++++++------ serde_derive/src/internals/check.rs | 4 ++-- serde_derive/src/internals/mod.rs | 9 +++++++++ 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs index 0e7c6edd..ec2eafe8 100644 --- a/serde_derive/src/bound.rs +++ b/serde_derive/src/bound.rs @@ -5,7 +5,7 @@ use syn::punctuated::{Pair, Punctuated}; use syn::visit::{self, Visit}; use internals::ast::{Container, Data}; -use internals::attr; +use internals::{attr, ungroup}; use proc_macro2::Span; @@ -114,7 +114,7 @@ pub fn with_bound( } impl<'ast> Visit<'ast> for FindTyParams<'ast> { fn visit_field(&mut self, field: &'ast syn::Field) { - if let syn::Type::Path(ty) = &field.ty { + if let syn::Type::Path(ty) = ungroup(&field.ty) { if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() { if self.all_type_params.contains(&t.ident) { self.associated_type_usage.push(ty); diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index aafde818..1f5733a6 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -8,7 +8,7 @@ use bound; use dummy; use fragment::{Expr, Fragment, Match, Stmts}; use internals::ast::{Container, Data, Field, Style, Variant}; -use internals::{attr, Ctxt, Derive}; +use internals::{attr, ungroup, Ctxt, Derive}; use pretend; use std::collections::BTreeSet; @@ -77,7 +77,7 @@ fn precondition(cx: &Ctxt, cont: &Container) { fn precondition_sized(cx: &Ctxt, cont: &Container) { if let Data::Struct(_, fields) = &cont.data { if let Some(last) = fields.last() { - if let syn::Type::Slice(_) = *last.ty { + if let syn::Type::Slice(_) = ungroup(last.ty) { cx.error_spanned_by( cont.original, "cannot deserialize a dynamically sized struct", diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index 44f75702..190e4d14 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -1,5 +1,5 @@ use internals::symbol::*; -use internals::Ctxt; +use internals::{ungroup, Ctxt}; use proc_macro2::{Group, Span, TokenStream, TokenTree}; use quote::ToTokens; use std::borrow::Cow; @@ -1737,7 +1737,7 @@ fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { // cow: Cow<'a, str>, // } fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { - let path = match ty { + let path = match ungroup(ty) { syn::Type::Path(ty) => &ty.path, _ => { return false; @@ -1764,7 +1764,7 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { } fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { - let path = match ty { + let path = match ungroup(ty) { syn::Type::Path(ty) => &ty.path, _ => { return false; @@ -1811,7 +1811,7 @@ fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { // r: &'a str, // } fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { - match ty { + match ungroup(ty) { syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), _ => false, } @@ -1822,14 +1822,14 @@ fn is_str(ty: &syn::Type) -> bool { } fn is_slice_u8(ty: &syn::Type) -> bool { - match ty { + match ungroup(ty) { syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), _ => false, } } fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { - match ty { + match ungroup(ty) { syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), _ => false, } diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index bf4cb170..30ede1ce 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -1,6 +1,6 @@ use internals::ast::{Container, Data, Field, Style}; use internals::attr::{Identifier, TagType}; -use internals::{Ctxt, Derive}; +use internals::{ungroup, Ctxt, Derive}; use syn::{Member, Type}; /// Cross-cutting checks that require looking at more than a single attrs @@ -396,7 +396,7 @@ fn member_message(member: &Member) -> String { } fn allow_transparent(field: &Field, derive: Derive) -> bool { - if let Type::Path(ty) = field.ty { + if let Type::Path(ty) = ungroup(&field.ty) { if let Some(seg) = ty.path.segments.last() { if seg.ident == "PhantomData" { return false; diff --git a/serde_derive/src/internals/mod.rs b/serde_derive/src/internals/mod.rs index 688588e2..d36b6e45 100644 --- a/serde_derive/src/internals/mod.rs +++ b/serde_derive/src/internals/mod.rs @@ -8,8 +8,17 @@ mod case; mod check; mod symbol; +use syn::Type; + #[derive(Copy, Clone)] pub enum Derive { Serialize, Deserialize, } + +pub fn ungroup(mut ty: &Type) -> &Type { + while let Type::Group(group) = ty { + ty = &group.elem; + } + ty +}