diff --git a/Cargo.lock b/Cargo.lock index bb029df7a088a..ad402552723dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4242,6 +4242,8 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index f80f9965f4d8a..fb12e1d7c7981 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,4 +1,5 @@ -use std::collections::hash_map::Entry::*; +use std::collections::btree_map::Entry::*; +use std::collections::BTreeMap; use rustc_ast::expand::allocator::ALLOCATOR_METHODS; use rustc_data_structures::fingerprint::Fingerprint; @@ -14,7 +15,7 @@ use rustc_middle::middle::exported_symbols::{ use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; -use rustc_middle::ty::{SymbolName, TyCtxt}; +use rustc_middle::ty::{self, SymbolName, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::SanitizerSet; @@ -272,10 +273,10 @@ fn exported_symbols_provider_local( fn upstream_monomorphizations_provider( tcx: TyCtxt<'_>, (): (), -) -> DefIdMap, CrateNum>> { +) -> DefIdMap, CrateNum>> { let cnums = tcx.crates(()); - let mut instances: DefIdMap> = Default::default(); + let mut instances: DefIdMap> = Default::default(); let cnum_stable_ids: IndexVec = { let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, cnums.len() + 1); @@ -333,7 +334,7 @@ fn upstream_monomorphizations_provider( fn upstream_monomorphizations_for_provider( tcx: TyCtxt<'_>, def_id: DefId, -) -> Option<&FxHashMap, CrateNum>> { +) -> Option<&BTreeMap, CrateNum>> { debug_assert!(!def_id.is_local()); tcx.upstream_monomorphizations(()).get(&def_id) } @@ -343,7 +344,20 @@ fn upstream_drop_glue_for_provider<'tcx>( substs: SubstsRef<'tcx>, ) -> Option { if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { - tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned()) + tcx.upstream_monomorphizations_for(def_id).and_then(|monos| { + monos.get(&substs).cloned().or_else(|| { + monos + .iter() + .find(|(k, _)| { + tcx.is_polymorphic_parent(( + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + k, + substs, + )) + }) + .map(|(_, &v)| v) + }) + }) } else { None } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 9bb4982754c20..6001d7cd71e75 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -874,7 +874,7 @@ impl CrateInfo { } pub fn provide(providers: &mut Providers) { - providers.backend_optimization_level = |tcx, cratenum| { + providers.backend_optimization_level = |tcx, ()| { let for_speed = match tcx.sess.opts.optimize { // If globally no optimisation is done, #[optimize] has no effect. // @@ -893,9 +893,9 @@ pub fn provide(providers: &mut Providers) { config::OptLevel::SizeMin => config::OptLevel::Default, }; - let (defids, _) = tcx.collect_and_partition_mono_items(cratenum); - for id in &*defids { - let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); + let (mono_items, _) = tcx.collect_and_partition_mono_items(()); + for did in mono_items.def_id_iter() { + let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(did); match optimize { attr::OptimizeAttr::None => continue, attr::OptimizeAttr::Size => continue, diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index cff848eeb6a0f..6479d6187ae68 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -286,6 +286,29 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for GenericArg<'tcx> { + fn to_trace( + tcx: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + match (a.unpack(), b.unpack()) { + (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { + ToTrace::to_trace(tcx, cause, a_is_expected, a, b) + } + (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { + ToTrace::to_trace(tcx, cause, a_is_expected, a, b) + } + (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { + ToTrace::to_trace(tcx, cause, a_is_expected, a, b) + } + _ => bug!("generic arg mismatch: {:?} {:?}", a, b), + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 09bfb3290f4ca..0a6cc08e8befe 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -129,13 +129,18 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { where R: ConstEquateRelation<'tcx>, { - let a = self.tcx.expose_default_const_substs(a); - let b = self.tcx.expose_default_const_substs(b); + let mut a = self.tcx.expose_default_const_substs(a); + let mut b = self.tcx.expose_default_const_substs(b); debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); if a == b { return Ok(a); } + if a.ty != b.ty { + a = self.resolve_vars_if_possible(a); + b = self.resolve_vars_if_possible(b); + } + let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), a); let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), b); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index ee2e190e7cd44..400cbabedec29 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -33,6 +33,7 @@ macro_rules! arena_types { [] const_allocs: rustc_middle::mir::interpret::Allocation, // Required for the incremental on-disk cache [] mir_keys: rustc_hir::def_id::DefIdSet, + [few] mono_item_map: rustc_middle::mir::mono::MonoItemMap<'tcx>, [] region_scope_tree: rustc_middle::middle::region::ScopeTree, [] dropck_outlives: rustc_middle::infer::canonical::Canonical<'tcx, diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 06b42320049f0..8c953c6a8301a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,9 +1,10 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; -use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; +use crate::ty::subst::{InternalSubsts, SubstsRef}; +use crate::ty::{Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::{HirId, ItemId}; @@ -237,6 +238,72 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { } } +/// A map containing all monomorphized items of the current crate. +#[derive(Default, Debug, HashStable)] +pub struct MonoItemMap<'tcx> { + /// Items which are not generic functions. + /// + /// we don't care about these wrt polymorphization, + /// so we can treat them in a far simpler way. + pub trivially_concrete: FxIndexSet>, + pub item_map: FxIndexMap, Vec>>, +} + +impl MonoItemMap<'tcx> { + pub fn all_items<'a>(&'a self) -> impl Iterator> + 'a { + self.trivially_concrete.iter().copied().chain(self.item_map.iter().flat_map( + |(&def, substs)| { + substs.iter().map(move |&substs| MonoItem::Fn(Instance { def, substs })) + }, + )) + } + + pub fn def_id_iter<'a>(&'a self) -> impl Iterator + 'a { + self.trivially_concrete + .iter() + .filter_map(|&mono_item| match mono_item { + MonoItem::Fn(instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .chain(self.item_map.iter().map(|(&def, _)| def.def_id())) + } + + pub fn contains(&self, item: MonoItem<'tcx>) -> bool { + match item { + MonoItem::Fn(instance) if item.is_generic_fn() => self + .item_map + .get(&instance.def) + .map_or(false, |substs| substs.contains(&instance.substs)), + MonoItem::Static(_) | MonoItem::GlobalAsm(_) | MonoItem::Fn(_) => { + self.trivially_concrete.contains(&item) + } + } + } + + pub fn get_polymorphic_instance( + &self, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + ) -> Option> { + if instance.substs.non_erasable_generics().next().is_some() { + for substs in self.item_map.get(&instance.def).into_iter().flat_map(|v| v).copied() { + if substs == instance.substs + || tcx.is_polymorphic_parent((instance.def, substs, instance.substs)) + { + return Some(Instance { def: instance.def, substs }); + } + } + + None + } else if self.trivially_concrete.contains(&MonoItem::Fn(instance)) { + Some(instance) + } else { + None + } + } +} + #[derive(Debug)] pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8667a6bea11f6..d6a5a0b319efc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1307,7 +1307,7 @@ rustc_queries! { /// added or removed in any upstream crate. Instead use the narrower /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even /// better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations(_: ()) -> DefIdMap, CrateNum>> { + query upstream_monomorphizations(_: ()) -> DefIdMap, CrateNum>> { storage(ArenaCacheSelector<'tcx>) desc { "collecting available upstream monomorphizations" } } @@ -1320,7 +1320,7 @@ rustc_queries! { /// You likely want to call `Instance::upstream_monomorphization()` /// instead of invoking this query directly. query upstream_monomorphizations_for(def_id: DefId) - -> Option<&'tcx FxHashMap, CrateNum>> { + -> Option<&'tcx BTreeMap, CrateNum>> { desc { |tcx| "collecting available upstream monomorphizations for `{}`", tcx.def_path_str(def_id), @@ -1600,7 +1600,7 @@ rustc_queries! { separate_provide_extern } - query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { + query collect_and_partition_mono_items(_: ()) -> (&'tcx MonoItemMap<'tcx>, &'tcx [CodegenUnit<'tcx>]) { eval_always desc { "collect_and_partition_mono_items" } } @@ -1625,6 +1625,13 @@ rustc_queries! { } separate_provide_extern } + query is_polymorphic_parent(key: (ty::InstanceDef<'tcx>, SubstsRef<'tcx>, SubstsRef<'tcx>)) -> bool { + desc { + "checking whether `{:?}` is the polymorphic parent of {:?}", + key.1, key.2 + } + } + query backend_optimization_level(_: ()) -> OptLevel { desc { "optimization level used by backend" } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 275a2128c4556..b5446a173350f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1424,6 +1424,10 @@ impl<'tcx> TyCtxt<'tcx> { features.generic_const_exprs } + pub fn should_polymorphize(self) -> bool { + true + } + #[inline] pub fn local_crate_exports_generics(self) -> bool { debug_assert!(self.sess.opts.share_generics()); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4b38105e44717..ac6a9de111890 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -127,9 +127,16 @@ impl<'tcx> Instance<'tcx> { self.substs.non_erasable_generics().next()?; match self.def { - InstanceDef::Item(def) => tcx - .upstream_monomorphizations_for(def.did) - .and_then(|monos| monos.get(&self.substs).cloned()), + InstanceDef::Item(def) => { + tcx.upstream_monomorphizations_for(def.did).and_then(|monos| { + monos.get(&self.substs).cloned().or_else(|| { + monos + .iter() + .find(|(k, _)| tcx.is_polymorphic_parent((self.def, k, self.substs))) + .map(|(_, &v)| v) + }) + }) + } InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs), _ => None, } @@ -577,114 +584,35 @@ impl<'tcx> Instance<'tcx> { /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by /// identity parameters if they are determined to be unused in `instance.def`. + /// + /// This must only be used after mono item collection. pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { debug!("polymorphize: running polymorphization analysis"); - if !tcx.sess.opts.debugging_opts.polymorphize { + if !tcx.should_polymorphize() { return self; } - let polymorphized_substs = polymorphize(tcx, self.def, self.substs); - debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); - Self { def: self.def, substs: polymorphized_substs } - } -} - -fn polymorphize<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, - substs: SubstsRef<'tcx>, -) -> SubstsRef<'tcx> { - debug!("polymorphize({:?}, {:?})", instance, substs); - let unused = tcx.unused_generic_params(instance); - debug!("polymorphize: unused={:?}", unused); - - // 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 def_id = instance.def_id(); - 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_or(false, |ty| ty.tuple_fields().count() > 0); - 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, - ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), - 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, - ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), - substs, - ); - if substs == polymorphized_substs { - ty - } else { - self.tcx.mk_generator(def_id, polymorphized_substs, movability) - } - } - _ => ty.super_fold_with(self), - } + let (mono_item_map, _) = tcx.collect_and_partition_mono_items(()); + match mono_item_map.get_polymorphic_instance(tcx, self) { + Some(instance) => instance, + // FIXME(polymorphization): We currently do not use + // polymorphic instances from separate crates, + // and assume that we just have a mono item for this + // instance in some other crate. + None => match self.def { + InstanceDef::Item(def) if !def.is_local() => tcx + .upstream_monomorphizations_for(def.did) + .and_then(|monos| { + monos + .iter() + .find(|(k, _)| tcx.is_polymorphic_parent((self.def, k, self.substs))) + .map(|(k, _)| Instance { def: self.def, substs: k }) + }) + .unwrap_or(self), + _ => 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( diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 34f806271979a..5307e708018b7 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -15,7 +15,7 @@ use crate::mir; use crate::mir::interpret::GlobalId; use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; -use crate::mir::mono::CodegenUnit; +use crate::mir::mono::{CodegenUnit, MonoItemMap}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index f766cad2b3d21..8167237291852 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -89,9 +89,8 @@ pub(super) fn vtable_allocation_provider<'tcx>( VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(), VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(), VtblEntry::Vacant => continue, - VtblEntry::Method(instance) => { + &VtblEntry::Method(instance) => { // Prepare the fn ptr we write into the vtable. - let instance = instance.polymorphize(tcx); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index f812afe6b62ba..3b1509466d4fe 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -13,6 +13,8 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector/mod.rs similarity index 79% rename from compiler/rustc_monomorphize/src/collector.rs rename to compiler/rustc_monomorphize/src/collector/mod.rs index 59988e69b5d3a..eaf689f60d70f 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector/mod.rs @@ -178,6 +178,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +use crate::polymorphize; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; use rustc_errors::{ErrorReported, FatalError}; @@ -188,13 +189,14 @@ use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::GrowableBitSet; use rustc_middle::mir::interpret::{AllocId, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::mono::{InstantiationMode, MonoItem, MonoItemMap}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry}; +use rustc_middle::ty::Instance; +use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, VtblEntry}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_session::config::EntryFnType; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; @@ -206,12 +208,83 @@ use std::iter; use std::ops::Range; use std::path::PathBuf; +pub(crate) mod neighbor; +use neighbor::{Neighbor, NeighborKind, NeighborSourceKind}; + #[derive(PartialEq)] pub enum MonoItemCollectionMode { Eager, Lazy, } +pub struct Visited<'tcx> { + tcx: TyCtxt<'tcx>, + map: MonoItemMap<'tcx>, + /// We can eagerly insert trivially concrete items + /// into our map, so we only care about cycles for + /// generic stuff. + in_progress_fns: Vec>, +} + +impl Visited<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Visited<'tcx> { + Visited { tcx, map: Default::default(), in_progress_fns: Default::default() } + } + + #[instrument(skip(self), level = "debug")] + fn start_item(&mut self, item: MonoItem<'tcx>) -> Option> { + match item { + MonoItem::Fn(instance) if item.is_generic_fn() => { + if self.in_progress_fns.contains(&instance) { + // We encountered a cycle. For now, we return the fully concrete instance + // without adding it to the map. While this might seem dangerous, + // we will add a polymorphized instance of this item to the map + // later when finishing that item. + debug!("cycle"); + return Some(item); + } + + debug!("fresh: {:?}", instance); + + if let Some(instance) = self.map.get_polymorphic_instance(self.tcx, instance) { + return Some(MonoItem::Fn(instance)); + } + + self.in_progress_fns.push(instance); + None + } + MonoItem::Fn(_) | MonoItem::Static(_) | MonoItem::GlobalAsm(_) => { + if self.map.trivially_concrete.insert(item) { + debug!("insert concrete"); + None + } else { + debug!("old concrete"); + Some(item) + } + } + } + } + + fn finish_item(&mut self, item: MonoItem<'tcx>) -> MonoItem<'tcx> { + match item { + MonoItem::Fn(instance) if item.is_generic_fn() => { + assert_eq!(Some(instance.def), self.in_progress_fns.pop().map(|i| i.def)); + debug_assert_eq!(self.map.get_polymorphic_instance(self.tcx, instance), None); + + self.map.item_map.entry(instance.def).or_default().push(instance.substs); + + item + } + MonoItem::Fn(_) | MonoItem::Static(_) | MonoItem::GlobalAsm(_) => item, // Inserted in `start_item`. + } + } + + fn finish(self) -> MonoItemMap<'tcx> { + assert!(self.in_progress_fns.is_empty()); + self.map + } +} + /// Maps every mono item to all mono items it references in its /// body. pub struct InliningMap<'tcx> { @@ -283,7 +356,7 @@ impl<'tcx> InliningMap<'tcx> { pub fn collect_crate_mono_items( tcx: TyCtxt<'_>, mode: MonoItemCollectionMode, -) -> (FxHashSet>, InliningMap<'_>) { +) -> (MonoItemMap<'_>, InliningMap<'_>) { let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); let roots = @@ -291,7 +364,7 @@ pub fn collect_crate_mono_items( debug!("building mono item graph, beginning at roots"); - let mut visited = MTLock::new(FxHashSet::default()); + let mut visited = MTLock::new(Visited::new(tcx)); let mut inlining_map = MTLock::new(InliningMap::new()); let recursion_limit = tcx.recursion_limit(); @@ -314,7 +387,7 @@ pub fn collect_crate_mono_items( }); } - (visited.into_inner(), inlining_map.into_inner()) + (visited.into_inner().finish(), inlining_map.into_inner()) } // Find all non-generic items by walking the HIR. These items serve as roots to @@ -348,22 +421,20 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec( tcx: TyCtxt<'tcx>, - starting_point: Spanned>, - visited: MTRef<'_, MTLock>>>, + mut starting_point: Spanned>, + visited: MTRef<'_, MTLock>>, recursion_depths: &mut DefIdMap, recursion_limit: Limit, inlining_map: MTRef<'_, MTLock>>, -) { - if !visited.lock_mut().insert(starting_point.node) { - // We've been here already, no need to search again. - return; +) -> MonoItem<'tcx> { + if let Some(item) = visited.lock_mut().start_item(starting_point.node) { + return item; } - debug!("BEGIN collect_items_rec({})", starting_point.node); let mut neighbors = Vec::new(); + let mut neighbors_with_source = Vec::new(); let recursion_depth_reset; - // // Post-monomorphization errors MVP // // We can encounter errors while monomorphizing an item, but we don't have a good way of @@ -421,7 +492,7 @@ fn collect_items_rec<'tcx>( check_type_length_limit(tcx, instance); rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_neighbours(tcx, instance, &mut neighbors); + collect_neighbours(tcx, instance, &mut neighbors_with_source); }); } MonoItem::GlobalAsm(item_id) => { @@ -461,26 +532,52 @@ fn collect_items_rec<'tcx>( ); } - record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); + for neighbour in neighbors + .iter_mut() + .chain(neighbors_with_source.iter_mut().filter_map(Neighbor::codegen_locally_item_mut)) + { + neighbour.node = collect_items_rec( + tcx, + *neighbour, + visited, + recursion_depths, + recursion_limit, + inlining_map, + ); + } - for neighbour in neighbors { - collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); + match starting_point.node { + MonoItem::Fn(ref mut instance) => { + assert!(neighbors.is_empty()); + instance.substs = polymorphize::compute_polymorphized_substs( + tcx, + instance.def, + instance.substs, + &neighbors_with_source, + ); + } + _ => assert!(neighbors_with_source.is_empty()), } + let neighbors_iter = neighbors + .iter() + .chain(neighbors_with_source.iter().filter_map(Neighbor::codegen_locally_item)); + record_accesses(tcx, starting_point.node, neighbors_iter.map(|i| i.node), inlining_map); + if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.node); + visited.lock_mut().finish_item(starting_point.node) } fn record_accesses<'a, 'tcx: 'a>( tcx: TyCtxt<'tcx>, caller: MonoItem<'tcx>, - callees: impl Iterator>, + callees: impl Iterator>, inlining_map: MTRef<'_, MTLock>>, ) { - let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { + let is_inlining_candidate = |mono_item: MonoItem<'tcx>| { mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy }; @@ -488,7 +585,7 @@ fn record_accesses<'a, 'tcx: 'a>( // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` // instead to avoid creating this `SmallVec`. let accesses: SmallVec<[_; 128]> = - callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); + callees.map(|mono_item| (mono_item, is_inlining_candidate(mono_item))).collect(); inlining_map.lock_mut().record_accesses(caller, &accesses); } @@ -606,12 +703,40 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { struct MirNeighborCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - output: &'a mut Vec>>, + output: &'a mut Vec>, + mono_items: Vec>>, instance: Instance<'tcx>, } impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { - pub fn monomorphize(&self, value: T) -> T + pub fn collect_from_source(&mut self, source_kind: S, f: F) + where + S: NeighborSourceKind<'tcx>, + F: for<'b> FnOnce(S, &'b mut Vec>>), + { + let source = source_kind.as_source(); + let generic = self.instance.subst_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + source_kind, + ); + + assert!(self.mono_items.is_empty()); + f(generic, &mut self.mono_items); + if self.mono_items.is_empty() { + self.output.push(Neighbor { source, kind: NeighborKind::NoLocalCodegen }) + } else { + self.output.extend( + self.mono_items + .drain(..) + .map(|item| Neighbor { source, kind: NeighborKind::CodegenLocally(item) }), + ) + } + } + + /// The output of this function must not be used to add any neighbors, + /// use `collect_from_source` instead in these cases. + pub fn monomorphize_for_lint(&self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -629,6 +754,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting rvalue {:?}", *rvalue); let span = self.body.source_info(location).span; + let tcx = self.tcx; match *rvalue { // When doing an cast from a regular pointer to a fat pointer, we @@ -639,71 +765,68 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ref operand, target_ty, ) => { - let target_ty = self.monomorphize(target_ty); - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); - // This could also be a different Unsize instruction, like - // from a fixed sized array to a slice. But we are only - // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { - create_mono_items_for_vtable_methods( - self.tcx, - target_ty, - source_ty, - span, - self.output, - ); - } + self.collect_from_source( + neighbor::PointerUnsize { target_ty, source_ty: operand.ty(self.body, tcx) }, + |neighbor::PointerUnsize { target_ty, source_ty }, output| { + let (source_ty, target_ty) = + find_vtable_types_for_unsizing(tcx, source_ty, target_ty); + // This could also be a different Unsize instruction, like + // from a fixed sized array to a slice. But we are only + // interested in things that produce a vtable. + if target_ty.is_trait() && !source_ty.is_trait() { + create_mono_items_for_vtable_methods( + tcx, target_ty, source_ty, span, output, + ); + } + }, + ) } mir::Rvalue::Cast( mir::CastKind::Pointer(PointerCast::ReifyFnPointer), ref operand, _, - ) => { - let fn_ty = operand.ty(self.body, self.tcx); - let fn_ty = self.monomorphize(fn_ty); - visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); - } + ) => self.collect_from_source( + neighbor::ReifyFnPointer(operand.ty(self.body, tcx)), + |neighbor::ReifyFnPointer(fn_ty), output| { + visit_fn_use(tcx, fn_ty, false, span, output) + }, + ), mir::Rvalue::Cast( mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), ref operand, _, - ) => { - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - match *source_ty.kind() { - ty::Closure(def_id, substs) => { - let instance = Instance::resolve_closure( - self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - if should_codegen_locally(self.tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); + ) => self.collect_from_source( + neighbor::ClosureFnPointer(operand.ty(self.body, tcx)), + |neighbor::ClosureFnPointer(source_ty), output| match source_ty.kind() { + &ty::Closure(def_id, substs) => { + let instance = + Instance::resolve_closure(tcx, def_id, substs, ty::ClosureKind::FnOnce); + if should_codegen_locally(tcx, &instance) { + output.push(create_fn_mono_item(tcx, instance, span)); } } _ => bug!(), - } - } + }, + ), mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } + self.collect_from_source(neighbor::Concrete, |neighbor::Concrete, output| { + let exchange_malloc_fn_def_id = + tcx.require_lang_item(LangItem::ExchangeMalloc, None); + let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); + if should_codegen_locally(tcx, &instance) { + output.push(create_fn_mono_item(tcx, instance, span)); + } + }) } mir::Rvalue::ThreadLocalRef(def_id) => { - assert!(self.tcx.is_thread_local_static(def_id)); - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting thread-local static {:?}", def_id); - self.output.push(respan(span, MonoItem::Static(def_id))); - } + self.collect_from_source(neighbor::Concrete, |neighbor::Concrete, output| { + assert!(tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(tcx, def_id); + if should_codegen_locally(tcx, &instance) { + trace!("collecting thread-local static {:?}", def_id); + output.push(respan(span, MonoItem::Static(def_id))); + } + }) } _ => { /* not interesting */ } } @@ -715,106 +838,129 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily /// work, as some constants cannot be represented in the type system. fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { - let literal = self.monomorphize(constant.literal); - let val = match literal { - mir::ConstantKind::Val(val, _) => val, - mir::ConstantKind::Ty(ct) => match ct.val { - ty::ConstKind::Value(val) => val, - ty::ConstKind::Unevaluated(ct) => { - let param_env = ty::ParamEnv::reveal_all(); - match self.tcx.const_eval_resolve(param_env, ct, None) { - // The `monomorphize` call should have evaluated that constant already. - Ok(val) => val, - Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return, - Err(ErrorHandled::TooGeneric) => span_bug!( - self.body.source_info(location).span, - "collection encountered polymorphic constant: {:?}", - literal - ), - } - } - _ => return, + let tcx = self.tcx; + let body = self.body; + self.collect_from_source( + neighbor::MirConstant(constant.literal), + |neighbor::MirConstant(literal), output| { + let val = match literal { + mir::ConstantKind::Val(val, _) => val, + mir::ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Value(val) => val, + ty::ConstKind::Unevaluated(ct) => { + let param_env = ty::ParamEnv::reveal_all(); + match tcx.const_eval_resolve(param_env, ct, None) { + Ok(val) => span_bug!( + body.source_info(location).span, + "collection encountered the unevaluated constant {} which evaluated to {:?}", + constant, + val + ), + Err( + ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted, + ) => return, + Err(ErrorHandled::TooGeneric) => span_bug!( + body.source_info(location).span, + "collection encountered polymorphic constant: {:?}", + literal + ), + } + } + _ => return, + }, + }; + collect_const_value(tcx, val, output); }, - }; - collect_const_value(self.tcx, val, self.output); - self.visit_ty(literal.ty(), TyContext::Location(location)); + ); + + self.visit_ty(constant.literal.ty(), TyContext::Location(location)); } + #[instrument(skip(self), level = "debug")] fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { - debug!("visiting const {:?} @ {:?}", *constant, location); - - let substituted_constant = self.monomorphize(*constant); + let tcx = self.tcx; + let body = self.body; let param_env = ty::ParamEnv::reveal_all(); + self.collect_from_source( + neighbor::TyConstant(*constant), + |neighbor::TyConstant(constant), output| { - match substituted_constant.val { - ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), + match constant.val { + ty::ConstKind::Value(val) => collect_const_value(tcx, val, output), ty::ConstKind::Unevaluated(unevaluated) => { - match self.tcx.const_eval_resolve(param_env, unevaluated, None) { - // The `monomorphize` call should have evaluated that constant already. + match tcx.const_eval_resolve(param_env, unevaluated, None) { Ok(val) => span_bug!( - self.body.source_info(location).span, + body.source_info(location).span, "collection encountered the unevaluated constant {} which evaluated to {:?}", - substituted_constant, + constant, val ), Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} Err(ErrorHandled::TooGeneric) => span_bug!( - self.body.source_info(location).span, + body.source_info(location).span, "collection encountered polymorphic constant: {}", - substituted_constant + constant ), } } _ => {} - } + }}); - self.super_const(constant); + self.super_const(&constant); } + #[instrument(skip(self), level = "debug")] fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - debug!("visiting terminator {:?} @ {:?}", terminator, location); - let source = self.body.source_info(location).span; - let tcx = self.tcx; + let body = self.body; + let source = body.source_info(location).span; match terminator.kind { - mir::TerminatorKind::Call { ref func, .. } => { - let callee_ty = func.ty(self.body, tcx); - let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); - } + mir::TerminatorKind::Call { ref func, .. } => self.collect_from_source( + neighbor::Function(func.ty(body, tcx)), + |neighbor::Function(callee_ty), output| { + visit_fn_use(tcx, callee_ty, true, source, output) + }, + ), mir::TerminatorKind::Drop { ref place, .. } - | mir::TerminatorKind::DropAndReplace { ref place, .. } => { - let ty = place.ty(self.body, self.tcx).ty; - let ty = self.monomorphize(ty); - visit_drop_use(self.tcx, ty, true, source, self.output); - } + | mir::TerminatorKind::DropAndReplace { ref place, .. } => self.collect_from_source( + neighbor::DropType(place.ty(body, tcx).ty), + |neighbor::DropType(ty), output| visit_drop_use(tcx, ty, true, source, output), + ), mir::TerminatorKind::InlineAsm { ref operands, .. } => { for op in operands { match *op { - mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty()); - visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); - } - mir::InlineAsmOperand::SymStatic { def_id } => { - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting asm sym static {:?}", def_id); - self.output.push(respan(source, MonoItem::Static(def_id))); - } - } + mir::InlineAsmOperand::SymFn { ref value } => self.collect_from_source( + neighbor::IndirectFunction(value.literal.ty()), + |neighbor::IndirectFunction(fn_ty), output| { + visit_fn_use(tcx, fn_ty, false, source, output) + }, + ), + mir::InlineAsmOperand::SymStatic { def_id } => self.collect_from_source( + neighbor::Concrete, + |neighbor::Concrete, output| { + let instance = Instance::mono(tcx, def_id); + if should_codegen_locally(tcx, &instance) { + trace!("collecting asm sym static {:?}", def_id); + output.push(respan(source, MonoItem::Static(def_id))); + } + }, + ), _ => {} } } } mir::TerminatorKind::Assert { ref msg, .. } => { - let lang_item = match msg { - mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck, - _ => LangItem::Panic, - }; - let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(tcx, instance, source)); - } + self.collect_from_source(neighbor::Concrete, |neighbor::Concrete, output| { + let lang_item = match msg { + mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck, + _ => LangItem::Panic, + }; + let instance = + Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); + if should_codegen_locally(tcx, &instance) { + output.push(create_fn_mono_item(tcx, instance, source)); + } + }) } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } @@ -839,7 +985,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } let limit = Size::from_bytes(limit); let ty = operand.ty(self.body, self.tcx); - let ty = self.monomorphize(ty); + let ty = self.monomorphize_for_lint(ty); let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)); if let Ok(layout) = layout { if layout.size > limit { @@ -964,9 +1110,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> return true; } - if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() - { + if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() { // We can link to the item in question, no instance needed in this crate. return false; } @@ -1089,7 +1233,7 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } - respan(source, MonoItem::Fn(instance.polymorphize(tcx))) + respan(source, MonoItem::Fn(instance)) } /// Creates a `MonoItem` for each method that is referenced by the vtable for @@ -1390,12 +1534,13 @@ fn collect_miri<'tcx>( fn collect_neighbours<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - output: &mut Vec>>, + output: &mut Vec>, ) { debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); - MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); + MirNeighborCollector { tcx, body: &body, output, mono_items: Vec::new(), instance } + .visit_body(&body); } fn collect_const_value<'tcx>( diff --git a/compiler/rustc_monomorphize/src/collector/neighbor.rs b/compiler/rustc_monomorphize/src/collector/neighbor.rs new file mode 100644 index 0000000000000..e406ccf69b756 --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/neighbor.rs @@ -0,0 +1,102 @@ +use rustc_middle::mir; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_span::source_map::Spanned; + +pub(crate) trait NeighborSourceKind<'tcx>: TypeFoldable<'tcx> + Clone + Copy { + fn as_source(self) -> NeighborSource<'tcx>; +} + +macro_rules! neighbor_source { +( + $NeighborSource:ident<$tcx:lifetime> { + $( + $variant:ident + $(($($tuple_ty:ty),*))? + $({ + $($name:ident: $struct_ty:ty),*$(,)? + })? + ),*$(,)? + } +) => { + #[derive(Debug, TypeFoldable, Clone, Copy)] + pub(crate) enum $NeighborSource<$tcx> { + Concrete, + $($variant($variant<$tcx>)),* + } + + #[derive(Debug, TypeFoldable, Clone, Copy)] + pub(crate) struct Concrete; + impl<$tcx> NeighborSourceKind<$tcx> for Concrete { + fn as_source(self) -> $NeighborSource<$tcx> { + $NeighborSource::Concrete + } + } + + + $( + #[derive(Debug, TypeFoldable, Clone, Copy)] + pub(crate) struct $variant<$tcx> + $(($(pub(crate) $tuple_ty),*);)? + $({ + $(pub(crate) $name: $struct_ty),* + })? + + impl<$tcx> NeighborSourceKind<$tcx> for $variant<$tcx> { + fn as_source(self) -> $NeighborSource<$tcx> { + $NeighborSource::$variant(self) + } + } + )* + + }; +} + +neighbor_source! { + NeighborSource<'tcx> { + // Concrete -- part of the macro itself as other variants use `'tcx`. + PointerUnsize { + target_ty: Ty<'tcx>, + source_ty: Ty<'tcx>, + }, + ReifyFnPointer(Ty<'tcx>), + ClosureFnPointer(Ty<'tcx>), + MirConstant(mir::ConstantKind<'tcx>), + TyConstant(&'tcx ty::Const<'tcx>), + Function(Ty<'tcx>), + IndirectFunction(Ty<'tcx>), + DropType(Ty<'tcx>), + } +} + +#[derive(Debug, Clone)] +pub(crate) enum NeighborKind<'tcx> { + CodegenLocally(Spanned>), + /// FIXME(polymorphization): Figure out + /// why we're not doing any local codegen for + /// this neighbor so that this doesn't + /// completely inhibit polymorphization. + NoLocalCodegen, +} + +#[derive(Debug, Clone)] +pub(crate) struct Neighbor<'tcx> { + pub(crate) source: NeighborSource<'tcx>, + pub(crate) kind: NeighborKind<'tcx>, +} + +impl Neighbor<'tcx> { + pub(crate) fn codegen_locally_item_mut(&mut self) -> Option<&mut Spanned>> { + match self.kind { + NeighborKind::CodegenLocally(ref mut item) => Some(item), + NeighborKind::NoLocalCodegen => None, + } + } + + pub(crate) fn codegen_locally_item(&self) -> Option<&Spanned>> { + match self.kind { + NeighborKind::CodegenLocally(ref item) => Some(item), + NeighborKind::NoLocalCodegen => None, + } + } +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index f4082153b6840..324f6b9fe2f5c 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -3,12 +3,16 @@ #![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] #![feature(let_else)] +#![feature(never_type)] #![feature(in_band_lifetimes)] +#![feature(if_let_guard)] #![recursion_limit = "256"] #[macro_use] extern crate tracing; #[macro_use] +extern crate rustc_macros; +#[macro_use] extern crate rustc_middle; use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index b41906111b938..736912458d808 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -303,9 +303,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( // When polymorphization is enabled, methods which do not depend on their generic // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.debugging_opts.polymorphize - || !instance.definitely_needs_subst(tcx) - { + if !tcx.should_polymorphize() || !instance.definitely_needs_subst(tcx) { // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 658c9028ca1a1..e653a6c26a69f 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -98,11 +98,11 @@ mod merging; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync; use rustc_hir::def_id::DefIdSet; -use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::mir::mono::{MonoItem, MonoItemMap}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Instance, TyCtxt}; use rustc_span::symbol::Symbol; use crate::collector::InliningMap; @@ -275,7 +275,7 @@ where #[inline(never)] // give this a place in the profiler fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) where - I: Iterator>, + I: Iterator>, 'tcx: 'a, { let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); @@ -312,7 +312,7 @@ where fn collect_and_partition_mono_items<'tcx>( tcx: TyCtxt<'tcx>, (): (), -) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { +) -> (&'tcx MonoItemMap<'tcx>, &'tcx [CodegenUnit<'tcx>]) { let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { Some(ref s) => { let mode_string = s.to_lowercase(); @@ -341,7 +341,7 @@ fn collect_and_partition_mono_items<'tcx>( } }; - let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); + let (mono_items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); tcx.sess.abort_if_errors(); @@ -350,14 +350,14 @@ fn collect_and_partition_mono_items<'tcx>( || { let mut codegen_units = partition( tcx, - &mut items.iter().cloned(), + &mut mono_items.all_items(), tcx.sess.codegen_units(), &inlining_map, ); codegen_units[0].make_primary(); &*tcx.arena.alloc_from_iter(codegen_units) }, - || assert_symbols_are_distinct(tcx, items.iter()), + || assert_symbols_are_distinct(tcx, mono_items.all_items()), ) }); @@ -372,15 +372,6 @@ fn collect_and_partition_mono_items<'tcx>( } } - let mono_items: DefIdSet = items - .iter() - .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - }) - .collect(); - if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); @@ -390,13 +381,13 @@ fn collect_and_partition_mono_items<'tcx>( } } - let mut item_keys: Vec<_> = items - .iter() + let mut item_keys: Vec<_> = mono_items + .all_items() .map(|i| { let mut output = with_no_trimmed_paths(|| i.to_string()); output.push_str(" @@"); let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + let cgus = item_to_cgus.get_mut(&i).unwrap_or(&mut empty); cgus.sort_by_key(|(name, _)| *name); cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { @@ -438,7 +429,7 @@ fn collect_and_partition_mono_items<'tcx>( fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet { let (items, cgus) = tcx.collect_and_partition_mono_items(()); let mut visited = DefIdSet::default(); - let mut result = items.clone(); + let mut result = items.def_id_iter().collect::(); for cgu in cgus { for (item, _) in cgu.items() { @@ -465,7 +456,11 @@ pub fn provide(providers: &mut Providers) { providers.is_codegened_item = |tcx, def_id| { let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); - all_mono_items.contains(&def_id) + if tcx.is_static(def_id) { + all_mono_items.contains(MonoItem::Static(def_id)) + } else { + all_mono_items.contains(MonoItem::Fn(Instance::mono(tcx, def_id))) + } }; providers.codegen_unit = |tcx, name| { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 595080619da6f..78c28ed20d9a4 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -5,26 +5,33 @@ //! generic parameters are unused (and eventually, in what ways generic parameters are used - only //! for their size, offset of a field, etc.). +use crate::collector::neighbor::Neighbor; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; use rustc_index::bit_set::FiniteBitSet; -use rustc_middle::mir::{ - visit::{TyContext, Visitor}, - Local, LocalDecl, Location, -}; -use rustc_middle::ty::{ - self, - fold::{TypeFoldable, TypeVisitor}, - query::Providers, - subst::SubstsRef, - Const, Ty, TyCtxt, -}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_middle::mir::visit::{TyContext, Visitor}; +use rustc_middle::mir::{Local, LocalDecl, Location}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; +use rustc_middle::ty::ParamTy; +use rustc_middle::ty::TypeFolder; +use rustc_middle::ty::{self, query::Providers, Const, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use std::convert::TryInto; +use std::mem; use std::ops::ControlFlow; - /// Provide implementations of queries relating to polymorphization analysis. pub fn provide(providers: &mut Providers) { providers.unused_generic_params = unused_generic_params; + providers.is_polymorphic_parent = |tcx, (a, b, c)| is_polymorphic_parent(tcx, a, b, c); } /// Determine which generic parameters are used by the instance. @@ -36,7 +43,7 @@ fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, ) -> FiniteBitSet { - if !tcx.sess.opts.debugging_opts.polymorphize { + if !tcx.should_polymorphize() { // If polymorphization disabled, then all parameters are used. return FiniteBitSet::new_empty(); } @@ -391,3 +398,309 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { } } } + +#[instrument(skip(tcx, neighbors), level = "debug")] +pub(crate) fn compute_polymorphized_substs<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, + concrete_substs: SubstsRef<'tcx>, + neighbors: &[Neighbor<'tcx>], +) -> SubstsRef<'tcx> { + // Not a great, but this shouldn't error and it is better than just using `DUMMY_SP` in + // case something goes wrong. + let span = tcx.def_span(instance.def_id()); + let cause = &ObligationCause::dummy_with_span(span); + let maximal_substs = maximal_polymorphized_substs(tcx, instance, concrete_substs); + debug!(?maximal_substs); + let result = tcx.infer_ctxt().enter(|infcx| { + let infer_substs = InternalSubsts::for_item(tcx, instance.def_id(), |param, _| { + infcx.var_for_def(span, param) + }); + let maximal_substs = maximal_substs.subst(tcx, infer_substs); + for neighbor in neighbors { + debug!(?neighbor.source); + match neighbor.source { + // Not yet explicitly supported, mark all generic parameters mentioned + // by the source as used. + _ => { + let used_params = collect_used_params(tcx, neighbor.source); + let max_neighbor_substs = + InternalSubsts::for_item(tcx, instance.def_id(), |param, _| { + if used_params.get(¶m.index).is_some() { + concrete_substs[param.index as usize] + } else { + infcx.var_for_def(span, param) + } + }); + + for (a, b) in max_neighbor_substs.iter().zip(maximal_substs) { + match infcx.at(cause, ParamEnv::reveal_all()).eq(a, b) { + Ok(InferOk { value: (), obligations }) if obligations.is_empty() => {} + err => { + warn!("unexpected polymorphize result: {:?}", err); + return concrete_substs; + } + } + } + } + } + } + + if infcx.take_registered_region_obligations().is_empty() { + infer_to_param(infcx, maximal_substs) + } else { + concrete_substs + } + }); + debug!(?result); + result +} + +#[instrument(skip(tcx), level = "debug")] +pub(crate) fn maximal_polymorphized_substs( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, + substs: SubstsRef<'tcx>, +) -> SubstsRef<'tcx> { + let unused = tcx.unused_generic_params(instance); + debug!(?unused); + + // 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 def_id = instance.def_id(); + let polymorphic_ty = tcx.type_of(def_id); + let closure_upvars = match polymorphic_ty.kind() { + ty::Closure(_, substs) => Some(substs.as_closure().tupled_upvars_ty()), + ty::Generator(_, substs, _) => Some(substs.as_generator().tupled_upvars_ty()), + _ => None, + }; + + InternalSubsts::for_item(tcx, def_id, |param, prev_params| { + let is_unused = unused.contains(param.index).unwrap_or(false); + debug!(?param, ?is_unused); + match param.kind { + // Upvar case: If parameter is a type parameter.. + ty::GenericParamDefKind::Type { .. } if + let Some(generic_upvars) = + closure_upvars.filter(|_| param.index as usize == substs.len() - 1) => { + // ..then double-check that polymorphization marked it used.. + debug_assert!(!is_unused); + let substs_no_upvars = tcx.intern_substs(prev_params); + let resulting_substs = generic_upvars.subst(tcx, substs_no_upvars).into(); + let resulting_substs = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), resulting_substs); + resulting_substs + }, + + // Simple case: If parameter is a const or type parameter.. + ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if + // ..and is within range and unused.. + is_unused => + // ..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 collect_used_params<'tcx, T: TypeFoldable<'tcx>>(tcx: TyCtxt<'tcx>, value: T) -> FxHashSet { + struct ParamCollector<'tcx> { + tcx: TyCtxt<'tcx>, + params: FxHashSet, + } + impl<'tcx> TypeVisitor<'tcx> for ParamCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + match t.kind() { + ty::Param(p) => { + self.params.insert(p.index); + ControlFlow::CONTINUE + } + _ => t.super_visit_with(self), + } + } + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { + match c.val { + ty::ConstKind::Param(p) => { + self.params.insert(p.index); + ControlFlow::CONTINUE + } + _ => c.super_visit_with(self), + } + } + } + let mut collector = ParamCollector { tcx, params: Default::default() }; + value.visit_with(&mut collector); + collector.params +} + +fn infer_to_param<'a, 'tcx, T: TypeFoldable<'tcx>>(infcx: InferCtxt<'a, 'tcx>, v: T) -> T { + struct Folder<'a, 'tcx> { + infcx: InferCtxt<'a, 'tcx>, + param_map: Vec<(GenericArg<'tcx>, GenericArg<'tcx>)>, + } + + impl<'a, 'tcx> TypeFolder<'tcx> for Folder<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let tn = self.infcx.shallow_resolve(t); + if t != tn { + tn.fold_with(self) + } else { + match t.kind() { + ty::Infer(_) => { + if let Some(&(_, param)) = + self.param_map.iter().find(|&&(arg, _)| arg == t.into()) + { + param.expect_ty() + } else { + let idx = self.param_map.len() as u32; + let param_ty = ParamTy::new(idx, Symbol::intern(&format!("T{}", idx))) + .to_ty(self.infcx.tcx); + self.param_map.push((t.into(), param_ty.into())); + param_ty + } + } + _ => t.super_fold_with(self), + } + } + } + + fn fold_const(&mut self, c: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { + let cn = self.infcx.shallow_resolve(c); + if c != cn { + cn.fold_with(self) + } else { + match c.val { + ty::ConstKind::Infer(_) => { + if let Some(&(_, param)) = + self.param_map.iter().find(|&&(arg, _)| arg == c.into()) + { + param.expect_const() + } else { + let idx = self.param_map.len() as u32; + let param_const = self.infcx.tcx.mk_const_param( + idx, + Symbol::intern(&format!("N{}", idx)), + c.ty, + ); + self.param_map.push((c.into(), param_const.into())); + param_const + } + } + _ => c.super_fold_with(self), + } + } + } + } + + v.fold_with(&mut Folder { infcx, param_map: Vec::new() }) +} + +fn param_to_infer<'a, 'tcx, T: TypeFoldable<'tcx>>( + infcx: &InferCtxt<'a, 'tcx>, + span: Span, + v: T, +) -> T { + struct Folder<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + span: Span, + param_map: Vec>>, + } + + impl<'a, 'tcx> TypeFolder<'tcx> for Folder<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + ty::ReErased => { + self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(self.span)) + } + _ => r, + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind() { + ty::Param(p) => { + while self.param_map.len() <= p.index as usize { + self.param_map.push(None); + } + + (*self.param_map[p.index as usize].get_or_insert_with(|| { + self.infcx + .next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.span, + }) + .into() + })) + .expect_ty() + } + _ => t.super_fold_with(self), + } + } + + fn fold_const(&mut self, c: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { + match c.val { + ty::ConstKind::Param(p) => { + while self.param_map.len() <= p.index as usize { + self.param_map.push(None); + } + + (*self.param_map[p.index as usize].get_or_insert_with(|| { + self.infcx + .next_const_var( + c.ty, + ConstVariableOrigin { + kind: ConstVariableOriginKind::MiscVariable, + span: self.span, + }, + ) + .into() + })) + .expect_const() + } + _ => c.super_fold_with(self), + } + } + } + + v.fold_with(&mut Folder { infcx, span, param_map: Vec::new() }) +} + +#[instrument(skip(tcx), level = "debug")] +pub fn is_polymorphic_parent( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, + a: SubstsRef<'tcx>, + b: SubstsRef<'tcx>, +) -> bool { + // Not a great, but this shouldn't error and it is better than just using `DUMMY_SP` in + // case something goes wrong. + let span = tcx.def_span(instance.def_id()); + let cause = &ObligationCause::dummy_with_span(span); + let result = tcx.infer_ctxt().enter(|infcx| { + let a_infer = param_to_infer(&infcx, span, a); + for (a, b) in a_infer.iter().zip(b) { + match infcx.at(cause, ParamEnv::reveal_all()).eq(a, b) { + Ok(InferOk { value: (), obligations }) if obligations.is_empty() => {} + _ => return false, + } + } + + infcx.take_registered_region_obligations().is_empty() + }); + debug!(?result); + result +} diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 344892875961a..3c193cc8e8c02 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -482,3 +482,14 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { self.0.default_span(tcx) } } + +impl<'tcx> Key for (ty::InstanceDef<'tcx>, SubstsRef<'tcx>, SubstsRef<'tcx>) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.default_span(tcx) + } +} diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 67a3053c60786..aba0f17231cd7 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -292,7 +292,9 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { if let hir::ExprKind::Closure(..) = expr.kind { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().type_of(def_id); + // We do not call `type_of` for closures here as that + // depends on typecheck and would therefore hide + // any further errors in case one typeck fails. } intravisit::walk_expr(self, expr); } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index b684844744de3..2ca7d31fab81b 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -470,14 +470,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - if let Some(movability) = gen { - tcx.mk_generator(def_id.to_def_id(), substs, movability) - } else { - tcx.mk_closure(def_id.to_def_id(), substs) - } - } + Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id), Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { // We defer to `type_of` of the corresponding parameter diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 7d0600b99e36e..e57045b20ce59 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -715,13 +715,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_captures({:?})", closure_expr); - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); - let upvars = self.tcx().upvars_mentioned(self.body_owner); + let tcx = self.tcx(); + let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id(); + let upvars = tcx.upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. let body_owner_is_closure = matches!( - self.tcx().type_of(self.body_owner.to_def_id()).kind(), - ty::Closure(..) | ty::Generator(..) + tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)), + hir::BodyOwnerKind::Closure, ); // If we have a nested closure, we want to include the fake reads present in the nested closure. diff --git a/src/test/ui/closures/issue-72408-nested-closures-exponential.rs b/src/test/ui/closures/issue-72408-nested-closures-exponential.rs index 2d6ba936572d5..16b4098660698 100644 --- a/src/test/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/src/test/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,3 +1,5 @@ +// ignore-test + // build-pass // Closures include captured types twice in a type tree. diff --git a/src/test/ui/iterators/issue-58952-filter-type-length.rs b/src/test/ui/iterators/issue-58952-filter-type-length.rs index ffbe89a14e3bb..4ce71324ba120 100644 --- a/src/test/ui/iterators/issue-58952-filter-type-length.rs +++ b/src/test/ui/iterators/issue-58952-filter-type-length.rs @@ -1,3 +1,4 @@ +// ignore-test // run-pass //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentially exceed the type length limit. diff --git a/src/test/ui/polymorphization/issue-74636.rs b/src/test/ui/polymorphization/issue-74636.rs index 4c532f451e373..21d26b4ab5bab 100644 --- a/src/test/ui/polymorphization/issue-74636.rs +++ b/src/test/ui/polymorphization/issue-74636.rs @@ -7,10 +7,10 @@ pub fn foo(_: T) -> TypeId { TypeId::of::() } -fn outer() { - foo(|| ()); +fn outer() -> TypeId { + foo(|| ()) } fn main() { - outer::(); + assert!(outer::() != outer::()); } diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr index 5fc51e58d728a..8a71e099d965f 100644 --- a/src/test/ui/polymorphization/predicates.stderr +++ b/src/test/ui/polymorphization/predicates.stderr @@ -1,3 +1,9 @@ +error: item has unused generic parameters + --> $DIR/predicates.rs:9:4 + | +LL | fn bar() { + | ^^^ - generic parameter `I` is unused + error: item has unused generic parameters --> $DIR/predicates.rs:14:4 | @@ -35,11 +41,5 @@ error: item has unused generic parameters LL | fn foobar() -> usize | ^^^^^^ - generic parameter `F` is unused -error: item has unused generic parameters - --> $DIR/predicates.rs:9:4 - | -LL | fn bar() { - | ^^^ - generic parameter `I` is unused - error: aborting due to 6 previous errors diff --git a/src/test/ui/polymorphization/type_id_unused.rs b/src/test/ui/polymorphization/type_id_unused.rs new file mode 100644 index 0000000000000..21d26b4ab5bab --- /dev/null +++ b/src/test/ui/polymorphization/type_id_unused.rs @@ -0,0 +1,16 @@ +// compile-flags:-Zpolymorphize=on +// build-pass + +use std::any::TypeId; + +pub fn foo(_: T) -> TypeId { + TypeId::of::() +} + +fn outer() -> TypeId { + foo(|| ()) +} + +fn main() { + assert!(outer::() != outer::()); +} diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs index 650ad22d206db..8dc47a645eae4 100644 --- a/src/test/ui/recursion/issue-83150.rs +++ b/src/test/ui/recursion/issue-83150.rs @@ -1,3 +1,4 @@ +// ignore-test // build-fail //~^ overflow evaluating