// SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{Cfg, CfgAttr, Cfgs, Errors}; use proc_macro2::Ident; use std::{collections::VecDeque, marker::PhantomData}; use syn::{ punctuated::{Pair, Punctuated}, Token, }; struct State { cfgs: Cfgs, errors: Errors, _phantom: PhantomData

, } impl State

{ #[must_use] fn eval_cfg(&mut self, cfg: Cfg) -> bool { struct MyDispatch<'a> { cfg: Cfg, _phantom: PhantomData<&'a ()>, } impl<'a> PhaseDispatch for MyDispatch<'a> { type Args = &'a mut State

; type Output = bool; fn dispatch_collect( self, args: Self::Args, ) -> Self::Output { args.cfgs.insert_cfg(self.cfg, ()); true } fn dispatch_process( self, args: Self::Args, ) -> Self::Output { if let Some(&retval) = args.cfgs.cfgs_map.get(&self.cfg) { retval } else { args.errors.error(self.cfg, "unrecognized cfg -- cfg wasn't evaluated when running `__cfg_expansion_helper!`"); true } } } P::dispatch( MyDispatch { cfg, _phantom: PhantomData, }, self, ) } #[must_use] fn eval_cfgs( &mut self, mut attrs: Vec, ) -> Option, P>> { let mut queue = VecDeque::from(attrs); attrs = Vec::with_capacity(queue.len()); // cfg_attr is rare, and cfg can't increase length while let Some(attr) = queue.pop_front() { if attr.path().is_ident("cfg") { if let Some(cfg) = self.errors.ok(Cfg::parse_meta(&attr.meta)) { if !self.eval_cfg(cfg) { return None; } continue; } } else if attr.path().is_ident("cfg_attr") { if let Some(cfg_attr) = self.errors.ok(CfgAttr::parse_meta(&attr.meta)) { if self.eval_cfg(cfg_attr.to_cfg()) { // push onto queue since cfg_attr(, cfg_attr(, )) is valid for meta in cfg_attr.attrs { queue.push_front(syn::Attribute { pound_token: attr.pound_token, style: attr.style, bracket_token: attr.bracket_token, meta, }); } } continue; } } attrs.push(attr); } Some(Output::new(attrs)) } fn process_qself_and_path( &mut self, qself: Option, path: syn::Path, ) -> Option<(Output, P>, Output)> { let qself = if let Some(syn::QSelf { lt_token, ty, position, as_token, gt_token, }) = qself { ty.process(self)?.map(|ty| { Some(syn::QSelf { lt_token, ty, position, as_token, gt_token, }) }) } else { Output::new(None) }; let syn::Path { leading_colon, segments, } = path; // path segments don't get removed let path = segments.process(self)?.map(|segments| syn::Path { leading_colon, segments, }); Some((qself, path)) } } trait PhaseDispatch { type Args; type Output; fn dispatch_collect(self, args: Self::Args) -> Self::Output; fn dispatch_process(self, args: Self::Args) -> Self::Output; } trait Phase: Sized + 'static { type Output; type CfgsValue; fn output_new(v: T) -> Output; fn output_map U>(v: Output, f: F) -> Output; fn output_zip(t: Output, u: Output) -> Output<(T, U), Self>; fn dispatch(d: D, args: D::Args) -> D::Output; } struct CollectCfgsPhase; impl Phase for CollectCfgsPhase { type Output = (); type CfgsValue = (); fn output_new(_v: T) -> Output { Output(()) } fn output_map U>(_v: Output, _f: F) -> Output { Output(()) } fn output_zip(_t: Output, _u: Output) -> Output<(T, U), Self> { Output(()) } fn dispatch(d: D, args: D::Args) -> D::Output { d.dispatch_collect(args) } } struct ProcessCfgsPhase; impl Phase for ProcessCfgsPhase { type Output = T; type CfgsValue = bool; fn output_new(v: T) -> Output { Output(v) } fn output_map U>(v: Output, f: F) -> Output { Output(f(v.0)) } fn output_zip(t: Output, u: Output) -> Output<(T, U), Self> { Output((t.0, u.0)) } fn dispatch(d: D, args: D::Args) -> D::Output { d.dispatch_process(args) } } struct Output(P::Output); trait OutputZip: Sized { type Output; fn zip(self) -> Output; fn call R>(self, f: F) -> Output { self.zip().map(f) } } impl OutputZip

