Auto merge of #126023 - amandasystems:you-dropped-this-again, r=nikomatsakis

Remove confusing `use_polonius` flag and do less cloning

The `use_polonius` flag is both redundant and confusing since every function it's propagated to also checks if `all_facts` is `Some`, the true test of whether to generate Polonius facts for Polonius or for external consumers. This PR makes that path clearer by simply doing away with the argument and handling the logic in precisely two places: where facts are populated (check for `Some`), and where `all_facts` are initialised. It also delays some statements until after that check to avoid the miniscule performance penalty of executing them when Polonius is disabled.

This also addresses `@lqd's` concern in #125652 by reducing the size of what is cloned out of Polonius facts to just the facts being added, as opposed to the entire vector of potential inputs, and added descriptive comments.

*Reviewer note*: the comments in `add_extra_drop_facts` should be inspected by a reviewer, in particular the one on [L#259](https://github.com/rust-lang/rust/compare/master...amandasystems:you-dropped-this-again?expand=1#diff-aa727290e6670264df2face84f012897878e11a70e9c8b156543cfcd9619bac3R259) in this PR, which should be trivial for someone with the right background knowledge to address.

I also included some lints I found on the way there that I couldn't help myself from addressing.
This commit is contained in:
bors 2024-06-24 00:24:51 +00:00
commit d49994b060
13 changed files with 55 additions and 49 deletions

View File

@ -126,7 +126,7 @@ pub fn build(
) -> Self { ) -> Self {
let mut visitor = GatherBorrows { let mut visitor = GatherBorrows {
tcx, tcx,
body: body, body,
location_map: Default::default(), location_map: Default::default(),
activation_map: Default::default(), activation_map: Default::default(),
local_map: Default::default(), local_map: Default::default(),

View File

@ -213,7 +213,7 @@ pub(crate) fn cannot_reborrow_already_borrowed(
via(msg_old), via(msg_old),
); );
if msg_new == "" { if msg_new.is_empty() {
// If `msg_new` is empty, then this isn't a borrow of a union field. // If `msg_new` is empty, then this isn't a borrow of a union field.
err.span_label(span, format!("{kind_new} borrow occurs here")); err.span_label(span, format!("{kind_new} borrow occurs here"));
err.span_label(old_span, format!("{kind_old} borrow occurs here")); err.span_label(old_span, format!("{kind_old} borrow occurs here"));

View File

@ -43,9 +43,9 @@ fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
} }
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
state.borrows.clone_from(&self.borrows.entry_set_for_block(block)); state.borrows.clone_from(self.borrows.entry_set_for_block(block));
state.uninits.clone_from(&self.uninits.entry_set_for_block(block)); state.uninits.clone_from(self.uninits.entry_set_for_block(block));
state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block)); state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
} }
fn reconstruct_before_statement_effect( fn reconstruct_before_statement_effect(

View File

@ -895,7 +895,6 @@ fn add_static_impl_trait_suggestion(
for alias_ty in alias_tys { for alias_ty in alias_tys {
if alias_ty.span.desugaring_kind().is_some() { if alias_ty.span.desugaring_kind().is_some() {
// Skip `async` desugaring `impl Future`. // Skip `async` desugaring `impl Future`.
()
} }
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
if lt.ident.name == kw::Empty { if lt.ident.name == kw::Empty {

View File

@ -519,7 +519,7 @@ fn highlight_if_we_can_match_hir_ty(
} }
// Otherwise, let's descend into the referent types. // Otherwise, let's descend into the referent types.
search_stack.push((*referent_ty, &referent_hir_ty.ty)); search_stack.push((*referent_ty, referent_hir_ty.ty));
} }
// Match up something like `Foo<'1>` // Match up something like `Foo<'1>`
@ -558,7 +558,7 @@ fn highlight_if_we_can_match_hir_ty(
} }
(ty::RawPtr(mut_ty, _), hir::TyKind::Ptr(mut_hir_ty)) => { (ty::RawPtr(mut_ty, _), hir::TyKind::Ptr(mut_hir_ty)) => {
search_stack.push((*mut_ty, &mut_hir_ty.ty)); search_stack.push((*mut_ty, mut_hir_ty.ty));
} }
_ => { _ => {
@ -652,7 +652,7 @@ fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Opti
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
self.infcx.tcx, self.infcx.tcx,
&self.upvars, self.upvars,
upvar_index, upvar_index,
); );
let region_name = self.synthesize_region_name(); let region_name = self.synthesize_region_name();
@ -717,7 +717,7 @@ fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Opti
.output; .output;
span = output.span(); span = output.span();
if let hir::FnRetTy::Return(ret) = output { if let hir::FnRetTy::Return(ret) = output {
hir_ty = Some(self.get_future_inner_return_ty(*ret)); hir_ty = Some(self.get_future_inner_return_ty(ret));
} }
" of async function" " of async function"
} }
@ -958,7 +958,7 @@ fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait(
{ {
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
self.infcx.tcx, self.infcx.tcx,
&self.upvars, self.upvars,
upvar_index, upvar_index,
); );
let region_name = self.synthesize_region_name(); let region_name = self.synthesize_region_name();

View File

@ -114,7 +114,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
move_data, move_data,
elements, elements,
upvars, upvars,
polonius_input,
); );
// Create the region inference context, taking ownership of the // Create the region inference context, taking ownership of the

