1
Fork 0

Rollup merge of #82765 - oli-obk:polymorphization_regression, r=davidtwco

Fix polymorphization ICE on associated types in trait decls using const generics in bounds

r? `@davidtwco`

only the last commit actually changes something
This commit is contained in:
Guillaume Gomez 2021-03-04 21:56:35 +01:00 committed by GitHub
commit f74231fd27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 54 deletions

View file

@ -438,18 +438,6 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
#[inline]
pub fn optimized_mir_or_const_arg_mir(
self,
def: ty::WithOptConstParam<DefId>,
) -> &'tcx Body<'tcx> {
if let Some((did, param_did)) = def.as_const_arg() {
self.mir_for_ctfe_of_const_arg((did, param_did))
} else {
self.optimized_mir(def.did)
}
}
#[inline] #[inline]
pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> { pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
if let Some((did, param_did)) = def.as_const_arg() { if let Some((did, param_did)) = def.as_const_arg() {

View file

@ -499,7 +499,7 @@ impl<'tcx> Instance<'tcx> {
} }
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
/// identify parameters if they are determined to be unused in `instance.def`. /// identity parameters if they are determined to be unused in `instance.def`.
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
debug!("polymorphize: running polymorphization analysis"); debug!("polymorphize: running polymorphization analysis");
if !tcx.sess.opts.debugging_opts.polymorphize { if !tcx.sess.opts.debugging_opts.polymorphize {

View file

@ -2963,7 +2963,10 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def), | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using // If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version. // `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => self.optimized_mir_or_const_arg_mir(def), _ => {
assert_eq!(def.const_param_did, None);
self.optimized_mir(def.did)
}
}, },
ty::InstanceDef::VtableShim(..) ty::InstanceDef::VtableShim(..)
| ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ReifyShim(..)

View file

