Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphization: Look at called functions for usedness of generic params #106233

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_index/src/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2089,10 +2089,38 @@ impl<T: FiniteBitSetTy> FiniteBitSet<T> {
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<T> {
FullFiniteBitSetIter::new(*self)
}
}

impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
fn default() -> Self {
Self::new_empty()
}
}

/// An iterator that iterates over a finite bitset and yields every bit.
pub struct FullFiniteBitSetIter<T: FiniteBitSetTy> {
bitset: FiniteBitSet<T>,
position: u32,
}

impl<T: FiniteBitSetTy> FullFiniteBitSetIter<T> {
fn new(bitset: FiniteBitSet<T>) -> Self {
Self { bitset, position: 0 }
}
}

impl<T: FiniteBitSetTy> Iterator for FullFiniteBitSetIter<T> {
type Item = bool;

fn next(&mut self) -> Option<Self::Item> {
self.bitset.contains(self.position).map(|bit| {
self.position += 1;
bit
})
}
}
8 changes: 8 additions & 0 deletions compiler/rustc_macros/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ struct QueryModifiers {
/// A cycle error results in a delay_bug call
cycle_delay_bug: Option<Ident>,

/// A cycle error will not be reported.
recover_cycle: Option<Ident>,

/// Don't hash the result, instead just mark a query red if it runs
no_hash: Option<Ident>,

Expand Down Expand Up @@ -125,6 +128,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
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;
Expand Down Expand Up @@ -179,6 +183,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
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" {
Expand Down Expand Up @@ -206,6 +212,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
desc,
fatal_cycle,
cycle_delay_bug,
recover_cycle,
no_hash,
anon,
eval_always,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -384,7 +384,7 @@ define_tables! {
trait_item_def_id: Table<DefIndex, RawDefId>,
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
// `def_keys` and `def_path_hashes` represent a lazy version of a
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1839,13 +1839,14 @@ rustc_queries! {
desc { "getting codegen unit `{sym}`" }
}

query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
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 {
Expand Down
45 changes: 43 additions & 2 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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..
Expand All @@ -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),

Expand Down Expand Up @@ -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<u32>);

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<u32> {
self.0.iter()
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ trivially_parameterized_over_tcx! {
ty::ImplPolarity,
ty::ReprOptions,
ty::TraitDef,
ty::UnusedGenericParams,
ty::Visibility<DefIndex>,
ty::adjustment::CoerceUnsizedInfo,
ty::fast_reject::SimplifiedType,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use rustc_span::Span;

use std::fmt::Write;

use crate::ty::UnusedGenericParams;

impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
Expand All @@ -32,6 +34,14 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
}
}

impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for UnusedGenericParams {
fn from_cycle_error(_: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> 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<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
let err = tcx.ty_error();
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_monomorphize/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ pub struct TypeLengthLimit {
pub type_length: usize,
}

pub struct UnusedGenericParams {
pub struct UnusedGenericParamsHint {
pub span: Span,
pub param_spans: Vec<Span>,
pub param_names: Vec<String>,
}

impl IntoDiagnostic<'_> for UnusedGenericParams {
impl IntoDiagnostic<'_> for UnusedGenericParamsHint {
#[track_caller]
fn into_diagnostic(
self,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_monomorphize/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
Loading