From 4e116e14263ac27b4f0e4362638f281c06183813 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Sat, 7 Oct 2017 09:20:13 -0500 Subject: [PATCH 1/5] Convert return type of get_vtable_methods to Vec --- src/librustc/traits/mod.rs | 4 ++-- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/meth.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index bdfbefd13649e..b58ffd4c7b8f2 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -653,7 +653,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn get_vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) - -> impl Iterator)>> + 'a + -> Vec)>> { debug!("get_vtable_methods({:?})", trait_ref); @@ -696,7 +696,7 @@ pub fn get_vtable_methods<'a, 'tcx>( Some((def_id, substs)) }) - }) + }).collect() } impl<'tcx,O> Obligation<'tcx,O> { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 9d1e36fa58106..835283aa09b4f 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -850,7 +850,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Walk all methods of the trait, including those of its supertraits let methods = traits::get_vtable_methods(tcx, poly_trait_ref); - let methods = methods.filter_map(|method| method) + let methods = methods.into_iter().filter_map(|method| method) .map(|(def_id, substs)| ty::Instance::resolve( tcx, ty::ParamEnv::empty(traits::Reveal::All), diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 88407947f0ef4..72f580c2d3867 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -87,7 +87,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let Some(trait_ref) = trait_ref { let trait_ref = trait_ref.with_self_ty(tcx, ty); - let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { + let methods = traits::get_vtable_methods(tcx, trait_ref).into_iter().map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { callee::resolve_and_get_fn(ccx, def_id, substs) }) From b640c2b95a13ead0285490323b55bfbe01da8e60 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Sat, 7 Oct 2017 16:55:09 -0500 Subject: [PATCH 2/5] get_vtable_methods => vtable_methods query --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/traits/mod.rs | 12 +++++++----- src/librustc/ty/maps/config.rs | 6 ++++++ src/librustc/ty/maps/keys.rs | 9 +++++++++ src/librustc/ty/maps/mod.rs | 6 ++++++ src/librustc/ty/maps/plumbing.rs | 1 + src/librustc_trans/collector.rs | 2 +- src/librustc_trans/meth.rs | 3 +-- 8 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index b44262416343d..4600cdbc692e7 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -506,6 +506,7 @@ define_dep_nodes!( <'tcx> [] SpecializationGraph(DefId), [] ObjectSafety(DefId), [] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> }, + [] VtableMethods { trait_ref: PolyTraitRef<'tcx> }, [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index b58ffd4c7b8f2..8da0f8f13ff81 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -650,12 +650,12 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Given a trait `trait_ref`, iterates the vtable entries /// that come from `trait_ref`, including its supertraits. #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. -pub fn get_vtable_methods<'a, 'tcx>( +pub fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Vec)>> { - debug!("get_vtable_methods({:?})", trait_ref); + debug!("vtable_methods({:?})", trait_ref); supertraits(tcx, trait_ref).flat_map(move |trait_ref| { let trait_methods = tcx.associated_items(trait_ref.def_id()) @@ -664,12 +664,12 @@ pub fn get_vtable_methods<'a, 'tcx>( // Now list each method's DefId and Substs (for within its trait). // If the method can never be called from this object, produce None. trait_methods.map(move |trait_method| { - debug!("get_vtable_methods: trait_method={:?}", trait_method); + debug!("vtable_methods: trait_method={:?}", trait_method); let def_id = trait_method.def_id; // Some methods cannot be called on an object; skip those. if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { - debug!("get_vtable_methods: not vtable safe"); + debug!("vtable_methods: not vtable safe"); return None; } @@ -690,7 +690,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // do not want to try and trans it, in that case (see #23435). let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("get_vtable_methods: predicates do not hold"); + debug!("vtable_methods: predicates do not hold"); return None; } @@ -836,6 +836,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, trans_fulfill_obligation: trans::trans_fulfill_obligation, + vtable_methods, ..*providers }; } @@ -846,6 +847,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, trans_fulfill_obligation: trans::trans_fulfill_obligation, + vtable_methods, ..*providers }; } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index dee1516e0f8b3..137039598a55b 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -503,6 +503,12 @@ impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> { } } +impl<'tcx> QueryDescription for queries::vtable_methods<'tcx> { + fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String { + format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())) + } +} + impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("seeing if the crate has enabled `Copy` closures") diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index 1bd4f3e657eb0..ee4523d6f3e1e 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -143,6 +143,15 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } } +impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ + fn map_crate(&self) -> CrateNum { + self.def_id().krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + impl<'tcx> Key for Ty<'tcx> { fn map_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 2001de88803aa..872069d381b9b 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -228,6 +228,8 @@ define_maps! { <'tcx> [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies, [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn is_mir_available: IsMirAvailable(DefId) -> bool, + [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) + -> Vec)>>, [] fn trans_fulfill_obligation: fulfill_obligation_dep_node( (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, @@ -470,3 +472,7 @@ fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstru fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::OutputFilenames } + +fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::VtableMethods{ trait_ref } +} diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 6135538176109..462149c2ed8e5 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -749,6 +749,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::CodegenUnit | DepKind::CompileCodegenUnit | DepKind::FulfillObligation | + DepKind::VtableMethods | // These are just odd DepKind::Null | diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 835283aa09b4f..084787000016e 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -849,7 +849,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(!poly_trait_ref.has_escaping_regions()); // Walk all methods of the trait, including those of its supertraits - let methods = traits::get_vtable_methods(tcx, poly_trait_ref); + let methods = tcx.vtable_methods(poly_trait_ref); let methods = methods.into_iter().filter_map(|method| method) .map(|(def_id, substs)| ty::Instance::resolve( tcx, diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 72f580c2d3867..66d633cf9a1f1 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -9,7 +9,6 @@ // except according to those terms. use llvm::ValueRef; -use rustc::traits; use callee; use common::*; use builder::Builder; @@ -87,7 +86,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let Some(trait_ref) = trait_ref { let trait_ref = trait_ref.with_self_ty(tcx, ty); - let methods = traits::get_vtable_methods(tcx, trait_ref).into_iter().map(|opt_mth| { + let methods = tcx.vtable_methods(trait_ref).into_iter().map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { callee::resolve_and_get_fn(ccx, def_id, substs) }) From 81f9d4e78f3bc17bc803c793ecac43861ee5eed5 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Mon, 9 Oct 2017 10:39:53 -0500 Subject: [PATCH 3/5] Wrap vtable_methods return type in RC --- src/librustc/traits/mod.rs | 84 +++++++++++++++++---------------- src/librustc/ty/maps/mod.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/meth.rs | 3 +- 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 8da0f8f13ff81..53a974a4bbbd3 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -653,50 +653,52 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) - -> Vec)>> + -> Rc)>>> { debug!("vtable_methods({:?})", trait_ref); - supertraits(tcx, trait_ref).flat_map(move |trait_ref| { - let trait_methods = tcx.associated_items(trait_ref.def_id()) - .filter(|item| item.kind == ty::AssociatedKind::Method); - - // Now list each method's DefId and Substs (for within its trait). - // If the method can never be called from this object, produce None. - trait_methods.map(move |trait_method| { - debug!("vtable_methods: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; - - // Some methods cannot be called on an object; skip those. - if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { - debug!("vtable_methods: not vtable safe"); - return None; - } - - // the method may have some early-bound lifetimes, add - // regions for those - let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.types.re_erased, - |def, _| trait_ref.substs().type_for_def(def)); - - // the trait type may have higher-ranked lifetimes in it; - // so erase them if they appear, so that we get the type - // at some particular call site - let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs)); - - // It's possible that the method relies on where clauses that - // do not hold for this particular set of type parameters. - // Note that this method could then never be called, so we - // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("vtable_methods: predicates do not hold"); - return None; - } - - Some((def_id, substs)) - }) - }).collect() + Rc::new( + supertraits(tcx, trait_ref).flat_map(move |trait_ref| { + let trait_methods = tcx.associated_items(trait_ref.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Method); + + // Now list each method's DefId and Substs (for within its trait). + // If the method can never be called from this object, produce None. + trait_methods.map(move |trait_method| { + debug!("vtable_methods: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; + + // Some methods cannot be called on an object; skip those. + if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { + debug!("vtable_methods: not vtable safe"); + return None; + } + + // the method may have some early-bound lifetimes, add + // regions for those + let substs = Substs::for_item(tcx, def_id, + |_, _| tcx.types.re_erased, + |def, _| trait_ref.substs().type_for_def(def)); + + // the trait type may have higher-ranked lifetimes in it; + // so erase them if they appear, so that we get the type + // at some particular call site + let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs)); + + // It's possible that the method relies on where clauses that + // do not hold for this particular set of type parameters. + // Note that this method could then never be called, so we + // do not want to try and trans it, in that case (see #23435). + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + if !normalize_and_test_predicates(tcx, predicates.predicates) { + debug!("vtable_methods: predicates do not hold"); + return None; + } + + Some((def_id, substs)) + }) + }).collect() + ) } impl<'tcx,O> Obligation<'tcx,O> { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 872069d381b9b..4b68f5addd2be 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -229,7 +229,7 @@ define_maps! { <'tcx> [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn is_mir_available: IsMirAvailable(DefId) -> bool, [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) - -> Vec)>>, + -> Rc)>>>, [] fn trans_fulfill_obligation: fulfill_obligation_dep_node( (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 084787000016e..33a2e96ee6621 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -850,7 +850,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Walk all methods of the trait, including those of its supertraits let methods = tcx.vtable_methods(poly_trait_ref); - let methods = methods.into_iter().filter_map(|method| method) + let methods = methods.iter().cloned().filter_map(|method| method) .map(|(def_id, substs)| ty::Instance::resolve( tcx, ty::ParamEnv::empty(traits::Reveal::All), diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 66d633cf9a1f1..3253a0339a850 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -86,7 +86,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let Some(trait_ref) = trait_ref { let trait_ref = trait_ref.with_self_ty(tcx, ty); - let methods = tcx.vtable_methods(trait_ref).into_iter().map(|opt_mth| { + let methods = tcx.vtable_methods(trait_ref); + let methods = methods.iter().cloned().map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { callee::resolve_and_get_fn(ccx, def_id, substs) }) From 2160bab0dac479e72f49932c1c71cb3d01f4e9f6 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Mon, 9 Oct 2017 10:41:19 -0500 Subject: [PATCH 4/5] Remove export of vtable_methods --- src/librustc/traits/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 53a974a4bbbd3..1fddb1864175f 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -650,7 +650,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Given a trait `trait_ref`, iterates the vtable entries /// that come from `trait_ref`, including its supertraits. #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. -pub fn vtable_methods<'a, 'tcx>( +fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Rc)>>> From fcb8bc9d4e08924d4e4bde1ef4995b329fbc11b5 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Thu, 12 Oct 2017 16:45:07 -0500 Subject: [PATCH 5/5] Remove recursion from `define_{provider|map}_struct` --- src/librustc/ty/maps/plumbing.rs | 103 ++----------------------------- 1 file changed, 4 insertions(+), 99 deletions(-) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 462149c2ed8e5..3f215303ccbee 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -468,8 +468,7 @@ macro_rules! define_maps { define_provider_struct! { tcx: $tcx, - input: ($(([$($modifiers)*] [$name] [$K] [$V]))*), - output: () + input: ($(([$($modifiers)*] [$name] [$K] [$V]))*) } impl<$tcx> Copy for Providers<$tcx> {} @@ -480,78 +479,19 @@ macro_rules! define_maps { } macro_rules! define_map_struct { - // Initial state (tcx: $tcx:tt, - input: $input:tt) => { - define_map_struct! { - tcx: $tcx, - input: $input, - output: () - } - }; - - // Final output - (tcx: $tcx:tt, - input: (), - output: ($($output:tt)*)) => { + input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Maps<$tcx> { providers: IndexVec>, query_stack: RefCell)>>, - $($output)* - } - }; - - // Field recognized and ready to shift into the output - (tcx: $tcx:tt, - ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]), - input: $input:tt, - output: ($($output:tt)*)) => { - define_map_struct! { - tcx: $tcx, - input: $input, - output: ($($output)* - $(#[$attr])* $($pub)* $name: RefCell>>,) - } - }; - - // No modifiers left? This is a private item. - (tcx: $tcx:tt, - input: (([] $attrs:tt $name:tt) $($input:tt)*), - output: $output:tt) => { - define_map_struct! { - tcx: $tcx, - ready: ([] $attrs $name), - input: ($($input)*), - output: $output - } - }; - - // Skip other modifiers - (tcx: $tcx:tt, - input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), - output: $output:tt) => { - define_map_struct! { - tcx: $tcx, - input: (([$($modifiers)*] $($fields)*) $($input)*), - output: $output + $($(#[$attr])* $name: RefCell>>,)* } }; } macro_rules! define_provider_struct { - // Initial state: - (tcx: $tcx:tt, input: $input:tt) => { - define_provider_struct! { - tcx: $tcx, - input: $input, - output: () - } - }; - - // Final state: (tcx: $tcx:tt, - input: (), - output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => { + input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => { pub struct Providers<$tcx> { $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)* } @@ -566,41 +506,6 @@ macro_rules! define_provider_struct { } } }; - - // Something ready to shift: - (tcx: $tcx:tt, - ready: ($name:tt $K:tt $V:tt), - input: $input:tt, - output: ($($output:tt)*)) => { - define_provider_struct! { - tcx: $tcx, - input: $input, - output: ($($output)* ($name $K $V)) - } - }; - - // Regular queries produce a `V` only. - (tcx: $tcx:tt, - input: (([] $name:tt $K:tt $V:tt) $($input:tt)*), - output: $output:tt) => { - define_provider_struct! { - tcx: $tcx, - ready: ($name $K $V), - input: ($($input)*), - output: $output - } - }; - - // Skip modifiers. - (tcx: $tcx:tt, - input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), - output: $output:tt) => { - define_provider_struct! { - tcx: $tcx, - input: (([$($modifiers)*] $($fields)*) $($input)*), - output: $output - } - }; }