@ -30,9 +30,8 @@ pub fn provide(providers: &mut Providers) {
/// Determine which generic parameters are used by the function/method/closure represented by /// 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` /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
/// indicates all parameters are used). /// indicates all parameters are used).
#[instrument(skip(tcx))]
fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> { fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
debug!("unused_generic_params({:?})", def_id);
if !tcx.sess.opts.debugging_opts.polymorphize { if !tcx.sess.opts.debugging_opts.polymorphize {
// If polymorphization disabled, then all parameters are used. // If polymorphization disabled, then all parameters are used.
return FiniteBitSet::new_empty(); return FiniteBitSet::new_empty();
@ -46,7 +45,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
} }
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);
debug!("unused_generic_params: generics={:?}", generics); debug!(?generics);
// Exit early when there are no parameters to be unused. // Exit early when there are no parameters to be unused.
if generics.count() == 0 { if generics.count() == 0 {
@ -57,11 +56,11 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
let context = tcx.hir().body_const_context(def_id.expect_local()); let context = tcx.hir().body_const_context(def_id.expect_local());
match context { match context {
Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
debug!("unused_generic_params: (no mir available) def_id={:?}", def_id); debug!("no mir available");
return FiniteBitSet::new_empty(); return FiniteBitSet::new_empty();
} }
Some(_) if !tcx.is_ctfe_mir_available(def_id) => { Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
debug!("unused_generic_params: (no ctfe mir available) def_id={:?}", def_id); debug!("no ctfe mir available");
return FiniteBitSet::new_empty(); return FiniteBitSet::new_empty();
} }
_ => {} _ => {}
@ -72,9 +71,9 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
let mut unused_parameters = FiniteBitSet::<u32>::new_empty(); let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
unused_parameters.set_range(0..generics_count); unused_parameters.set_range(0..generics_count);
debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters); debug!(?unused_parameters, "(start)");
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters); debug!(?unused_parameters, "(after default)");
// Visit MIR and accumululate used generic parameters. // Visit MIR and accumululate used generic parameters.
let body = match context { let body = match context {
@ -85,10 +84,10 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
}; };
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters }; let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
vis.visit_body(body); vis.visit_body(body);
debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters); debug!(?unused_parameters, "(after visitor)");
mark_used_by_predicates(tcx, def_id, &mut unused_parameters); mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
debug!("unused_generic_params: (end) unused_parameters={:?}", unused_parameters); debug!(?unused_parameters, "(end)");
// Emit errors for debugging and testing if enabled. // Emit errors for debugging and testing if enabled.
if !unused_parameters.is_empty() { if !unused_parameters.is_empty() {
@ -101,24 +100,55 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy /// 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 /// 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. /// be `true` if the item that `unused_generic_params` was invoked on is a closure.
#[instrument(skip(tcx, def_id, generics, unused_parameters))]
fn mark_used_by_default_parameters<'tcx>( fn mark_used_by_default_parameters<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: DefId, def_id: DefId,
generics: &'tcx ty::Generics, generics: &'tcx ty::Generics,
unused_parameters: &mut FiniteBitSet<u32>, unused_parameters: &mut FiniteBitSet<u32>,
) { ) {
if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) { match tcx.def_kind(def_id) {
for param in &generics.params { DefKind::Closure | DefKind::Generator => {
debug!("mark_used_by_default_parameters: (closure/gen) param={:?}", param); for param in &generics.params {
unused_parameters.clear(param.index); debug!(?param, "(closure/gen)");
}
} else {
for param in &generics.params {
debug!("mark_used_by_default_parameters: (other) param={:?}", param);
if let ty::GenericParamDefKind::Lifetime = param.kind {
unused_parameters.clear(param.index); unused_parameters.clear(param.index);
} }
} }
DefKind::Mod
| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static
| DefKind::Ctor(_, _)
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::Macro(_)
| DefKind::ExternCrate
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Impl => {
for param in &generics.params {
debug!(?param, "(other)");
if let ty::GenericParamDefKind::Lifetime = param.kind {
unused_parameters.clear(param.index);
}
}
}
} }
if let Some(parent) = generics.parent { if let Some(parent) = generics.parent {
@ -128,6 +158,7 @@ fn mark_used_by_default_parameters<'tcx>(
/// Search the predicates on used generic parameters for any unused generic parameters, and mark /// Search the predicates on used generic parameters for any unused generic parameters, and mark
/// those as used. /// those as used.
#[instrument(skip(tcx, def_id))]
fn mark_used_by_predicates<'tcx>( fn mark_used_by_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: DefId, def_id: DefId,
@ -135,16 +166,12 @@ fn mark_used_by_predicates<'tcx>(
) { ) {
let def_id = tcx.closure_base_def_id(def_id); let def_id = tcx.closure_base_def_id(def_id);
let predicates = tcx.explicit_predicates_of(def_id); let predicates = tcx.explicit_predicates_of(def_id);
debug!("mark_used_by_predicates: predicates_of={:?}", predicates);
let mut current_unused_parameters = FiniteBitSet::new_empty(); let mut current_unused_parameters = FiniteBitSet::new_empty();
// Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
// bit set so that this is skipped if all parameters are already used. // bit set so that this is skipped if all parameters are already used.
while current_unused_parameters != *unused_parameters { while current_unused_parameters != *unused_parameters {
debug!( debug!(?current_unused_parameters, ?unused_parameters);
"mark_used_by_predicates: current_unused_parameters={:?} = unused_parameters={:?}",
current_unused_parameters, unused_parameters
);
current_unused_parameters = *unused_parameters; current_unused_parameters = *unused_parameters;
for (predicate, _) in predicates.predicates { for (predicate, _) in predicates.predicates {
@ -169,13 +196,13 @@ fn mark_used_by_predicates<'tcx>(
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
/// parameter which was unused. /// parameter which was unused.
#[instrument(skip(tcx, generics))]
fn emit_unused_generic_params_error<'tcx>( fn emit_unused_generic_params_error<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: DefId, def_id: DefId,
generics: &'tcx ty::Generics, generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>, unused_parameters: &FiniteBitSet<u32>,
) { ) {
debug!("emit_unused_generic_params_error: def_id={:?}", def_id);
let base_def_id = tcx.closure_base_def_id(def_id); let base_def_id = tcx.closure_base_def_id(def_id);
if !tcx if !tcx
.get_attrs(base_def_id) .get_attrs(base_def_id)
@ -185,7 +212,6 @@ fn emit_unused_generic_params_error<'tcx>(
return; return;
} }
debug!("emit_unused_generic_params_error: unused_parameters={:?}", unused_parameters);
let fn_span = match tcx.opt_item_name(def_id) { let fn_span = match tcx.opt_item_name(def_id) {
Some(ident) => ident.span, Some(ident) => ident.span,
_ => tcx.def_span(def_id), _ => tcx.def_span(def_id),
@ -197,7 +223,7 @@ fn emit_unused_generic_params_error<'tcx>(
while let Some(generics) = next_generics { while let Some(generics) = next_generics {
for param in &generics.params { for param in &generics.params {
if unused_parameters.contains(param.index).unwrap_or(false) { if unused_parameters.contains(param.index).unwrap_or(false) {
debug!("emit_unused_generic_params_error: param={:?}", param); debug!(?param);
let def_span = tcx.def_span(param.def_id); let def_span = tcx.def_span(param.def_id);
err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name)); err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name));
} }
@ -219,25 +245,23 @@ struct MarkUsedGenericParams<'a, 'tcx> {
impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
/// Invoke `unused_generic_params` on a body contained within the current item (e.g. /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
/// a closure, generator or constant). /// a closure, generator or constant).
#[instrument(skip(self, def_id, substs))]
fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { 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(def_id);
debug!( debug!(?self.unused_parameters, ?unused);
"visit_child_body: unused_parameters={:?} unused={:?}",
self.unused_parameters, unused
);
for (i, arg) in substs.iter().enumerate() { for (i, arg) in substs.iter().enumerate() {
let i = i.try_into().unwrap(); let i = i.try_into().unwrap();
if !unused.contains(i).unwrap_or(false) { if !unused.contains(i).unwrap_or(false) {
arg.visit_with(self); arg.visit_with(self);
} }
} }
debug!("visit_child_body: unused_parameters={:?}", self.unused_parameters); debug!(?self.unused_parameters);
} }
} }
impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
#[instrument(skip(self, local))]
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
debug!("visit_local_decl: local_decl={:?}", local_decl);
if local == Local::from_usize(1) { if local == Local::from_usize(1) {
let def_kind = self.tcx.def_kind(self.def_id); let def_kind = self.tcx.def_kind(self.def_id);
if matches!(def_kind, DefKind::Closure | DefKind::Generator) { if matches!(def_kind, DefKind::Closure | DefKind::Generator) {
@ -245,7 +269,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
// happens because the first argument to the closure is a reference to itself and // happens because the first argument to the closure is a reference to itself and
// that will call `visit_substs`, resulting in each generic parameter captured being // that will call `visit_substs`, resulting in each generic parameter captured being
// considered used by default. // considered used by default.
debug!("visit_local_decl: skipping closure substs"); debug!("skipping closure substs");
return; return;
} }
} }
@ -263,15 +287,15 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
#[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
match c.val { match c.val {
ty::ConstKind::Param(param) => { ty::ConstKind::Param(param) => {
debug!("visit_const: param={:?}", param); debug!(?param);
self.unused_parameters.clear(param.index); self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
@ -296,15 +320,15 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
} }
} }
#[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("visit_ty: ty={:?}", ty);
if !ty.has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
match *ty.kind() { match *ty.kind() {
ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
debug!("visit_ty: def_id={:?}", def_id); debug!(?def_id);
// Avoid cycle errors with generators. // Avoid cycle errors with generators.
if def_id == self.def_id { if def_id == self.def_id {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
@ -316,7 +340,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
ty::Param(param) => { ty::Param(param) => {
debug!("visit_ty: param={:?}", param); debug!(?param);
self.unused_parameters.clear(param.index); self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
@ -333,8 +357,8 @@ struct HasUsedGenericParams<'a> {
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
type BreakTy = (); type BreakTy = ();
#[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -351,8 +375,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
} }
} }
#[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("visit_ty: ty={:?}", ty);
if !ty.has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }