diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index b369be252185b..e4b7c24a24989 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -1034,6 +1034,30 @@ pub trait FiniteBitSetTy: fn checked_shr(self, rhs: u32) -> Option; } +impl FiniteBitSetTy for u32 { + const DOMAIN_SIZE: u32 = 32; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u32; + const ZERO: Self = 0u32; + + fn checked_shl(self, rhs: u32) -> Option { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:032b}", self.0) + } +} + impl FiniteBitSetTy for u64 { const DOMAIN_SIZE: u32 = 64; diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 3c045df45da16..10dc407c060fe 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1150,7 +1150,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { self.root .tables .unused_generic_params diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 352b8bff7e2fb..aec9e8daa0f82 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -1134,8 +1134,11 @@ impl EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id)); - record!(self.tables.unused_generic_params[def_id.to_def_id()] <- - self.tcx.unused_generic_params(def_id)); + + let unused = self.tcx.unused_generic_params(def_id); + if !unused.is_empty() { + record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); + } } } diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 12d2f50363c1a..465461ebf9769 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -285,7 +285,7 @@ define_tables! { super_predicates: Table)>, mir: Table)>, promoted_mir: Table>)>, - unused_generic_params: Table>>, + unused_generic_params: Table>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 862c046358b84..7e9226f83c32d 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1319,7 +1319,7 @@ rustc_queries! { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet { + query unused_generic_params(key: DefId) -> FiniteBitSet { cache_on_disk_if { key.is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", diff --git a/src/librustc_mir/interpret/util.rs b/src/librustc_mir/interpret/util.rs index c0eac8a9305ee..57c5fc59cc0b8 100644 --- a/src/librustc_mir/interpret/util.rs +++ b/src/librustc_mir/interpret/util.rs @@ -47,14 +47,26 @@ where unused_params.contains(index).map(|unused| !unused).unwrap_or(true); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - if is_used && subst.needs_subst() { + match (is_used, subst.needs_subst()) { // Just in case there are closures or generators within this subst, // recurse. - if subst.super_visit_with(self) { + (true, true) if subst.super_visit_with(self) => { // Only return when we find a parameter so the remaining substs // are not skipped. return true; } + // Confirm that polymorphization replaced the parameter with + // `ty::Param`/`ty::ConstKind::Param`. + (false, true) if cfg!(debug_assertions) => match subst.unpack() { + ty::subst::GenericArgKind::Type(ty) => { + assert!(matches!(ty.kind, ty::Param(_))) + } + ty::subst::GenericArgKind::Const(ct) => { + assert!(matches!(ct.val, ty::ConstKind::Param(_))) + } + ty::subst::GenericArgKind::Lifetime(..) => (), + }, + _ => {} } } false diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs index 562f512c5dacf..8fc1458f59205 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/src/librustc_mir/monomorphize/polymorphize.rs @@ -28,7 +28,7 @@ pub fn provide(providers: &mut Providers) { /// Determine which generic parameters are used by the function/method/closure represented by /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` /// indicates all parameters are used). -fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { +fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { debug!("unused_generic_params({:?})", def_id); if !tcx.sess.opts.debugging_opts.polymorphize { @@ -36,6 +36,13 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { return FiniteBitSet::new_empty(); } + // Polymorphization results are stored in cross-crate metadata only when there are unused + // parameters, so assume that non-local items must have only used parameters (else this query + // would not be invoked, and the cross-crate metadata used instead). + if !def_id.is_local() { + return FiniteBitSet::new_empty(); + } + let generics = tcx.generics_of(def_id); debug!("unused_generic_params: generics={:?}", generics); @@ -53,7 +60,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { // 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(); + let mut unused_parameters = FiniteBitSet::::new_empty(); unused_parameters.set_range(0..generics_count); debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters); mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); @@ -84,7 +91,7 @@ fn mark_used_by_default_parameters<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &mut FiniteBitSet, + unused_parameters: &mut FiniteBitSet, ) { if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) { for param in &generics.params { @@ -110,11 +117,11 @@ fn mark_used_by_default_parameters<'tcx>( fn mark_used_by_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - unused_parameters: &mut FiniteBitSet, + unused_parameters: &mut FiniteBitSet, ) { let def_id = tcx.closure_base_def_id(def_id); - let is_self_ty_used = |unused_parameters: &mut FiniteBitSet, self_ty: Ty<'tcx>| { + let is_self_ty_used = |unused_parameters: &mut FiniteBitSet, self_ty: Ty<'tcx>| { debug!("unused_generic_params: self_ty={:?}", self_ty); if let ty::Param(param) = self_ty.kind { !unused_parameters.contains(param.index).unwrap_or(false) @@ -123,7 +130,7 @@ fn mark_used_by_predicates<'tcx>( } }; - let mark_ty = |unused_parameters: &mut FiniteBitSet, ty: Ty<'tcx>| { + let mark_ty = |unused_parameters: &mut FiniteBitSet, ty: Ty<'tcx>| { let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters }; ty.visit_with(&mut vis); }; @@ -159,7 +166,7 @@ fn emit_unused_generic_params_error<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &FiniteBitSet, + unused_parameters: &FiniteBitSet, ) { debug!("emit_unused_generic_params_error: def_id={:?}", def_id); let base_def_id = tcx.closure_base_def_id(def_id); @@ -195,7 +202,7 @@ fn emit_unused_generic_params_error<'tcx>( struct UsedGenericParametersVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: DefId, - unused_parameters: &'a mut FiniteBitSet, + unused_parameters: &'a mut FiniteBitSet, } impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {