From d9decede3593e220d1a4f4a63b4c651b70073861 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 7 Aug 2020 12:28:52 +0100 Subject: [PATCH 1/5] instance: polymorphize upvar closures/generators This commit modifies how instances are polymorphized so that closures and generators have any closures or generators captured within their upvars also polymorphized - this avoids symbol clashes with the new symbol mangling scheme. Signed-off-by: David Wood --- src/librustc_middle/ty/instance.rs | 107 ++++++++++++++---- .../polymorphization/closure_in_upvar/fn.rs | 29 +++++ .../closure_in_upvar/fnmut.rs | 34 ++++++ .../closure_in_upvar/fnonce.rs | 34 ++++++ .../closure_in_upvar/other.rs | 38 +++++++ 5 files changed, 222 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/polymorphization/closure_in_upvar/fn.rs create mode 100644 src/test/ui/polymorphization/closure_in_upvar/fnmut.rs create mode 100644 src/test/ui/polymorphization/closure_in_upvar/fnonce.rs create mode 100644 src/test/ui/polymorphization/closure_in_upvar/other.rs diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 289a9db7327e0..bdacc04c291f4 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -474,26 +474,7 @@ impl<'tcx> Instance<'tcx> { } if let InstanceDef::Item(def) = self.def { - let unused = tcx.unused_generic_params(def.did); - - if unused.is_empty() { - // Exit early if every parameter was used. - return self; - } - - debug!("polymorphize: unused={:?}", unused); - let polymorphized_substs = - InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind { - // If parameter is a const or type parameter.. - ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if - // ..and is within range and unused.. - unused.contains(param.index).unwrap_or(false) => - // ..then use the identity for this parameter. - tcx.mk_param_from_def(param), - // Otherwise, use the parameter as before. - _ => self.substs[param.index as usize], - }); - + let polymorphized_substs = polymorphize(tcx, def.did, self.substs); debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); Self { def: self.def, substs: polymorphized_substs } } else { @@ -502,6 +483,92 @@ impl<'tcx> Instance<'tcx> { } } +fn polymorphize<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> SubstsRef<'tcx> { + debug!("polymorphize({:?}, {:?})", def_id, substs); + let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize: unused={:?}", unused); + + if unused.is_empty() { + // Exit early if every parameter was used. + return substs; + } + + // If this is a closure or generator then we need to handle the case where another closure + // from the function is captured as an upvar and hasn't been polymorphized. In this case, + // the unpolymorphized upvar closure would result in a polymorphized closure producing + // multiple mono items (and eventually symbol clashes). + let upvars_ty = if tcx.is_closure(def_id) { + Some(substs.as_closure().tupled_upvars_ty()) + } else if tcx.type_of(def_id).is_generator() { + Some(substs.as_generator().tupled_upvars_ty()) + } else { + None + }; + let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false); + debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); + + struct PolymorphizationFolder<'tcx> { + tcx: TyCtxt<'tcx>, + }; + + impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("fold_ty: ty={:?}", ty); + match ty.kind { + ty::Closure(def_id, substs) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + self.tcx.mk_closure(def_id, polymorphized_substs) + } + ty::Generator(def_id, substs, movability) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + self.tcx.mk_generator(def_id, polymorphized_substs, movability) + } + _ => ty.super_fold_with(self), + } + } + } + + InternalSubsts::for_item(tcx, def_id, |param, _| { + let is_unused = unused.contains(param.index).unwrap_or(false); + debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused); + match param.kind { + // Upvar case: If parameter is a type parameter.. + ty::GenericParamDefKind::Type { .. } if + // ..and has upvars.. + has_upvars && + // ..and this param has the same type as the tupled upvars.. + upvars_ty == Some(substs[param.index as usize].expect_ty()) => { + // ..then double-check that polymorphization marked it used.. + debug_assert!(!is_unused); + // ..and polymorphize any closures/generators captured as upvars. + let upvars_ty = upvars_ty.unwrap(); + let polymorphized_upvars_ty = upvars_ty.fold_with( + &mut PolymorphizationFolder { tcx }); + debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty); + ty::GenericArg::from(polymorphized_upvars_ty) + }, + + // Simple case: If parameter is a const or type parameter.. + ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if + // ..and is within range and unused.. + unused.contains(param.index).unwrap_or(false) => + // ..then use the identity for this parameter. + tcx.mk_param_from_def(param), + + // Otherwise, use the parameter as before. + _ => substs[param.index as usize], + } + }) +} + fn needs_fn_once_adapter_shim( actual_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, diff --git a/src/test/ui/polymorphization/closure_in_upvar/fn.rs b/src/test/ui/polymorphization/closure_in_upvar/fn.rs new file mode 100644 index 0000000000000..b0b39dbd3df61 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fn.rs @@ -0,0 +1,29 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + let x = |_: ()| (); + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs new file mode 100644 index 0000000000000..ba75f6c5a1099 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + // Mutate an upvar from `x` so that it implements `FnMut`. + let mut outer = 3; + let mut x = |_: ()| { + outer = 4; + () + }; + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let mut y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs new file mode 100644 index 0000000000000..e9761ad0bcb20 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + // Move a non-copy type into `x` so that it implements `FnOnce`. + let outer = Vec::::new(); + let x = move |_: ()| { + let inner = outer; + () + }; + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/other.rs b/src/test/ui/polymorphization/closure_in_upvar/other.rs new file mode 100644 index 0000000000000..7614aa83fcd15 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/other.rs @@ -0,0 +1,38 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn y_uses_f(f: impl Fn()) { + let x = |_: ()| (); + + let y = || { + f(); + x(()); + }; + + f(); + y(); +} + +fn x_uses_f(f: impl Fn()) { + let x = |_: ()| { f(); }; + + let y = || x(()); + + f(); + y(); +} + +fn entry_a() { + x_uses_f(|| ()); + y_uses_f(|| ()); +} + +fn entry_b() { + x_uses_f(|| ()); + y_uses_f(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} From 0d9924a87b862529591c3039959fef5bc7c95359 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 7 Aug 2020 17:11:16 +0100 Subject: [PATCH 2/5] instance: always polymorphize substs By always polymorphizing substitutions, functions which take closures as arguments (e.g. `impl Fn()`) can have fewer mono items when some of the argument closures can be polymorphized. Signed-off-by: David Wood --- src/librustc_middle/ty/instance.rs | 46 ++++--------------- .../polymorphization/pr-75255.rs | 37 +++++++++++++++ 2 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 src/test/codegen-units/polymorphization/pr-75255.rs diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index bdacc04c291f4..294bdd76d93ad 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -492,25 +492,6 @@ fn polymorphize<'tcx>( let unused = tcx.unused_generic_params(def_id); debug!("polymorphize: unused={:?}", unused); - if unused.is_empty() { - // Exit early if every parameter was used. - return substs; - } - - // If this is a closure or generator then we need to handle the case where another closure - // from the function is captured as an upvar and hasn't been polymorphized. In this case, - // the unpolymorphized upvar closure would result in a polymorphized closure producing - // multiple mono items (and eventually symbol clashes). - let upvars_ty = if tcx.is_closure(def_id) { - Some(substs.as_closure().tupled_upvars_ty()) - } else if tcx.type_of(def_id).is_generator() { - Some(substs.as_generator().tupled_upvars_ty()) - } else { - None - }; - let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false); - debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); - struct PolymorphizationFolder<'tcx> { tcx: TyCtxt<'tcx>, }; @@ -540,31 +521,20 @@ fn polymorphize<'tcx>( let is_unused = unused.contains(param.index).unwrap_or(false); debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused); match param.kind { - // Upvar case: If parameter is a type parameter.. - ty::GenericParamDefKind::Type { .. } if - // ..and has upvars.. - has_upvars && - // ..and this param has the same type as the tupled upvars.. - upvars_ty == Some(substs[param.index as usize].expect_ty()) => { - // ..then double-check that polymorphization marked it used.. - debug_assert!(!is_unused); - // ..and polymorphize any closures/generators captured as upvars. - let upvars_ty = upvars_ty.unwrap(); - let polymorphized_upvars_ty = upvars_ty.fold_with( - &mut PolymorphizationFolder { tcx }); - debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty); - ty::GenericArg::from(polymorphized_upvars_ty) - }, - - // Simple case: If parameter is a const or type parameter.. + // If parameter is a const or type parameter.. ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if // ..and is within range and unused.. unused.contains(param.index).unwrap_or(false) => // ..then use the identity for this parameter. tcx.mk_param_from_def(param), - // Otherwise, use the parameter as before. - _ => substs[param.index as usize], + // Otherwise, use the parameter as before (polymorphizing any closures or generators). + _ => { + let arg = substs[param.index as usize]; + let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx }); + debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg); + ty::GenericArg::from(polymorphized_arg) + } } }) } diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs new file mode 100644 index 0000000000000..ea9a6e8b18187 --- /dev/null +++ b/src/test/codegen-units/polymorphization/pr-75255.rs @@ -0,0 +1,37 @@ +// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1 +// ignore-tidy-linelength + +#![crate_type = "rlib"] + +// Test that only one copy of `Iter::map` is generated. + +fn foo() { + let x = [1, 2, 3, std::mem::size_of::()]; + x.iter().map(|_| ()); +} + +pub fn dispatch() { + foo::(); + foo::>(); +} + +//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0], pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.0[External] +//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0], (), pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.1[Internal] + +// These are all the items that aren't relevant to the test. +//~ MONO_ITEM fn core::mem[0]::size_of[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::null[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External] +//~ MONO_ITEM fn pr_75255::foo[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::foo[0]> @@ pr_75255-cgu.1[Internal] From 5827b5a4bd0bb35251da12fc972aa1d5a210116f Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 7 Aug 2020 17:50:45 +0100 Subject: [PATCH 3/5] ty: add `MAY_POLYMORPHIZE` flag This commit adds a `MAY_POLYMORPHIZE` which checks for closures and generators so that polymorphization of substs does not need to traverse every substs. Signed-off-by: David Wood --- src/librustc_middle/ty/flags.rs | 4 ++++ src/librustc_middle/ty/fold.rs | 6 ++++++ src/librustc_middle/ty/instance.rs | 6 +++++- src/librustc_middle/ty/mod.rs | 4 ++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 27f50c240db67..1782c38f5739b 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -85,6 +85,8 @@ impl FlagComputation { } &ty::Generator(_, ref substs, _) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + let substs = substs.as_generator(); let should_remove_further_specializable = !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); @@ -107,6 +109,8 @@ impl FlagComputation { } &ty::Closure(_, substs) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + let substs = substs.as_closure(); let should_remove_further_specializable = !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 492f8ce9ef1a9..c7dbd79e0330d 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -150,6 +150,12 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } + /// Does this value contain closures or generators such that it may require + /// polymorphization? + fn may_polymorphize(&self) -> bool { + self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE) + } + /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { pub struct Visitor(F); diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 294bdd76d93ad..439e35c975781 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -528,7 +528,11 @@ fn polymorphize<'tcx>( // ..then use the identity for this parameter. tcx.mk_param_from_def(param), - // Otherwise, use the parameter as before (polymorphizing any closures or generators). + // If the parameter does not contain any closures or generators, then use the + // substitution directly. + _ if !substs.may_polymorphize() => substs[param.index as usize], + + // Otherwise, use the substitution after polymorphizing. _ => { let arg = substs[param.index as usize]; let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx }); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index bd45f866abc8b..349add46fb28d 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -575,6 +575,10 @@ bitflags! { /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? const STILL_FURTHER_SPECIALIZABLE = 1 << 17; + + /// Does this value contain closures or generators such that it may require + /// polymorphization? + const MAY_POLYMORPHIZE = 1 << 18; } } From 4ccaf6f38ce5b617635ec5dc738275c681090eff Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 7 Aug 2020 17:51:40 +0100 Subject: [PATCH 4/5] instance: avoid unnecessary `mk_` calls This commit avoids unnecessary calls to `mk_closure` and `mk_generator` by checking if the polymorphized substs match the original substs. Signed-off-by: David Wood --- src/librustc_middle/ty/instance.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 439e35c975781..0eea10513d1fa 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -506,11 +506,19 @@ fn polymorphize<'tcx>( match ty.kind { ty::Closure(def_id, substs) => { let polymorphized_substs = polymorphize(self.tcx, def_id, substs); - self.tcx.mk_closure(def_id, polymorphized_substs) + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_closure(def_id, polymorphized_substs) + } } ty::Generator(def_id, substs, movability) => { let polymorphized_substs = polymorphize(self.tcx, def_id, substs); - self.tcx.mk_generator(def_id, polymorphized_substs, movability) + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_generator(def_id, polymorphized_substs, movability) + } } _ => ty.super_fold_with(self), } From ac50d61785ae5112b9b4e30a58cfcffe096b31ec Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 7 Aug 2020 17:57:21 +0100 Subject: [PATCH 5/5] instance: polymorphize `FnDef` substs This commit extends previous polymorphization of substs to polymorphize `FnDef`. Signed-off-by: David Wood --- src/librustc_middle/ty/flags.rs | 2 ++ src/librustc_middle/ty/fold.rs | 2 +- src/librustc_middle/ty/instance.rs | 8 +++++++ src/librustc_middle/ty/mod.rs | 2 +- .../polymorphization/pr-75255.rs | 23 +++++++++++++++---- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 1782c38f5739b..81f7474962c8d 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -196,6 +196,8 @@ impl FlagComputation { } &ty::FnDef(_, substs) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + self.add_substs(substs); } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index c7dbd79e0330d..87434f3f26777 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -150,7 +150,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } - /// Does this value contain closures or generators such that it may require + /// Does this value contain closures, generators or functions such that it may require /// polymorphization? fn may_polymorphize(&self) -> bool { self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE) diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 0eea10513d1fa..cf876db26bc76 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -512,6 +512,14 @@ fn polymorphize<'tcx>( self.tcx.mk_closure(def_id, polymorphized_substs) } } + ty::FnDef(def_id, substs) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_fn_def(def_id, polymorphized_substs) + } + } ty::Generator(def_id, substs, movability) => { let polymorphized_substs = polymorphize(self.tcx, def_id, substs); if substs == polymorphized_substs { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 349add46fb28d..c82fb2712c216 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -576,7 +576,7 @@ bitflags! { /// replaced later, in a way that would change the results of `impl` specialization? const STILL_FURTHER_SPECIALIZABLE = 1 << 17; - /// Does this value contain closures or generators such that it may require + /// Does this value contain closures, generators or functions such that it may require /// polymorphization? const MAY_POLYMORPHIZE = 1 << 18; } diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs index ea9a6e8b18187..af47b440640af 100644 --- a/src/test/codegen-units/polymorphization/pr-75255.rs +++ b/src/test/codegen-units/polymorphization/pr-75255.rs @@ -3,20 +3,33 @@ #![crate_type = "rlib"] -// Test that only one copy of `Iter::map` is generated. +// Test that only one copy of `Iter::map` and `iter::repeat` are generated. + +fn unused() -> u64 { + 42 +} fn foo() { let x = [1, 2, 3, std::mem::size_of::()]; x.iter().map(|_| ()); } +//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0], pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.0[External] +//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0], (), pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.1[Internal] + +fn bar() { + std::iter::repeat(unused::); +} + +//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0] u64> @@ pr_75255-cgu.1[Internal] + pub fn dispatch() { foo::(); foo::>(); -} -//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0], pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.0[External] -//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0], (), pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.1[Internal] + bar::(); + bar::>(); +} // These are all the items that aren't relevant to the test. //~ MONO_ITEM fn core::mem[0]::size_of[0] @@ pr_75255-cgu.1[Internal] @@ -35,3 +48,5 @@ pub fn dispatch() { //~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External] //~ MONO_ITEM fn pr_75255::foo[0] @@ pr_75255-cgu.1[Internal] //~ MONO_ITEM fn pr_75255::foo[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0]> @@ pr_75255-cgu.1[Internal]