diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index e4f716c31945c..a61d3ab40a5ca 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -40,12 +40,11 @@ where let index = index .try_into() .expect("more generic parameters than can fit into a `u32`"); - let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. // Just in case there are closures or generators within this subst, // recurse. - if is_used && subst.needs_subst() { + if unused_params.is_used(index) && subst.needs_subst() { return subst.visit_with(self); } } diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 15179392c88cd..ef5fc3817e791 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -2089,6 +2089,11 @@ impl FiniteBitSet { self.within_domain(index) .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE) } + + /// Returns an iterator over the bitset, yielding every bit. + pub fn iter(&self) -> FullFiniteBitSetIter { + FullFiniteBitSetIter::new(*self) + } } impl Default for FiniteBitSet { @@ -2096,3 +2101,26 @@ impl Default for FiniteBitSet { Self::new_empty() } } + +/// An iterator that iterates over a finite bitset and yields every bit. +pub struct FullFiniteBitSetIter { + bitset: FiniteBitSet, + position: u32, +} + +impl FullFiniteBitSetIter { + fn new(bitset: FiniteBitSet) -> Self { + Self { bitset, position: 0 } + } +} + +impl Iterator for FullFiniteBitSetIter { + type Item = bool; + + fn next(&mut self) -> Option { + self.bitset.contains(self.position).map(|bit| { + self.position += 1; + bit + }) + } +} diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 08e42a8a08f92..f5626e9958b98 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -97,6 +97,9 @@ struct QueryModifiers { /// A cycle error results in a delay_bug call cycle_delay_bug: Option, + /// A cycle error will not be reported. + recover_cycle: Option, + /// Don't hash the result, instead just mark a query red if it runs no_hash: Option, @@ -125,6 +128,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut desc = None; let mut fatal_cycle = None; let mut cycle_delay_bug = None; + let mut recover_cycle = None; let mut no_hash = None; let mut anon = None; let mut eval_always = None; @@ -179,6 +183,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(fatal_cycle = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); + } else if modifier == "recover_cycle" { + try_insert!(recover_cycle = modifier); } else if modifier == "no_hash" { try_insert!(no_hash = modifier); } else if modifier == "anon" { @@ -206,6 +212,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { desc, fatal_cycle, cycle_delay_bug, + recover_cycle, no_hash, anon, eval_always, @@ -327,6 +334,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { fatal_cycle, arena_cache, cycle_delay_bug, + recover_cycle, no_hash, anon, eval_always, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0d9f216700fb1..bdc4ae391f043 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1429,7 +1429,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); let unused = tcx.unused_generic_params(instance); - if !unused.is_empty() { + if !unused.all_used() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 26a41f633fffa..bf9be714daf7e 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -13,7 +13,7 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::{BitSet, FiniteBitSet}; +use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ReprOptions, Ty}; +use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams}; use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_serialize::opaque::FileEncoder; use rustc_session::config::SymbolManglingVersion; @@ -384,7 +384,7 @@ define_tables! { trait_item_def_id: Table, inherent_impls: Table>, expn_that_defined: Table>, - unused_generic_params: Table>>, + unused_generic_params: Table>, params_in_repr: Table>>, repr_options: Table>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 37db2274f678f..3b9a25650d598 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1839,13 +1839,14 @@ rustc_queries! { desc { "getting codegen unit `{sym}`" } } - query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet { + query unused_generic_params(key: ty::InstanceDef<'tcx>) -> UnusedGenericParams { cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", tcx.def_path_str(key.def_id()) } separate_provide_extern + recover_cycle } query backend_optimization_level(_: ()) -> OptLevel { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 35d369ffc891c..cb402a4e2165c 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -6,6 +6,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; +use rustc_index::bit_set::{FiniteBitSet, FullFiniteBitSetIter}; use rustc_macros::HashStable; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::Symbol; @@ -711,7 +712,7 @@ fn polymorphize<'tcx>( } InternalSubsts::for_item(tcx, def_id, |param, _| { - let is_unused = unused.contains(param.index).unwrap_or(false); + let is_unused = unused.is_unused(param.index); debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused); match param.kind { // Upvar case: If parameter is a type parameter.. @@ -733,7 +734,7 @@ fn polymorphize<'tcx>( // 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) => + unused.is_unused(param.index) => // ..then use the identity for this parameter. tcx.mk_param_from_def(param), @@ -774,3 +775,43 @@ fn needs_fn_once_adapter_shim( (ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce, _) => Err(()), } } + +// Set bits represent unused generic parameters. +// An empty set indicates that all parameters are used. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)] +pub struct UnusedGenericParams(FiniteBitSet); + +impl UnusedGenericParams { + pub fn new_all_unused(amount: u32) -> Self { + let mut bitset = FiniteBitSet::new_empty(); + bitset.set_range(0..amount); + Self(bitset) + } + + pub fn new_all_used() -> Self { + Self(FiniteBitSet::new_empty()) + } + + pub fn mark_used(&mut self, idx: u32) { + self.0.clear(idx); + } + + pub fn is_unused(&self, idx: u32) -> bool { + self.0.contains(idx).unwrap_or(false) + } + + pub fn is_used(&self, idx: u32) -> bool { + !self.is_unused(idx) + } + + pub fn all_used(&self) -> bool { + self.0.is_empty() + } + + /// Iterates over all the flags in the internal bitset. This will not only return the flags + /// for the generic paramters but also more than that, so the caller has to make sure to limit + /// iteration by the actual amount of flags. + pub fn iter_over_eager(&self) -> FullFiniteBitSetIter { + self.0.iter() + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f01d74539a12e..fa571d480b646 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -86,7 +86,7 @@ pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ShortInstance}; +pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::rvalue_scopes::RvalueScopes; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index a21e3961cb627..72f451985796b 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -60,6 +60,7 @@ trivially_parameterized_over_tcx! { ty::ImplPolarity, ty::ReprOptions, ty::TraitDef, + ty::UnusedGenericParams, ty::Visibility, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedType, diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 642900d3ab429..9d4ee22a7273b 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -34,7 +34,7 @@ use crate::ty::layout::TyAndLayout; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::GeneratorDiagnosticData; -use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams}; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; @@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::hir_id::OwnerId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; -use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; +use rustc_index::vec::IndexVec; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c242be5703123..cb1bab36816fe 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -12,6 +12,8 @@ use rustc_span::Span; use std::fmt::Write; +use crate::ty::UnusedGenericParams; + impl<'tcx> Value, DepKind> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. @@ -32,6 +34,14 @@ impl<'tcx> Value, DepKind> for ty::SymbolName<'_> { } } +impl<'tcx> Value, DepKind> for UnusedGenericParams { + fn from_cycle_error(_: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self { + // Cycles can happen with recursive functions. We just conservatively assume + // that all parameters are used in recursive functions. + Self::new_all_used() + } +} + impl<'tcx> Value, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo]) -> Self { let err = tcx.ty_error(); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index aa3227cac2de4..5233cfb21203b 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -32,13 +32,13 @@ pub struct TypeLengthLimit { pub type_length: usize, } -pub struct UnusedGenericParams { +pub struct UnusedGenericParamsHint { pub span: Span, pub param_spans: Vec, pub param_names: Vec, } -impl IntoDiagnostic<'_> for UnusedGenericParams { +impl IntoDiagnostic<'_> for UnusedGenericParamsHint { #[track_caller] fn into_diagnostic( self, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b616ed35d99d7..b6b1c2cbbafe7 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_windows)] #![feature(control_flow_enum)] +#![feature(let_chains)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 703ed09a254a9..7e61acc84720c 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -6,23 +6,26 @@ //! for their size, offset of a field, etc.). use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; -use rustc_index::bit_set::FiniteBitSet; -use rustc_middle::mir::{ - self, - visit::{TyContext, Visitor}, - Constant, ConstantKind, Local, LocalDecl, Location, -}; use rustc_middle::ty::{ self, query::Providers, subst::SubstsRef, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, - Const, Ty, TyCtxt, + Const, Ty, TyCtxt, UnusedGenericParams, +}; +use rustc_middle::{ + mir::{ + self, + visit::{TyContext, Visitor}, + Constant, ConstantKind, Local, LocalDecl, Location, + }, + ty::Instance, }; use rustc_span::symbol::sym; use std::ops::ControlFlow; +use std::{convert::TryInto, iter}; -use crate::errors::UnusedGenericParams; +use crate::errors::UnusedGenericParamsHint; /// Provide implementations of queries relating to polymorphization analysis. pub fn provide(providers: &mut Providers) { @@ -33,19 +36,21 @@ pub fn provide(providers: &mut Providers) { /// /// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all /// parameters are used). +#[instrument(skip(tcx), level = "debug")] fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, -) -> FiniteBitSet { +) -> UnusedGenericParams { if !tcx.sess.opts.unstable_opts.polymorphize { // If polymorphization disabled, then all parameters are used. - return FiniteBitSet::new_empty(); + return UnusedGenericParams::new_all_used(); } let def_id = instance.def_id(); // Exit early if this instance should not be polymorphized. if !should_polymorphize(tcx, def_id, instance) { - return FiniteBitSet::new_empty(); + debug!("Should not polymorphize instance"); + return UnusedGenericParams::new_all_used(); } let generics = tcx.generics_of(def_id); @@ -53,14 +58,14 @@ fn unused_generic_params<'tcx>( // Exit early when there are no parameters to be unused. if generics.count() == 0 { - return FiniteBitSet::new_empty(); + debug!("No generics"); + return UnusedGenericParams::new_all_used(); } // Create a bitset with N rightmost ones for each parameter. let generics_count: u32 = generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); - let mut unused_parameters = FiniteBitSet::::new_empty(); - unused_parameters.set_range(0..generics_count); + let mut unused_parameters = UnusedGenericParams::new_all_unused(generics_count); debug!(?unused_parameters, "(start)"); mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); @@ -78,7 +83,7 @@ fn unused_generic_params<'tcx>( debug!(?unused_parameters, "(end)"); // Emit errors for debugging and testing if enabled. - if !unused_parameters.is_empty() { + if !unused_parameters.all_used() { emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters); } @@ -136,13 +141,13 @@ fn mark_used_by_default_parameters<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &mut FiniteBitSet, + unused_parameters: &mut UnusedGenericParams, ) { match tcx.def_kind(def_id) { DefKind::Closure | DefKind::Generator => { for param in &generics.params { debug!(?param, "(closure/gen)"); - unused_parameters.clear(param.index); + unused_parameters.mark_used(param.index); } } DefKind::Mod @@ -178,7 +183,7 @@ fn mark_used_by_default_parameters<'tcx>( for param in &generics.params { debug!(?param, "(other)"); if let ty::GenericParamDefKind::Lifetime = param.kind { - unused_parameters.clear(param.index); + unused_parameters.mark_used(param.index); } } } @@ -196,7 +201,7 @@ fn emit_unused_generic_params_error<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &FiniteBitSet, + unused_parameters: &UnusedGenericParams, ) { let base_def_id = tcx.typeck_root_def_id(def_id); if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) { @@ -213,7 +218,7 @@ fn emit_unused_generic_params_error<'tcx>( let mut next_generics = Some(generics); while let Some(generics) = next_generics { for param in &generics.params { - if unused_parameters.contains(param.index).unwrap_or(false) { + if unused_parameters.is_unused(param.index) { debug!(?param); let def_span = tcx.def_span(param.def_id); param_spans.push(def_span); @@ -224,14 +229,14 @@ fn emit_unused_generic_params_error<'tcx>( next_generics = generics.parent.map(|did| tcx.generics_of(did)); } - tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names }); + tcx.sess.emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names }); } /// Visitor used to aggregate generic parameter uses. struct MarkUsedGenericParams<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: DefId, - unused_parameters: &'a mut FiniteBitSet, + unused_parameters: &'a mut UnusedGenericParams, } impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { @@ -244,12 +249,35 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { debug!(?self.unused_parameters, ?unused); for (i, arg) in substs.iter().enumerate() { let i = i.try_into().unwrap(); - if !unused.contains(i).unwrap_or(false) { + if unused.is_used(i) { arg.visit_with(self); } } debug!(?self.unused_parameters); } + + fn maybe_ignore_unused_fn_def_const(&mut self, ty: Ty<'tcx>) { + if let ty::FnDef(def_id, substs) = *ty.kind() + && let param_env = self.tcx.param_env(def_id) + && let Ok(substs) = self.tcx.try_normalize_erasing_regions(param_env, substs) + && let Ok(Some(instance)) = Instance::resolve(self.tcx, param_env, def_id, substs) + && let unused_params = self.tcx.unused_generic_params(instance.def) + && !unused_params.all_used() + { + debug!(?unused_params, "Referencing a function that has unused generic params, not marking them all as used"); + + for (subst, is_unused) in iter::zip(substs, unused_params.iter_over_eager()) { + if let ty::GenericArgKind::Type(subst_ty) = subst.unpack() + && let ty::Param(param) = subst_ty.kind() + && !is_unused + { + self.unused_parameters.mark_used(param.index); + } + } + } else { + ty.visit_with(self); + } + } } impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { @@ -270,7 +298,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) { + #[instrument(level = "debug", skip(self))] + fn visit_constant(&mut self, ct: &Constant<'tcx>, _: Location) { match ct.literal { ConstantKind::Ty(c) => { c.visit_with(self); @@ -287,9 +316,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } } - Visitor::visit_ty(self, ty, TyContext::Location(location)); + self.maybe_ignore_unused_fn_def_const(ty); + } + ConstantKind::Val(_, ty) => { + self.maybe_ignore_unused_fn_def_const(ty); } - ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)), } } @@ -308,7 +339,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { match c.kind() { ty::ConstKind::Param(param) => { debug!(?param); - self.unused_parameters.clear(param.index); + self.unused_parameters.mark_used(param.index); ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) @@ -317,7 +348,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.visit_child_body(def.did, substs); ControlFlow::CONTINUE } - _ => c.super_visit_with(self), + _ => { + self.maybe_ignore_unused_fn_def_const(c.ty()); + ControlFlow::CONTINUE + } } } @@ -342,55 +376,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } ty::Param(param) => { debug!(?param); - self.unused_parameters.clear(param.index); + self.unused_parameters.mark_used(param.index); ControlFlow::CONTINUE } _ => ty.super_visit_with(self), } } } - -/// Visitor used to check if a generic parameter is used. -struct HasUsedGenericParams<'a> { - unused_parameters: &'a FiniteBitSet, -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { - type BreakTy = (); - - #[instrument(level = "debug", skip(self))] - fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { - if !c.has_non_region_param() { - return ControlFlow::CONTINUE; - } - - match c.kind() { - ty::ConstKind::Param(param) => { - if self.unused_parameters.contains(param.index).unwrap_or(false) { - ControlFlow::CONTINUE - } else { - ControlFlow::BREAK - } - } - _ => c.super_visit_with(self), - } - } - - #[instrument(level = "debug", skip(self))] - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.has_non_region_param() { - return ControlFlow::CONTINUE; - } - - match ty.kind() { - ty::Param(param) => { - if self.unused_parameters.contains(param.index).unwrap_or(false) { - ControlFlow::CONTINUE - } else { - ControlFlow::BREAK - } - } - _ => ty.super_visit_with(self), - } - } -} diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 6125ad4eff118..75fdbb4eea3b9 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -205,6 +205,9 @@ macro_rules! handle_cycle_error { ([]) => {{ rustc_query_system::HandleCycleError::Error }}; + ([(recover_cycle) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::Recover + }}; ([(fatal_cycle) $($rest:tt)*]) => {{ rustc_query_system::HandleCycleError::Fatal }}; diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index cf2f04c7486b8..df86bf4ec5cf2 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -12,6 +12,7 @@ pub struct CycleStack { #[derive(Copy, Clone)] pub enum HandleCycleError { + Recover, Error, Fatal, DelayBug, diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index b3b939eae88dc..b2913746d19d1 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -162,6 +162,11 @@ where error.delay_as_bug(); Value::from_cycle_error(tcx, &cycle_error.cycle) } + Recover => { + // FIXME: We don't really want to create the error in the first place. + error.cancel(); + Value::from_cycle_error(tcx, &cycle_error.cycle) + } } } diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs index c2e06d067dc6e..eb5c25bf9a9c0 100644 --- a/src/test/codegen-units/polymorphization/unused_type_parameters.rs +++ b/src/test/codegen-units/polymorphization/unused_type_parameters.rs @@ -41,12 +41,11 @@ mod functions { //~ MONO_ITEM fn functions::used_argument:: // // Function uses type parameter in substitutions to another function. - pub fn used_substs() { + pub fn forwarded() { unused::() } -//~ MONO_ITEM fn functions::used_substs:: -//~ MONO_ITEM fn functions::used_substs:: +//~ MONO_ITEM fn functions::forwarded:: } @@ -144,15 +143,13 @@ mod closures { //~ MONO_ITEM fn closures::used_upvar:: // Closure uses type parameter in substitutions to another function. - pub fn used_substs() { + pub fn forwarded() { let x = || super::functions::unused::(); x() } -//~ MONO_ITEM fn closures::used_substs::::{closure#0} -//~ MONO_ITEM fn closures::used_substs::::{closure#0} -//~ MONO_ITEM fn closures::used_substs:: -//~ MONO_ITEM fn closures::used_substs:: +//~ MONO_ITEM fn closures::forwarded::::{closure#0} +//~ MONO_ITEM fn closures::forwarded:: } mod methods { @@ -197,12 +194,11 @@ mod methods { //~ MONO_ITEM fn methods::Foo::::used_both:: // Function uses type parameter in substitutions to another function. - pub fn used_substs() { + pub fn forwarded() { super::functions::unused::() } -//~ MONO_ITEM fn methods::Foo::::used_substs -//~ MONO_ITEM fn methods::Foo::::used_substs +//~ MONO_ITEM fn methods::Foo::::forwarded // Function has an unused type parameter from impl and fn. pub fn closure_unused_all() -> u32 { @@ -260,15 +256,13 @@ mod methods { //~ MONO_ITEM fn methods::Foo::::closure_used_impl:: // Closure uses type parameter in substitutions to another function. - pub fn closure_used_substs() { + pub fn closure_forwarded() { let x = || super::functions::unused::(); x() } -//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} -//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} -//~ MONO_ITEM fn methods::Foo::::closure_used_substs -//~ MONO_ITEM fn methods::Foo::::closure_used_substs +//~ MONO_ITEM fn methods::Foo::::closure_forwarded::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_forwarded } } @@ -280,7 +274,7 @@ fn dispatch() { functions::used_binding_value::(); functions::used_binding_type::(); functions::used_argument::(Default::default()); - functions::used_substs::(); + functions::forwarded::(); closures::no_parameters(); let _ = closures::unused::(); @@ -290,19 +284,19 @@ fn dispatch() { let _ = closures::used_argument::(Default::default()); let _ = closures::used_argument_closure::(); let _ = closures::used_upvar::(); - let _ = closures::used_substs::(); + let _ = closures::forwarded::(); methods::Foo::::unused_impl(); methods::Foo::::unused_both::(); methods::Foo::::used_impl(); methods::Foo::::used_fn::(); methods::Foo::::used_both::(); - methods::Foo::::used_substs(); + methods::Foo::::forwarded(); let _ = methods::Foo::::closure_unused_all::(); let _ = methods::Foo::::closure_used_both::(); let _ = methods::Foo::::closure_used_impl::(); let _ = methods::Foo::::closure_used_fn::(); - let _ = methods::Foo::::closure_used_substs(); + let _ = methods::Foo::::closure_forwarded(); } //~ MONO_ITEM fn dispatch:: diff --git a/src/test/ui/polymorphization/const_parameters/closures.rs b/src/test/ui/polymorphization/const_parameters/closures.rs index 2f41beeb9691a..358449540ca49 100644 --- a/src/test/ui/polymorphization/const_parameters/closures.rs +++ b/src/test/ui/polymorphization/const_parameters/closures.rs @@ -53,7 +53,9 @@ pub fn unused_upvar() -> usize { // Closure uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() -> usize { + //~^ ERROR item has unused generic parameters let x = || unused::(); + //~^ ERROR item has unused generic parameters x() } diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr index 4e927f7732fa1..c8242a217ed1a 100644 --- a/src/test/ui/polymorphization/const_parameters/closures.stderr +++ b/src/test/ui/polymorphization/const_parameters/closures.stderr @@ -40,5 +40,20 @@ LL | let x: usize = T; LL | let y = || x; | ^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: item has unused generic parameters + --> $DIR/closures.rs:57:13 + | +LL | pub fn used_substs() -> usize { + | -------------- generic parameter `T` is unused +LL | +LL | let x = || unused::(); + | ^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:55:8 + | +LL | pub fn used_substs() -> usize { + | ^^^^^^^^^^^ -------------- generic parameter `T` is unused + +error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/polymorphization/const_parameters/functions.rs b/src/test/ui/polymorphization/const_parameters/functions.rs index cbc1b63fbc4e6..377bdd9f37f23 100644 --- a/src/test/ui/polymorphization/const_parameters/functions.rs +++ b/src/test/ui/polymorphization/const_parameters/functions.rs @@ -26,6 +26,7 @@ pub fn used_binding() -> usize { // Function uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() { + //~^ ERROR item has unused generic parameters unused::() } diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr index 9d0922ac7ca03..7489d6a733ea0 100644 --- a/src/test/ui/polymorphization/const_parameters/functions.stderr +++ b/src/test/ui/polymorphization/const_parameters/functions.stderr @@ -13,5 +13,11 @@ error: item has unused generic parameters LL | pub fn unused() { | ^^^^^^ -------------- generic parameter `T` is unused -error: aborting due to previous error; 1 warning emitted +error: item has unused generic parameters + --> $DIR/functions.rs:28:8 + | +LL | pub fn used_substs() { + | ^^^^^^^^^^^ -------------- generic parameter `T` is unused + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr index 80bb2af25cc21..a3b2f75b12d4a 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:10:4 + | +LL | fn bar() { + | ^^^ - generic parameter `I` is unused + error: item has unused generic parameters --> $DIR/predicates.rs:15:4 | @@ -35,17 +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:10:4 - | -LL | fn bar() { - | ^^^ - generic parameter `I` is unused - -note: the above error was encountered while instantiating `fn foo::, T>` - --> $DIR/predicates.rs:86:5 - | -LL | foo(x.iter()); - | ^^^^^^^^^^^^^ - error: aborting due to 6 previous errors diff --git a/src/test/ui/polymorphization/type_parameters/closures.rs b/src/test/ui/polymorphization/type_parameters/closures.rs index 07ab1355a47cf..4c4a973ce3262 100644 --- a/src/test/ui/polymorphization/type_parameters/closures.rs +++ b/src/test/ui/polymorphization/type_parameters/closures.rs @@ -80,7 +80,9 @@ pub fn used_upvar() -> T { // Closure uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() -> u32 { + //~^ ERROR item has unused generic parameters let x = || unused::(); + //~^ ERROR item has unused generic parameters x() } @@ -137,7 +139,9 @@ impl Foo { // Closure uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() -> u32 { + //~^ ERROR item has unused generic parameters let x = || unused::(); + //~^ ERROR item has unused generic parameters x() } } diff --git a/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr index 94a4a08bd2fc2..f66e099b2db7b 100644 --- a/src/test/ui/polymorphization/type_parameters/closures.stderr +++ b/src/test/ui/polymorphization/type_parameters/closures.stderr @@ -23,7 +23,22 @@ LL | let add_one = |x: u32| x + 1; | ^^^^^^^^ error: item has unused generic parameters - --> $DIR/closures.rs:94:23 + --> $DIR/closures.rs:84:13 + | +LL | pub fn used_substs() -> u32 { + | - generic parameter `T` is unused +LL | +LL | let x = || unused::(); + | ^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:82:8 + | +LL | pub fn used_substs() -> u32 { + | ^^^^^^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/closures.rs:96:23 | LL | impl Foo { | - generic parameter `F` is unused @@ -35,7 +50,7 @@ LL | let add_one = |x: u32| x + 1; | ^^^^^^^^ error: item has unused generic parameters - --> $DIR/closures.rs:92:12 + --> $DIR/closures.rs:94:12 | LL | impl Foo { | - generic parameter `F` is unused @@ -44,7 +59,7 @@ LL | pub fn unused_all() -> u32 { | ^^^^^^^^^^ - generic parameter `G` is unused error: item has unused generic parameters - --> $DIR/closures.rs:128:23 + --> $DIR/closures.rs:130:23 | LL | pub fn used_impl() -> u32 { | - generic parameter `G` is unused @@ -53,13 +68,13 @@ LL | let add_one = |x: u32| { | ^^^^^^^^ error: item has unused generic parameters - --> $DIR/closures.rs:126:12 + --> $DIR/closures.rs:128:12 | LL | pub fn used_impl() -> u32 { | ^^^^^^^^^ - generic parameter `G` is unused error: item has unused generic parameters - --> $DIR/closures.rs:115:23 + --> $DIR/closures.rs:117:23 | LL | impl Foo { | - generic parameter `F` is unused @@ -68,7 +83,7 @@ LL | let add_one = |x: u32| { | ^^^^^^^^ error: item has unused generic parameters - --> $DIR/closures.rs:113:12 + --> $DIR/closures.rs:115:12 | LL | impl Foo { | - generic parameter `F` is unused @@ -76,5 +91,23 @@ LL | impl Foo { LL | pub fn used_fn() -> u32 { | ^^^^^^^ -error: aborting due to 9 previous errors +error: item has unused generic parameters + --> $DIR/closures.rs:143:17 + | +LL | impl Foo { + | - generic parameter `F` is unused +... +LL | let x = || unused::(); + | ^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:141:12 + | +LL | impl Foo { + | - generic parameter `F` is unused +... +LL | pub fn used_substs() -> u32 { + | ^^^^^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/src/test/ui/polymorphization/type_parameters/functions.rs b/src/test/ui/polymorphization/type_parameters/functions.rs index aad957e1dd362..fd7aeb31d047c 100644 --- a/src/test/ui/polymorphization/type_parameters/functions.rs +++ b/src/test/ui/polymorphization/type_parameters/functions.rs @@ -34,6 +34,7 @@ pub fn used_argument(_: T) {} // Function uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() { + //~^ ERROR item has unused generic parameters unused::() } @@ -75,6 +76,7 @@ impl Foo { // Function uses generic parameter in substitutions to another function. #[rustc_polymorphize_error] pub fn used_substs() { + //~^ ERROR item has unused generic parameters unused::() } } diff --git a/src/test/ui/polymorphization/type_parameters/functions.stderr b/src/test/ui/polymorphization/type_parameters/functions.stderr index d629ff7bb4d3a..ad540003d84c9 100644 --- a/src/test/ui/polymorphization/type_parameters/functions.stderr +++ b/src/test/ui/polymorphization/type_parameters/functions.stderr @@ -5,7 +5,13 @@ LL | pub fn unused() { | ^^^^^^ - generic parameter `T` is unused error: item has unused generic parameters - --> $DIR/functions.rs:45:12 + --> $DIR/functions.rs:36:8 + | +LL | pub fn used_substs() { + | ^^^^^^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/functions.rs:46:12 | LL | impl Foo { | - generic parameter `F` is unused @@ -14,7 +20,7 @@ LL | pub fn unused_impl() { | ^^^^^^^^^^^ error: item has unused generic parameters - --> $DIR/functions.rs:51:12 + --> $DIR/functions.rs:52:12 | LL | impl Foo { | - generic parameter `F` is unused @@ -23,7 +29,7 @@ LL | pub fn unused_both() { | ^^^^^^^^^^^ - generic parameter `G` is unused error: item has unused generic parameters - --> $DIR/functions.rs:63:12 + --> $DIR/functions.rs:64:12 | LL | impl Foo { | - generic parameter `F` is unused @@ -31,5 +37,14 @@ LL | impl Foo { LL | pub fn used_fn() { | ^^^^^^^ -error: aborting due to 4 previous errors +error: item has unused generic parameters + --> $DIR/functions.rs:78:12 + | +LL | impl Foo { + | - generic parameter `F` is unused +... +LL | pub fn used_substs() { + | ^^^^^^^^^^^ + +error: aborting due to 6 previous errors