for () { type Output = (); fn zip(self) -> Output { Output::new(()) } } impl OutputZip

for (Output,) { type Output = (T,); fn zip(self) -> Output { self.0.map(|v| (v,)) } } macro_rules! impl_zip { ($first_arg:ident: $first_T:ident, $($arg:ident: $T:ident),* $(,)?) => { impl_zip!(@step [], [($first_arg: $first_T) $(($arg: $T))*], (),); }; ( @impl($first_arg:tt,), $tuple_pat:tt, ) => {}; ( @impl(($first_arg:ident: $first_T:ident), $(($arg:ident: $T:ident),)*), $tuple_pat:tt, ) => { impl<$first_T, $($T,)* P: Phase> OutputZip

for (Output<$first_T, P>, $(Output<$T, P>),*) { type Output = ($first_T, $($T),*); fn zip(self) -> Output<($first_T, $($T),*), P> { let (tuples, $($arg),*) = self; $(let tuples = P::output_zip(tuples, $arg);)* tuples.map(|$tuple_pat| ($first_arg, $($arg),*)) } } }; ( @step [$($cur:tt)*], [], $tuple_pat:tt, ) => {}; ( @step [$($cur:tt)*], [($next_arg:ident: $next_T:ident) $($rest:tt)*], (), ) => { impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), $next_arg,); impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], $next_arg,); }; ( @step [$($cur:tt)*], [($next_arg:ident: $next_T:ident) $($rest:tt)*], $tuple_pat:tt, ) => { impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), ($tuple_pat, $next_arg),); impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], ($tuple_pat, $next_arg),); }; } impl_zip!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, t11: T11); impl Copy for Output where P::Output: Copy {} impl Clone for Output where P::Output: Clone, { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Output { fn new(v: T) -> Self { P::output_new(v) } fn map U>(self, f: F) -> Output { P::output_map(self, f) } } trait Process: Sized { #[must_use] fn process(self, state: &mut State

) -> Option>; } impl Process

