Skip to content

Commit 68fa840

Browse files
committed
Look at called functions for usedness of generic params
When a generic param is only used in a const fndef where it is in turn unused, then it's unused in the caller as well. This causes query cycles on recursive functions, we need to recover from them and ignore them.
1 parent 04418fa commit 68fa840

File tree

4 files changed

+82
-10
lines changed

4 files changed

+82
-10
lines changed

compiler/rustc_index/src/bit_set.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,10 +2089,38 @@ impl<T: FiniteBitSetTy> FiniteBitSet<T> {
20892089
self.within_domain(index)
20902090
.then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
20912091
}
2092+
2093+
/// Returns an iterator over the bitset, yielding every bit.
2094+
pub fn iter(&self) -> FullFiniteBitSetIter<T> {
2095+
FullFiniteBitSetIter::new(*self)
2096+
}
20922097
}
20932098

20942099
impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
20952100
fn default() -> Self {
20962101
Self::new_empty()
20972102
}
20982103
}
2104+
2105+
/// An iterator that iterates over a finite bitset and yields every bit.
2106+
pub struct FullFiniteBitSetIter<T: FiniteBitSetTy> {
2107+
bitset: FiniteBitSet<T>,
2108+
position: u32,
2109+
}
2110+
2111+
impl<T: FiniteBitSetTy> FullFiniteBitSetIter<T> {
2112+
fn new(bitset: FiniteBitSet<T>) -> Self {
2113+
Self { bitset, position: 0 }
2114+
}
2115+
}
2116+
2117+
impl<T: FiniteBitSetTy> Iterator for FullFiniteBitSetIter<T> {
2118+
type Item = bool;
2119+
2120+
fn next(&mut self) -> Option<Self::Item> {
2121+
self.bitset.contains(self.position).map(|bit| {
2122+
self.position += 1;
2123+
bit
2124+
})
2125+
}
2126+
}

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::ErrorGuaranteed;
66
use rustc_hir::def::Namespace;
77
use rustc_hir::def_id::{CrateNum, DefId};
88
use rustc_hir::lang_items::LangItem;
9-
use rustc_index::bit_set::FiniteBitSet;
9+
use rustc_index::bit_set::{FiniteBitSet, FullFiniteBitSetIter};
1010
use rustc_macros::HashStable;
1111
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
1212
use rustc_span::Symbol;
@@ -807,4 +807,11 @@ impl UnusedGenericParams {
807807
pub fn all_used(&self) -> bool {
808808
self.0.is_empty()
809809
}
810+
811+
/// Iterates over all the flags in the internal bitset. This will not only return the flags
812+
/// for the generic paramters but also more than that, so the caller has to make sure to limit
813+
/// iteration by the actual amount of flags.
814+
pub fn iter_over_eager(&self) -> FullFiniteBitSetIter<u32> {
815+
self.0.iter()
816+
}
810817
}

compiler/rustc_monomorphize/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(array_windows)]
22
#![feature(control_flow_enum)]
3+
#![feature(let_chains)]
34
#![recursion_limit = "256"]
45
#![allow(rustc::potential_query_instability)]
56
#![deny(rustc::untranslatable_diagnostic)]

compiler/rustc_monomorphize/src/polymorphize.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@
66
//! for their size, offset of a field, etc.).
77
88
use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
9-
use rustc_middle::mir::{
10-
self,
11-
visit::{TyContext, Visitor},
12-
Constant, ConstantKind, Local, LocalDecl, Location,
13-
};
149
use rustc_middle::ty::{
1510
self,
1611
query::Providers,
1712
subst::SubstsRef,
1813
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
1914
Const, Ty, TyCtxt, UnusedGenericParams,
2015
};
16+
use rustc_middle::{
17+
mir::{
18+
self,
19+
visit::{TyContext, Visitor},
20+
Constant, ConstantKind, Local, LocalDecl, Location,
21+
},
22+
ty::Instance,
23+
};
2124
use rustc_span::symbol::sym;
2225
use std::ops::ControlFlow;
26+
use std::{convert::TryInto, iter};
2327

2428
use crate::errors::UnusedGenericParamsHint;
2529

@@ -32,6 +36,7 @@ pub fn provide(providers: &mut Providers) {
3236
///
3337
/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
3438
/// parameters are used).
39+
#[instrument(skip(tcx), level = "debug")]
3540
fn unused_generic_params<'tcx>(
3641
tcx: TyCtxt<'tcx>,
3742
instance: ty::InstanceDef<'tcx>,
@@ -44,6 +49,7 @@ fn unused_generic_params<'tcx>(
4449
let def_id = instance.def_id();
4550
// Exit early if this instance should not be polymorphized.
4651
if !should_polymorphize(tcx, def_id, instance) {
52+
debug!("Should not polymorphize instance");
4753
return UnusedGenericParams::new_all_used();
4854
}
4955

@@ -52,6 +58,7 @@ fn unused_generic_params<'tcx>(
5258

5359
// Exit early when there are no parameters to be unused.
5460
if generics.count() == 0 {
61+
debug!("No generics");
5562
return UnusedGenericParams::new_all_used();
5663
}
5764

@@ -248,6 +255,29 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
248255
}
249256
debug!(?self.unused_parameters);
250257
}
258+
259+
fn maybe_ignore_unused_fn_def_const(&mut self, ty: Ty<'tcx>) {
260+
if let ty::FnDef(def_id, substs) = *ty.kind()
261+
&& let param_env = self.tcx.param_env(def_id)
262+
&& let Ok(substs) = self.tcx.try_normalize_erasing_regions(param_env, substs)
263+
&& let Ok(Some(instance)) = Instance::resolve(self.tcx, param_env, def_id, substs)
264+
&& let unused_params = self.tcx.unused_generic_params(instance.def)
265+
&& !unused_params.all_used()
266+
{
267+
debug!(?unused_params, "Referencing a function that has unused generic params, not marking them all as used");
268+
269+
for (subst, is_unused) in iter::zip(substs, unused_params.iter_over_eager()) {
270+
if let ty::GenericArgKind::Type(subst_ty) = subst.unpack()
271+
&& let ty::Param(param) = subst_ty.kind()
272+
&& !is_unused
273+
{
274+
self.unused_parameters.mark_used(param.index);
275+
}
276+
}
277+
} else {
278+
ty.visit_with(self);
279+
}
280+
}
251281
}
252282

253283
impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
@@ -268,7 +298,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
268298
self.super_local_decl(local, local_decl);
269299
}
270300

271-
fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) {
301+
#[instrument(level = "debug", skip(self))]
302+
fn visit_constant(&mut self, ct: &Constant<'tcx>, _: Location) {
272303
match ct.literal {
273304
ConstantKind::Ty(c) => {
274305
c.visit_with(self);
@@ -285,9 +316,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
285316
}
286317
}
287318

288-
Visitor::visit_ty(self, ty, TyContext::Location(location));
319+
self.maybe_ignore_unused_fn_def_const(ty);
320+
}
321+
ConstantKind::Val(_, ty) => {
322+
self.maybe_ignore_unused_fn_def_const(ty);
289323
}
290-
ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
291324
}
292325
}
293326

@@ -315,7 +348,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
315348
self.visit_child_body(def.did, substs);
316349
ControlFlow::CONTINUE
317350
}
318-
_ => c.super_visit_with(self),
351+
_ => {
352+
self.maybe_ignore_unused_fn_def_const(c.ty());
353+
ControlFlow::CONTINUE
354+
}
319355
}
320356
}
321357

0 commit comments

Comments
 (0)