View File

@ -43,8 +43,8 @@ pub(crate) fn emit_facts<'tcx>(
emit_universal_region_facts( emit_universal_region_facts(
all_facts, all_facts,
borrow_set, borrow_set,
&universal_regions, universal_regions,
&universal_region_relations, universal_region_relations,
); );
emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);

View File

@ -344,7 +344,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
let reg_var = ty::RegionVid::from_usize(reg_var_idx); let reg_var = ty::RegionVid::from_usize(reg_var_idx);
let origin = var_to_origin.get(&reg_var).unwrap_or_else(|| &RegionCtxt::Unknown); let origin = var_to_origin.get(&reg_var).unwrap_or(&RegionCtxt::Unknown);
components[scc_idx.as_usize()].insert((reg_var, *origin)); components[scc_idx.as_usize()].insert((reg_var, *origin));
} }
@ -2216,7 +2216,7 @@ pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<
// #114907 where this happens via liveness and dropck outlives results. // #114907 where this happens via liveness and dropck outlives results.
// Therefore, we return a default value in case that happens, which should at worst emit a // Therefore, we return a default value in case that happens, which should at worst emit a
// suboptimal error, instead of the ICE. // suboptimal error, instead of the ICE.
self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other()) self.universe_causes.get(&universe).cloned().unwrap_or_else(UniverseInfo::other)
} }
/// Tries to find the terminator of the loop in which the region 'r' resides. /// Tries to find the terminator of the loop in which the region 'r' resides.

View File

@ -418,9 +418,7 @@ fn check_opaque_type_parameter_valid<'tcx>(
let opaque_param = opaque_generics.param_at(i, tcx); let opaque_param = opaque_generics.param_at(i, tcx);
let kind = opaque_param.kind.descr(); let kind = opaque_param.kind.descr();
if let Err(guar) = opaque_env.param_is_error(i) { opaque_env.param_is_error(i)?;
return Err(guar);
}
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg, ty: arg,

View File

