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 cleanup #106648

Merged
merged 2 commits into from
Jan 11, 2023
Merged
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
@@ -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);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
6 changes: 3 additions & 3 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
@@ -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<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
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1839,7 +1839,7 @@ 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 `{}`",
38 changes: 36 additions & 2 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
@@ -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;
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,36 @@ 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()
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/query.rs
Original file line number Diff line number Diff line change
@@ -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};
4 changes: 2 additions & 2 deletions compiler/rustc_monomorphize/src/errors.rs
Original file line number Diff line number Diff line change
@@ -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,
83 changes: 18 additions & 65 deletions compiler/rustc_monomorphize/src/polymorphize.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@
//! 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},
@@ -17,12 +16,12 @@ use rustc_middle::ty::{
query::Providers,
subst::SubstsRef,
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
Const, Ty, TyCtxt,
Const, Ty, TyCtxt, UnusedGenericParams,
};
use rustc_span::symbol::sym;
use std::ops::ControlFlow;

use crate::errors::UnusedGenericParams;
use crate::errors::UnusedGenericParamsHint;

/// Provide implementations of queries relating to polymorphization analysis.
pub fn provide(providers: &mut Providers) {
@@ -36,31 +35,30 @@ pub fn provide(providers: &mut Providers) {
fn unused_generic_params<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
) -> FiniteBitSet<u32> {
) -> 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();
return UnusedGenericParams::new_all_used();
}

let generics = tcx.generics_of(def_id);
debug!(?generics);

// Exit early when there are no parameters to be unused.
if generics.count() == 0 {
return FiniteBitSet::new_empty();
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::<u32>::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 +76,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 +134,13 @@ fn mark_used_by_default_parameters<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
generics: &'tcx ty::Generics,
unused_parameters: &mut FiniteBitSet<u32>,
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 +176,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 +194,7 @@ fn emit_unused_generic_params_error<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>,
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 +211,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 +222,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<u32>,
unused_parameters: &'a mut UnusedGenericParams,
}

impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
@@ -244,7 +242,7 @@ 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);
}
}
@@ -308,7 +306,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 })
@@ -342,55 +340,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> {
Copy link
Member

@compiler-errors compiler-errors Jan 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this not used? why wasn't deny(unused) triggering for it? lol... anyways r=me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe the trait impl was confusing it..

unused_parameters: &'a FiniteBitSet<u32>,
}

impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
type BreakTy = ();

#[instrument(level = "debug", skip(self))]
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
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<Self::BreakTy> {
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),
}
}
}