for syn::Item { fn process(self, _state: &mut State

) -> Option> { // don't recurse into items Some(Output::new(self)) } } impl Process

for Vec { fn process(self, state: &mut State

) -> Option> { state.eval_cfgs(self) } } impl, P: Phase> Process

for Box { fn process(self, state: &mut State

) -> Option> { Some(T::process(*self, state)?.map(Box::new)) } } trait ProcessVecElement { const REMOVE_ELEMENTS: bool; } impl ProcessVecElement for syn::Arm { const REMOVE_ELEMENTS: bool = true; } impl ProcessVecElement for syn::Stmt { const REMOVE_ELEMENTS: bool = true; } impl ProcessVecElement for syn::ForeignItem { const REMOVE_ELEMENTS: bool = true; } impl ProcessVecElement for syn::ImplItem { const REMOVE_ELEMENTS: bool = true; } impl ProcessVecElement for syn::Item { const REMOVE_ELEMENTS: bool = true; } impl ProcessVecElement for syn::TraitItem { const REMOVE_ELEMENTS: bool = true; } impl + ProcessVecElement, P: Phase> Process

for Vec { fn process(self, state: &mut State

) -> Option> { let mut output = Output::new(Vec::new()); for value in self { if let Some(value) = value.process(state) { output = (output, value).call(|(mut output, value)| { output.push(value); output }); } else if !T::REMOVE_ELEMENTS { return None; } } Some(output) } } trait ProcessOption { /// if a configured-off value causes this value to be `None` instead of propagating the configuring-off const REMOVE_VALUE: bool; } impl ProcessOption for syn::Abi { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::Block { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::WhereClause { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::Expr { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::Type { const REMOVE_VALUE: bool = true; } impl ProcessOption for Box { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::AngleBracketedGenericArguments { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::ImplRestriction { const REMOVE_VALUE: bool = false; } impl ProcessOption for syn::BoundLifetimes { const REMOVE_VALUE: bool = false; } impl ProcessOption for (Token![=], syn::Expr) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Token![=], syn::Type) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Token![if], Box) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Token![else], Box) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Token![&], Option) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Token![as], Ident) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Ident, Token![:]) { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Option, syn::Path, Token![for]) { const REMOVE_VALUE: bool = false; } impl ProcessOption for syn::BareVariadic { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::Variadic { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::LocalInit { const REMOVE_VALUE: bool = false; } impl ProcessOption for syn::Label { const REMOVE_VALUE: bool = true; } impl ProcessOption for syn::PatRest { const REMOVE_VALUE: bool = true; } impl ProcessOption for (Box, Token![:]) { const REMOVE_VALUE: bool = false; } impl ProcessOption for (Token![@], Box) { const REMOVE_VALUE: bool = false; } impl ProcessOption for (syn::token::Brace, Vec) { const REMOVE_VALUE: bool = false; } impl + ProcessOption, P: Phase> Process

for Option { fn process(self, state: &mut State

) -> Option> { if let Some(this) = self { match this.process(state) { Some(v) => Some(v.map(Some)), None => { if T::REMOVE_VALUE { Some(Output::new(None)) } else { None } } } } else { Some(Output::new(None)) } } } trait ProcessPunctuatedElement { const REMOVE_ELEMENTS: bool; } impl + ProcessPunctuatedElement, P: Phase, Punct: Default> Process

for Punctuated { fn process(self, state: &mut State

) -> Option> { let mut output = Output::new(Punctuated::::new()); for pair in self.into_pairs() { let (value, punct) = pair.into_tuple(); if let Some(value) = value.process(state) { output = (output, value).call(|(mut output, value)| { output.extend([Pair::new(value, punct)]); output }); } else if !T::REMOVE_ELEMENTS { return None; } } Some(output) } } impl ProcessPunctuatedElement for syn::PathSegment { const REMOVE_ELEMENTS: bool = false; } impl ProcessPunctuatedElement for syn::Type { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::Expr { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::Pat { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::CapturedParam { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::GenericArgument { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::GenericParam { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::Lifetime { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::WherePredicate { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::Variant { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::FnArg { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::BareFnArg { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::TypeParamBound { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::FieldValue { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::Field { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::FieldPat { const REMOVE_ELEMENTS: bool = true; } impl ProcessPunctuatedElement for syn::UseTree { const REMOVE_ELEMENTS: bool = true; } impl, U: Process

, P: Phase> Process

for (T, U) { fn process(self, state: &mut State

) -> Option> { let (t, u) = self; let t = t.process(state)?; let u = u.process(state)?; Some((t, u).zip()) } } impl, U: Process

, V: Process

, P: Phase> Process

for (T, U, V) { fn process(self, state: &mut State

) -> Option> { let (t, u, v) = self; let t = t.process(state)?; let u = u.process(state)?; let v = v.process(state)?; Some((t, u, v).zip()) } } macro_rules! process_no_op { ($ty:ty) => { impl Process

for $ty { fn process(self, _state: &mut State

) -> Option> { Some(Output::new(self)) } } impl ProcessOption for $ty { const REMOVE_VALUE: bool = false; } }; } process_no_op!(Token![Self]); process_no_op!(Token![abstract]); process_no_op!(Token![as]); process_no_op!(Token![async]); process_no_op!(Token![auto]); process_no_op!(Token![await]); process_no_op!(Token![become]); process_no_op!(Token![box]); process_no_op!(Token![break]); process_no_op!(Token![const]); process_no_op!(Token![continue]); process_no_op!(Token![crate]); process_no_op!(Token![default]); process_no_op!(Token![do]); process_no_op!(Token![dyn]); process_no_op!(Token![else]); process_no_op!(Token![enum]); process_no_op!(Token![extern]); process_no_op!(Token![final]); process_no_op!(Token![fn]); process_no_op!(Token![for]); process_no_op!(Token![if]); process_no_op!(Token![impl]); process_no_op!(Token![in]); process_no_op!(Token![let]); process_no_op!(Token![loop]); process_no_op!(Token![macro]); process_no_op!(Token![match]); process_no_op!(Token![mod]); process_no_op!(Token![move]); process_no_op!(Token![mut]); process_no_op!(Token![override]); process_no_op!(Token![priv]); process_no_op!(Token![pub]); process_no_op!(Token![raw]); process_no_op!(Token![ref]); process_no_op!(Token![return]); process_no_op!(Token![self]); process_no_op!(Token![static]); process_no_op!(Token![struct]); process_no_op!(Token![super]); process_no_op!(Token![trait]); process_no_op!(Token![try]); process_no_op!(Token![type]); process_no_op!(Token![typeof]); process_no_op!(Token![union]); process_no_op!(Token![unsafe]); process_no_op!(Token![unsized]); process_no_op!(Token![use]); process_no_op!(Token![virtual]); process_no_op!(Token![where]); process_no_op!(Token![while]); process_no_op!(Token![yield]); process_no_op!(Token![!]); process_no_op!(Token![!=]); process_no_op!(Token![#]); process_no_op!(Token![$]); process_no_op!(Token![%]); process_no_op!(Token![%=]); process_no_op!(Token![&]); process_no_op!(Token![&&]); process_no_op!(Token![&=]); process_no_op!(Token![*]); process_no_op!(Token![*=]); process_no_op!(Token![+]); process_no_op!(Token![+=]); process_no_op!(Token![,]); process_no_op!(Token![-]); process_no_op!(Token![-=]); process_no_op!(Token![->]); process_no_op!(Token![.]); process_no_op!(Token![..]); process_no_op!(Token![...]); process_no_op!(Token![..=]); process_no_op!(Token![/]); process_no_op!(Token![/=]); process_no_op!(Token![:]); process_no_op!(Token![::]); process_no_op!(Token![;]); process_no_op!(Token![<]); process_no_op!(Token![<-]); process_no_op!(Token![<<]); process_no_op!(Token![<<=]); process_no_op!(Token![<=]); process_no_op!(Token![=]); process_no_op!(Token![==]); process_no_op!(Token![=>]); process_no_op!(Token![>]); process_no_op!(Token![>=]); process_no_op!(Token![>>]); process_no_op!(Token![>>=]); process_no_op!(Token![?]); process_no_op!(Token![@]); process_no_op!(Token![^]); process_no_op!(Token![^=]); process_no_op!(Token![_]); process_no_op!(Token![|]); process_no_op!(Token![|=]); process_no_op!(Token![||]); process_no_op!(Token![~]); process_no_op!(syn::token::Brace); process_no_op!(syn::token::Bracket); process_no_op!(syn::token::Paren); process_no_op!(syn::token::Group); process_no_op!(Ident); process_no_op!(syn::Index); process_no_op!(syn::Lifetime); process_no_op!(syn::LitBool); process_no_op!(syn::LitByte); process_no_op!(syn::LitByteStr); process_no_op!(syn::LitChar); process_no_op!(syn::LitCStr); process_no_op!(syn::LitFloat); process_no_op!(syn::LitInt); process_no_op!(syn::LitStr); process_no_op!(proc_macro2::TokenStream); process_no_op!(proc_macro2::Literal); macro_rules! process_struct { ($ty:path { $($field:ident,)* }) => { impl Process

for $ty { fn process(self, state: &mut State

) -> Option> { let Self { $($field,)* } = self; $(let $field = $field.process(state)?;)* Some(($($field,)*).call(|($($field,)*)| Self { $($field,)* })) } } }; ($ty:path { $($fields_before:ident,)* #[qself] $qself:ident, $path:ident, $($fields_after:ident,)* }) => { impl Process

for $ty { fn process(self, state: &mut State

) -> Option> { let Self { $($fields_before,)* $qself, $path, $($fields_after,)* } = self; $(let $fields_before = $fields_before.process(state)?;)* let ($qself, $path) = state.process_qself_and_path($qself, $path)?; $(let $fields_after = $fields_after.process(state)?;)* Some(( $($fields_before,)* $qself, $path, $($fields_after,)* ).call(|( $($fields_before,)* $qself, $path, $($fields_after,)* )| Self { $($fields_before,)* $qself, $path, $($fields_after,)* })) } } }; } process_struct! { syn::Abi { extern_token, name, } } process_struct! { syn::AngleBracketedGenericArguments { colon2_token, lt_token, args, gt_token, } } process_struct! { syn::Arm { attrs, pat, guard, fat_arrow_token, body, comma, } } process_struct! { syn::AssocConst { ident, generics, eq_token, value, } } process_struct! { syn::AssocType { ident, generics, eq_token, ty, } } process_struct! { syn::BareFnArg { attrs, name, ty, } } process_struct! { syn::BareVariadic { attrs, name, dots, comma, } } process_struct! { syn::Block { brace_token, stmts, } } process_struct! { syn::BoundLifetimes { for_token, lt_token, lifetimes, gt_token, } } process_struct! { syn::ConstParam { attrs, const_token, ident, colon_token, ty, eq_token, default, } } process_struct! { syn::Constraint { ident, generics, colon_token, bounds, } } process_struct! { syn::DataEnum { enum_token, brace_token, variants, } } process_struct! { syn::DataStruct { struct_token, fields, semi_token, } } process_struct! { syn::DataUnion { union_token, fields, } } process_struct! { syn::DeriveInput { attrs, vis, ident, generics, data, } } process_struct! { syn::ExprArray { attrs, bracket_token, elems, } } process_struct! { syn::ExprAssign { attrs, left, eq_token, right, } } process_struct! { syn::ExprAsync { attrs, async_token, capture, block, } } process_struct! { syn::ExprAwait { attrs, base, dot_token, await_token, } } process_struct! { syn::ExprBinary { attrs, left, op, right, } } process_struct! { syn::ExprBlock { attrs, label, block, } } process_struct! { syn::ExprBreak { attrs, break_token, label, expr, } } process_struct! { syn::ExprCall { attrs, func, paren_token, args, } } process_struct! { syn::ExprCast { attrs, expr, as_token, ty, } } process_struct! { syn::ExprClosure { attrs, lifetimes, constness, movability, asyncness, capture, or1_token, inputs, or2_token, output, body, } } process_struct! { syn::ExprConst { attrs, const_token, block, } } process_struct! { syn::ExprContinue { attrs, continue_token, label, } } process_struct! { syn::ExprField { attrs, base, dot_token, member, } } process_struct! { syn::ExprForLoop { attrs, label, for_token, pat, in_token, expr, body, } } process_struct! { syn::ExprGroup { attrs, group_token, expr, } } process_struct! { syn::ExprIf { attrs, if_token, cond, then_branch, else_branch, } } process_struct! { syn::ExprIndex { attrs, expr, bracket_token, index, } } process_struct! { syn::ExprInfer { attrs, underscore_token, } } process_struct! { syn::ExprLet { attrs, let_token, pat, eq_token, expr, } } process_struct! { syn::ExprLit { attrs, lit, } } process_struct! { syn::ExprLoop { attrs, label, loop_token, body, } } process_struct! { syn::ExprMacro { attrs, mac, } } process_struct! { syn::ExprMatch { attrs, match_token, expr, brace_token, arms, } } process_struct! { syn::ExprMethodCall { attrs, receiver, dot_token, method, turbofish, paren_token, args, } } process_struct! { syn::ExprParen { attrs, paren_token, expr, } } process_struct! { syn::ExprPath { attrs, #[qself] qself, path, } } process_struct! { syn::ExprRange { attrs, start, limits, end, } } process_struct! { syn::ExprRawAddr { attrs, and_token, raw, mutability, expr, } } process_struct! { syn::ExprReference { attrs, and_token, mutability, expr, } } process_struct! { syn::ExprRepeat { attrs, bracket_token, expr, semi_token, len, } } process_struct! { syn::ExprReturn { attrs, return_token, expr, } } process_struct! { syn::ExprStruct { attrs, #[qself] qself, path, brace_token, fields, dot2_token, rest, } } process_struct! { syn::ExprTry { attrs, expr, question_token, } } process_struct! { syn::ExprTryBlock { attrs, try_token, block, } } process_struct! { syn::ExprTuple { attrs, paren_token, elems, } } process_struct! { syn::ExprUnary { attrs, op, expr, } } process_struct! { syn::ExprUnsafe { attrs, unsafe_token, block, } } process_struct! { syn::ExprWhile { attrs, label, while_token, cond, body, } } process_struct! { syn::ExprYield { attrs, yield_token, expr, } } process_struct! { syn::Field { attrs, vis, mutability, ident, colon_token, ty, } } process_struct! { syn::FieldPat { attrs, member, colon_token, pat, } } process_struct! { syn::FieldValue { attrs, member, colon_token, expr, } } process_struct! { syn::FieldsNamed { brace_token, named, } } process_struct! { syn::FieldsUnnamed { paren_token, unnamed, } } process_struct! { syn::ForeignItemFn { attrs, vis, sig, semi_token, } } process_struct! { syn::ForeignItemMacro { attrs, mac, semi_token, } } process_struct! { syn::ForeignItemStatic { attrs, vis, static_token, mutability, ident, colon_token, ty, semi_token, } } process_struct! { syn::ForeignItemType { attrs, vis, type_token, ident, generics, semi_token, } } process_struct! { syn::Generics { lt_token, params, gt_token, where_clause, } } process_struct! { syn::ImplItemConst { attrs, vis, defaultness, const_token, ident, generics, colon_token, ty, eq_token, expr, semi_token, } } process_struct! { syn::ImplItemFn { attrs, vis, defaultness, sig, block, } } process_struct! { syn::ImplItemMacro { attrs, mac, semi_token, } } process_struct! { syn::ImplItemType { attrs, vis, defaultness, type_token, ident, generics, eq_token, ty, semi_token, } } process_struct! { syn::ItemConst { attrs, vis, const_token, ident, generics, colon_token, ty, eq_token, expr, semi_token, } } process_struct! { syn::ItemEnum { attrs, vis, enum_token, ident, generics, brace_token, variants, } } process_struct! { syn::ItemExternCrate { attrs, vis, extern_token, crate_token, ident, rename, semi_token, } } process_struct! { syn::ItemFn { attrs, vis, sig, block, } } process_struct! { syn::ItemForeignMod { attrs, unsafety, abi, brace_token, items, } } process_struct! { syn::ItemImpl { attrs, defaultness, unsafety, impl_token, generics, trait_, self_ty, brace_token, items, } } process_struct! { syn::ItemMacro { attrs, ident, mac, semi_token, } } process_struct! { syn::ItemMod { attrs, vis, unsafety, mod_token, ident, content, semi, } } process_struct! { syn::ItemStatic { attrs, vis, static_token, mutability, ident, colon_token, ty, eq_token, expr, semi_token, } } process_struct! { syn::ItemStruct { attrs, vis, struct_token, ident, generics, fields, semi_token, } } process_struct! { syn::ItemTrait { attrs, vis, unsafety, auto_token, restriction, trait_token, ident, generics, colon_token, supertraits, brace_token, items, } } process_struct! { syn::ItemTraitAlias { attrs, vis, trait_token, ident, generics, eq_token, bounds, semi_token, } } process_struct! { syn::ItemType { attrs, vis, type_token, ident, generics, eq_token, ty, semi_token, } } process_struct! { syn::ItemUnion { attrs, vis, union_token, ident, generics, fields, } } process_struct! { syn::ItemUse { attrs, vis, use_token, leading_colon, tree, semi_token, } } process_struct! { syn::Label { name, colon_token, } } process_struct! { syn::LifetimeParam { attrs, lifetime, colon_token, bounds, } } process_struct! { syn::Local { attrs, let_token, pat, init, semi_token, } } process_struct! { syn::LocalInit { eq_token, expr, diverge, } } process_struct! { syn::Macro { path, bang_token, delimiter, tokens, } } process_struct! { syn::MetaList { path, delimiter, tokens, } } process_struct! { syn::MetaNameValue { path, eq_token, value, } } process_struct! { syn::ParenthesizedGenericArguments { paren_token, inputs, output, } } process_struct! { syn::PatIdent { attrs, by_ref, mutability, ident, subpat, } } process_struct! { syn::PatOr { attrs, leading_vert, cases, } } process_struct! { syn::PatParen { attrs, paren_token, pat, } } process_struct! { syn::PatReference { attrs, and_token, mutability, pat, } } process_struct! { syn::PatRest { attrs, dot2_token, } } process_struct! { syn::PatSlice { attrs, bracket_token, elems, } } process_struct! { syn::PatStruct { attrs, #[qself] qself, path, brace_token, fields, rest, } } process_struct! { syn::PatTuple { attrs, paren_token, elems, } } process_struct! { syn::PatTupleStruct { attrs, #[qself] qself, path, paren_token, elems, } } process_struct! { syn::PatType { attrs, pat, colon_token, ty, } } process_struct! { syn::PatWild { attrs, underscore_token, } } process_struct! { syn::Path { leading_colon, segments, } } process_struct! { syn::PathSegment { ident, arguments, } } process_struct! { syn::PreciseCapture { use_token, lt_token, params, gt_token, } } process_struct! { syn::PredicateLifetime { lifetime, colon_token, bounds, } } process_struct! { syn::PredicateType { lifetimes, bounded_ty, colon_token, bounds, } } process_struct! { syn::Receiver { attrs, reference, mutability, self_token, colon_token, ty, } } process_struct! { syn::Signature { constness, asyncness, unsafety, abi, fn_token, ident, generics, paren_token, inputs, variadic, output, } } process_struct! { syn::StmtMacro { attrs, mac, semi_token, } } process_struct! { syn::TraitBound { paren_token, modifier, lifetimes, path, } } process_struct! { syn::TraitItemConst { attrs, const_token, ident, generics, colon_token, ty, default, semi_token, } } process_struct! { syn::TraitItemFn { attrs, sig, default, semi_token, } } process_struct! { syn::TraitItemMacro { attrs, mac, semi_token, } } process_struct! { syn::TraitItemType { attrs, type_token, ident, generics, colon_token, bounds, default, semi_token, } } process_struct! { syn::TypeArray { bracket_token, elem, semi_token, len, } } process_struct! { syn::TypeBareFn { lifetimes, unsafety, abi, fn_token, paren_token, inputs, variadic, output, } } process_struct! { syn::TypeGroup { group_token, elem, } } process_struct! { syn::TypeImplTrait { impl_token, bounds, } } process_struct! { syn::TypeInfer { underscore_token, } } process_struct! { syn::TypeMacro { mac, } } process_struct! { syn::TypeNever { bang_token, } } process_struct! { syn::TypeParam { attrs, ident, colon_token, bounds, eq_token, default, } } process_struct! { syn::TypeParen { paren_token, elem, } } process_struct! { syn::TypePath { #[qself] qself, path, } } process_struct! { syn::TypePtr { star_token, const_token, mutability, elem, } } process_struct! { syn::TypeReference { and_token, lifetime, mutability, elem, } } process_struct! { syn::TypeSlice { bracket_token, elem, } } process_struct! { syn::TypeTraitObject { dyn_token, bounds, } } process_struct! { syn::TypeTuple { paren_token, elems, } } process_struct! { syn::UseGlob { star_token, } } process_struct! { syn::UseGroup { brace_token, items, } } process_struct! { syn::UseName { ident, } } process_struct! { syn::UsePath { ident, colon2_token, tree, } } process_struct! { syn::UseRename { ident, as_token, rename, } } process_struct! { syn::Variadic { attrs, pat, dots, comma, } } process_struct! { syn::Variant { attrs, ident, fields, discriminant, } } process_struct! { syn::VisRestricted { pub_token, paren_token, in_token, path, } } process_struct! { syn::WhereClause { where_token, predicates, } } macro_rules! process_enum { ($path:path { $($variant:ident$(($($field:ident),* $(,)?))?,)* }) => { impl Process

for $path { fn process(self, state: &mut State

) -> Option> { match self { $(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)* } } } }; ($path:path { $($variant:ident$(($($field:ident),* $(,)?))?,)* #[no_op] _, }) => { impl Process

for $path { fn process(self, state: &mut State

) -> Option> { #![allow(unused_variables)] match self { $(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)* _ => Some(Output::new(self)), } } } }; } process_enum! { syn::AttrStyle { Outer, Inner(f0), } } process_enum! { syn::BinOp { Add(f0), Sub(f0), Mul(f0), Div(f0), Rem(f0), And(f0), Or(f0), BitXor(f0), BitAnd(f0), BitOr(f0), Shl(f0), Shr(f0), Eq(f0), Lt(f0), Le(f0), Ne(f0), Ge(f0), Gt(f0), AddAssign(f0), SubAssign(f0), MulAssign(f0), DivAssign(f0), RemAssign(f0), BitXorAssign(f0), BitAndAssign(f0), BitOrAssign(f0), ShlAssign(f0), ShrAssign(f0), #[no_op] _, } } process_enum! { syn::CapturedParam { Lifetime(f0), Ident(f0), #[no_op] _, } } process_enum! { syn::Data { Struct(f0), Enum(f0), Union(f0), } } process_enum! { syn::Expr { Array(f0), Assign(f0), Async(f0), Await(f0), Binary(f0), Block(f0), Break(f0), Call(f0), Cast(f0), Closure(f0), Const(f0), Continue(f0), Field(f0), ForLoop(f0), Group(f0), If(f0), Index(f0), Infer(f0), Let(f0), Lit(f0), Loop(f0), Macro(f0), Match(f0), MethodCall(f0), Paren(f0), Path(f0), Range(f0), RawAddr(f0), Reference(f0), Repeat(f0), Return(f0), Struct(f0), Try(f0), TryBlock(f0), Tuple(f0), Unary(f0), Unsafe(f0), Verbatim(f0), While(f0), Yield(f0), #[no_op] _, } } process_enum! { syn::FieldMutability { None, #[no_op] _, } } process_enum! { syn::Fields { Named(f0), Unnamed(f0), Unit, } } process_enum! { syn::FnArg { Receiver(f0), Typed(f0), } } process_enum! { syn::ForeignItem { Fn(f0), Static(f0), Type(f0), Macro(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::GenericArgument { Lifetime(f0), Type(f0), Const(f0), AssocType(f0), AssocConst(f0), Constraint(f0), #[no_op] _, } } process_enum! { syn::GenericParam { Lifetime(f0), Type(f0), Const(f0), } } process_enum! { syn::ImplItem { Const(f0), Fn(f0), Type(f0), Macro(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::ImplRestriction { #[no_op] _, } } process_enum! { syn::Lit { Str(f0), ByteStr(f0), CStr(f0), Byte(f0), Char(f0), Int(f0), Float(f0), Bool(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::MacroDelimiter { Paren(f0), Brace(f0), Bracket(f0), } } process_enum! { syn::Member { Named(f0), Unnamed(f0), } } process_enum! { syn::Meta { Path(f0), List(f0), NameValue(f0), } } process_enum! { syn::Pat { Const(f0), Ident(f0), Lit(f0), Macro(f0), Or(f0), Paren(f0), Path(f0), Range(f0), Reference(f0), Rest(f0), Slice(f0), Struct(f0), Tuple(f0), TupleStruct(f0), Type(f0), Verbatim(f0), Wild(f0), #[no_op] _, } } process_enum! { syn::PathArguments { None, AngleBracketed(f0), Parenthesized(f0), } } process_enum! { syn::PointerMutability { Const(f0), Mut(f0), } } process_enum! { syn::RangeLimits { HalfOpen(f0), Closed(f0), } } process_enum! { syn::ReturnType { Default, Type(f0, f1), } } process_enum! { syn::StaticMutability { Mut(f0), None, #[no_op] _, } } process_enum! { syn::Stmt { Local(f0), Item(f0), Expr(f0, f1), Macro(f0), } } process_enum! { syn::TraitBoundModifier { None, Maybe(f0), } } process_enum! { syn::TraitItem { Const(f0), Fn(f0), Type(f0), Macro(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::Type { Array(f0), BareFn(f0), Group(f0), ImplTrait(f0), Infer(f0), Macro(f0), Never(f0), Paren(f0), Path(f0), Ptr(f0), Reference(f0), Slice(f0), TraitObject(f0), Tuple(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::TypeParamBound { Trait(f0), Lifetime(f0), PreciseCapture(f0), Verbatim(f0), #[no_op] _, } } process_enum! { syn::UnOp { Deref(f0), Not(f0), Neg(f0), #[no_op] _, } } process_enum! { syn::UseTree { Path(f0), Name(f0), Rename(f0), Glob(f0), Group(f0), } } process_enum! { syn::Visibility { Public(f0), Restricted(f0), Inherited, } } process_enum! { syn::WherePredicate { Lifetime(f0), Type(f0), #[no_op] _, } } struct TopItem(syn::Item); impl Process

for TopItem { fn process(self, state: &mut State

) -> Option> { match self.0 { syn::Item::Const(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Enum(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::ExternCrate(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Fn(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::ForeignMod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Impl(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Macro(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Mod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Static(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Struct(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Trait(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::TraitAlias(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Type(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Union(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), syn::Item::Use(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), _ => Some(Output::new(self)), } } } pub(crate) fn process_cfgs(item: syn::Item, cfgs: Cfgs) -> syn::Result> { let mut state = State:: { cfgs, errors: Errors::new(), _phantom: PhantomData, }; let retval = TopItem(item).process(&mut state).map(|v| v.0 .0); state.errors.finish()?; Ok(retval) } pub(crate) fn collect_cfgs(item: syn::Item) -> syn::Result> { let mut state = State:: { cfgs: Cfgs::default(), errors: Errors::new(), _phantom: PhantomData, }; let (None | Some(Output(()))) = TopItem(item).process(&mut state); state.errors.finish()?; Ok(state.cfgs) }