@ -12,9 +12,7 @@
use std::rc::Rc; use std::rc::Rc;
use crate::{ use crate::{
constraints::OutlivesConstraintSet, constraints::OutlivesConstraintSet, region_infer::values::LivenessValues,
facts::{AllFacts, AllFactsExt},
region_infer::values::LivenessValues,
universal_regions::UniversalRegions, universal_regions::UniversalRegions,
}; };
@ -38,7 +36,6 @@ pub(super) fn generate<'mir, 'tcx>(
elements: &Rc<DenseLocationMap>, elements: &Rc<DenseLocationMap>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
use_polonius: bool,
) { ) {
debug!("liveness::generate"); debug!("liveness::generate");
@ -49,11 +46,8 @@ pub(super) fn generate<'mir, 'tcx>(
); );
let (relevant_live_locals, boring_locals) = let (relevant_live_locals, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, body); compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
if facts_enabled { polonius::populate_access_facts(typeck, body, move_data);
polonius::populate_access_facts(typeck, body, move_data);
};
trace::trace( trace::trace(
typeck, typeck,

View File

@ -87,10 +87,10 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
body: &Body<'tcx>, body: &Body<'tcx>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
) { ) {
debug!("populate_access_facts()");
let location_table = typeck.borrowck_context.location_table;
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
debug!("populate_access_facts()");
let location_table = typeck.borrowck_context.location_table;
let mut extractor = UseFactsExtractor { let mut extractor = UseFactsExtractor {
var_defined_at: &mut facts.var_defined_at, var_defined_at: &mut facts.var_defined_at,
var_used_at: &mut facts.var_used_at, var_used_at: &mut facts.var_used_at,

View File

@ -217,35 +217,52 @@ fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
/// Add facts for all locals with free regions, since regions may outlive /// Add facts for all locals with free regions, since regions may outlive
/// the function body only at certain nodes in the CFG. /// the function body only at certain nodes in the CFG.
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) -> Option<()> { fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) -> Option<()> {
let drop_used = self // This collect is more necessary than immediately apparent
.cx // because these facts go into `add_drop_live_facts_for()`,
.typeck // which also writes to `all_facts`, and so this is genuinely
.borrowck_context // a simulatneous overlapping mutable borrow.
.all_facts // FIXME for future hackers: investigate whether this is
.as_ref() // actually necessary; these facts come from Polonius
.map(|facts| facts.var_dropped_at.clone())?; // and probably maybe plausibly does not need to go back in.
// It may be necessary to just pick out the parts of
// `add_drop_live_facts_for()` that make sense.
let facts_to_add: Vec<_> = {
let drop_used = &self.cx.typeck.borrowck_context.all_facts.as_ref()?.var_dropped_at;
let relevant_live_locals: FxIndexSet<_> = relevant_live_locals.iter().copied().collect(); let relevant_live_locals: FxIndexSet<_> =
relevant_live_locals.iter().copied().collect();
let locations = IntervalSet::new(self.cx.elements.num_points()); drop_used
.iter()
.filter_map(|(local, location_index)| {
let local_ty = self.cx.body.local_decls[*local].ty;
if relevant_live_locals.contains(local) || !local_ty.has_free_regions() {
return None;
}
for (local, location_index) in drop_used {
if !relevant_live_locals.contains(&local) {
let local_ty = self.cx.body.local_decls[local].ty;
if local_ty.has_free_regions() {
let location = match self let location = match self
.cx .cx
.typeck .typeck
.borrowck_context .borrowck_context
.location_table .location_table
.to_location(location_index) .to_location(*location_index)
{ {
RichLocation::Start(l) => l, RichLocation::Start(l) => l,
RichLocation::Mid(l) => l, RichLocation::Mid(l) => l,
}; };
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
} Some((*local, local_ty, location))
} })
.collect()
};
// FIXME: these locations seem to have a special meaning (e.g. everywhere, at the end, ...), but I don't know which one. Please help me rename it to something descriptive!
// Also, if this IntervalSet is used in many places, it maybe should have a newtype'd
// name with a description of what it means for future mortals passing by.
let locations = IntervalSet::new(self.cx.elements.num_points());
for (local, local_ty, location) in facts_to_add {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
} }
Some(()) Some(())
} }

View File

@ -133,7 +133,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
elements: &Rc<DenseLocationMap>, elements: &Rc<DenseLocationMap>,
upvars: &[&ty::CapturedPlace<'tcx>], upvars: &[&ty::CapturedPlace<'tcx>],
use_polonius: bool,
) -> MirTypeckResults<'tcx> { ) -> MirTypeckResults<'tcx> {
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints { let mut constraints = MirTypeckRegionConstraints {
@ -189,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
checker.check_signature_annotation(body); checker.check_signature_annotation(body);
liveness::generate(&mut checker, body, elements, flow_inits, move_data, use_polonius); liveness::generate(&mut checker, body, elements, flow_inits, move_data);
translate_outlives_facts(&mut checker); translate_outlives_facts(&mut checker);
let opaque_type_values = infcx.take_opaque_types(); let opaque_type_values = infcx.take_opaque_types();