Skip to content

Instantly share code, notes, and snippets.

@davidtwco
Last active August 17, 2020 15:11
Show Gist options
  • Save davidtwco/5a190c39c6c74b8d021549bb6c002ec6 to your computer and use it in GitHub Desktop.
Save davidtwco/5a190c39c6c74b8d021549bb6c002ec6 to your computer and use it in GitHub Desktop.
unused_generic_params taking an InstanceDef, experimentation resulting from rust-lang/rust#75414.
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index 10b89cdd15a..5cc4185f3b7 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -84,6 +84,12 @@ impl IntoArgs for (CrateNum, DefId) {
}
}
+impl IntoArgs for ty::InstanceDef<'tcx> {
+ fn into_args(self) -> (DefId, DefId) {
+ (self.def_id(), self.def_id())
+ }
+}
+
provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { cdata.get_type(def_id.index, tcx) }
generics_of => { cdata.get_generics(def_id.index, tcx.sess) }
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 6723e236a1f..07af6ce27b1 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -1127,7 +1127,9 @@ impl EncodeContext<'a, 'tcx> {
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));
- let unused = self.tcx.unused_generic_params(def_id);
+ let instance =
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
+ let unused = self.tcx.unused_generic_params(instance);
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index a8f6723a356..f8f6a4cdb1e 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -1319,11 +1319,11 @@ rustc_queries! {
query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
desc { "codegen_unit" }
}
- query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
- cache_on_disk_if { key.is_local() }
+ query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+ cache_on_disk_if { key.def_id().is_local() }
desc {
|tcx| "determining which generic parameters are unused by `{}`",
- tcx.def_path_str(key)
+ tcx.def_path_str(key.def_id())
}
}
query backend_optimization_level(_: CrateNum) -> OptLevel {
diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs
index f969a281890..6e4667cf0be 100644
--- a/src/librustc_middle/ty/instance.rs
+++ b/src/librustc_middle/ty/instance.rs
@@ -163,6 +163,22 @@ impl<'tcx> InstanceDef<'tcx> {
}
}
+ /// Returns the `DefId` of instances which might not require codegen locally.
+ pub fn maybe_codegen_locally_def_id(self) -> Option<DefId> {
+ match self {
+ ty::InstanceDef::Item(def) => Some(def.did),
+ ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
+ ty::InstanceDef::VtableShim(..)
+ | ty::InstanceDef::ReifyShim(..)
+ | ty::InstanceDef::ClosureOnceShim { .. }
+ | ty::InstanceDef::Virtual(..)
+ | ty::InstanceDef::FnPtrShim(..)
+ | ty::InstanceDef::DropGlue(..)
+ | ty::InstanceDef::Intrinsic(_)
+ | ty::InstanceDef::CloneShim(..) => None,
+ }
+ }
+
#[inline]
pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
match self {
@@ -243,6 +259,27 @@ impl<'tcx> InstanceDef<'tcx> {
_ => false,
}
}
+
+ /// Returns `true` when the MIR body associated with this instance should be monomorphized
+ /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see
+ /// `Instance::substs_for_mir_body`).
+ ///
+ /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR
+ /// body should perform necessary substitutions.
+ pub fn has_polymorphic_mir_body(&self) -> bool {
+ match *self {
+ InstanceDef::CloneShim(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::DropGlue(_, Some(_)) => false,
+ InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::Item(_)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::VtableShim(..) => true,
+ }
+ }
}
impl<'tcx> fmt::Display for Instance<'tcx> {
@@ -473,7 +510,7 @@ impl<'tcx> Instance<'tcx> {
return self;
}
- let polymorphized_substs = polymorphize(tcx, self.def_id(), self.substs);
+ let polymorphized_substs = polymorphize(tcx, self.def, self.substs);
debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
Self { def: self.def, substs: polymorphized_substs }
}
@@ -481,17 +518,18 @@ impl<'tcx> Instance<'tcx> {
fn polymorphize<'tcx>(
tcx: TyCtxt<'tcx>,
- def_id: DefId,
+ instance: ty::InstanceDef<'tcx>,
substs: SubstsRef<'tcx>,
) -> SubstsRef<'tcx> {
- debug!("polymorphize({:?}, {:?})", def_id, substs);
- let unused = tcx.unused_generic_params(def_id);
+ debug!("polymorphize({:?}, {:?})", instance, substs);
+ let unused = tcx.unused_generic_params(instance);
debug!("polymorphize: unused={:?}", unused);
// If this is a closure or generator then we need to handle the case where another closure
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
// the unpolymorphized upvar closure would result in a polymorphized closure producing
// multiple mono items (and eventually symbol clashes).
+ let def_id = instance.def_id();
let upvars_ty = if tcx.is_closure(def_id) {
Some(substs.as_closure().tupled_upvars_ty())
} else if tcx.type_of(def_id).is_generator() {
@@ -515,7 +553,12 @@ fn polymorphize<'tcx>(
debug!("fold_ty: ty={:?}", ty);
match ty.kind {
ty::Closure(def_id, substs) => {
- let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
+
if substs == polymorphized_substs {
ty
} else {
@@ -523,7 +566,12 @@ fn polymorphize<'tcx>(
}
}
ty::Generator(def_id, substs, movability) => {
- let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
+
if substs == polymorphized_substs {
ty
} else {
diff --git a/src/librustc_mir/interpret/util.rs b/src/librustc_mir/interpret/util.rs
index 57c5fc59cc0..d903b48ffce 100644
--- a/src/librustc_mir/interpret/util.rs
+++ b/src/librustc_mir/interpret/util.rs
@@ -38,7 +38,8 @@ where
ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, ..)
| ty::FnDef(def_id, substs) => {
- let unused_params = self.tcx.unused_generic_params(def_id);
+ let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+ let unused_params = self.tcx.unused_generic_params(instance);
for (index, subst) in substs.into_iter().enumerate() {
let index = index
.try_into()
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index e724180f4d8..1a95381edaa 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -764,21 +764,13 @@ fn visit_instance_use<'tcx>(
}
}
-// Returns `true` if we should codegen an instance in the local crate.
-// Returns `false` if we can just link to the upstream crate and therefore don't
-// need a mono item.
+/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
+/// can just link to the upstream crate and therefore don't need a mono item.
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
- let def_id = match instance.def {
- ty::InstanceDef::Item(def) => def.did,
- ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
- ty::InstanceDef::VtableShim(..)
- | ty::InstanceDef::ReifyShim(..)
- | ty::InstanceDef::ClosureOnceShim { .. }
- | ty::InstanceDef::Virtual(..)
- | ty::InstanceDef::FnPtrShim(..)
- | ty::InstanceDef::DropGlue(..)
- | ty::InstanceDef::Intrinsic(_)
- | ty::InstanceDef::CloneShim(..) => return true,
+ let def_id = if let Some(def_id) = instance.def.maybe_codegen_locally_def_id() {
+ def_id
+ } else {
+ return true;
};
if tcx.is_foreign_item(def_id) {
diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs
index fc9f7f1af62..2f592eb2649 100644
--- a/src/librustc_mir/monomorphize/polymorphize.rs
+++ b/src/librustc_mir/monomorphize/polymorphize.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::{
fold::{TypeFoldable, TypeVisitor},
query::Providers,
subst::SubstsRef,
- Const, Ty, TyCtxt,
+ Const, InstanceDef, Ty, TyCtxt,
};
use rustc_span::symbol::sym;
use std::convert::TryInto;
@@ -26,24 +26,27 @@ pub fn provide(providers: &mut Providers) {
providers.unused_generic_params = unused_generic_params;
}
-/// 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`
+/// Determine which generic parameters are used by the `instance`.
+///
+/// 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<u32> {
- debug!("unused_generic_params({:?})", def_id);
+fn unused_generic_params<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: InstanceDef<'tcx>,
+) -> FiniteBitSet<u32> {
+ debug!("unused_generic_params({:?})", instance);
+ // If polymorphization disabled, then all parameters are used.
if !tcx.sess.opts.debugging_opts.polymorphize {
- // If polymorphization disabled, then all parameters are used.
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() {
+ // Exit early if this instance should not be polymorphized.
+ if !should_polymorphize(tcx, instance) {
return FiniteBitSet::new_empty();
}
+ let def_id = instance.def_id();
let generics = tcx.generics_of(def_id);
debug!("unused_generic_params: generics={:?}", generics);
@@ -52,23 +55,18 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
return FiniteBitSet::new_empty();
}
- // Exit early when there is no MIR available.
- if !tcx.is_mir_available(def_id) {
- debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
- return FiniteBitSet::new_empty();
- }
-
// 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);
debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters);
+
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
// Visit MIR and accumululate used generic parameters.
- let body = tcx.optimized_mir(def_id);
+ let body = tcx.instance_mir(instance);
let mut vis =
UsedGenericParametersVisitor { tcx, def_id, unused_parameters: &mut unused_parameters };
vis.visit_body(body);
@@ -85,6 +83,40 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
unused_parameters
}
+/// Returns `true` if the `InstanceDef` should be polymorphized.
+fn should_polymorphize<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> bool {
+ // If a instance's MIR body is not polymorphic then the modified substitutions that are derived
+ // from polymorphization's result won't make any difference.
+ if !instance.has_polymorphic_mir_body() {
+ return false;
+ }
+
+ // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
+ if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) {
+ return false;
+ }
+
+ let def_id = if let Some(def_id) = instance.maybe_codegen_locally_def_id() {
+ def_id
+ } else {
+ return true;
+ };
+
+ // 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 false;
+ }
+
+ // Without available MIR, polymorphization has nothing to analyze.
+ if !tcx.is_mir_available(def_id) {
+ return false;
+ }
+
+ true
+}
+
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
@@ -214,7 +246,9 @@ impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
/// a closure, generator or constant).
fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
- let unused = self.tcx.unused_generic_params(def_id);
+ let unused = self
+ .tcx
+ .unused_generic_params(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)));
debug!(
"visit_child_body: unused_parameters={:?} unused={:?}",
self.unused_parameters, unused
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 80164840334..4835928a834 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -949,7 +949,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
(default: PLT is disabled if full relro is enabled)"),
polonius: bool = (false, parse_bool, [UNTRACKED],
"enable polonius-based borrow-checker (default: no)"),
- polymorphize: bool = (false, parse_bool, [TRACKED],
+ polymorphize: bool = (true, parse_bool, [TRACKED],
"perform polymorphization analysis"),
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to prepend the linker invocation (can be used several times)"),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment